Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
"@backstage/core": "^0.1.1-alpha.21",
|
||||
"@backstage/plugin-catalog": "^0.1.1-alpha.21",
|
||||
"@backstage/theme": "^0.1.1-alpha.21",
|
||||
"@material-ui/core": "^4.9.1",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
"@rjsf/core": "^2.1.0",
|
||||
|
||||
@@ -30,6 +30,8 @@ export class ScaffolderApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the scaffolding of a component, given a template and its
|
||||
* parameter values.
|
||||
*
|
||||
* @param template Template entity for the scaffolder to use. New project is going to be created out of this template.
|
||||
* @param values Parameters for the template, e.g. name, description
|
||||
@@ -49,7 +51,9 @@ export class ScaffolderApi {
|
||||
});
|
||||
|
||||
if (response.status !== 201) {
|
||||
throw new Error(await response.text());
|
||||
const status = `${response.status} ${response.statusText}`;
|
||||
const body = await response.text();
|
||||
throw new Error(`Backend request failed, ${status} ${body.trim()}`);
|
||||
}
|
||||
|
||||
const { id } = await response.json();
|
||||
@@ -57,9 +61,8 @@ export class ScaffolderApi {
|
||||
}
|
||||
|
||||
async getJob(jobId: string) {
|
||||
const url = `${await this.discoveryApi.getBaseUrl(
|
||||
'scaffolder',
|
||||
)}/v1/job/${encodeURIComponent(jobId)}`;
|
||||
const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');
|
||||
const url = `${baseUrl}/v1/job/${encodeURIComponent(jobId)}`;
|
||||
return fetch(url).then(x => x.json());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Box,
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
AccordionSummary,
|
||||
Box,
|
||||
CircularProgress,
|
||||
LinearProgress,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
|
||||
import cn from 'classnames';
|
||||
import moment from 'moment';
|
||||
import React, { Suspense, useEffect, useState } from 'react';
|
||||
@@ -37,8 +40,7 @@ const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
button: {
|
||||
order: -1,
|
||||
marginRight: 0,
|
||||
marginLeft: '-20px',
|
||||
margin: '0 1em 0 -20px',
|
||||
},
|
||||
cardContent: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
@@ -109,7 +111,7 @@ export const JobStage = ({ endedAt, startedAt, name, log, status }: Props) => {
|
||||
onChange={(_, newState) => setExpanded(newState)}
|
||||
>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
expandIcon={expanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
aria-controls={`panel-${name}-content`}
|
||||
id={`panel-${name}-header`}
|
||||
IconButtonProps={{
|
||||
@@ -117,7 +119,8 @@ export const JobStage = ({ endedAt, startedAt, name, log, status }: Props) => {
|
||||
}}
|
||||
>
|
||||
<Typography variant="button">
|
||||
{name} {timeElapsed && `(${timeElapsed})`}
|
||||
{name} {timeElapsed && `(${timeElapsed})`}{' '}
|
||||
{startedAt && !endedAt && <CircularProgress size="1em" />}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails className={classes.accordionDetails}>
|
||||
|
||||
@@ -51,7 +51,7 @@ export const JobStatusModal = ({
|
||||
return (
|
||||
<Dialog open onClose={onClose} fullWidth>
|
||||
<DialogTitle id="responsive-dialog-title">
|
||||
Creating component...
|
||||
Creating Component...
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{!job ? (
|
||||
|
||||
@@ -26,9 +26,10 @@ import {
|
||||
Progress,
|
||||
SupportButton,
|
||||
useApi,
|
||||
WarningPanel,
|
||||
} from '@backstage/core';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog';
|
||||
import { Button, Grid, Typography, Link } from '@material-ui/core';
|
||||
import { Button, Grid, Link, Typography } from '@material-ui/core';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import useStaleWhileRevalidate from 'swr';
|
||||
@@ -46,7 +47,8 @@ const getTemplateCardProps = (
|
||||
tags: (template.metadata?.tags as string[]) ?? [],
|
||||
};
|
||||
};
|
||||
export const ScaffolderPage: React.FC<{}> = () => {
|
||||
|
||||
export const ScaffolderPage = () => {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const errorApi = useApi(errorApiRef);
|
||||
|
||||
@@ -66,23 +68,23 @@ export const ScaffolderPage: React.FC<{}> = () => {
|
||||
return (
|
||||
<Page theme={pageTheme.home}>
|
||||
<Header
|
||||
pageTitleOverride="Create a new component"
|
||||
pageTitleOverride="Create a New Component"
|
||||
title={
|
||||
<>
|
||||
Create a new component <Lifecycle alpha shorthand />
|
||||
Create a New Component <Lifecycle alpha shorthand />
|
||||
</>
|
||||
}
|
||||
subtitle="Create new software components using standard templates"
|
||||
/>
|
||||
<Content>
|
||||
<ContentHeader title="Available templates">
|
||||
<ContentHeader title="Available Templates">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
component={RouterLink}
|
||||
to="/register-component"
|
||||
>
|
||||
Register existing component
|
||||
Register Existing Component
|
||||
</Button>
|
||||
<SupportButton>
|
||||
Create new software components using standard templates. Different
|
||||
@@ -101,16 +103,16 @@ export const ScaffolderPage: React.FC<{}> = () => {
|
||||
</Typography>
|
||||
)}
|
||||
{error && (
|
||||
<Typography variant="body2">
|
||||
<WarningPanel>
|
||||
Oops! Something went wrong loading the templates: {error.message}
|
||||
</Typography>
|
||||
</WarningPanel>
|
||||
)}
|
||||
<Grid container>
|
||||
{templates &&
|
||||
templates?.length > 0 &&
|
||||
templates.map(template => {
|
||||
return (
|
||||
<Grid item xs={12} sm={6} md={3}>
|
||||
<Grid key={template.metadata.uid} item xs={12} sm={6} md={3}>
|
||||
<TemplateCard {...getTemplateCardProps(template)} />
|
||||
</Grid>
|
||||
);
|
||||
|
||||
@@ -23,8 +23,8 @@ const useStyles = makeStyles(theme => ({
|
||||
header: {
|
||||
color: theme.palette.common.white,
|
||||
padding: theme.spacing(2, 2, 6),
|
||||
backgroundImage: (props: { gradientStart: string; gradientStop: string }) =>
|
||||
`linear-gradient(-137deg, ${props.gradientStart} 0%, ${props.gradientStop} 100%)`,
|
||||
backgroundImage: (props: { backgroundImage: string }) =>
|
||||
props.backgroundImage,
|
||||
},
|
||||
content: {
|
||||
padding: theme.spacing(2),
|
||||
@@ -56,8 +56,7 @@ export const TemplateCard = ({
|
||||
name,
|
||||
}: TemplateCardProps) => {
|
||||
const theme = pageTheme[type] ?? pageTheme.other;
|
||||
const [gradientStart, gradientStop] = theme.colors;
|
||||
const classes = useStyles({ gradientStart, gradientStop });
|
||||
const classes = useStyles({ backgroundImage: theme.backgroundImage });
|
||||
const href = generatePath(templateRoute.path, { templateName: name });
|
||||
|
||||
return (
|
||||
|
||||
@@ -91,8 +91,12 @@ export const TemplatePage = () => {
|
||||
const handleClose = () => setJobId(null);
|
||||
|
||||
const handleCreate = async () => {
|
||||
const job = await scaffolderApi.scaffold(template!, formState);
|
||||
setJobId(job);
|
||||
try {
|
||||
const job = await scaffolderApi.scaffold(template!, formState);
|
||||
setJobId(job);
|
||||
} catch (e) {
|
||||
errorApi.post(e);
|
||||
}
|
||||
};
|
||||
|
||||
const [entity, setEntity] = React.useState<TemplateEntityV1alpha1 | null>(
|
||||
@@ -157,7 +161,7 @@ export const TemplatePage = () => {
|
||||
/>
|
||||
)}
|
||||
{template && (
|
||||
<InfoCard title={template.metadata.title as string} noPadding>
|
||||
<InfoCard title={template.metadata.title} noPadding>
|
||||
<MultistepJsonForm
|
||||
formData={formState}
|
||||
onChange={handleChange}
|
||||
|
||||
@@ -14,13 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createPlugin } from '@backstage/core';
|
||||
import {
|
||||
createPlugin,
|
||||
createApiFactory,
|
||||
discoveryApiRef,
|
||||
} from '@backstage/core';
|
||||
import { ScaffolderPage } from './components/ScaffolderPage';
|
||||
import { TemplatePage } from './components/TemplatePage';
|
||||
import { rootRoute, templateRoute } from './routes';
|
||||
import { scaffolderApiRef, ScaffolderApi } from './api';
|
||||
|
||||
export const plugin = createPlugin({
|
||||
id: 'scaffolder',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: scaffolderApiRef,
|
||||
deps: { discoveryApi: discoveryApiRef },
|
||||
factory: ({ discoveryApi }) => new ScaffolderApi({ discoveryApi }),
|
||||
}),
|
||||
],
|
||||
register({ router }) {
|
||||
router.addRoute(rootRoute, ScaffolderPage);
|
||||
router.addRoute(templateRoute, TemplatePage);
|
||||
|
||||
Reference in New Issue
Block a user