Merge pull request #1942 from spotify/feature/create-app-plugins

create-app: include catalog and scaffolder as part of the template
This commit is contained in:
Fredrik Adelöw
2020-08-19 18:14:50 +02:00
committed by GitHub
25 changed files with 172 additions and 262 deletions
+1 -1
View File
@@ -246,7 +246,7 @@ async function testAppServe(pluginName, appDir) {
try {
const browser = new Browser();
await waitForPageWithText(browser, '/', 'Welcome to Backstage');
await waitForPageWithText(browser, '/', 'Backstage Service Catalog');
await waitForPageWithText(
browser,
`/${pluginName}`,
@@ -0,0 +1,33 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Coverage directory generated when running tests with coverage
coverage
# Dependencies
node_modules/
# Node version directives
.nvmrc
# dotenv environment variables file
.env
.env.test
# Build output
dist
# Temporary change files created by Vim
*.swp
# MkDocs build output
site
# Local configuration files
*.local.yaml
@@ -24,3 +24,33 @@ techdocs:
auth:
providers: {}
catalog:
locations:
# Backstage Example Component
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-order-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/podcast-api-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/queue-proxy-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/searcher-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-lib-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/www-artist-component.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/shuffle-api-component.yaml
# Backstage Example Templates
- type: github
target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml
- type: github
target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml
- type: github
target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml
@@ -1,8 +1,6 @@
describe('App', () => {
it('should render the welcome page', () => {
it('should render the catalog', () => {
cy.visit('/');
cy.contains('Welcome to Backstage');
cy.contains('Getting Started');
cy.contains('Quick Links');
cy.contains('Backstage Service Catalog');
});
});
@@ -5,13 +5,14 @@
"dependencies": {
"@material-ui/core": "^4.9.1",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
"@backstage/cli": "^{{version}}",
"@backstage/core": "^{{version}}",
"@backstage/plugin-catalog": "^{{version}}",
"@backstage/plugin-register-component": "^{{version}}",
"@backstage/plugin-scaffolder": "^{{version}}",
"@backstage/test-utils": "^{{version}}",
"@backstage/theme": "^{{version}}",
"history": "^5.0.0",
"plugin-welcome": "0.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router": "6.0.0-beta.0",
@@ -10,6 +10,7 @@ describe('App', () => {
{
data: {
app: { title: 'Test' },
backend: { baseUrl: 'http://localhost:7000' },
},
context: 'test',
},
@@ -1,8 +1,16 @@
import { createApp } from '@backstage/core';
import React, { FC } from 'react';
import {
createApp,
AlertDisplay,
OAuthRequestDialog,
SidebarPage,
} from '@backstage/core';
import { apis } from './apis';
import * as plugins from './plugins';
import { AppSidebar } from './sidebar';
const app = createApp({
apis,
plugins: Object.values(plugins),
});
@@ -12,8 +20,13 @@ const AppRoutes = app.getRoutes();
const App: FC<{}> = () => (
<AppProvider>
<AlertDisplay />
<OAuthRequestDialog />
<AppRouter>
<AppRoutes />
<SidebarPage>
<AppSidebar />
<AppRoutes />
</SidebarPage>
</AppRouter>
</AppProvider>
);
@@ -0,0 +1,53 @@
import {
ApiRegistry,
alertApiRef,
errorApiRef,
AlertApiForwarder,
ConfigApi,
ErrorApiForwarder,
ErrorAlerter,
oauthRequestApiRef,
OAuthRequestManager,
storageApiRef,
WebStorage,
} from '@backstage/core';
import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog';
import { scaffolderApiRef, ScaffolderApi } from '@backstage/plugin-scaffolder';
export const apis = (config: ConfigApi) => {
// eslint-disable-next-line no-console
console.log(`Creating APIs for ${config.getString('app.title')}`);
const backendUrl = config.getString('backend.baseUrl');
const builder = ApiRegistry.builder();
const alertApi = builder.add(alertApiRef, new AlertApiForwarder());
const errorApi = builder.add(
errorApiRef,
new ErrorAlerter(alertApi, new ErrorApiForwarder()),
);
builder.add(storageApiRef, WebStorage.create({ errorApi }));
builder.add(oauthRequestApiRef, new OAuthRequestManager());
builder.add(
catalogApiRef,
new CatalogClient({
apiOrigin: backendUrl,
basePath: '/catalog',
}),
);
builder.add(
scaffolderApiRef,
new ScaffolderApi({
apiOrigin: backendUrl,
basePath: '/scaffolder/v1',
}),
);
return builder.build();
};
@@ -1 +1,3 @@
export { plugin as WelcomePlugin } from 'plugin-welcome';
export { plugin as CatalogPlugin } from '@backstage/plugin-catalog';
export { plugin as RegisterComponent } from '@backstage/plugin-register-component';
export { plugin as ScaffolderPlugin } from '@backstage/plugin-scaffolder';
@@ -0,0 +1,28 @@
import React from 'react';
import HomeIcon from '@material-ui/icons/Home';
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
import {
Sidebar,
SidebarItem,
SidebarDivider,
SidebarSpace,
SidebarUserSettings,
SidebarThemeToggle,
SidebarPinButton,
} from '@backstage/core';
export const AppSidebar = () => (
<Sidebar>
<SidebarDivider />
{/* Global nav, not org-specific */}
<SidebarItem icon={HomeIcon} to="./" text="Home" />
<SidebarItem icon={CreateComponentIcon} to="create" text="Create..." />
{/* End global nav */}
<SidebarDivider />
<SidebarSpace />
<SidebarDivider />
<SidebarThemeToggle />
<SidebarUserSettings />
<SidebarPinButton />
</Sidebar>
);
@@ -1,3 +0,0 @@
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint')],
};
@@ -1,3 +0,0 @@
# Title
Welcome to the welcome plugin!
@@ -1,4 +0,0 @@
import { createDevApp } from '@backstage/dev-utils';
import { plugin } from '../src/plugin';
createDevApp().registerPlugin(plugin).render();
@@ -1,41 +0,0 @@
{
"name": "plugin-welcome",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
"private": true,
"publishConfig": {
"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": "^{{version}}",
"@backstage/theme": "^{{version}}",
"@material-ui/core": "^4.9.1",
"@material-ui/icons": "^4.9.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-use": "^15.3.3",
"react-router-dom": "6.0.0-beta.0"
},
"devDependencies": {
"@backstage/cli": "^{{version}}",
"@backstage/dev-utils": "^{{version}}",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"jest-fetch-mock": "^3.0.3"
},
"files": [
"dist"
]
}
@@ -1,58 +0,0 @@
import React, { FC } from 'react';
import { HeaderLabel } from '@backstage/core';
const timeFormat = { hour: '2-digit', minute: '2-digit' };
const utcOptions = { timeZone: 'UTC', ...timeFormat };
const nycOptions = { timeZone: 'America/New_York', ...timeFormat };
const tyoOptions = { timeZone: 'Asia/Tokyo', ...timeFormat };
const stoOptions = { timeZone: 'Europe/Stockholm', ...timeFormat };
const defaultTimes = {
timeNY: '',
timeUTC: '',
timeTYO: '',
timeSTO: '',
};
function getTimes() {
const d = new Date();
const lang = window.navigator.language;
// Using the browser native toLocaleTimeString instead of huge moment-tz
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString
const timeNY = d.toLocaleTimeString(lang, nycOptions);
const timeUTC = d.toLocaleTimeString(lang, utcOptions);
const timeTYO = d.toLocaleTimeString(lang, tyoOptions);
const timeSTO = d.toLocaleTimeString(lang, stoOptions);
return { timeNY, timeUTC, timeTYO, timeSTO };
}
const HomePageTimer: FC<{}> = () => {
const [{ timeNY, timeUTC, timeTYO, timeSTO }, setTimes] = React.useState(
defaultTimes,
);
React.useEffect(() => {
setTimes(getTimes());
const intervalId = setInterval(() => {
setTimes(getTimes());
}, 1000);
return () => {
clearInterval(intervalId);
};
}, []);
return (
<>
<HeaderLabel label="NYC" value={timeNY} />
<HeaderLabel label="UTC" value={timeUTC} />
<HeaderLabel label="STO" value={timeSTO} />
<HeaderLabel label="TYO" value={timeTYO} />
</>
);
};
export default HomePageTimer;
@@ -1 +0,0 @@
export { default } from './Timer';
@@ -1,16 +0,0 @@
import React from 'react';
import { render } from '@testing-library/react';
import WelcomePage from './WelcomePage';
import { ThemeProvider } from '@material-ui/core';
import { lightTheme } from '@backstage/theme';
describe('WelcomePage', () => {
it('should render', () => {
const rendered = render(
<ThemeProvider theme={lightTheme}>
<WelcomePage />
</ThemeProvider>,
);
expect(rendered.baseElement).toBeInTheDocument();
});
});
@@ -1,106 +0,0 @@
import React, { FC } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import {
Typography,
Grid,
List,
ListItem,
ListItemText,
Link,
} from '@material-ui/core';
import Timer from '../Timer';
import {
Content,
InfoCard,
Header,
Page,
pageTheme,
ContentHeader,
SupportButton,
} from '@backstage/core';
const WelcomePage: FC<{}> = () => {
const profile = { givenName: '' };
return (
<Page theme={pageTheme.home}>
<Header
title={`Welcome ${profile.givenName || 'to Backstage'}`}
subtitle="Some quick intro and links."
>
<Timer />
</Header>
<Content>
<ContentHeader title="Getting Started">
<SupportButton />
</ContentHeader>
<Grid container>
<Grid item xs={12} md={6}>
<InfoCard>
<Typography variant="body1" gutterBottom>
You now have a running instance of Backstage!
<span role="img" aria-label="confetti">
🎉
</span>
Let's make sure you get the most out of this platform by walking
you through the basics.
</Typography>
<Typography variant="h6" gutterBottom>
The Setup
</Typography>
<Typography variant="body1" paragraph>
Backstage is put together from three base concepts: the core,
the app and the plugins.
</Typography>
<List>
<ListItem>
<ListItemText primary="The core is responsible for base functionality." />
</ListItem>
<ListItem>
<ListItemText primary="The app provides the base UI and connects the plugins." />
</ListItem>
<ListItem>
<ListItemText
primary="The plugins make Backstage useful for the end users with
specific views and functionality."
/>
</ListItem>
</List>
<Typography variant="h6" gutterBottom>
Try It Out
</Typography>
<Typography variant="body1" paragraph>
We suggest you either check out the documentation for{' '}
<Link href="https://github.com/spotify/backstage/blob/master/docs/plugins/create-a-plugin.md">
creating a plugin
</Link>{' '}
or have a look in the code for the{' '}
<Link component={RouterLink} to="/home">
Home Page
</Link>{' '}
in the directory "plugins/home-page/src".
</Typography>
</InfoCard>
</Grid>
<Grid item>
<InfoCard>
<Typography variant="h5">Quick Links</Typography>
<List>
<ListItem>
<Link href="https://backstage.io">backstage.io</Link>
</ListItem>
<ListItem>
<Link href="https://github.com/spotify/backstage/blob/master/docs/plugins/create-a-plugin.md">
Create a plugin
</Link>
</ListItem>
</List>
</InfoCard>
</Grid>
</Grid>
</Content>
</Page>
);
};
export default WelcomePage;
@@ -1 +0,0 @@
export { default } from './WelcomePage';
@@ -1 +0,0 @@
export { plugin } from './plugin';
@@ -1,7 +0,0 @@
import { plugin } from './plugin';
describe('welcome', () => {
it('should export plugin', () => {
expect(plugin).toBeDefined();
});
});
@@ -1,9 +0,0 @@
import { createPlugin } from '@backstage/core';
import WelcomePage from './components/WelcomePage';
export const plugin = createPlugin({
id: 'welcome',
register({ router }) {
router.registerRoute('/', WelcomePage);
},
});
@@ -1 +0,0 @@
import '@testing-library/jest-dom';
@@ -9,6 +9,7 @@
"exclude": ["node_modules"],
"compilerOptions": {
"outDir": "dist",
"rootDir": ".",
"skipLibCheck": true
}
}
+2 -1
View File
@@ -7,6 +7,7 @@
"plugins/*/migrations"
],
"compilerOptions": {
"outDir": "dist"
"outDir": "dist",
"rootDir": "."
}
}