From a6dcc0a6efda0201b4123cae2b8167b7978614e6 Mon Sep 17 00:00:00 2001 From: Dan Wilson Date: Fri, 15 Sep 2023 11:21:22 +0000 Subject: [PATCH] small ui fixes in pipelines (#501) --- web/src/components/Console/Console.tsx | 2 +- .../ConsoleLogs/ConsoleLogs.module.scss | 8 +- .../ConsoleLogs/ConsoleLogs.module.scss.d.ts | 1 + .../components/ConsoleLogs/ConsoleLogs.tsx | 4 +- .../ConsoleStep/ConsoleStep.module.scss | 4 + .../ConsoleStep/ConsoleStep.module.scss.d.ts | 1 + .../components/ConsoleStep/ConsoleStep.tsx | 9 +- .../ExecutionPageHeader.tsx | 53 ++++--- .../ExecutionStageList/ExecutionStageList.tsx | 11 +- .../ExecutionText/ExecutionText.module.scss | 7 - .../ExecutionText.module.scss.d.ts | 1 - .../ExecutionText/ExecutionText.tsx | 25 ++- .../NewSecretModalButton.tsx | 8 +- .../NewTriggerModalButton.module.scss | 4 + .../NewTriggerModalButton.module.scss.d.ts | 1 + .../NewTriggerModalButton.tsx | 51 ++++--- .../PipelineTriggersTab.tsx | 142 ++++++++++-------- .../UpdateSecretModal/UpdateSecretModal.tsx | 6 +- web/src/framework/strings/stringTypes.ts | 1 + web/src/hooks/useLiveTimeHook.tsx | 28 ++++ web/src/i18n/strings.en.yaml | 1 + web/src/layouts/menu/DefaultMenu.tsx | 6 +- web/src/layouts/menu/NavMenuItem.module.scss | 5 + .../layouts/menu/NavMenuItem.module.scss.d.ts | 1 + web/src/layouts/menu/NavMenuItem.tsx | 5 +- web/src/pages/Execution/Execution.module.scss | 6 +- .../Execution/Execution.module.scss.d.ts | 2 +- web/src/pages/Execution/Execution.tsx | 4 +- web/src/pages/ExecutionList/ExecutionList.tsx | 31 ++-- .../PipelineList/PipelineList.module.scss | 7 - .../PipelineList.module.scss.d.ts | 1 - web/src/pages/PipelineList/PipelineList.tsx | 57 ++++--- web/src/utils/Utils.ts | 19 ++- 33 files changed, 322 insertions(+), 190 deletions(-) create mode 100644 web/src/hooks/useLiveTimeHook.tsx diff --git a/web/src/components/Console/Console.tsx b/web/src/components/Console/Console.tsx index a6235c693..419af4f65 100644 --- a/web/src/components/Console/Console.tsx +++ b/web/src/components/Console/Console.tsx @@ -34,7 +34,7 @@ const Console: FC = ({ stage, repoPath }) => { {stage?.started && stage?.stopped && ( - {getString('executions.completedTime', { timeString: timeDistance(stage?.stopped, Date.now()) })} + {getString('executions.completedTime', { timeString: timeDistance(stage?.stopped, Date.now(), true) })} )} diff --git a/web/src/components/ConsoleLogs/ConsoleLogs.module.scss b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss index 62f38b756..ceac6045f 100644 --- a/web/src/components/ConsoleLogs/ConsoleLogs.module.scss +++ b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss @@ -1,5 +1,5 @@ .logLayout { - margin-left: 30px !important; + margin-left: 23px !important; } .lineNumber { @@ -7,6 +7,8 @@ color: #999; margin-right: 16px; font-family: 'Roboto Mono' !important; + user-select: none !important; + text-align: right !important; } .log { @@ -14,3 +16,7 @@ margin-bottom: var(--spacing-medium); font-family: 'Roboto Mono' !important; } + +.time { + user-select: none !important; +} diff --git a/web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts index 988827c65..68f4566ef 100644 --- a/web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts +++ b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts @@ -3,3 +3,4 @@ export declare const lineNumber: string export declare const log: string export declare const logLayout: string +export declare const time: string diff --git a/web/src/components/ConsoleLogs/ConsoleLogs.tsx b/web/src/components/ConsoleLogs/ConsoleLogs.tsx index 5e9c0ce24..8bbb2c11d 100644 --- a/web/src/components/ConsoleLogs/ConsoleLogs.tsx +++ b/web/src/components/ConsoleLogs/ConsoleLogs.tsx @@ -13,10 +13,10 @@ const ConsoleLogs: FC = ({ logs }) => { {logs.map((log, index) => { return ( - {log.pos} + {typeof log.pos === 'number' && {log.pos + 1}} {log.out} - {log.time}s + {log.time}s ) })} diff --git a/web/src/components/ConsoleStep/ConsoleStep.module.scss b/web/src/components/ConsoleStep/ConsoleStep.module.scss index 3bf78fd03..8da16bfdc 100644 --- a/web/src/components/ConsoleStep/ConsoleStep.module.scss +++ b/web/src/components/ConsoleStep/ConsoleStep.module.scss @@ -33,3 +33,7 @@ } } } + +.time { + user-select: none !important; +} diff --git a/web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts b/web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts index d4984fd99..88a9861f0 100644 --- a/web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts +++ b/web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts @@ -3,4 +3,5 @@ export declare const loading: string export declare const spin: string export declare const stepLayout: string +export declare const time: string export declare const timeoutIcon: string diff --git a/web/src/components/ConsoleStep/ConsoleStep.tsx b/web/src/components/ConsoleStep/ConsoleStep.tsx index 7f34b3df7..0366e9a8e 100644 --- a/web/src/components/ConsoleStep/ConsoleStep.tsx +++ b/web/src/components/ConsoleStep/ConsoleStep.tsx @@ -58,10 +58,13 @@ const ConsoleStep: FC = ({ step, stageNumber, repoPath, pipeli } } return () => { + if (step?.status === ExecutionState.RUNNING && isOpened) { + refetch() + } setStreamingLogs([]) if (eventSourceRef.current) eventSourceRef.current.close() } - }, [executionNumber, pipelineName, repoPath, stageNumber, step?.number, step?.status]) + }, [executionNumber, isOpened, pipelineName, repoPath, stageNumber, step?.name, step?.number, step?.status]) let icon if (step?.status === ExecutionState.SUCCESS) { @@ -107,7 +110,9 @@ const ConsoleStep: FC = ({ step, stageNumber, repoPath, pipeli {icon} {step?.name} - {step?.started && step?.stopped &&
{timeDistance(step?.stopped, step?.started)}
} + {step?.started && step?.stopped && ( + {timeDistance(step?.stopped, step?.started, true)} + )} {isOpened && content} diff --git a/web/src/components/ExecutionPageHeader/ExecutionPageHeader.tsx b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.tsx index 57714c1c2..9b9178d80 100644 --- a/web/src/components/ExecutionPageHeader/ExecutionPageHeader.tsx +++ b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.tsx @@ -9,10 +9,12 @@ import { useAppContext } from 'AppContext' import { useGetSpaceParam } from 'hooks/useGetSpaceParam' import type { CODEProps } from 'RouteDefinitions' import type { GitInfoProps } from 'utils/GitUtils' -import { ExecutionStatus } from 'components/ExecutionStatus/ExecutionStatus' +import { ExecutionState, ExecutionStatus } from 'components/ExecutionStatus/ExecutionStatus' import { getStatus } from 'utils/ExecutionUtils' import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator' import { timeDistance } from 'utils/Utils' +import { useLiveTimer } from 'hooks/useLiveTimeHook' +import { CommitActions } from 'components/CommitActions/CommitActions' import css from './ExecutionPageHeader.module.scss' interface BreadcrumbLink { @@ -48,6 +50,8 @@ export function ExecutionPageHeader({ const { getString } = useStrings() const space = useGetSpaceParam() const { routes } = useAppContext() + const isActive = executionInfo?.status === ExecutionState.RUNNING + const currentTime = useLiveTimer(true) if (!repoMetadata) { return null @@ -94,23 +98,38 @@ export function ExecutionPageHeader({ {executionInfo.source} - - {executionInfo.hash?.slice(0, 6)} - + {executionInfo.hash && ( + + + + )} - - - - {timeDistance(executionInfo.started, executionInfo.finished)} - - - - - {timeDistance(executionInfo.finished, Date.now())} ago - - + {executionInfo.started && ( + + + + {isActive + ? timeDistance(executionInfo.started, currentTime, true) // Live update time when status is 'RUNNING' + : timeDistance(executionInfo.started, executionInfo.finished, true)} + + {executionInfo.finished && ( + <> + + + + {timeDistance(executionInfo.finished, currentTime, true)} ago + + + )} + + )} ) } diff --git a/web/src/components/ExecutionStageList/ExecutionStageList.tsx b/web/src/components/ExecutionStageList/ExecutionStageList.tsx index 5e0058a34..5009f4fb3 100644 --- a/web/src/components/ExecutionStageList/ExecutionStageList.tsx +++ b/web/src/components/ExecutionStageList/ExecutionStageList.tsx @@ -5,6 +5,7 @@ import type { TypesStage } from 'services/code' import { ExecutionState, ExecutionStatus } from 'components/ExecutionStatus/ExecutionStatus' import { getStatus } from 'utils/ExecutionUtils' import { timeDistance } from 'utils/Utils' +import { useLiveTimer } from 'hooks/useLiveTimeHook' import css from './ExecutionStageList.module.scss' interface ExecutionStageListProps { @@ -21,6 +22,9 @@ interface ExecutionStageProps { } const ExecutionStage: FC = ({ stage, isSelected = false, setSelectedStage }) => { + const isActive = stage?.status === ExecutionState.RUNNING + const currentTime = useLiveTimer(isActive) + return ( = ({ stage, isSelected = false, se {stage.name} - {timeDistance(stage.started, stage.stopped)} + {stage.started && (stage.stopped || isActive) && ( + + {/* Use live time when running, static time when finished */} + {timeDistance(stage.started, isActive ? currentTime : stage.stopped, true)} + + )} ) diff --git a/web/src/components/ExecutionText/ExecutionText.module.scss b/web/src/components/ExecutionText/ExecutionText.module.scss index d716efe36..ff9935811 100644 --- a/web/src/components/ExecutionText/ExecutionText.module.scss +++ b/web/src/components/ExecutionText/ExecutionText.module.scss @@ -3,13 +3,6 @@ font-weight: 600 !important; } -.hash { - color: var(--primary-7) !important; - font-family: Roboto Mono !important; - font-size: var(--font-size-small) !important; - font-weight: 500 !important; -} - .pillContainer { background-color: var(--grey-100) !important; color: var(--grey-500) !important; diff --git a/web/src/components/ExecutionText/ExecutionText.module.scss.d.ts b/web/src/components/ExecutionText/ExecutionText.module.scss.d.ts index 89c04ec14..8054e7aa9 100644 --- a/web/src/components/ExecutionText/ExecutionText.module.scss.d.ts +++ b/web/src/components/ExecutionText/ExecutionText.module.scss.d.ts @@ -1,6 +1,5 @@ /* eslint-disable */ // This is an auto-generated file export declare const author: string -export declare const hash: string export declare const pillContainer: string export declare const pillText: string diff --git a/web/src/components/ExecutionText/ExecutionText.tsx b/web/src/components/ExecutionText/ExecutionText.tsx index 31a44e426..fac6dbac9 100644 --- a/web/src/components/ExecutionText/ExecutionText.tsx +++ b/web/src/components/ExecutionText/ExecutionText.tsx @@ -1,11 +1,11 @@ import React from 'react' -import { Avatar, Layout, Text, Utils } from '@harnessio/uicore' -import { Link } from 'react-router-dom' +import { Avatar, Container, Layout, Text, Utils } from '@harnessio/uicore' import { GitCommit, GitFork, Label } from 'iconoir-react' import { Color } from '@harnessio/design-system' import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator' import { useAppContext } from 'AppContext' import type { EnumTriggerAction } from 'services/code' +import { CommitActions } from 'components/CommitActions/CommitActions' import css from './ExecutionText.module.scss' export enum ExecutionTrigger { @@ -146,17 +146,16 @@ export const ExecutionText: React.FC = ({ {componentToRender} - { - e.stopPropagation() - }}> - {commitRef?.slice(0, 6)} - + + + ) } diff --git a/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx b/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx index 9b7a4206c..cf501ff0b 100644 --- a/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx +++ b/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx @@ -94,7 +94,11 @@ export const NewSecretModalButton: React.FC = ({ formName="addSecret" enableReinitialize={true} validationSchema={yup.object().shape({ - name: yup.string().trim().required(), + name: yup + .string() + .trim() + .required() + .matches(/^[a-zA-Z_][a-zA-Z0-9-_.]*$/, getString('validation.nameLogic')), value: yup.string().trim().required() })} validateOnChange @@ -118,7 +122,7 @@ export const NewSecretModalButton: React.FC = ({ tooltipProps={{ dataTooltipId: 'secretDescriptionTextField' }} - inputGroup={{ type: 'password' }} + inputGroup={{ type: 'password', autoComplete: 'new-password' }} /> = ({ validationSchema={yup.object().shape({ name: yup .string() - .required('name is required') - .matches( - /^[a-zA-Z_][a-zA-Z0-9-_.]*$/, - 'name must start with a letter or _ and only contain [a-zA-Z0-9-_.]' - ), + .trim() + .required() + .matches(/^[a-zA-Z_][a-zA-Z0-9-_.]*$/, getString('validation.nameLogic')), actions: yup.array().of(yup.string()) })} validateOnChange @@ -113,24 +111,29 @@ export const NewTriggerModalButton: React.FC = ({ {getString('triggers.actions')} - - {triggerActions.map(action => ( - { - if (event.currentTarget.checked) { - formik.setFieldValue('actions', [...formik.values.actions, action.value]) - } else { - formik.setFieldValue( - 'actions', - formik.values.actions.filter((value: string) => value !== action.value) - ) - } - }} - /> + + {allActions.map((actionGroup, index) => ( + + {actionGroup.map(action => ( + { + if (event.currentTarget.checked) { + formik.setFieldValue('actions', [...formik.values.actions, action.value]) + } else { + formik.setFieldValue( + 'actions', + formik.values.actions.filter((value: string) => value !== action.value) + ) + } + }} + /> + ))} + ))} diff --git a/web/src/components/PipelineTriggersTab/PipelineTriggersTab.tsx b/web/src/components/PipelineTriggersTab/PipelineTriggersTab.tsx index 837237bc1..edfe12269 100644 --- a/web/src/components/PipelineTriggersTab/PipelineTriggersTab.tsx +++ b/web/src/components/PipelineTriggersTab/PipelineTriggersTab.tsx @@ -29,16 +29,24 @@ type TriggerAction = { value: string } -export const triggerActions: TriggerAction[] = [ +const branchActions: TriggerAction[] = [ { name: 'Branch Created', value: 'branch_created' }, - { name: 'Branch Updated', value: 'branch_updated' }, - { name: 'Pull Request Branch Updated', value: 'pullreq_branch_updated' }, + { name: 'Branch Updated', value: 'branch_updated' } +] + +const pullRequestActions: TriggerAction[] = [ { name: 'Pull Request Created', value: 'pullreq_created' }, - { name: 'Pull Request Reopened', value: 'pullreq_reopened' }, + { name: 'Pull Request Updated', value: 'pullreq_branch_updated' }, + { name: 'Pull Request Reopened', value: 'pullreq_reopened' } +] + +const tagActions: TriggerAction[] = [ { name: 'Tag Created', value: 'tag_created' }, { name: 'Tag Updated', value: 'tag_updated' } ] +export const allActions: TriggerAction[][] = [branchActions, pullRequestActions, tagActions] + interface TriggerMenuItemProps { name: string lastUpdated: number @@ -177,25 +185,29 @@ const TriggerDetails = ({ />
- - {triggerActions.map(action => ( - { - if (event.currentTarget.checked) { - formik.setFieldValue('actions', [...formik.values.actions, action.value]) - } else { - formik.setFieldValue( - 'actions', - formik.values.actions.filter((value: string) => value !== action.value) - ) - } - }} - /> + + {allActions.map((actionGroup, index) => ( + + {actionGroup.map(action => ( + { + if (event.currentTarget.checked) { + formik.setFieldValue('actions', [...formik.values.actions, action.value]) + } else { + formik.setFieldValue( + 'actions', + formik.values.actions.filter((value: string) => value !== action.value) + ) + } + }} + /> + ))} + ))}
@@ -203,9 +215,9 @@ const TriggerDetails = ({ spacing="small" padding={{ top: 'large', left: 'large', right: 'large' }} style={{ alignItems: 'center' }}> -