Scaffolder: display entity button
Co-authored-by: Fredrik Adelöw <freben@gmail.com> Co-authored-by: blam<ben@blam.sh>
This commit is contained in:
@@ -45,11 +45,11 @@ export function registerLegacyActions(
|
||||
registry.register({
|
||||
id: 'legacy:prepare',
|
||||
async handler(ctx) {
|
||||
ctx.logger.info('Preparing the skeleton');
|
||||
const { protocol, url } = ctx.parameters;
|
||||
const preparer =
|
||||
protocol === 'file' ? new FilePreparer() : preparers.get(url as string);
|
||||
|
||||
ctx.logger.info('Prepare the skeleton');
|
||||
await preparer.prepare({
|
||||
url: url as string,
|
||||
logger: ctx.logger,
|
||||
@@ -61,11 +61,8 @@ export function registerLegacyActions(
|
||||
registry.register({
|
||||
id: 'legacy:template',
|
||||
async handler(ctx) {
|
||||
const { logger } = ctx;
|
||||
|
||||
ctx.logger.info('Running the templater');
|
||||
const templater = templaters.get(ctx.parameters.templater as string);
|
||||
|
||||
logger.info('Run the templater');
|
||||
await templater.run({
|
||||
workspacePath: ctx.workspacePath,
|
||||
dockerClient,
|
||||
@@ -120,15 +117,14 @@ export function registerLegacyActions(
|
||||
registry.register({
|
||||
id: 'catalog:register',
|
||||
async handler(ctx) {
|
||||
const { logger } = ctx;
|
||||
const { catalogInfoUrl } = ctx.parameters; // TODO update schema
|
||||
const { catalogInfoUrl } = ctx.parameters;
|
||||
ctx.logger.info(`Registering ${catalogInfoUrl} in the catalog`);
|
||||
|
||||
logger.info(`Registering ${catalogInfoUrl} in the catalog`);
|
||||
const result = await catalogClient.addLocation({
|
||||
type: 'url',
|
||||
target: catalogInfoUrl as string,
|
||||
});
|
||||
if (result.entities.length === 1) {
|
||||
if (result.entities.length >= 1) {
|
||||
const { kind, name, namespace } = getEntityName(result.entities[0]);
|
||||
ctx.output('entityRef', `${kind}:${namespace}/${name}`);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class TaskWorker {
|
||||
|
||||
async runOneTask(task: Task) {
|
||||
try {
|
||||
const { actionRegistry, logger } = this.options;
|
||||
const { actionRegistry } = this.options;
|
||||
|
||||
const workspacePath = path.join(
|
||||
this.options.workingDirectory,
|
||||
|
||||
@@ -90,6 +90,7 @@ export function templateEntityToSpec(
|
||||
output: {
|
||||
remoteUrl: '{{ steps.publish.output.remoteUrl }}',
|
||||
catalogInfoUrl: '{{ steps.publish.output.catalogInfoUrl }}',
|
||||
entityRef: '{{ steps.register.output.entityRef }}',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +25,14 @@ import Typography from '@material-ui/core/Typography';
|
||||
import { useParams } from 'react-router';
|
||||
import { useTaskEventStream } from '../hooks/useEventStream';
|
||||
import LazyLog from 'react-lazylog/build/LazyLog';
|
||||
import { CircularProgress, StepButton, StepIconProps } from '@material-ui/core';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Paper,
|
||||
StepButton,
|
||||
StepIconProps,
|
||||
} from '@material-ui/core';
|
||||
import { Status } from '../../types';
|
||||
import { DateTime, Interval } from 'luxon';
|
||||
import { useInterval } from 'react-use';
|
||||
@@ -33,6 +40,8 @@ import clsx from 'clsx';
|
||||
import Check from '@material-ui/icons/Check';
|
||||
import Cancel from '@material-ui/icons/Cancel';
|
||||
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
||||
import { EntityRefLink } from '@backstage/plugin-catalog-react';
|
||||
import { parseEntityName } from '@backstage/catalog-model';
|
||||
|
||||
// typings are wrong for this library, so fallback to not parsing types.
|
||||
const humanizeDuration = require('humanize-duration');
|
||||
@@ -197,7 +206,7 @@ export const TaskStatusStepper = memo(
|
||||
const TaskLogger = memo(({ log }: { log: string }) => {
|
||||
return (
|
||||
<div style={{ height: '80vh' }}>
|
||||
<LazyLog text={log} extraLines={1} follow />
|
||||
<LazyLog text={log} extraLines={1} follow selectableLines enableSearch />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -212,7 +221,6 @@ export const TaskPage = () => {
|
||||
const { taskId } = useParams();
|
||||
const taskStream = useTaskEventStream(taskId);
|
||||
const completed = taskStream.completed;
|
||||
|
||||
const steps = useMemo(
|
||||
() =>
|
||||
taskStream.task?.spec.steps.map(step => ({
|
||||
@@ -221,17 +229,17 @@ export const TaskPage = () => {
|
||||
})) ?? [],
|
||||
[taskStream],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const activeStep = steps.find(step =>
|
||||
const mostRecentFailedOrActiveStep = steps.find(step =>
|
||||
['failed', 'processing'].includes(step.status),
|
||||
);
|
||||
|
||||
if (completed) {
|
||||
if (completed && !mostRecentFailedOrActiveStep) {
|
||||
setLastActiveStepId(steps[steps.length - 1]?.id);
|
||||
return;
|
||||
}
|
||||
|
||||
setLastActiveStepId(activeStep?.id);
|
||||
setLastActiveStepId(mostRecentFailedOrActiveStep?.id);
|
||||
}, [steps, completed]);
|
||||
|
||||
const currentStepId = userSelectedStepId ?? lastActiveStepId;
|
||||
@@ -253,6 +261,7 @@ export const TaskPage = () => {
|
||||
taskStream.loading === false &&
|
||||
!taskStream.task;
|
||||
|
||||
const entityRef = taskStream.output?.entityRef;
|
||||
return (
|
||||
<Page themeId="home">
|
||||
<Header
|
||||
@@ -268,18 +277,31 @@ export const TaskPage = () => {
|
||||
{taskNotFound ? (
|
||||
<div>Task not found</div>
|
||||
) : (
|
||||
<Grid container>
|
||||
<Grid item xs={3}>
|
||||
<TaskStatusStepper
|
||||
steps={steps}
|
||||
currentStepId={currentStepId}
|
||||
onUserStepChange={setUserSelectedStepId}
|
||||
/>
|
||||
<div>
|
||||
<Grid container>
|
||||
<Grid item xs={3}>
|
||||
<Paper>
|
||||
<TaskStatusStepper
|
||||
steps={steps}
|
||||
currentStepId={currentStepId}
|
||||
onUserStepChange={setUserSelectedStepId}
|
||||
/>
|
||||
{entityRef && (
|
||||
<Box px={3} pb={3}>
|
||||
<Button variant="outlined">
|
||||
<EntityRefLink entityRef={parseEntityName(entityRef)}>
|
||||
Open in catalog
|
||||
</EntityRefLink>
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<TaskLogger log={logAsString} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<TaskLogger log={logAsString} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
)}
|
||||
</Content>
|
||||
</Page>
|
||||
|
||||
@@ -26,6 +26,8 @@ type Step = {
|
||||
startedAt?: string;
|
||||
};
|
||||
|
||||
type TaskOutput = { entityRef?: string } & { [key in string]: string };
|
||||
|
||||
export type TaskStream = {
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
@@ -33,17 +35,23 @@ export type TaskStream = {
|
||||
completed: boolean;
|
||||
task?: ScaffolderTask;
|
||||
steps: { [stepId in string]: Step };
|
||||
output?: TaskOutput;
|
||||
};
|
||||
|
||||
type ReducerLogEntry = {
|
||||
createdAt: string;
|
||||
body: { stepId?: string; status?: Status; message: string };
|
||||
body: {
|
||||
stepId?: string;
|
||||
status?: Status;
|
||||
message: string;
|
||||
output?: TaskOutput;
|
||||
};
|
||||
};
|
||||
|
||||
type ReducerAction =
|
||||
| { type: 'INIT'; data: ScaffolderTask }
|
||||
| { type: 'LOGS'; data: ReducerLogEntry[] }
|
||||
| { type: 'COMPLETED' }
|
||||
| { type: 'COMPLETED'; data: ReducerLogEntry }
|
||||
| { type: 'ERROR'; data: Error };
|
||||
|
||||
function reducer(draft: TaskStream, action: ReducerAction) {
|
||||
@@ -101,6 +109,7 @@ function reducer(draft: TaskStream, action: ReducerAction) {
|
||||
|
||||
case 'COMPLETED': {
|
||||
draft.completed = true;
|
||||
draft.output = action.data.body.output;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -164,6 +173,10 @@ export const useTaskEventStream = (taskId: string): TaskStream => {
|
||||
switch (event.type) {
|
||||
case 'log':
|
||||
return collectedLogEvents.push(event);
|
||||
case 'completion':
|
||||
emitLogs();
|
||||
dispatch({ type: 'COMPLETED', data: event });
|
||||
return undefined;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unhandled event type ${event.type} in observer`,
|
||||
@@ -174,10 +187,6 @@ export const useTaskEventStream = (taskId: string): TaskStream => {
|
||||
emitLogs();
|
||||
dispatch({ type: 'ERROR', data: error });
|
||||
},
|
||||
complete: () => {
|
||||
emitLogs();
|
||||
dispatch({ type: 'COMPLETED' });
|
||||
},
|
||||
});
|
||||
},
|
||||
error => {
|
||||
|
||||
Reference in New Issue
Block a user