diff --git a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml index 17f9ebbf7d..058e2a715f 100644 --- a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml @@ -4,7 +4,9 @@ metadata: name: react-ssr-template title: React SSR Template description: Next.js application skeleton for creating isomorphic web applications. + annotations: + tags: Recommended,React spec: - type: cookiecutter + processor: cookiecutter + type: website path: '.' - diff --git a/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml b/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml new file mode 100644 index 0000000000..d44d926ef4 --- /dev/null +++ b/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Template +metadata: + name: springboot-template + title: Spring Boot Service + description: Standard Spring Boot (Java) microservice with recommended configuration. + annotations: + tags: Recommended,Java +spec: + processor: cookiecutter + type: service + path: '.' diff --git a/plugins/scaffolder-backend/scripts/mock-data b/plugins/scaffolder-backend/scripts/mock-data index be3fa2b6cf..594bd76607 100755 --- a/plugins/scaffolder-backend/scripts/mock-data +++ b/plugins/scaffolder-backend/scripts/mock-data @@ -1,8 +1,12 @@ #!/usr/bin/env bash -curl \ ---location \ ---request POST 'localhost:7000/catalog/locations' \ ---header 'Content-Type: application/json' \ ---data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/react-ssr-template/template.yaml\"}" - +for URL in \ + 'react-ssr-template' \ + 'springboot-template' \ +; do \ + curl \ + --location \ + --request POST 'localhost:7000/catalog/locations' \ + --header 'Content-Type: application/json' \ + --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/${URL}/template.yaml\"}" +done diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 6710fdc1f7..683d277be2 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -31,7 +31,8 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-router-dom": "6.0.0-alpha.5", - "react-use": "^14.2.0" + "react-use": "^14.2.0", + "swr": "^0.2.2" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.9", diff --git a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx index 1dbd993d93..a6dbac8f83 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { Lifecycle, Content, @@ -24,6 +24,7 @@ import { Page, pageTheme, useApi, + errorApiRef, } from '@backstage/core'; import { catalogApiRef } from '@backstage/plugin-catalog'; import { @@ -35,25 +36,25 @@ import { } from '@material-ui/core'; import { Link as RouterLink } from 'react-router-dom'; import TemplateCard from '../TemplateCard'; -import { useAsync } from 'react-use'; +import useStaleWhileRevalidate from 'swr'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; const ScaffolderPage: React.FC<{}> = () => { const catalogApi = useApi(catalogApiRef); + const errorApi = useApi(errorApiRef); - const { value, loading } = useAsync(async () => { - const entities = await catalogApi.getEntities({ kind: 'Template' }); - return (entities as TemplateEntityV1alpha1[]).map(template => ({ - id: template.metadata.uid, - type: template.spec.type, - name: template.metadata.name, - // TODO(shmidt-i): decide on tags - tags: ['not-implemented'], - description: template.metadata.description ?? '-', - // TODO(shmidt-i): decide on owner - ownerId: '-', - })); - }); + const { data: templates, isValidating, error } = useStaleWhileRevalidate( + 'templates/all', + async () => + catalogApi.getEntities({ kind: 'Template' }) as Promise< + TemplateEntityV1alpha1[] + >, + ); + + useEffect(() => { + if (!error) return; + errorApi.post(error); + }, [error, errorApi]); return ( @@ -89,23 +90,26 @@ const ScaffolderPage: React.FC<{}> = () => { . - {loading ? ( - - ) : ( - - {value!.map(item => { + {isValidating && } + + {templates && + templates.map(template => { return ( - + + + ); })} - - )} + ); diff --git a/plugins/scaffolder/src/components/TemplateCard.tsx b/plugins/scaffolder/src/components/TemplateCard.tsx index 618eda64f1..6d47f05693 100644 --- a/plugins/scaffolder/src/components/TemplateCard.tsx +++ b/plugins/scaffolder/src/components/TemplateCard.tsx @@ -14,14 +14,7 @@ * limitations under the License. */ import React, { FC } from 'react'; -import { - Button, - Card, - Chip, - Grid, - Typography, - makeStyles, -} from '@material-ui/core'; +import { Button, Card, Chip, Typography, makeStyles } from '@material-ui/core'; const useStyles = makeStyles(theme => ({ header: { @@ -59,25 +52,23 @@ const TemplateCard: FC = ({ const classes = useStyles(); return ( - - -
- {type} - {title} + +
+ {type} + {title} +
+
+ {tags?.map(tag => ( + + ))} + + {description} + +
+
-
- {tags?.map(tag => ( - - ))} - - {description} - -
- -
-
- - +
+
); };