From 73760c688f211ff4d1932d5b62262374a93ef637 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Fri, 12 Feb 2021 15:13:08 +0100 Subject: [PATCH] Scaffolder: display entity button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: blam --- .../src/scaffolder/stages/legacy.ts | 14 ++--- .../src/scaffolder/tasks/TaskWorker.ts | 2 +- .../src/scaffolder/tasks/TemplateConverter.ts | 1 + .../src/components/TaskPage/TaskPage.tsx | 58 +++++++++++++------ .../src/components/hooks/useEventStream.ts | 21 +++++-- 5 files changed, 62 insertions(+), 34 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts b/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts index 5cead565f1..efba57a063 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts @@ -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}`); } diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts index 4511a836f6..6eac36b3f3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts @@ -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, diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts index 20e8886884..4139948513 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts @@ -90,6 +90,7 @@ export function templateEntityToSpec( output: { remoteUrl: '{{ steps.publish.output.remoteUrl }}', catalogInfoUrl: '{{ steps.publish.output.catalogInfoUrl }}', + entityRef: '{{ steps.register.output.entityRef }}', }, }; } diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx index e2a19f9f63..40a52d8b93 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx @@ -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 (
- +
); }); @@ -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 (
{ {taskNotFound ? (
Task not found
) : ( - - - +
+ + + + + {entityRef && ( + + + + )} + + + + + - - - - +
)} diff --git a/plugins/scaffolder/src/components/hooks/useEventStream.ts b/plugins/scaffolder/src/components/hooks/useEventStream.ts index 8bd8bb4d6c..210fd8cb9b 100644 --- a/plugins/scaffolder/src/components/hooks/useEventStream.ts +++ b/plugins/scaffolder/src/components/hooks/useEventStream.ts @@ -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 => {