Merge branch 'master' of https://github.com/spotify/backstage
@@ -93,9 +93,11 @@ jobs:
|
||||
if: ${{ steps.yarn-lock.outcome == 'success' }}
|
||||
run: yarn lerna -- run test --since origin/master -- --coverage
|
||||
|
||||
- name: test all packages
|
||||
- name: test all packages (and upload coverage)
|
||||
if: ${{ steps.yarn-lock.outcome == 'failure' }}
|
||||
run: yarn lerna -- run test -- --coverage
|
||||
run: |
|
||||
yarn lerna -- run test -- --coverage
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
- name: verify plugin template
|
||||
run: yarn lerna -- run diff -- --check
|
||||
|
||||
@@ -59,8 +59,10 @@ jobs:
|
||||
- name: verify type dependencies
|
||||
run: yarn lint:type-deps
|
||||
|
||||
- name: test
|
||||
run: yarn lerna -- run test -- --coverage
|
||||
- name: test (and upload coverage)
|
||||
run: |
|
||||
yarn lerna -- run test -- --coverage
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
# Publishes current version of packages that are not already present in the registry
|
||||
- name: publish
|
||||
|
||||
@@ -62,35 +62,7 @@ Have you started using Backstage? Adding your company to [ADOPTERS](ADOPTERS.md)
|
||||
|
||||
So...feel ready to jump in? Let's do this. 👏🏻💯
|
||||
|
||||
To run a Backstage app, you will need to have the following installed:
|
||||
|
||||
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
||||
- [NodeJS](https://nodejs.org/en/download/) - Active LTS Release, currently v12
|
||||
- [yarn](https://classic.yarnpkg.com/en/docs/install)
|
||||
|
||||
After cloning this repo, open a terminal window and start the example app using the following commands from the project root:
|
||||
|
||||
```bash
|
||||
yarn install # Install dependencies
|
||||
|
||||
yarn start # Start dev server, use --check to enable linting and type-checks
|
||||
```
|
||||
|
||||
The final `yarn start` command should open a local instance of Backstage in your browser, otherwise open one of the URLs printed in the terminal.
|
||||
|
||||
Depending on the work you're doing, you often also want to run the example backend. Start the backend in a separate terminal session using the following:
|
||||
|
||||
```bash
|
||||
cd packages/backend
|
||||
|
||||
yarn start
|
||||
|
||||
yarn lerna run mock-data # Populate the backend with mock data
|
||||
```
|
||||
|
||||
And that's it! You are good to go 👍
|
||||
|
||||
If you need help, just jump into our [Discord chatroom](https://discord.gg/MUpMjP2).
|
||||
Start by reading our [Getting Started](https://backstage.io/docs/getting-started/) page. If you need help, just jump into our [Discord chatroom](https://discord.gg/MUpMjP2).
|
||||
|
||||
# Coding Guidelines
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||

|
||||
[](https://discord.gg/EBHEGzX)
|
||||

|
||||
[](https://codecov.io/gh/spotify/backstage)
|
||||
[](https://github.com/spotify/backstage/releases)
|
||||
|
||||
## What is Backstage?
|
||||
@@ -31,33 +32,7 @@ A detailed project roadmap, including already delivered milestones, is available
|
||||
|
||||
## Getting Started
|
||||
|
||||
There are two different ways to get started with Backstage, either by creating a standalone app, or by cloning this repo. Which method you use depends on what you're planning to do.
|
||||
|
||||
Creating a standalone instance makes it simpler to customize the application for your needs whilst staying up to date with the project. You will also depend on `@backstage` packages from NPM, making the project much smaller. This is the recommended approach if you want to kick the tyres of Backstage or setup your own instance.
|
||||
|
||||
On the other hand, if you want to contribute plugins or to the project in general, it's easier to fork and clone this project. That will let you stay up to date with the latest changes, and gives you an easier path to make Pull Requests towards this repo.
|
||||
|
||||
### Creating a Standalone App
|
||||
|
||||
Backstage provides the `@backstage/create-app` package to scaffold standalone instances of Backstage. You will need to have
|
||||
[NodeJS](https://nodejs.org/en/download/) Active LTS Release installed
|
||||
(currently v12), and [yarn](https://classic.yarnpkg.com/en/docs/install). You will also need to have [Docker](https://docs.docker.com/engine/install/) installed to use some features like Software Templates and TechDocs.
|
||||
|
||||
Using `npx` you can then run the following to create an app in a chosen subdirectory of your current working directory:
|
||||
|
||||
```bash
|
||||
npx @backstage/create-app
|
||||
```
|
||||
|
||||
You will be taken through a wizard to create your app, and the output should look something like this. You can read more about this process [here](https://backstage.io/docs/getting-started/create-an-app)
|
||||
|
||||
### Contributing to Backstage
|
||||
|
||||
You can read more in our [CONTRIBUTING.md](./CONTRIBUTING.md#get-started) guide, which can help you get setup with a Backstage development environment.
|
||||
|
||||
### Next steps
|
||||
|
||||
Take a look at the [Getting Started](https://backstage.io/docs/getting-started/index) guide to learn how to set up Backstage, and how to develop on the platform.
|
||||
Check out [the documentation](https://backstage.io/docs/getting-started) on how to start using Backstage.
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ to? Edit this file
|
||||
|
||||
## Technology
|
||||
|
||||
- [What static site generator is TechDocs using?](./#what-static-site-generator-is-techdocs-using)
|
||||
- [What is the mkdocs-techdocs-core plugin?](./#what-is-the-mkdocs-techdocs-core-plugin)
|
||||
- [What static site generator is TechDocs using?](#what-static-site-generator-is-techdocs-using)
|
||||
- [What is the mkdocs-techdocs-core plugin?](#what-is-the-mkdocs-techdocs-core-plugin)
|
||||
|
||||
#### What static site generator is TechDocs using?
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ Spotify’s developer experience offering with 2,400+ documentation sites and
|
||||
|
||||
## Project roadmap
|
||||
|
||||
| Version | Description |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [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] | 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. |
|
||||
| Version | Description |
|
||||
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [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] | 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
|
||||
|
||||
@@ -1,84 +1,50 @@
|
||||
---
|
||||
id: index
|
||||
title: Running Backstage Locally
|
||||
title: Getting Started
|
||||
---
|
||||
|
||||
First make sure you are using NodeJS with an Active LTS Release, currently v12.
|
||||
This is made easy with a version manager such as nvm which allows for version
|
||||
switching.
|
||||
There are two different ways to get started with Backstage, either by creating a
|
||||
standalone app, or by cloning this repo. Which method you use depends on what
|
||||
you're planning to do.
|
||||
|
||||
Creating a standalone instance makes it simpler to customize the application for
|
||||
your needs whilst staying up to date with the project. You will also depend on
|
||||
`@backstage` packages from NPM, making the project much smaller. This is the
|
||||
recommended approach if you want to kick the tyres of Backstage or setup your
|
||||
own instance.
|
||||
|
||||
On the other hand, if you want to contribute plugins or to the project in
|
||||
general, it's easier to fork and clone this project. That will let you stay up
|
||||
to date with the latest changes, and gives you an easier path to make Pull
|
||||
Requests towards this repo.
|
||||
|
||||
### Creating a Standalone App
|
||||
|
||||
Backstage provides the `@backstage/create-app` package to scaffold standalone
|
||||
instances of Backstage. You will need to have
|
||||
[NodeJS](https://nodejs.org/en/download/) Active LTS Release installed
|
||||
(currently v12), and [yarn](https://classic.yarnpkg.com/en/docs/install). You
|
||||
will also need to have [Docker](https://docs.docker.com/engine/install/)
|
||||
installed to use some features like Software Templates and TechDocs.
|
||||
|
||||
Using `npx` you can then run the following to create an app in a chosen
|
||||
subdirectory of your current working directory:
|
||||
|
||||
```bash
|
||||
# Checking your version
|
||||
node --version
|
||||
> v14.7.0
|
||||
|
||||
# Adding a second node version
|
||||
nvm install 12
|
||||
> Downloading and installing node v12.18.3...
|
||||
> Now using node v12.18.3 (npm v6.14.6)
|
||||
npx @backstage/create-app
|
||||
```
|
||||
|
||||
To get up and running with a local Backstage to evaluate it, let's clone it off
|
||||
of GitHub and run an initial build.
|
||||
You will be taken through a wizard to create your app, and the output should
|
||||
look something like this. You can read more about this process
|
||||
[here](https://backstage.io/docs/getting-started/create-an-app).
|
||||
|
||||
```bash
|
||||
# Start from your local development folder
|
||||
git clone git@github.com:spotify/backstage.git
|
||||
cd backstage
|
||||
### Contributing to Backstage
|
||||
|
||||
# Fetch our dependencies and run an initial build
|
||||
yarn install
|
||||
yarn tsc
|
||||
yarn build
|
||||
```
|
||||
You can read more in our
|
||||
[CONTRIBUTING](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md)
|
||||
guide, which can help you get setup with a Backstage development environment.
|
||||
|
||||
Phew! Now you have a local repository that's ready to run and to add any open
|
||||
source contributions into.
|
||||
### Next steps
|
||||
|
||||
We are now going to launch two things: an example Backstage frontend app, and an
|
||||
example Backstage backend that the frontend talks to. You are going to need two
|
||||
terminal windows, both starting from the Backstage project root.
|
||||
|
||||
In the first window, run
|
||||
|
||||
```bash
|
||||
cd packages/backend
|
||||
yarn start
|
||||
```
|
||||
|
||||
That starts up a backend instance on port 7000.
|
||||
|
||||
In the other window, we will first populate the catalog with some nice mock data
|
||||
to look at, and then launch the frontend. These commands are run from the
|
||||
project root, not inside the backend directory.
|
||||
|
||||
```bash
|
||||
yarn lerna run mock-data
|
||||
yarn start
|
||||
```
|
||||
|
||||
That starts up the frontend on port 3000, and should automatically open a
|
||||
browser window showing it.
|
||||
|
||||
Congratulations! That should be it. Let us know how it went
|
||||
[on discord](https://discord.gg/EBHEGzX), file issues for any
|
||||
[feature](https://github.com/spotify/backstage/issues/new?labels=help+wanted&template=feature_template.md)
|
||||
or
|
||||
[plugin suggestions](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME),
|
||||
or
|
||||
[bugs](https://github.com/spotify/backstage/issues/new?labels=bug&template=bug_template.md)
|
||||
you have, and feel free to
|
||||
[contribute](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md)!
|
||||
|
||||
## Creating a Plugin
|
||||
|
||||
The value of Backstage grows with every new plugin that gets added. Here is a
|
||||
collection of tutorials that will guide you through setting up and extending an
|
||||
instance of Backstage with your own plugins.
|
||||
|
||||
- [Development Environment](development-environment.md)
|
||||
- [Create a Backstage Plugin](../plugins/create-a-plugin.md)
|
||||
- [Structure of a Plugin](../plugins/structure-of-a-plugin.md)
|
||||
- [Utility APIs](../api/utility-apis.md)
|
||||
|
||||
[Back to Docs](../README.md)
|
||||
Take a look at the [Running Backstage Locally](./running-backstage-locally.md)
|
||||
guide to learn how to set up Backstage, and how to develop on the platform.
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
id: running-backstage-locally
|
||||
title: Running Backstage Locally
|
||||
---
|
||||
|
||||
First make sure you are using NodeJS with an Active LTS Release, currently v12.
|
||||
This is made easy with a version manager such as nvm which allows for version
|
||||
switching.
|
||||
|
||||
```bash
|
||||
# Checking your version
|
||||
node --version
|
||||
> v14.7.0
|
||||
|
||||
# Adding a second node version
|
||||
nvm install 12
|
||||
> Downloading and installing node v12.18.3...
|
||||
> Now using node v12.18.3 (npm v6.14.6)
|
||||
```
|
||||
|
||||
To get up and running with a local Backstage to evaluate it, let's clone it off
|
||||
of GitHub and run an initial build.
|
||||
|
||||
```bash
|
||||
# Start from your local development folder
|
||||
git clone git@github.com:spotify/backstage.git
|
||||
cd backstage
|
||||
|
||||
# Fetch our dependencies and run an initial build
|
||||
yarn install
|
||||
yarn tsc
|
||||
yarn build
|
||||
```
|
||||
|
||||
Phew! Now you have a local repository that's ready to run and to add any open
|
||||
source contributions into.
|
||||
|
||||
We are now going to launch two things: an example Backstage frontend app, and an
|
||||
example Backstage backend that the frontend talks to. You are going to need two
|
||||
terminal windows, both starting from the Backstage project root.
|
||||
|
||||
In the first window, run
|
||||
|
||||
```bash
|
||||
cd packages/backend
|
||||
yarn start
|
||||
```
|
||||
|
||||
That starts up a backend instance on port 7000.
|
||||
|
||||
In the other window, we will first populate the catalog with some nice mock data
|
||||
to look at, and then launch the frontend. These commands are run from the
|
||||
project root, not inside the backend directory.
|
||||
|
||||
```bash
|
||||
yarn lerna run mock-data
|
||||
yarn start
|
||||
```
|
||||
|
||||
That starts up the frontend on port 3000, and should automatically open a
|
||||
browser window showing it.
|
||||
|
||||
Congratulations! That should be it. Let us know how it went
|
||||
[on discord](https://discord.gg/EBHEGzX), file issues for any
|
||||
[feature](https://github.com/spotify/backstage/issues/new?labels=help+wanted&template=feature_template.md)
|
||||
or
|
||||
[plugin suggestions](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME),
|
||||
or
|
||||
[bugs](https://github.com/spotify/backstage/issues/new?labels=bug&template=bug_template.md)
|
||||
you have, and feel free to
|
||||
[contribute](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md)!
|
||||
|
||||
## Creating a Plugin
|
||||
|
||||
The value of Backstage grows with every new plugin that gets added. Here is a
|
||||
collection of tutorials that will guide you through setting up and extending an
|
||||
instance of Backstage with your own plugins.
|
||||
|
||||
- [Development Environment](development-environment.md)
|
||||
- [Create a Backstage Plugin](../plugins/create-a-plugin.md)
|
||||
- [Structure of a Plugin](../plugins/structure-of-a-plugin.md)
|
||||
- [Utility APIs](../api/utility-apis.md)
|
||||
|
||||
[Back to Docs](../README.md)
|
||||
@@ -52,7 +52,10 @@ configuration will lead to the proxy acting on backend requests to
|
||||
|
||||
The value inside each route is either a simple URL string, or an object on the
|
||||
format accepted by
|
||||
[http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware).
|
||||
[http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware). It
|
||||
is also possible to limit the forwarded HTTP methods with the configuration
|
||||
`allowedMethods`, for example `allowedMethods: ['GET']` to enforce read-only
|
||||
access.
|
||||
|
||||
If the value is a string, it is assumed to correspond to:
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
],
|
||||
"Getting Started": [
|
||||
"getting-started/index",
|
||||
"getting-started/running-backstage-locally",
|
||||
"getting-started/installation",
|
||||
"getting-started/development-environment",
|
||||
"getting-started/create-an-app",
|
||||
|
||||
@@ -93,8 +93,10 @@ const siteConfig = {
|
||||
cleanUrl: true,
|
||||
|
||||
// Open Graph and Twitter card images.
|
||||
ogImage: 'img/logo-gradient-on-dark.svg',
|
||||
twitterImage: 'img/logo-gradient-on-dark.svg',
|
||||
ogImage:
|
||||
'logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_04_Icon_Teal.png',
|
||||
twitterImage:
|
||||
'logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_04_Icon_Teal.png',
|
||||
|
||||
// For sites with a sizable amount of content, set collapsible to true.
|
||||
// Expand/collapse the links and subcategories under categories.
|
||||
|
||||
|
Before Width: | Height: | Size: 299 KiB After Width: | Height: | Size: 299 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
@@ -12,7 +12,8 @@ nav:
|
||||
- Strategies for adopting: 'overview/adopting.md'
|
||||
- Logo assets: 'overview/logos.md'
|
||||
- Getting started:
|
||||
- Running Backstage locally: 'getting-started/index.md'
|
||||
- Getting Started: 'getting-started/index.md'
|
||||
- Running Backstage locally: 'getting-started/running-backstage-locally.md'
|
||||
- Installation: 'getting-started/installation.md'
|
||||
- Local development: 'getting-started/development-environment.md'
|
||||
- Demo deployment: https://backstage-demo.roadie.io
|
||||
|
||||
@@ -86,3 +86,9 @@ export const Languages = () => (
|
||||
<CodeSnippet text={PYTHON} language="python" showLineNumbers />
|
||||
</InfoCard>
|
||||
);
|
||||
|
||||
export const CopyCode = () => (
|
||||
<InfoCard title="Copy Code">
|
||||
<CodeSnippet text={JAVASCRIPT} language="javascript" showCopyCodeButton />
|
||||
</InfoCard>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
|
||||
import { CodeSnippet } from './CodeSnippet';
|
||||
@@ -55,4 +55,14 @@ describe('<CodeSnippet />', () => {
|
||||
expect(queryByText(/2/)).toBeInTheDocument();
|
||||
expect(queryByText(/3/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('copy code using button', async () => {
|
||||
document.execCommand = jest.fn();
|
||||
const rendered = render(
|
||||
wrapInTestApp(<CodeSnippet {...minProps} showCopyCodeButton />),
|
||||
);
|
||||
const button = rendered.getByTitle('Text copied to clipboard');
|
||||
fireEvent.click(button);
|
||||
expect(document.execCommand).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,19 +20,22 @@ import SyntaxHighlighter from 'react-syntax-highlighter';
|
||||
import { docco, dark } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
|
||||
import { useTheme } from '@material-ui/core';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { CopyTextButton } from '../CopyTextButton';
|
||||
|
||||
type Props = {
|
||||
text: string;
|
||||
language: string;
|
||||
showLineNumbers?: boolean;
|
||||
showCopyCodeButton?: boolean;
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
showLineNumbers: false,
|
||||
showCopyCodeButton: false,
|
||||
};
|
||||
|
||||
export const CodeSnippet: FC<Props> = props => {
|
||||
const { text, language, showLineNumbers } = {
|
||||
const { text, language, showLineNumbers, showCopyCodeButton } = {
|
||||
...defaultProps,
|
||||
...props,
|
||||
};
|
||||
@@ -41,13 +44,20 @@ export const CodeSnippet: FC<Props> = props => {
|
||||
const mode = theme.palette.type === 'dark' ? dark : docco;
|
||||
|
||||
return (
|
||||
<SyntaxHighlighter
|
||||
language={language}
|
||||
style={mode}
|
||||
showLineNumbers={showLineNumbers}
|
||||
>
|
||||
{text}
|
||||
</SyntaxHighlighter>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<SyntaxHighlighter
|
||||
language={language}
|
||||
style={mode}
|
||||
showLineNumbers={showLineNumbers}
|
||||
>
|
||||
{text}
|
||||
</SyntaxHighlighter>
|
||||
{showCopyCodeButton && (
|
||||
<div style={{ position: 'absolute', top: 0, right: 0 }}>
|
||||
<CopyTextButton text={text} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -56,4 +66,5 @@ CodeSnippet.propTypes = {
|
||||
text: PropTypes.string.isRequired,
|
||||
language: PropTypes.string.isRequired,
|
||||
showLineNumbers: PropTypes.bool,
|
||||
showCopyCodeButton: PropTypes.bool,
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
import { CopyTextButton } from './CopyTextButton';
|
||||
import {
|
||||
@@ -76,7 +76,7 @@ describe('<CopyTextButton />', () => {
|
||||
),
|
||||
);
|
||||
const button = rendered.getByTitle('mockTooltip');
|
||||
button.click();
|
||||
fireEvent.click(button);
|
||||
expect(document.execCommand).toHaveBeenCalled();
|
||||
rendered.getByText('mockTooltip');
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ export const CopyTextButton: FC<Props> = props => {
|
||||
};
|
||||
const classes = useStyles(props);
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleCopyClick: MouseEventHandler = e => {
|
||||
@@ -82,9 +82,8 @@ export const CopyTextButton: FC<Props> = props => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
style={{ position: 'absolute', top: -9999, left: 9999 }}
|
||||
defaultValue={text}
|
||||
/>
|
||||
|
||||
@@ -2,8 +2,15 @@ FROM node:12
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY . .
|
||||
# Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
|
||||
# The skeleton contains the package.json of each package in the monorepo,
|
||||
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
|
||||
ADD yarn.lock package.json skeleton.tar ./
|
||||
|
||||
RUN yarn install --frozen-lockfile --production
|
||||
|
||||
# This will copy the contents of the dist-workspace when running the build-image command.
|
||||
# Do not use this Dockerfile outside of that command, as it will copy in the source code instead.
|
||||
COPY . .
|
||||
|
||||
CMD ["node", "packages/backend"]
|
||||
|
||||
@@ -39,7 +39,7 @@ export const EntityPageApi: FC<{ entity: Entity }> = ({ entity }) => {
|
||||
<Grid container spacing={3}>
|
||||
{apiNames.map(api => (
|
||||
<Grid item xs={12} key={api}>
|
||||
<ApiDefinitionCard title={api} apiEntity={apiEntities!.get(api)} />
|
||||
<ApiDefinitionCard apiEntity={apiEntities!.get(api)} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
@@ -15,31 +15,92 @@
|
||||
*/
|
||||
|
||||
import { ApiEntity } from '@backstage/catalog-model';
|
||||
import { InfoCard } from '@backstage/core';
|
||||
import { TabbedCard, CardTab } from '@backstage/core';
|
||||
import React from 'react';
|
||||
import { ApiDefinitionWidget } from '../ApiDefinitionWidget';
|
||||
import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import { OpenApiDefinitionWidget } from '../OpenApiDefinitionWidget';
|
||||
import { AsyncApiDefinitionWidget } from '../AsyncApiDefinitionWidget';
|
||||
|
||||
type Props = {
|
||||
title?: string;
|
||||
apiEntity?: ApiEntity;
|
||||
type ApiDefinitionWidget = {
|
||||
type: string;
|
||||
title: string;
|
||||
component: (definition: string) => React.ReactElement;
|
||||
rawLanguage?: string;
|
||||
};
|
||||
|
||||
export const ApiDefinitionCard = ({ title, apiEntity }: Props) => {
|
||||
export function defaultDefinitionWidgets(): ApiDefinitionWidget[] {
|
||||
return [
|
||||
{
|
||||
type: 'openapi',
|
||||
title: 'OpenAPI',
|
||||
rawLanguage: 'yaml',
|
||||
component: definition => (
|
||||
<OpenApiDefinitionWidget definition={definition} />
|
||||
),
|
||||
},
|
||||
{
|
||||
type: 'asyncapi',
|
||||
title: 'AsyncAPI',
|
||||
rawLanguage: 'yaml',
|
||||
component: definition => (
|
||||
<AsyncApiDefinitionWidget definition={definition} />
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
type Props = {
|
||||
apiEntity?: ApiEntity;
|
||||
definitionWidgets?: ApiDefinitionWidget[];
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
definitionWidgets: defaultDefinitionWidgets(),
|
||||
};
|
||||
|
||||
export const ApiDefinitionCard = (props: Props) => {
|
||||
const { apiEntity, definitionWidgets } = {
|
||||
...defaultProps,
|
||||
...props,
|
||||
};
|
||||
|
||||
if (!apiEntity) {
|
||||
return <Alert severity="error">Could not fetch the API</Alert>;
|
||||
}
|
||||
|
||||
const definitionWidget = definitionWidgets.find(
|
||||
d => d.type === apiEntity.spec.type,
|
||||
);
|
||||
|
||||
if (definitionWidget) {
|
||||
return (
|
||||
<InfoCard title={title}>
|
||||
<Alert severity="error">Could not fetch the API</Alert>
|
||||
</InfoCard>
|
||||
<TabbedCard title={apiEntity.metadata.name}>
|
||||
<CardTab label={definitionWidget.title}>
|
||||
{definitionWidget.component(apiEntity.spec.definition)}
|
||||
</CardTab>
|
||||
<CardTab label="Raw">
|
||||
<PlainApiDefinitionWidget
|
||||
definition={apiEntity.spec.definition}
|
||||
language={definitionWidget.rawLanguage || apiEntity.spec.type}
|
||||
/>
|
||||
</CardTab>
|
||||
</TabbedCard>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<InfoCard title={title} subheader={apiEntity.spec.type}>
|
||||
<ApiDefinitionWidget
|
||||
type={apiEntity.spec.type}
|
||||
definition={apiEntity.spec.definition}
|
||||
/>
|
||||
</InfoCard>
|
||||
<TabbedCard
|
||||
title={apiEntity.metadata.name}
|
||||
children={[
|
||||
// Has to be an array, otherwise typescript doesn't like that this has only a single child
|
||||
<CardTab label={apiEntity.spec.type}>
|
||||
<PlainApiDefinitionWidget
|
||||
definition={apiEntity.spec.definition}
|
||||
language={apiEntity.spec.type}
|
||||
/>
|
||||
</CardTab>,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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 { AsyncApiDefinitionWidget } from '../AsyncApiDefinitionWidget';
|
||||
import { OpenApiDefinitionWidget } from '../OpenApiDefinitionWidget';
|
||||
import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget';
|
||||
|
||||
type Props = {
|
||||
type: string;
|
||||
definition: string;
|
||||
};
|
||||
|
||||
export const ApiDefinitionWidget = ({ type, definition }: Props) => {
|
||||
switch (type) {
|
||||
case 'openapi':
|
||||
return <OpenApiDefinitionWidget definition={definition} />;
|
||||
|
||||
case 'asyncapi':
|
||||
return <AsyncApiDefinitionWidget definition={definition} />;
|
||||
|
||||
default:
|
||||
return (
|
||||
<PlainApiDefinitionWidget definition={definition} language={type} />
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* 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 { ApiDefinitionWidget } from './ApiDefinitionWidget';
|
||||
@@ -136,7 +136,7 @@ const useStyles = makeStyles(theme => ({
|
||||
}));
|
||||
|
||||
type Props = {
|
||||
definition: any;
|
||||
definition: string;
|
||||
};
|
||||
|
||||
export const AsyncApiDefinitionWidget = ({ definition }: Props) => {
|
||||
|
||||
@@ -66,7 +66,7 @@ const useStyles = makeStyles(theme => ({
|
||||
}));
|
||||
|
||||
type Props = {
|
||||
definition: any;
|
||||
definition: string;
|
||||
};
|
||||
|
||||
export const OpenApiDefinitionWidget = ({ definition }: Props) => {
|
||||
|
||||
@@ -23,5 +23,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const PlainApiDefinitionWidget = ({ definition, language }: Props) => {
|
||||
return <CodeSnippet text={definition} language={language} />;
|
||||
return (
|
||||
<CodeSnippet text={definition} language={language} showCopyCodeButton />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,5 +15,8 @@
|
||||
*/
|
||||
|
||||
export { ApiDefinitionCard } from './ApiDefinitionCard';
|
||||
export { AsyncApiDefinitionWidget } from './AsyncApiDefinitionWidget';
|
||||
export { OpenApiDefinitionWidget } from './OpenApiDefinitionWidget';
|
||||
export { PlainApiDefinitionWidget } from './PlainApiDefinitionWidget';
|
||||
export { useComponentApiNames } from './useComponentApiNames';
|
||||
export { useComponentApiEntities } from './useComponentApiEntities';
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"@backstage/backend-common": "^0.1.1-alpha.21",
|
||||
"@backstage/config": "^0.1.1-alpha.21",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/http-proxy-middleware": "^0.19.3",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"http-proxy-middleware": "^0.19.1",
|
||||
|
||||
@@ -18,10 +18,11 @@ import { Config } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import createProxyMiddleware, {
|
||||
Config as ProxyConfig,
|
||||
Config as ProxyMiddlewareConfig,
|
||||
Proxy,
|
||||
} from 'http-proxy-middleware';
|
||||
import { Logger } from 'winston';
|
||||
import http from 'http';
|
||||
|
||||
export interface RouterOptions {
|
||||
logger: Logger;
|
||||
@@ -30,6 +31,10 @@ export interface RouterOptions {
|
||||
pathPrefix: string;
|
||||
}
|
||||
|
||||
export interface ProxyConfig extends ProxyMiddlewareConfig {
|
||||
allowedMethods?: string[];
|
||||
}
|
||||
|
||||
// Creates a proxy middleware, possibly with defaults added on top of the
|
||||
// given config.
|
||||
function buildMiddleware(
|
||||
@@ -58,7 +63,12 @@ function buildMiddleware(
|
||||
// Attach the logger to the proxy config
|
||||
fullConfig.logProvider = () => logger;
|
||||
|
||||
return createProxyMiddleware(fullConfig);
|
||||
// Only permit the allowed HTTP methods if configured
|
||||
const filter = (_pathname: string, req: http.IncomingMessage): boolean => {
|
||||
return fullConfig?.allowedMethods?.includes(req.method!) ?? true;
|
||||
};
|
||||
|
||||
return createProxyMiddleware(filter, fullConfig);
|
||||
}
|
||||
|
||||
export async function createRouter(
|
||||
|
||||
@@ -4209,7 +4209,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69"
|
||||
integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA==
|
||||
|
||||
"@types/http-proxy-middleware@*":
|
||||
"@types/http-proxy-middleware@*", "@types/http-proxy-middleware@^0.19.3":
|
||||
version "0.19.3"
|
||||
resolved "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz#b2eb96fbc0f9ac7250b5d9c4c53aade049497d03"
|
||||
integrity sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA==
|
||||
@@ -14876,11 +14876,16 @@ node-fetch-npm@^2.0.2:
|
||||
json-parse-better-errors "^1.0.0"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
node-fetch@2.6.0, node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0:
|
||||
node-fetch@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||
|
||||
node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-forge@0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
|
||||
|
||||