Generate documentation for registered actions
Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}>;
|
||||
|
||||
Reference in New Issue
Block a user