diff --git a/web/src/components/ExecutionPageHeader/ExecutionPageHeader.module.scss b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.module.scss new file mode 100644 index 000000000..a890740b2 --- /dev/null +++ b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.module.scss @@ -0,0 +1,42 @@ +.pageHeader { + height: auto !important; + flex-direction: column !important; + align-items: flex-start !important; + gap: var(--spacing-small) !important; +} + +.header { + width: 100% !important; + gap: var(--spacing-small) !important; + + a { + font-size: var(--font-size-small); + color: var(--primary-7); + } +} + +.breadcrumb { + align-items: center; + + a { + font-size: var(--font-size-small); + color: var(--primary-7); + } +} + +.hash { + color: var(--primary-7) !important; + font-family: Roboto Mono !important; + font-size: var(--font-size-small) !important; + font-weight: 500 !important; +} + +.timer { + margin: 0 0 0 auto !important; +} + +.executionInfo { + width: 100% !important; + align-items: center !important; + margin-left: 0 !important; +} diff --git a/web/src/components/ExecutionPageHeader/ExecutionPageHeader.module.scss.d.ts b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.module.scss.d.ts new file mode 100644 index 000000000..ef2552a90 --- /dev/null +++ b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.module.scss.d.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +// this is an auto-generated file +declare const styles: { + readonly pageHeader: string + readonly header: string + readonly breadcrumb: string + readonly hash: string + readonly timer: string + readonly executionInfo: string +} +export default styles diff --git a/web/src/components/ExecutionPageHeader/ExecutionPageHeader.tsx b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.tsx new file mode 100644 index 000000000..4870c424b --- /dev/null +++ b/web/src/components/ExecutionPageHeader/ExecutionPageHeader.tsx @@ -0,0 +1,121 @@ +import React, { Fragment } from 'react' +import { Layout, Text, PageHeader, Utils, Avatar, FlexExpander } from '@harnessio/uicore' +import { Icon } from '@harnessio/icons' +import { Color } from '@harnessio/design-system' +import { Link, useParams } from 'react-router-dom' +import { Calendar, GitFork, Timer } from 'iconoir-react' +import { useStrings } from 'framework/strings' +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 { getStatus } from 'utils/PipelineUtils' +import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator' +import { timeDistance } from 'utils/Utils' +import css from './ExecutionPageHeader.module.scss' + +interface BreadcrumbLink { + label: string + url: string +} + +interface ExecutionInfo { + message: string + authorName: string + authorEmail: string + source: string + hash: string + status: string + started: number + finished: number +} + +interface ExecutionPageHeaderProps extends Optional, 'repoMetadata'> { + title: string | JSX.Element + dataTooltipId: string + extraBreadcrumbLinks?: BreadcrumbLink[] + executionInfo?: ExecutionInfo +} + +export function ExecutionPageHeader({ + repoMetadata, + title, + extraBreadcrumbLinks = [], + executionInfo +}: ExecutionPageHeaderProps) { + const { gitRef } = useParams() + const { getString } = useStrings() + const space = useGetSpaceParam() + const { routes } = useAppContext() + + if (!repoMetadata) { + return null + } + + return ( + + {getString('repositories')} + + + {repoMetadata.uid} + + {extraBreadcrumbLinks.map(link => ( + + + {link.label} + + ))} + + } + content={ + executionInfo && ( + // TODO - margin left not playing ball... why? + + + + {executionInfo.message} + + + + + {executionInfo.authorName} + + + + + {executionInfo.source} + + + + {executionInfo.hash?.slice(0, 6)} + + + + + + {timeDistance(executionInfo.started, executionInfo.finished)} + + + + + + {timeDistance(executionInfo.finished, Date.now())} ago + + + + ) + } + /> + ) +} diff --git a/web/src/components/ExecutionStageList/ExecutionStageList.tsx b/web/src/components/ExecutionStageList/ExecutionStageList.tsx index 399be3cf6..eceeea265 100644 --- a/web/src/components/ExecutionStageList/ExecutionStageList.tsx +++ b/web/src/components/ExecutionStageList/ExecutionStageList.tsx @@ -1,9 +1,10 @@ import React, { FC } from 'react' -import { Container, Layout, Text } from '@harnessio/uicore' +import { Container, FlexExpander, Layout, Text } from '@harnessio/uicore' import cx from 'classnames' import type { TypesStage } from 'services/code' import { ExecutionState, ExecutionStatus } from 'components/ExecutionStatus/ExecutionStatus' import { getStatus } from 'utils/PipelineUtils' +import { timeDistance } from 'utils/Utils' import css from './ExecutionStageList.module.scss' interface ExecutionStageListProps { @@ -37,6 +38,8 @@ const ExecutionStage: FC = ({ stage, isSelected = false, se {stage.name} + + {timeDistance(stage.started, stage.stopped)} ) diff --git a/web/src/pages/Execution/Execution.tsx b/web/src/pages/Execution/Execution.tsx index 630bfa022..3c069a0c0 100644 --- a/web/src/pages/Execution/Execution.tsx +++ b/web/src/pages/Execution/Execution.tsx @@ -12,7 +12,7 @@ import { getErrorMessage, voidFn } from 'utils/Utils' import { useStrings } from 'framework/strings' import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner' import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata' -import { RepositoryPageHeader } from 'components/RepositoryPageHeader/RepositoryPageHeader' +import { ExecutionPageHeader } from 'components/ExecutionPageHeader/ExecutionPageHeader' import noExecutionImage from '../RepositoriesListing/no-repo.svg' import css from './Execution.module.scss' @@ -35,7 +35,7 @@ const Execution = () => { return ( - { } ] } + executionInfo={{ + message: execution?.message as string, + authorName: execution?.author_name as string, + authorEmail: execution?.author_email as string, + source: execution?.source as string, + hash: execution?.after as string, + status: execution?.status as string, + started: execution?.started as number, + finished: execution?.finished as number + }} /> { {/* TODO need logic here for different trigger types */} {`${record.author_name} triggered manually`} - {/* TODO Will need to replace this with commit component - wont match Yifan designs */} - - {record.after} - + { + e.stopPropagation() + }}> + {record.after?.slice(0, 6)} + ) diff --git a/web/src/pages/PipelineList/PipelineList.tsx b/web/src/pages/PipelineList/PipelineList.tsx index d64f4ebe1..a6641acb9 100644 --- a/web/src/pages/PipelineList/PipelineList.tsx +++ b/web/src/pages/PipelineList/PipelineList.tsx @@ -15,7 +15,7 @@ import { Color } from '@harnessio/design-system' import cx from 'classnames' import type { CellProps, Column } from 'react-table' import Keywords from 'react-keywords' -import { useHistory } from 'react-router-dom' +import { Link, useHistory } from 'react-router-dom' import { useGet } from 'restful-react' import { Calendar, Timer, GitFork } from 'iconoir-react' import { useStrings } from 'framework/strings' @@ -33,11 +33,13 @@ import { RepositoryPageHeader } from 'components/RepositoryPageHeader/Repository import { ExecutionStatus, ExecutionState } from 'components/ExecutionStatus/ExecutionStatus' import { getStatus } from 'utils/PipelineUtils' import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator' +import { useGetSpaceParam } from 'hooks/useGetSpaceParam' import noPipelineImage from '../RepositoriesListing/no-repo.svg' import css from './PipelineList.module.scss' const PipelineList = () => { const { routes } = useAppContext() + const space = useGetSpaceParam() const history = useHistory() const { getString } = useStrings() const [searchTerm, setSearchTerm] = useState() @@ -119,11 +121,18 @@ const PipelineList = () => { {record.source} - {/* TODO Will need to replace this with commit component - wont match Yifan designs */} - - {/* {record.after} */} - hardcoded - + { + e.stopPropagation() + }}> + {/* {record.after?.slice(0, 6)} */} + {'hardcoded'.slice(0, 6)} + ) : (