diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json
index b332c37c28..a97d339ba8 100644
--- a/plugins/scaffolder/package.json
+++ b/plugins/scaffolder/package.json
@@ -43,6 +43,8 @@
"classnames": "^2.2.6",
"clsx": "^1.1.1",
"git-url-parse": "^11.4.4",
+ "humanize-duration": "^3.25.1",
+ "luxon": "^1.25.0",
"moment": "^2.26.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
@@ -61,6 +63,7 @@
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+ "@types/humanize-duration": "^3.18.1",
"@types/jest": "^26.0.7",
"@types/node": "^12.0.0",
"cross-fetch": "^3.0.6",
diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx
index 2e7781bc92..01aa110582 100644
--- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx
+++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx
@@ -26,6 +26,12 @@ import { useParams } from 'react-router';
import { useTaskEventStream } from '../hooks/useEventStream';
import LazyLog from 'react-lazylog/build/LazyLog';
import { StepButton, StepIconProps } from '@material-ui/core';
+import { Status } from '../../types';
+import { DateTime, Interval } from 'luxon';
+import { useInterval } from 'react-use';
+
+// typings are wrong for this library, so fallback to not parsing types.
+const humanizeDuration = require('humanize-duration');
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -42,13 +48,48 @@ const useStyles = makeStyles((theme: Theme) =>
resetContainer: {
padding: theme.spacing(3),
},
+ labelWrapper: {
+ display: 'flex',
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ stepWrapper: {
+ width: '100%',
+ },
}),
);
-type Steps = {
+type TaskS = {
id: string;
name: string;
status: Status;
+ startedAt?: string;
+ endedAt?: string;
+};
+
+const StepTimeTicker = ({ step }: { step: TaskS }) => {
+ const [time, setTime] = useState('');
+
+ useInterval(() => {
+ if (!step.startedAt) {
+ setTime('');
+ return;
+ }
+
+ const end = step.endedAt
+ ? DateTime.fromISO(step.endedAt)
+ : DateTime.local();
+
+ const startedAt = DateTime.fromISO(step.startedAt);
+ const formatted = Interval.fromDateTimes(startedAt, end)
+ .toDuration()
+ .valueOf();
+
+ setTime(humanizeDuration(formatted, { round: true }));
+ }, 1000);
+
+ return {time};
};
export const TaskStatusStepper = memo(
@@ -57,7 +98,7 @@ export const TaskStatusStepper = memo(
currentStepId,
onUserStepChange,
}: {
- steps: Steps[];
+ steps: TaskS[];
currentStepId: string | undefined;
onUserStepChange: (id: string) => void;
}) => {
@@ -78,8 +119,12 @@ export const TaskStatusStepper = memo(
onUserStepChange(step.id)}>
- {step.name}
+
+ {step.name}
+
+
@@ -108,6 +153,7 @@ export const TaskPage = () => {
);
const { taskId } = useParams();
const taskStream = useTaskEventStream(taskId);
+ const completed = taskStream.completed;
const steps = useMemo(
() =>
@@ -121,8 +167,14 @@ export const TaskPage = () => {
const activeStep = steps.find(step =>
['failed', 'processing'].includes(step.status),
);
+
+ if (completed) {
+ setLastActiveStepId(steps[steps.length - 1]?.id);
+ return;
+ }
+
setLastActiveStepId(activeStep?.id);
- }, [steps]);
+ }, [steps, completed]);
const currentStepId = userSelectedStepId ?? lastActiveStepId;
@@ -151,14 +203,14 @@ export const TaskPage = () => {
/>
-
+
-
+