From 34855e83635c46cb0094cb076894be9aa3f35f55 Mon Sep 17 00:00:00 2001 From: michaeljguarino Date: Sat, 25 May 2024 10:41:00 -0400 Subject: [PATCH] Add a restart run button This mutation has been implemented already, and it's very useful for testing --- assets/src/components/stacks/run/Sidecar.tsx | 52 +++++++++++++++++-- assets/src/components/stacks/run/Sidenav.tsx | 7 ++- .../src/components/stacks/run/plan/Plan.tsx | 22 +++++--- .../stacks/run/progress/Progress.tsx | 20 ++++++- .../components/stacks/run/progress/Step.tsx | 13 ++--- assets/src/generated/graphql.ts | 41 +++++++++++++++ assets/src/graph/stacks.graphql | 6 +++ .../pubsub/protocols/notifiable.ex | 2 +- 8 files changed, 143 insertions(+), 20 deletions(-) diff --git a/assets/src/components/stacks/run/Sidecar.tsx b/assets/src/components/stacks/run/Sidecar.tsx index d785c46c4e..80cd7bfa8d 100644 --- a/assets/src/components/stacks/run/Sidecar.tsx +++ b/assets/src/components/stacks/run/Sidecar.tsx @@ -1,37 +1,66 @@ -import React, { ReactNode } from 'react' -import { Button, Sidecar, SidecarItem } from '@pluralsh/design-system' +import { ReactNode } from 'react' +import { + Button, + ReloadIcon, + Sidecar, + SidecarItem, +} from '@pluralsh/design-system' import { useTheme } from 'styled-components' import moment from 'moment' import { GqlError } from 'components/utils/Alert' +import { useNavigate, useParams } from 'react-router-dom' + +import { getStackRunsAbsPath } from 'routes/stacksRoutesConsts' + import { StackRun, + StackStatus, useApproveStackRunMutation, + useRestartStackRunMutation, } from '../../../generated/graphql' import { ResponsiveLayoutSidecarContainer } from '../../utils/layout/ResponsiveLayoutSidecarContainer' import UserInfo from '../../utils/UserInfo' import { ClusterProviderIcon } from '../../utils/Provider' +import { StackRunStatusChip } from '../StackRunStatusChip' interface StackRunSidecarProps { stackRun: StackRun refetch?: Nullable<() => void> } +const TERMINAL_STATES = [ + StackStatus.Successful, + StackStatus.Cancelled, + StackStatus.Failed, +] + export default function StackRunSidecar({ stackRun, refetch, }: StackRunSidecarProps): ReactNode { + const { stackId } = useParams() const theme = useTheme() + const navigate = useNavigate() const [mutation, { loading, error }] = useApproveStackRunMutation({ variables: { id: stackRun.id }, onCompleted: () => refetch?.(), }) + const [restart, { loading: restartLoading, error: restartError }] = + useRestartStackRunMutation({ + variables: { id: stackRun.id }, + onCompleted: ({ restartStackRun }) => + navigate(getStackRunsAbsPath(stackId, restartStackRun?.id)), + }) + + const terminal = TERMINAL_STATES.includes(stackRun.status) + if (error) return - console.log(stackRun) + if (restartError) return return ( )} + {terminal && ( + + )} - {stackRun.id} + + + {stackRun.approval ? 'Required' : 'Not required'} diff --git a/assets/src/components/stacks/run/Sidenav.tsx b/assets/src/components/stacks/run/Sidenav.tsx index 7af9311554..d121169ca4 100644 --- a/assets/src/components/stacks/run/Sidenav.tsx +++ b/assets/src/components/stacks/run/Sidenav.tsx @@ -84,7 +84,12 @@ function StackRunSidenavHeader({ }} > } + icon={ + + } size="small" /> () - const value = JSON.parse(stackRun.state?.plan ?? '{}') + const value = stackRun.state?.plan ?? '' return ( - + + + ) } diff --git a/assets/src/components/stacks/run/progress/Progress.tsx b/assets/src/components/stacks/run/progress/Progress.tsx index d3f725be98..752564748d 100644 --- a/assets/src/components/stacks/run/progress/Progress.tsx +++ b/assets/src/components/stacks/run/progress/Progress.tsx @@ -4,16 +4,33 @@ import { ReactNode, useMemo } from 'react' import { useOutletContext } from 'react-router-dom' import sortBy from 'lodash/sortBy' -import { StackRun } from '../../../../generated/graphql' +import { StackRun, StepStatus } from '../../../../generated/graphql' import Step from './Step' +function currentStep(steps) { + for (let i = steps.length - 1; i > 0; i--) { + const { status } = steps[i] + + if ( + status === StepStatus.Running || + status === StepStatus.Successful || + status === StepStatus.Failed + ) { + return steps[i].id + } + } + + return steps[0].id +} + export default function StackRunProgress(): ReactNode { const { stackRun } = useOutletContext<{ stackRun: StackRun }>() const sorted = useMemo( () => sortBy(stackRun.steps, (s) => s?.index), [stackRun.steps] ) + const openId = currentStep(sorted) return ( ))} diff --git a/assets/src/components/stacks/run/progress/Step.tsx b/assets/src/components/stacks/run/progress/Step.tsx index fc2917db0e..e981f7ba75 100644 --- a/assets/src/components/stacks/run/progress/Step.tsx +++ b/assets/src/components/stacks/run/progress/Step.tsx @@ -26,14 +26,13 @@ import CommandLog from '../../../builds/build/progress/CommandLog' interface StepProps { step: RunStep + open?: boolean } -export default function Step({ step }: StepProps): ReactNode { +export default function Step({ step, open }: StepProps): ReactNode { const ref = useRef() - const [folded, setFolded] = useState( - step.status === StepStatus.Successful || step.status === StepStatus.Pending - ) + const [folded, setFolded] = useState(undefined) const [logs, setLogs] = useState(step?.logs as Array) const command = useMemo( @@ -62,6 +61,8 @@ export default function Step({ step }: StepProps): ReactNode { setLogs(step?.logs as Array) }, [step?.logs]) + const show = folded === undefined ? open : !folded + return (
- {folded ? ( + {!show ? ( - {!folded && ( + {show && ( ; + + +export type RestartStackRunMutation = { __typename?: 'RootMutationType', restartStackRun?: { __typename?: 'StackRun', id: string, insertedAt?: string | null, message?: string | null, status: StackStatus, approval?: boolean | null, approvedAt?: string | null, git: { __typename?: 'GitRef', ref: string }, approver?: { __typename?: 'User', name: string, email: string } | null } | null }; + export type LogsDeltaSubscriptionVariables = Exact<{ id: Scalars['ID']['input']; }>; @@ -17826,6 +17833,39 @@ export function useApproveStackRunMutation(baseOptions?: Apollo.MutationHookOpti export type ApproveStackRunMutationHookResult = ReturnType; export type ApproveStackRunMutationResult = Apollo.MutationResult; export type ApproveStackRunMutationOptions = Apollo.BaseMutationOptions; +export const RestartStackRunDocument = gql` + mutation RestartStackRun($id: ID!) { + restartStackRun(id: $id) { + ...StackRun + } +} + ${StackRunFragmentDoc}`; +export type RestartStackRunMutationFn = Apollo.MutationFunction; + +/** + * __useRestartStackRunMutation__ + * + * To run a mutation, you first call `useRestartStackRunMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useRestartStackRunMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [restartStackRunMutation, { data, loading, error }] = useRestartStackRunMutation({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useRestartStackRunMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(RestartStackRunDocument, options); + } +export type RestartStackRunMutationHookResult = ReturnType; +export type RestartStackRunMutationResult = Apollo.MutationResult; +export type RestartStackRunMutationOptions = Apollo.BaseMutationOptions; export const LogsDeltaDocument = gql` subscription LogsDelta($id: ID!) { runLogsDelta(stepId: $id) { @@ -18440,6 +18480,7 @@ export const namedOperations = { DeleteStack: 'DeleteStack', KickStack: 'KickStack', ApproveStackRun: 'ApproveStackRun', + RestartStackRun: 'RestartStackRun', CreateAccessToken: 'CreateAccessToken', DeleteAccessToken: 'DeleteAccessToken', Logout: 'Logout' diff --git a/assets/src/graph/stacks.graphql b/assets/src/graph/stacks.graphql index 9502a197ae..fea60a3723 100644 --- a/assets/src/graph/stacks.graphql +++ b/assets/src/graph/stacks.graphql @@ -267,6 +267,12 @@ mutation ApproveStackRun($id: ID!) { } } +mutation RestartStackRun($id: ID!) { + restartStackRun(id: $id) { + ...StackRun + } +} + subscription LogsDelta($id: ID!) { runLogsDelta(stepId: $id) { delta diff --git a/lib/console/deployments/pubsub/protocols/notifiable.ex b/lib/console/deployments/pubsub/protocols/notifiable.ex index f0edad186f..5661478c7e 100644 --- a/lib/console/deployments/pubsub/protocols/notifiable.ex +++ b/lib/console/deployments/pubsub/protocols/notifiable.ex @@ -75,7 +75,7 @@ defimpl Console.Deployments.PubSub.Notifiable, for: Console.PubSub.PipelineGateU def message(_), do: :ok end -defimpl Console.Deployments.PubSub.Notifiable, for: [Console.PubSub.StackRunCreated, Console.PubSub.StackRunUpdated, Console.PubSub.StackRunDeleted] do +defimpl Console.Deployments.PubSub.Notifiable, for: Console.PubSub.StackRunCreated do alias Console.Deployments.Notifications.Utils def message(%{item: run}) do