From 15a4fe04bd4a6d1be9e527a5e36f5848cf9c95dd Mon Sep 17 00:00:00 2001 From: Dan Wilson Date: Tue, 29 Aug 2023 16:00:01 +0100 Subject: [PATCH] pipeline console WIP --- .../components/Console/Console.module.scss | 32 ++++++++++ .../Console/Console.module.scss.d.ts | 10 +++ web/src/components/Console/Console.tsx | 48 ++++++++++++++ .../ConsoleLogs/ConsoleLogs.module.scss | 14 ++++ .../ConsoleLogs/ConsoleLogs.module.scss.d.ts | 8 +++ .../components/ConsoleLogs/ConsoleLogs.tsx | 36 +++++++++++ .../ConsoleStep/ConsoleStep.module.scss | 5 ++ .../ConsoleStep/ConsoleStep.module.scss.d.ts | 6 ++ .../components/ConsoleStep/ConsoleStep.tsx | 64 +++++++++++++++++++ .../ExecutionStageList.module.scss | 39 +++++++++++ .../ExecutionStageList.module.scss.d.ts | 11 ++++ .../ExecutionStageList/ExecutionStageList.tsx | 56 ++++++++++++++++ web/src/pages/Execution/Execution.module.scss | 55 ++++++++++++++++ .../Execution/Execution.module.scss.d.ts | 2 + web/src/pages/Execution/Execution.tsx | 46 ++++++++++--- web/src/pages/ExecutionList/ExecutionList.tsx | 4 +- 16 files changed, 426 insertions(+), 10 deletions(-) create mode 100644 web/src/components/Console/Console.module.scss create mode 100644 web/src/components/Console/Console.module.scss.d.ts create mode 100644 web/src/components/Console/Console.tsx create mode 100644 web/src/components/ConsoleLogs/ConsoleLogs.module.scss create mode 100644 web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts create mode 100644 web/src/components/ConsoleLogs/ConsoleLogs.tsx create mode 100644 web/src/components/ConsoleStep/ConsoleStep.module.scss create mode 100644 web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts create mode 100644 web/src/components/ConsoleStep/ConsoleStep.tsx create mode 100644 web/src/components/ExecutionStageList/ExecutionStageList.module.scss create mode 100644 web/src/components/ExecutionStageList/ExecutionStageList.module.scss.d.ts create mode 100644 web/src/components/ExecutionStageList/ExecutionStageList.tsx diff --git a/web/src/components/Console/Console.module.scss b/web/src/components/Console/Console.module.scss new file mode 100644 index 000000000..b7df1b8b6 --- /dev/null +++ b/web/src/components/Console/Console.module.scss @@ -0,0 +1,32 @@ +.container { + display: flex; + flex-direction: column; + background-color: black; + height: 100%; + overflow-y: auto; +} + +.log { + color: white; + font-family: Inconsolata, monospace; + font-size: 2rem; +} + +.header { + position: sticky; + top: 0; + background-color: var(--black); + height: var(--log-content-header-height); + + .headerLayout { + display: flex; + align-items: baseline; + border-bottom: 1px solid var(--grey-800); + padding: var(--spacing-medium) 0; + font-weight: 600; + } +} + +.steps { + padding: var(--spacing-medium) !important; +} diff --git a/web/src/components/Console/Console.module.scss.d.ts b/web/src/components/Console/Console.module.scss.d.ts new file mode 100644 index 000000000..5e3d1c140 --- /dev/null +++ b/web/src/components/Console/Console.module.scss.d.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ +// this is an auto-generated file +declare const styles: { + readonly container: string + readonly log: string + readonly header: string + readonly headerLayout: string + readonly steps: string +} +export default styles diff --git a/web/src/components/Console/Console.tsx b/web/src/components/Console/Console.tsx new file mode 100644 index 000000000..cf332a4d8 --- /dev/null +++ b/web/src/components/Console/Console.tsx @@ -0,0 +1,48 @@ +import React, { FC } from 'react' +import { useParams } from 'react-router-dom' +import { Container, Layout, Text } from '@harnessio/uicore' +import { Color, FontVariation } from '@harnessio/design-system' +import { useGetSpaceParam } from 'hooks/useGetSpaceParam' +import type { CODEProps } from 'RouteDefinitions' +import type { TypesStage } from 'services/code' +import ConsoleStep from 'components/ConsoleStep/ConsoleStep' +import css from './Console.module.scss' + +interface ConsoleProps { + stage: TypesStage | undefined +} + +const Console: FC = ({ stage }) => { + const space = useGetSpaceParam() + const { pipeline, execution: executionNum } = useParams() + + return ( +
+ + + + {stage?.name} + + + {/* this needs fixed */} + Success in 5 mins + + + + + {stage?.steps?.map((step, index) => ( + + ))} + +
+ ) +} + +export default Console diff --git a/web/src/components/ConsoleLogs/ConsoleLogs.module.scss b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss new file mode 100644 index 000000000..e327875be --- /dev/null +++ b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss @@ -0,0 +1,14 @@ +.logLayout { + margin-left: 2.3rem !important; +} + +.lineNumber { + width: 1.5rem; + color: #999; + margin-right: 1rem; +} + +.log { + color: white !important; + margin-bottom: 1rem; +} diff --git a/web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts new file mode 100644 index 000000000..898a53cd0 --- /dev/null +++ b/web/src/components/ConsoleLogs/ConsoleLogs.module.scss.d.ts @@ -0,0 +1,8 @@ +/* eslint-disable */ +// this is an auto-generated file +declare const styles: { + readonly logLayout: string + readonly lineNumber: string + readonly log: string +} +export default styles diff --git a/web/src/components/ConsoleLogs/ConsoleLogs.tsx b/web/src/components/ConsoleLogs/ConsoleLogs.tsx new file mode 100644 index 000000000..7d4dffe84 --- /dev/null +++ b/web/src/components/ConsoleLogs/ConsoleLogs.tsx @@ -0,0 +1,36 @@ +import { Layout, Text } from '@harnessio/uicore' +import React, { FC } from 'react' +import css from './ConsoleLogs.module.scss' + +// currently a string - should be an array of strings in future +interface ConsoleLogsProps { + logs: string +} + +interface log { + pos: number + out: string + time: number +} + +const convertStringToLogArray = (logs: string): log[] => { + const logStrings = logs.split('\n').map(log => { + return JSON.parse(log) + }) + + return logStrings +} + +const ConsoleLogs: FC = ({ logs }) => { + const logArray = convertStringToLogArray(logs) + return logArray.map((log, index) => { + return ( + + {log.pos} + {log.out} + + ) + }) +} + +export default ConsoleLogs diff --git a/web/src/components/ConsoleStep/ConsoleStep.module.scss b/web/src/components/ConsoleStep/ConsoleStep.module.scss new file mode 100644 index 000000000..b37bc0c2e --- /dev/null +++ b/web/src/components/ConsoleStep/ConsoleStep.module.scss @@ -0,0 +1,5 @@ +.stepLayout { + display: flex; + align-items: center; + cursor: pointer; +} diff --git a/web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts b/web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts new file mode 100644 index 000000000..95262a110 --- /dev/null +++ b/web/src/components/ConsoleStep/ConsoleStep.module.scss.d.ts @@ -0,0 +1,6 @@ +/* eslint-disable */ +// this is an auto-generated file +declare const styles: { + readonly stepLayout: string +} +export default styles diff --git a/web/src/components/ConsoleStep/ConsoleStep.tsx b/web/src/components/ConsoleStep/ConsoleStep.tsx new file mode 100644 index 000000000..76f4787ba --- /dev/null +++ b/web/src/components/ConsoleStep/ConsoleStep.tsx @@ -0,0 +1,64 @@ +import { Icon } from '@harnessio/icons' +import { FlexExpander, Layout } from '@harnessio/uicore' +import React, { FC, useEffect } from 'react' +import { useGet } from 'restful-react' +import { Text } from '@harnessio/uicore' +import type { TypesStep } from 'services/code' +import { timeDistance } from 'utils/Utils' +import ConsoleLogs from 'components/ConsoleLogs/ConsoleLogs' +import css from './ConsoleStep.module.scss' + +interface ConsoleStepProps { + step: TypesStep | undefined + stageNumber: number | undefined + spaceName: string + pipelineName: string | undefined + executionNumber: number +} + +const ConsoleStep: FC = ({ step, stageNumber, spaceName, pipelineName, executionNumber }) => { + const [isOpened, setIsOpened] = React.useState(false) + + const { data, error, loading, refetch } = useGet({ + path: `/api/v1/pipelines/${spaceName}/${pipelineName}/+/executions/${executionNumber}/logs/${String( + stageNumber + )}/${String(step?.number)}`, + lazy: true + }) + + // this refetches any open steps when the stage number changes - really it shouldnt refetch until reopened... + useEffect(() => { + setIsOpened(false) + refetch() + }, [stageNumber, refetch]) + + return ( + <> + { + setIsOpened(!isOpened) + if (!data && !loading) refetch() + }}> + + + {step?.name} + + {step?.started && step?.stopped &&
{timeDistance(step?.stopped, step?.started)}
} +
+ + {isOpened ? ( + loading ? ( +
Loading...
+ ) : error ? ( +
Error: {error}
+ ) : data ? ( + + ) : null + ) : null} + + ) +} + +export default ConsoleStep diff --git a/web/src/components/ExecutionStageList/ExecutionStageList.module.scss b/web/src/components/ExecutionStageList/ExecutionStageList.module.scss new file mode 100644 index 000000000..a95292525 --- /dev/null +++ b/web/src/components/ExecutionStageList/ExecutionStageList.module.scss @@ -0,0 +1,39 @@ +.container { + display: flex; + flex-direction: column; + height: 100%; +} + +.menu { + --stage-title-height: 54px; + + width: 100%; + height: 100%; + + .menuItem { + margin: 0.5rem 0 0.5rem 1rem !important; + cursor: pointer; + + .layout { + display: flex; + align-items: center; + min-height: var(--stage-title-height); + padding: 0 var(--spacing-medium) 0 var(--spacing-medium); + border-radius: 10px 0 0 10px !important; + + &.selected { + background-color: var(--primary-1); + + .uid { + color: var(--primary-7) !important; + } + } + + .uid { + color: var(--grey-700) !important; + font-weight: 600 !important; + font-size: 1rem !important; + } + } + } +} diff --git a/web/src/components/ExecutionStageList/ExecutionStageList.module.scss.d.ts b/web/src/components/ExecutionStageList/ExecutionStageList.module.scss.d.ts new file mode 100644 index 000000000..0980665f8 --- /dev/null +++ b/web/src/components/ExecutionStageList/ExecutionStageList.module.scss.d.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +// this is an auto-generated file +declare const styles: { + readonly container: string + readonly menu: string + readonly menuItem: string + readonly layout: string + readonly selected: string + readonly uid: string +} +export default styles diff --git a/web/src/components/ExecutionStageList/ExecutionStageList.tsx b/web/src/components/ExecutionStageList/ExecutionStageList.tsx new file mode 100644 index 000000000..8364dad2a --- /dev/null +++ b/web/src/components/ExecutionStageList/ExecutionStageList.tsx @@ -0,0 +1,56 @@ +import React, { FC } from 'react' +import { Container, Layout, Text } from '@harnessio/uicore' +import { Icon } from '@harnessio/icons' +import cx from 'classnames' +import type { TypesStage } from 'services/code' +import css from './ExecutionStageList.module.scss' + +interface ExecutionStageListProps { + stages: TypesStage[] + selectedStage: number | null + setSelectedStage: (selectedStep: number | null) => void +} + +interface ExecutionStageProps { + stage: TypesStage + isSelected?: boolean + selectedStage: number | null + setSelectedStage: (selectedStage: number | null) => void +} + +const ExecutionStage: FC = ({ stage, isSelected = false, setSelectedStage = () => {} }) => { + return ( + { + setSelectedStage(stage.number || null) + }}> + + + + {stage.name} + + + + ) +} + +const ExecutionStageList: FC = ({ stages, setSelectedStage, selectedStage }) => { + return ( + + {stages.map((stage, index) => { + return ( + + ) + })} + + ) +} + +export default ExecutionStageList diff --git a/web/src/pages/Execution/Execution.module.scss b/web/src/pages/Execution/Execution.module.scss index f1fb64bb6..524ad90cf 100644 --- a/web/src/pages/Execution/Execution.module.scss +++ b/web/src/pages/Execution/Execution.module.scss @@ -1,4 +1,59 @@ .main { min-height: var(--page-height); background-color: var(--primary-bg) !important; + + :global { + .Resizer { + background-color: var(--grey-300); + opacity: 0.2; + z-index: 1; + box-sizing: border-box; + background-clip: padding-box; + } + + .Resizer:hover { + transition: all 2s ease; + } + + .Resizer.horizontal { + margin: -5px 0; + border-top: 5px solid rgba(255, 255, 255, 0); + border-bottom: 5px solid rgba(255, 255, 255, 0); + cursor: row-resize; + } + + .Resizer.horizontal:hover { + border-top: 5px solid rgba(0, 0, 0, 0.5); + border-bottom: 5px solid rgba(0, 0, 0, 0.5); + } + + .Resizer.vertical { + width: 11px; + margin: 0 -5px; + border-left: 5px solid rgba(255, 255, 255, 0); + border-right: 5px solid rgba(255, 255, 255, 0); + cursor: col-resize; + } + + .Resizer.vertical:hover { + border-left: 5px solid rgba(0, 0, 0, 0.5); + border-right: 5px solid rgba(0, 0, 0, 0.5); + } + + .Resizer.disabled { + cursor: not-allowed; + } + + .Resizer.disabled:hover { + border-color: transparent; + } + } +} + +.container { + height: calc(100vh - var(--page-header-height)); +} + +.withError { + display: grid; } diff --git a/web/src/pages/Execution/Execution.module.scss.d.ts b/web/src/pages/Execution/Execution.module.scss.d.ts index 9e614bf2d..9828b69dc 100644 --- a/web/src/pages/Execution/Execution.module.scss.d.ts +++ b/web/src/pages/Execution/Execution.module.scss.d.ts @@ -2,5 +2,7 @@ // this is an auto-generated file declare const styles: { readonly main: string + readonly container: string + readonly withError: string } export default styles diff --git a/web/src/pages/Execution/Execution.tsx b/web/src/pages/Execution/Execution.tsx index 4dd4d2c2d..dfa7d0d44 100644 --- a/web/src/pages/Execution/Execution.tsx +++ b/web/src/pages/Execution/Execution.tsx @@ -1,29 +1,59 @@ -import React from 'react' -import { Container, PageHeader } from '@harnessio/uicore' +import { Container, PageHeader, PageBody } from '@harnessio/uicore' +import React, { useState } from 'react' +import cx from 'classnames' import { useParams } from 'react-router-dom' import { useGet } from 'restful-react' +import SplitPane from 'react-split-pane' import { useGetSpaceParam } from 'hooks/useGetSpaceParam' import type { CODEProps } from 'RouteDefinitions' import type { TypesExecution } from 'services/code' +import ExecutionStageList from 'components/ExecutionStageList/ExecutionStageList' +import Console from 'components/Console/Console' +import { getErrorMessage, voidFn } from 'utils/Utils' +import { useStrings } from 'framework/strings' +import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner' +import noExecutionImage from '../RepositoriesListing/no-repo.svg' import css from './Execution.module.scss' const Execution = () => { const space = useGetSpaceParam() const { pipeline, execution: executionNum } = useParams() + const { getString } = useStrings() const { - data: execution - // error, - // loading, - // refetch - // response + data: execution, + error, + loading, + refetch } = useGet({ path: `/api/v1/pipelines/${space}/${pipeline}/+/executions/${executionNum}` }) + const [selectedStage, setSelectedStage] = useState(null) + return ( - + + !execution, + image: noExecutionImage, + message: getString('executions.noData') + // button: NewExecutionButton + }}> + + + + {selectedStage && } + + ) } diff --git a/web/src/pages/ExecutionList/ExecutionList.tsx b/web/src/pages/ExecutionList/ExecutionList.tsx index 2df41ec93..b36455047 100644 --- a/web/src/pages/ExecutionList/ExecutionList.tsx +++ b/web/src/pages/ExecutionList/ExecutionList.tsx @@ -61,7 +61,7 @@ const ExecutionList = () => { const columns: Column[] = useMemo( () => [ { - Header: getString('repos.name'), + Header: getString('executions.name'), width: 'calc(100% - 180px)', Cell: ({ row }: CellProps) => { const record = row.original @@ -127,7 +127,7 @@ const ExecutionList = () => { routes.toCODEExecution({ space, pipeline: pipeline as string, - execution: String(executionInfo.id) + execution: String(executionInfo.number) }) ) }