From ab2c12fa1dad1fcf647cd8c4028f84b38e023c0f Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 16 Jan 2023 17:02:15 +0100 Subject: [PATCH] chore: moved across the work from previous branch Signed-off-by: blam --- .../src/components/hooks/useEventStream.ts | 2 +- plugins/scaffolder/src/next/Router/Router.tsx | 14 ++++- .../scaffolder/src/next/TaskPage/TaskPage.tsx | 63 +++++++++++++++++++ .../src/next/TaskPage/TaskSteps/TaskSteps.tsx | 63 +++++++++++++++++++ .../src/next/TaskPage/TaskSteps/index.ts | 16 +++++ plugins/scaffolder/src/next/TaskPage/index.ts | 16 +++++ .../TemplateWizardPage/TemplateWizardPage.tsx | 17 +++-- 7 files changed, 183 insertions(+), 8 deletions(-) create mode 100644 plugins/scaffolder/src/next/TaskPage/TaskPage.tsx create mode 100644 plugins/scaffolder/src/next/TaskPage/TaskSteps/TaskSteps.tsx create mode 100644 plugins/scaffolder/src/next/TaskPage/TaskSteps/index.ts create mode 100644 plugins/scaffolder/src/next/TaskPage/index.ts diff --git a/plugins/scaffolder/src/components/hooks/useEventStream.ts b/plugins/scaffolder/src/components/hooks/useEventStream.ts index 0b36c85ad8..be0ff922a4 100644 --- a/plugins/scaffolder/src/components/hooks/useEventStream.ts +++ b/plugins/scaffolder/src/components/hooks/useEventStream.ts @@ -25,7 +25,7 @@ import { import { useApi } from '@backstage/core-plugin-api'; import { Subscription } from '@backstage/types'; -type Step = { +export type Step = { id: string; status: ScaffolderTaskStatus; endedAt?: string; diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx index 8dd47b478e..f5e186eb67 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/next/Router/Router.tsx @@ -28,7 +28,14 @@ import { import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '../TemplateListPage/TemplateGroups'; import { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default'; -import { nextSelectedTemplateRouteRef } from '../routes'; + +import { FormProps } from '../types'; +import { + nextScaffolderTaskRouteRef, + nextSelectedTemplateRouteRef, +} from '../routes'; +import { ErrorPage } from '@backstage/core-components'; +import { TaskPage } from '../TaskPage'; /** * The Props for the Scaffolder Router @@ -91,6 +98,11 @@ export const Router = (props: PropsWithChildren) => { } /> + } /> + } + /> ); }; diff --git a/plugins/scaffolder/src/next/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/next/TaskPage/TaskPage.tsx new file mode 100644 index 0000000000..f259231e4d --- /dev/null +++ b/plugins/scaffolder/src/next/TaskPage/TaskPage.tsx @@ -0,0 +1,63 @@ +/* + * Copyright 2023 The Backstage Authors + * + * 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, { useMemo } from 'react'; +import { Page, Header, Content } from '@backstage/core-components'; +import { useTaskEventStream } from '../../components/hooks/useEventStream'; +import { useParams } from 'react-router-dom'; +import { Box, LinearProgress, Paper } from '@material-ui/core'; +import { TaskSteps } from './TaskSteps'; + +export const TaskPage = () => { + const { taskId } = useParams(); + // check that task Id actually exists, and that it's valid. otherwise redirect to something more useful. + const taskStream = useTaskEventStream(taskId!); + const steps = useMemo( + () => + taskStream.task?.spec.steps.map(step => ({ + ...step, + ...taskStream?.steps?.[step.id], + })) ?? [], + [taskStream], + ); + + const activeStep = React.useMemo(() => { + for (let i = steps.length - 1; i >= 0; i--) { + if (steps[i].status !== 'open') { + return i; + } + } + + return 0; + }, [steps]); + + return ( + +
+ + + + + + + + + + ); +}; diff --git a/plugins/scaffolder/src/next/TaskPage/TaskSteps/TaskSteps.tsx b/plugins/scaffolder/src/next/TaskPage/TaskSteps/TaskSteps.tsx new file mode 100644 index 0000000000..fb24a8a832 --- /dev/null +++ b/plugins/scaffolder/src/next/TaskPage/TaskSteps/TaskSteps.tsx @@ -0,0 +1,63 @@ +/* + * Copyright 2022 The Backstage Authors + * + * 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 { + Stepper as MuiStepper, + Step as MuiStep, + StepButton as MuiStepButton, + StepLabel as MuiStepLabel, +} from '@material-ui/core'; +import { TaskStep } from '@backstage/plugin-scaffolder-common'; +import { Step } from '../../../components/hooks/useEventStream'; + +interface StepperProps { + steps: (TaskStep & Step)[]; + activeStep?: number; + setActiveStep?: (step: number) => void; +} + +export const TaskSteps = (props: StepperProps) => { + return ( + + {props.steps.map((step, index) => { + const isCompleted = step.status === 'completed'; + const isFailed = step.status === 'failed'; + const isActive = step.status === 'processing'; + const isSkipped = step.status === 'skipped'; + + return ( + + + + {step.name} + + + + ); + })} + + ); +}; diff --git a/plugins/scaffolder/src/next/TaskPage/TaskSteps/index.ts b/plugins/scaffolder/src/next/TaskPage/TaskSteps/index.ts new file mode 100644 index 0000000000..28724ba512 --- /dev/null +++ b/plugins/scaffolder/src/next/TaskPage/TaskSteps/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * 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 { TaskSteps } from './TaskSteps'; diff --git a/plugins/scaffolder/src/next/TaskPage/index.ts b/plugins/scaffolder/src/next/TaskPage/index.ts new file mode 100644 index 0000000000..9b6e502fed --- /dev/null +++ b/plugins/scaffolder/src/next/TaskPage/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * 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 { TaskPage } from './TaskPage'; diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index d24482a583..b71d0bd7a3 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -28,12 +28,17 @@ import { Workflow, type LayoutOptions, } from '@backstage/plugin-scaffolder-react'; -import { NextFieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; +import { + NextFieldExtensionOptions, + FormProps, +} from '@backstage/plugin-scaffolder-react'; import { JsonValue } from '@backstage/types'; -import { type FormProps } from '../types'; -import { nextRouteRef } from '../routes'; -import { scaffolderTaskRouteRef, selectedTemplateRouteRef } from '../../routes'; import { Header, Page } from '@backstage/core-components'; +import { + nextRouteRef, + nextScaffolderTaskRouteRef, + nextSelectedTemplateRouteRef, +} from '../routes'; export type TemplateWizardPageProps = { customFieldExtensions: NextFieldExtensionOptions[]; @@ -43,12 +48,12 @@ export type TemplateWizardPageProps = { export const TemplateWizardPage = (props: TemplateWizardPageProps) => { const rootRef = useRouteRef(nextRouteRef); - const taskRoute = useRouteRef(scaffolderTaskRouteRef); + const taskRoute = useRouteRef(nextScaffolderTaskRouteRef); const { secrets } = useTemplateSecrets(); const scaffolderApi = useApi(scaffolderApiRef); const navigate = useNavigate(); const { templateName, namespace } = useRouteRefParams( - selectedTemplateRouteRef, + nextSelectedTemplateRouteRef, ); const templateRef = stringifyEntityRef({