Generate documentation for registered actions

Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2021-03-05 14:54:28 +01:00
parent f864373df1
commit a195fd752f
7 changed files with 208 additions and 1 deletions
@@ -38,4 +38,8 @@ export class TemplateActionRegistry {
}
return action;
}
list(): TemplateAction<any>[] {
return [...this.actions.values()];
}
}
@@ -347,6 +347,15 @@ export async function createRouter(
}
},
)
.get('/v2/actions', async (_req, res) => {
const actionsList = actionRegistry.list().map(action => {
return {
id: action.id,
schema: action.schema,
};
});
res.json(actionsList);
})
.post('/v2/tasks', async (req, res) => {
const templateName: string = req.body.templateName;
const values: TemplaterValues = req.body.values;
+13 -1
View File
@@ -25,7 +25,7 @@ import {
} from '@backstage/core';
import { ScmIntegrations } from '@backstage/integration';
import ObservableImpl from 'zen-observable';
import { ScaffolderTask, Status } from './types';
import { ListActionsResponse, ScaffolderTask, Status } from './types';
export const scaffolderApiRef = createApiRef<ScaffolderApi>({
id: 'plugin.scaffolder.service',
@@ -72,6 +72,9 @@ export interface ScaffolderApi {
allowedHosts: string[];
}): Promise<{ type: string; title: string; host: string }[]>;
// Returns a list of all installed actions.
listActions(): Promise<ListActionsResponse>;
streamLogs({
taskId,
after,
@@ -227,4 +230,13 @@ export class ScaffolderClient implements ScaffolderApi {
);
});
}
/**
* @Returns ListActionsResponse containg all registered actions.
*/
async listActions(): Promise<ListActionsResponse> {
const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');
const response = await fetch(`${baseUrl}/v2/actions`);
return await response.json();
}
}
@@ -0,0 +1,154 @@
/*
* Copyright 2021 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 { useAsync } from 'react-use';
import {
useApi,
Progress,
Content,
Header,
Page,
ErrorPage,
Button,
ItemCardGrid,
ItemCardHeader,
} from '@backstage/core';
import { scaffolderApiRef } from '../../api';
import {
Card,
CardMedia,
CardContent,
CardActions,
Typography,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
makeStyles,
} from '@material-ui/core';
import { JSONSchema } from '@backstage/catalog-model';
const useStyles = makeStyles({
table: {
// minWidth: 650,
},
});
export const ActionsPage = () => {
const api = useApi(scaffolderApiRef);
const classes = useStyles();
const { loading, value, error } = useAsync(async () => {
return api.listActions();
});
if (loading) {
return <Progress />;
}
if (error) {
return (
<ErrorPage
statusMessage="Failed to load installed actions"
status="500"
/>
);
}
const formatRows = (input: JSONSchema) => {
const properties = input.properties;
if (!properties) {
return undefined;
}
const required = input.required ? input.required : [];
return Object.entries(properties).map(entry => {
const [key, props] = entry;
const isRequired = required.includes(key);
return (
<TableRow key={key}>
<TableCell>
{key}
{isRequired && <strong>*</strong>}
</TableCell>
<TableCell>{props.title}</TableCell>
<TableCell>{props.description}</TableCell>
<TableCell>{props.type}</TableCell>
</TableRow>
);
});
};
const items = value?.map(action => {
if (action.id.startsWith('legacy:')) {
return undefined;
}
return (
<>
<Typography variant="h4">{action.id}</Typography>
{action.schema?.input && (
<>
<Typography variant="h6">Input</Typography>
<TableContainer component={Paper}>
<Table size="small" className={classes.table}>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Title</TableCell>
<TableCell>Description</TableCell>
<TableCell>Type</TableCell>
</TableRow>
</TableHead>
<TableBody>{formatRows(action.schema?.input)}</TableBody>
</Table>
</TableContainer>
</>
)}
{action.schema?.output && (
<>
<Typography variant="h6">Output</Typography>
<TableContainer component={Paper}>
<Table size="small" className={classes.table}>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Title</TableCell>
<TableCell>Description</TableCell>
<TableCell>Type</TableCell>
</TableRow>
</TableHead>
<TableBody>{formatRows(action.schema?.output)}</TableBody>
</Table>
</TableContainer>
</>
)}
</>
);
});
return (
<Page themeId="home">
<Header
pageTitleOverride="Create a New Component"
title="Installed actions"
subtitle="This is the collection of all installed actions"
/>
<Content>{items}</Content>
</Page>
);
};
@@ -0,0 +1,17 @@
/*
* Copyright 2021 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 { ActionsPage } from './ActionsPage';
@@ -19,11 +19,13 @@ import { Routes, Route } from 'react-router';
import { ScaffolderPage } from './ScaffolderPage';
import { TemplatePage } from './TemplatePage';
import { TaskPage } from './TaskPage';
import { ActionsPage } from './ActionsPage';
export const Router = () => (
<Routes>
<Route path="/" element={<ScaffolderPage />} />
<Route path="/templates/:templateName" element={<TemplatePage />} />
<Route path="/tasks/:taskId" element={<TaskPage />} />
<Route path="/actions" element={<ActionsPage />} />
</Routes>
);
+9
View File
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JSONSchema } from '@backstage/catalog-model';
import { JsonValue } from '@backstage/config';
export type Status = 'open' | 'processing' | 'failed' | 'completed';
@@ -54,3 +55,11 @@ export type ScaffolderTask = {
lastHeartbeatAt: string;
createdAt: string;
};
export type ListActionsResponse = Array<{
id: string;
schema?: {
input?: JSONSchema;
output?: JSONSchema;
};
}>;