From 6b21f54a34fdab54d4abdb7e915eab383c94a39f Mon Sep 17 00:00:00 2001 From: Alan Greene Date: Fri, 27 Sep 2024 19:15:42 +0100 Subject: [PATCH] Improve display of skipped tasks When a task is skipped ensure this is communicated to the user instead of leaving it showing as 'pending'. In the case of when expressions, surface details of the when expression so the user can undertsand the reason for the task being skipped. Also remove elements that will never have content in this case such as the pod tab on the TaskRun details view, and replace the log container with a message indicating that the task was skipped and no logs will be available. Update the status icons and labels to differentiate between pending / not run and skipped. Apply similar changes for step-level when expressions which rely on the step actions feature being enabled. --- .../src/components/Actions/Actions.jsx | 6 +-- .../DetailsHeader/DetailsHeader.jsx | 32 ++++++++--- .../DetailsHeader/DetailsHeader.stories.js | 32 ++++++++++- .../DetailsHeader/DetailsHeader.test.jsx | 37 +++++++++++++ .../DetailsHeader/_DetailsHeader.scss | 2 +- .../components/src/components/Log/Log.jsx | 15 +++++- .../src/components/Log/Log.stories.jsx | 10 ++++ .../src/components/Log/Log.test.jsx | 13 +++++ .../components/PipelineRun/PipelineRun.jsx | 8 +++ .../PipelineRun/PipelineRun.stories.jsx | 31 ++++++++++- .../src/components/StatusIcon/StatusIcon.jsx | 10 ++++ .../StatusIcon/StatusIcon.stories.jsx | 16 +++++- .../components/StatusIcon/StatusIcon.test.jsx | 26 +++++++++ .../components/src/components/Step/Step.jsx | 11 +++- .../src/components/Step/Step.stories.js | 8 +++ .../src/components/Step/Step.test.jsx | 12 +++++ .../components/StepDetails/StepDetails.jsx | 18 ++++++- .../StepDetails/StepDetails.stories.jsx | 54 +++++++++++++++++-- .../StepDetails/StepDetails.test.jsx | 10 +++- .../components/src/components/Task/Task.jsx | 21 ++++++-- .../src/components/Task/Task.stories.jsx | 7 +++ .../src/components/Task/Task.test.jsx | 4 ++ .../TaskRunDetails/TaskRunDetails.jsx | 23 ++++---- .../TaskRunDetails/TaskRunDetails.stories.jsx | 10 ++++ .../TaskRunDetails/TaskRunDetails.test.jsx | 27 ++++++++++ .../src/components/TaskTree/TaskTree.jsx | 15 +++++- .../components/TaskTree/TaskTree.stories.jsx | 21 ++++++-- .../src/components/TaskTree/TaskTree.test.jsx | 23 ++++++-- src/containers/CustomRun/CustomRun.jsx | 4 +- src/nls/messages_de.json | 3 ++ src/nls/messages_en.json | 3 ++ src/nls/messages_es.json | 3 ++ src/nls/messages_fr.json | 3 ++ src/nls/messages_it.json | 3 ++ src/nls/messages_ja.json | 3 ++ src/nls/messages_ko.json | 3 ++ src/nls/messages_pt.json | 3 ++ src/nls/messages_zh-Hans.json | 3 ++ src/nls/messages_zh-Hant.json | 3 ++ 39 files changed, 488 insertions(+), 48 deletions(-) diff --git a/packages/components/src/components/Actions/Actions.jsx b/packages/components/src/components/Actions/Actions.jsx index 70b169e8e2..39b6e98213 100644 --- a/packages/components/src/components/Actions/Actions.jsx +++ b/packages/components/src/components/Actions/Actions.jsx @@ -11,7 +11,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { useState } from 'react'; +import { Fragment, useState } from 'react'; import { useIntl } from 'react-intl'; import { Button, @@ -105,7 +105,7 @@ export default function Actions({ items, kind, resource }) { } = item; const disabled = disable && disable(resource); return ( - <> + {hasDivider && } itemAction(resource), modalProperties) } /> - + ); })} diff --git a/packages/components/src/components/DetailsHeader/DetailsHeader.jsx b/packages/components/src/components/DetailsHeader/DetailsHeader.jsx index 41727cfd1d..e2808b4353 100644 --- a/packages/components/src/components/DetailsHeader/DetailsHeader.jsx +++ b/packages/components/src/components/DetailsHeader/DetailsHeader.jsx @@ -65,6 +65,13 @@ export default function DetailsHeader({ function getStatusLabel() { const { reason: taskReason, status: taskStatus } = getStatus(taskRun); + if (stepStatus?.terminationReason === 'Skipped') { + return intl.formatMessage({ + id: 'dashboard.taskRun.status.skipped', + defaultMessage: 'Skipped' + }); + } + if ( status === 'cancelled' || (status === 'terminated' && @@ -126,11 +133,16 @@ export default function DetailsHeader({ if (type === 'taskRun') { ({ reason: reasonToUse, status: statusToUse } = getStatus(taskRun)); statusLabel = - reasonToUse || - intl.formatMessage({ - id: 'dashboard.taskRun.status.pending', - defaultMessage: 'Pending' - }); + reason === 'tkn-dashboard:skipped' + ? intl.formatMessage({ + id: 'dashboard.taskRun.status.skipped', + defaultMessage: 'Skipped' + }) + : reasonToUse || + intl.formatMessage({ + id: 'dashboard.taskRun.status.pending', + defaultMessage: 'Pending' + }); } else { statusLabel = getStatusLabel(); } @@ -140,14 +152,20 @@ export default function DetailsHeader({ className="tkn--step-details-header" data-status={statusToUse} data-reason={reasonToUse} + data-termination-reason={stepStatus?.terminationReason} >

} hasWarning={hasWarning} - reason={reasonToUse} + reason={reason === 'tkn-dashboard:skipped' ? reason : reasonToUse} status={statusToUse} - {...(type === 'step' ? { type: 'inverse' } : null)} + {...(type === 'step' + ? { + terminationReason: stepStatus?.terminationReason, + type: 'inverse' + } + : null)} /> {displayName} diff --git a/packages/components/src/components/DetailsHeader/DetailsHeader.stories.js b/packages/components/src/components/DetailsHeader/DetailsHeader.stories.js index 93edccc867..8eefadfb0d 100644 --- a/packages/components/src/components/DetailsHeader/DetailsHeader.stories.js +++ b/packages/components/src/components/DetailsHeader/DetailsHeader.stories.js @@ -13,12 +13,13 @@ limitations under the License. import DetailsHeader from './DetailsHeader'; -const getTaskRun = ({ reason, status }) => ({ +const getTaskRun = ({ reason, status, terminationReason }) => ({ status: { conditions: [ { reason, status, + terminationReason, type: 'Succeeded' } ] @@ -71,6 +72,35 @@ export const CompletedWithWarning = { name: 'Completed with warning' }; +export const SkippedTask = { + args: { + reason: 'tkn-dashboard:skipped', + displayName: 'build', + taskRun: {}, + type: 'taskRun' + }, + argTypes: { + type: { + control: false + } + } +}; + +export const SkippedStep = { + args: { + reason: 'Completed', + status: 'terminated', + stepStatus: { terminationReason: 'Skipped' }, + displayName: 'build', + type: 'step' + }, + argTypes: { + type: { + control: false + } + } +}; + export const Failed = { args: { displayName: 'build', diff --git a/packages/components/src/components/DetailsHeader/DetailsHeader.test.jsx b/packages/components/src/components/DetailsHeader/DetailsHeader.test.jsx index 81e932f867..f23793a4da 100644 --- a/packages/components/src/components/DetailsHeader/DetailsHeader.test.jsx +++ b/packages/components/src/components/DetailsHeader/DetailsHeader.test.jsx @@ -104,6 +104,43 @@ describe('DetailsHeader', () => { expect(queryByText(/pending/i)).toBeTruthy(); }); + it('renders the skipped state for a step', () => { + const taskRun = { + status: { + conditions: [ + { + reason: 'Completed', + status: 'True', + type: 'Succeeded' + } + ] + } + }; + + const { queryByText } = render( + + ); + expect(queryByText(/skipped/i)).toBeTruthy(); + }); + + it('renders the skipped state for a TaskRun', () => { + const taskRun = {}; + + const { queryByText } = render( + + ); + expect(queryByText(/skipped/i)).toBeTruthy(); + }); + it('renders no duration for a running step', () => { const stepStatus = { running: { diff --git a/packages/components/src/components/DetailsHeader/_DetailsHeader.scss b/packages/components/src/components/DetailsHeader/_DetailsHeader.scss index dbe5ee18ae..6ccfeba376 100644 --- a/packages/components/src/components/DetailsHeader/_DetailsHeader.scss +++ b/packages/components/src/components/DetailsHeader/_DetailsHeader.scss @@ -86,7 +86,7 @@ header.tkn--step-details-header { color: $support-info; } } - &[data-status='terminated'][data-reason='Completed'], + &[data-status='terminated'][data-reason='Completed']:not([data-termination-reason='Skipped']), &[data-status='True'] { .tkn--status-label { color: $support-success; diff --git a/packages/components/src/components/Log/Log.jsx b/packages/components/src/components/Log/Log.jsx index a405115224..b3348b63b4 100644 --- a/packages/components/src/components/Log/Log.jsx +++ b/packages/components/src/components/Log/Log.jsx @@ -276,9 +276,16 @@ export class LogContainer extends Component { ); }; - getTrailerMessage = ({ exitCode, reason }) => { + getTrailerMessage = ({ exitCode, reason, terminationReason }) => { const { forcePolling, intl } = this.props; + if (terminationReason === 'Skipped') { + return intl.formatMessage({ + id: 'dashboard.pipelineRun.stepSkipped', + defaultMessage: 'Step skipped' + }); + } + if (reason && forcePolling) { return ( <> @@ -397,7 +404,11 @@ export class LogContainer extends Component { logTrailer = () => { const { forcePolling, stepStatus } = this.props; const { exitCode, reason } = (stepStatus && stepStatus.terminated) || {}; - const trailer = this.getTrailerMessage({ exitCode, reason }); + const trailer = this.getTrailerMessage({ + exitCode, + reason, + terminationReason: stepStatus?.terminationReason + }); if (!trailer) { return null; } diff --git a/packages/components/src/components/Log/Log.stories.jsx b/packages/components/src/components/Log/Log.stories.jsx index 8a1eb1f09a..20b0c543a0 100644 --- a/packages/components/src/components/Log/Log.stories.jsx +++ b/packages/components/src/components/Log/Log.stories.jsx @@ -97,6 +97,16 @@ export const Performance = { name: 'performance test (<20,000 lines with ANSI)' }; +export const Skipped = { + args: { + fetchLogs: () => 'This step was skipped', + stepStatus: { + terminated: { reason: 'Completed', exitCode: 0 }, + terminationReason: 'Skipped' + } + } +}; + export const Toolbar = { args: { fetchLogs: () => 'A log message', diff --git a/packages/components/src/components/Log/Log.test.jsx b/packages/components/src/components/Log/Log.test.jsx index aefe896caf..725fc7b6d6 100644 --- a/packages/components/src/components/Log/Log.test.jsx +++ b/packages/components/src/components/Log/Log.test.jsx @@ -61,6 +61,19 @@ describe('Log', () => { await waitFor(() => getByText(/step failed/i)); }); + it('renders skipped trailer', async () => { + const { getByText } = render( + 'testing'} + /> + ); + await waitFor(() => getByText(/step skipped/i)); + }); + it('renders pending trailer when step complete and forcePolling is true', async () => { const { getByText, queryByText } = render( skipped.name === selectedTaskId + ); + return ( <> {(selectedStepId && ( @@ -331,6 +337,7 @@ export default /* istanbul ignore next */ function PipelineRun({ definition={definition} logContainer={logContainer} onViewChange={onViewChange} + skippedTask={skippedTask} stepName={selectedStepId} stepStatus={stepStatus} taskRun={taskRun} @@ -341,6 +348,7 @@ export default /* istanbul ignore next */ function PipelineRun({ { }} onViewChange={selectedView => updateArgs({ view: selectedView })} pipelineRun={pipelineRun} - taskRuns={[taskRun, taskRunWithWarning]} + taskRuns={[ + taskRun, + taskRunWithWarning, + taskRunSkipped, + taskRunWithSkippedStep + ]} tasks={[task]} /> ); diff --git a/packages/components/src/components/StatusIcon/StatusIcon.jsx b/packages/components/src/components/StatusIcon/StatusIcon.jsx index cbaf912f11..f95071e277 100644 --- a/packages/components/src/components/StatusIcon/StatusIcon.jsx +++ b/packages/components/src/components/StatusIcon/StatusIcon.jsx @@ -18,6 +18,8 @@ import { CloseFilled, CloseOutline, Time as Pending, + Undefined, + UndefinedFilled, WarningAltFilled as WarningFilled } from '@carbon/react/icons'; import { classNames, isRunning } from '@tektoncd/dashboard-utils'; @@ -30,6 +32,7 @@ const icons = { error: CloseOutline, pending: Pending, running: Spinner, + skipped: Undefined, success: CheckmarkOutline, warning: WarningFilled }, @@ -38,6 +41,7 @@ const icons = { error: CloseFilled, pending: Pending, running: Spinner, + skipped: UndefinedFilled, success: CheckmarkFilled, warning: CheckmarkFilledWarning } @@ -63,11 +67,17 @@ export default function StatusIcon({ isCustomTask, reason, status, + terminationReason, title, type = 'normal' }) { let statusClass; if ( + (!status && reason === 'tkn-dashboard:skipped') || + terminationReason === 'Skipped' + ) { + statusClass = 'skipped'; + } else if ( (!status && !DefaultIcon) || (status === 'Unknown' && reason === 'Pending') ) { diff --git a/packages/components/src/components/StatusIcon/StatusIcon.stories.jsx b/packages/components/src/components/StatusIcon/StatusIcon.stories.jsx index 97814d7054..e121301f56 100644 --- a/packages/components/src/components/StatusIcon/StatusIcon.stories.jsx +++ b/packages/components/src/components/StatusIcon/StatusIcon.stories.jsx @@ -15,7 +15,7 @@ limitations under the License. import { Pending as DefaultStepIcon, PendingFilled as DefaultTaskIcon, - UndefinedFilled as UndefinedIcon + UnknownFilled as UnknownIcon } from '@carbon/react/icons'; import StatusIcon from './StatusIcon'; @@ -90,6 +90,10 @@ export const SucceededWithWarning = { name: 'Succeeded with warning' }; +export const Skipped = { + args: { status: 'True', terminationReason: 'Skipped' } +}; + export const DefaultTask = { args: { DefaultIcon: DefaultTaskIcon }, name: 'Task default - no status received yet' @@ -101,7 +105,7 @@ export const DefaultStep = { }; export const CustomRun = { - args: { DefaultIcon: UndefinedIcon }, + args: { DefaultIcon: UnknownIcon }, name: 'CustomRun (unknown status)' }; @@ -171,6 +175,10 @@ export const AllIcons = { Succeeded with warning +
  • + + Skipped +
  • Default - no status received yet @@ -199,6 +207,10 @@ export const AllIcons = { Succeeded with warning
  • +
  • + + Skipped +
  • Default - no status received yet diff --git a/packages/components/src/components/StatusIcon/StatusIcon.test.jsx b/packages/components/src/components/StatusIcon/StatusIcon.test.jsx index 67e07b7ce2..184c2a7833 100644 --- a/packages/components/src/components/StatusIcon/StatusIcon.test.jsx +++ b/packages/components/src/components/StatusIcon/StatusIcon.test.jsx @@ -23,6 +23,18 @@ describe('StatusIcon', () => { expect(queryByText(title)).toBeTruthy(); }); + it('renders success state', () => { + render(); + }); + + it('renders success with warning state', () => { + render(); + }); + + it('renders step success state', () => { + render(); + }); + it('renders PipelineRunCancelled state', () => { render(); }); @@ -39,6 +51,20 @@ describe('StatusIcon', () => { render(); }); + it('renders Skipped state', () => { + render( + + ); + }); + + it('renders Custom Task running state', () => { + render(); + }); + it('gracefully handles unsupported state', () => { render(); }); diff --git a/packages/components/src/components/Step/Step.jsx b/packages/components/src/components/Step/Step.jsx index c3fa96a764..f60d933ee1 100644 --- a/packages/components/src/components/Step/Step.jsx +++ b/packages/components/src/components/Step/Step.jsx @@ -23,7 +23,8 @@ export default function Step({ reason, selected, status, - stepName = 'unknown' + stepName = 'unknown', + terminationReason }) { const intl = useIntl(); @@ -33,6 +34,12 @@ export default function Step({ } function getStatusLabel() { + if (terminationReason === 'Skipped') { + return intl.formatMessage({ + id: 'dashboard.taskRun.status.skipped', + defaultMessage: 'Skipped' + }); + } if ( status === 'cancelled' || (status === 'terminated' && @@ -93,6 +100,7 @@ export default function Step({ data-status={status} data-reason={reason} data-selected={selected || undefined} + data-termination-reason={terminationReason} > diff --git a/packages/components/src/components/Step/Step.stories.js b/packages/components/src/components/Step/Step.stories.js index 63cafbb50d..0a7affc6c8 100644 --- a/packages/components/src/components/Step/Step.stories.js +++ b/packages/components/src/components/Step/Step.stories.js @@ -42,4 +42,12 @@ export const CompletedWithWarning = { name: 'Completed with warning' }; +export const Skipped = { + args: { + reason: 'Completed', + status: 'terminated', + terminationReason: 'Skipped' + } +}; + export const Error = { args: { reason: 'Error', status: 'terminated' } }; diff --git a/packages/components/src/components/Step/Step.test.jsx b/packages/components/src/components/Step/Step.test.jsx index f53c496899..c7cfdbe485 100644 --- a/packages/components/src/components/Step/Step.test.jsx +++ b/packages/components/src/components/Step/Step.test.jsx @@ -74,6 +74,18 @@ it('Step renders completed with warning state', () => { expect(queryByText(/Completed with exit code 1/i)).toBeTruthy(); }); +it('Step renders skipped state', () => { + const { queryByText } = render( + + ); + expect(queryByText(/Skipped/i)).toBeTruthy(); +}); + it('Step renders error state', () => { const { queryByText } = render(); expect(queryByText(/Failed/i)).toBeTruthy(); diff --git a/packages/components/src/components/StepDetails/StepDetails.jsx b/packages/components/src/components/StepDetails/StepDetails.jsx index faea392934..34af8b9f0a 100644 --- a/packages/components/src/components/StepDetails/StepDetails.jsx +++ b/packages/components/src/components/StepDetails/StepDetails.jsx @@ -17,6 +17,7 @@ import { getStatus, getStepStatusReason } from '@tektoncd/dashboard-utils'; import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react'; import DetailsHeader from '../DetailsHeader'; +import Log from '../Log'; import StepDefinition from '../StepDefinition'; const tabs = ['logs', 'details']; @@ -30,6 +31,7 @@ const StepDetails = ({ definition, logContainer, onViewChange = defaults.onViewChange, + skippedTask, stepName, stepStatus, taskRun = defaults.taskRun, @@ -77,7 +79,21 @@ const StepDetails = ({ - {selectedTabIndex === 0 && logContainer} + + {selectedTabIndex === 0 && skippedTask ? ( + + intl.formatMessage({ + id: 'dashboard.taskRun.logs.skipped', + defaultMessage: + 'This step did not run as the task was skipped. See task status for more details.' + }) + } + /> + ) : ( + logContainer + )} + {selectedTabIndex === 1 && ( diff --git a/packages/components/src/components/StepDetails/StepDetails.stories.jsx b/packages/components/src/components/StepDetails/StepDetails.stories.jsx index b7cf5e9188..80657cd04c 100644 --- a/packages/components/src/components/StepDetails/StepDetails.stories.jsx +++ b/packages/components/src/components/StepDetails/StepDetails.stories.jsx @@ -16,16 +16,23 @@ import { useArgs } from '@storybook/preview-api'; import Log from '../Log'; import StepDetails from './StepDetails'; -function getStepStatus({ exitCode = 0 } = {}) { - return { terminated: { exitCode, reason: 'Completed' } }; +function getStepStatus({ exitCode = 0, terminationReason } = {}) { + return { terminated: { exitCode, reason: 'Completed' }, terminationReason }; } const ansiLog = '\n=== demo-pipeline-run-1-build-skaffold-app-2mrdg-pod-59e217: build-step-git-source-skaffold-git-ml8j4 ===\n{"level":"info","ts":1553865693.943092,"logger":"fallback-logger","caller":"git-init/main.go:100","msg":"Successfully cloned https://github.com/GoogleContainerTools/skaffold @ \\"master\\" in path \\"/workspace\\""}\n\n=== demo-pipeline-run-1-build-skaffold-app-2mrdg-pod-59e217: build-step-build-and-push ===\n\u001b[36mINFO\u001b[0m[0000] Downloading base image golang:1.10.1-alpine3.7\n2019/03/29 13:21:34 No matching credentials were found, falling back on anonymous\n\u001b[36mINFO\u001b[0m[0001] Executing 0 build triggers\n\u001b[36mINFO\u001b[0m[0001] Unpacking rootfs as cmd RUN go build -o /app . requires it.\n\u001b[36mINFO\u001b[0m[0010] Taking snapshot of full filesystem...\n\u001b[36mINFO\u001b[0m[0015] Using files from context: [/workspace/examples/microservices/leeroy-app/app.go]\n\u001b[36mINFO\u001b[0m[0015] COPY app.go .\n\u001b[36mINFO\u001b[0m[0015] Taking snapshot of files...\n\u001b[36mINFO\u001b[0m[0015] RUN go build -o /app .\n\u001b[36mINFO\u001b[0m[0015] cmd: /bin/sh\n\u001b[36mINFO\u001b[0m[0015] args: [-c go build -o /app .]\n\u001b[36mINFO\u001b[0m[0016] Taking snapshot of full filesystem...\n\u001b[36mINFO\u001b[0m[0036] CMD ["./app"]\n\u001b[36mINFO\u001b[0m[0036] COPY --from=builder /app .\n\u001b[36mINFO\u001b[0m[0036] Taking snapshot of files...\nerror pushing image: failed to push to destination gcr.io/christiewilson-catfactory/leeroy-app:latest: Get https://gcr.io/v2/token?scope=repository%3Achristiewilson-catfactory%2Fleeroy-app%3Apush%2Cpull\u0026scope=repository%3Alibrary%2Falpine%3Apull\u0026service=gcr.io exit status 1\n\n=== demo-pipeline-run-1-build-skaffold-app-2mrdg-pod-59e217: nop ===\nBuild successful\n'; -function getLogContainer({ exitCode = 0 } = {}) { +function getLogContainer({ + exitCode = 0, + logContent = ansiLog, + terminationReason +} = {}) { return ( - ansiLog} stepStatus={getStepStatus({ exitCode })} /> + logContent} + stepStatus={getStepStatus({ exitCode, terminationReason })} + /> ); } @@ -70,3 +77,42 @@ export const WithWarning = { ); } }; + +export const SkippedTask = { + args: { + logContainer: getLogContainer(), + skippedTask: {} + }, + render: args => { + const [, updateArgs] = useArgs(); + return ( + updateArgs({ view: selectedView })} + /> + ); + } +}; + +export const SkippedStep = { + args: { + logContainer: getLogContainer({ + logContent: + 'Step was skipped due to when expressions were evaluated to false.', + terminationReason: 'Skipped' + }), + stepStatus: { + terminated: { exitCode: 0, reason: 'Completed' }, + terminationReason: 'Skipped' + } + }, + render: args => { + const [, updateArgs] = useArgs(); + return ( + updateArgs({ view: selectedView })} + /> + ); + } +}; diff --git a/packages/components/src/components/StepDetails/StepDetails.test.jsx b/packages/components/src/components/StepDetails/StepDetails.test.jsx index b65d52dbef..7cef088806 100644 --- a/packages/components/src/components/StepDetails/StepDetails.test.jsx +++ b/packages/components/src/components/StepDetails/StepDetails.test.jsx @@ -11,7 +11,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { fireEvent } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import { renderWithRouter } from '../../utils/test'; import StepDetails from './StepDetails'; @@ -53,4 +53,12 @@ describe('StepDetails', () => { fireEvent.click(getByText(/logs/i)); }); + + it('renders skipped Task state', async () => { + const { getByText } = renderWithRouter( + + ); + + await waitFor(() => getByText(/task was skipped/i)); + }); }); diff --git a/packages/components/src/components/Task/Task.jsx b/packages/components/src/components/Task/Task.jsx index 72002bcfa7..412d8412f0 100644 --- a/packages/components/src/components/Task/Task.jsx +++ b/packages/components/src/components/Task/Task.jsx @@ -45,7 +45,7 @@ class Task extends Component { const { reason, selectedStepId, steps } = this.props; let hasWarning = false; const stepData = updateUnexecutedSteps(steps).map(step => { - const { name } = step; + const { name, terminationReason } = step; const { exitCode, status, @@ -62,7 +62,14 @@ class Task extends Component { ? 'cancelled' : status; - return { exitCode, name, selected, stepReason, stepStatus }; + return { + exitCode, + name, + selected, + stepReason, + stepStatus, + terminationReason + }; }); if (propagateWarning) { @@ -237,7 +244,14 @@ class Task extends Component { {expanded && (
      {this.getStepData().map(step => { - const { exitCode, name, selected, stepReason, stepStatus } = step; + const { + exitCode, + name, + selected, + stepReason, + stepStatus, + terminationReason + } = step; return ( ); })} diff --git a/packages/components/src/components/Task/Task.stories.jsx b/packages/components/src/components/Task/Task.stories.jsx index 6b24cda1b1..56b6f1908c 100644 --- a/packages/components/src/components/Task/Task.stories.jsx +++ b/packages/components/src/components/Task/Task.stories.jsx @@ -51,6 +51,8 @@ export const Pending = { args: { ...Unknown.args, reason: 'Pending' } }; export const Running = { args: { ...Unknown.args, reason: 'Running' } }; +export const Skipped = { args: { reason: 'tkn-dashboard:skipped' } }; + export const Expanded = args => { const [, updateArgs] = useArgs(); @@ -64,6 +66,11 @@ export const Expanded = args => { reason="Running" steps={[ { name: 'lint', terminated: { exitCode: 0, reason: 'Completed' } }, + { + name: 'check', + terminated: { exitCode: 0, reason: 'Completed' }, + terminationReason: 'Skipped' + }, { name: 'test', terminated: { exitCode: 1, reason: 'Completed' } }, { name: 'build', running: {} }, { name: 'deploy', running: {} } diff --git a/packages/components/src/components/Task/Task.test.jsx b/packages/components/src/components/Task/Task.test.jsx index d2e3ad4ab4..bae6bf0a9f 100644 --- a/packages/components/src/components/Task/Task.test.jsx +++ b/packages/components/src/components/Task/Task.test.jsx @@ -147,6 +147,10 @@ describe('Task', () => { render(); }); + it('renders skipped state', () => { + render(); + }); + it('renders cancelled state', () => { render( + {intl.formatMessage({ id: 'dashboard.taskRun.params', defaultMessage: 'Parameters' @@ -180,7 +181,7 @@ const TaskRunDetails = ({ ); tabPanels.push( - + {selectedTabIndex === tabPanels.length && (
      {paramsTable}
      )} @@ -189,7 +190,7 @@ const TaskRunDetails = ({ } if (resultsTable) { tabList.push( - + {intl.formatMessage({ id: 'dashboard.taskRun.results', defaultMessage: 'Results' @@ -197,7 +198,7 @@ const TaskRunDetails = ({ ); tabPanels.push( - + {selectedTabIndex === tabPanels.length && (
      {resultsTable}
      )} @@ -205,7 +206,7 @@ const TaskRunDetails = ({ ); } tabList.push( - + {intl.formatMessage({ id: 'dashboard.taskRun.status', defaultMessage: 'Status' @@ -213,13 +214,14 @@ const TaskRunDetails = ({ ); tabPanels.push( - + {selectedTabIndex === tabPanels.length && (
      ); - if (pod) { - tabList.push(Pod); + if (!skippedTask && pod) { + tabList.push(Pod); tabPanels.push( - + {selectedTabIndex === tabPanels.length && (
      {hasEvents ? ( @@ -272,6 +274,7 @@ const TaskRunDetails = ({ diff --git a/packages/components/src/components/TaskRunDetails/TaskRunDetails.stories.jsx b/packages/components/src/components/TaskRunDetails/TaskRunDetails.stories.jsx index 77bff4649c..d5d36b16fb 100644 --- a/packages/components/src/components/TaskRunDetails/TaskRunDetails.stories.jsx +++ b/packages/components/src/components/TaskRunDetails/TaskRunDetails.stories.jsx @@ -194,3 +194,13 @@ export const Pod = { ); } }; + +export const Skipped = { + args: { + ...Pod.args, + skippedTask: { + reason: 'When Expressions evaluated to false', + whenExpressions: [{ cel: `'yes'=='missing'` }] + } + } +}; diff --git a/packages/components/src/components/TaskRunDetails/TaskRunDetails.test.jsx b/packages/components/src/components/TaskRunDetails/TaskRunDetails.test.jsx index 607377e371..c510574c1a 100644 --- a/packages/components/src/components/TaskRunDetails/TaskRunDetails.test.jsx +++ b/packages/components/src/components/TaskRunDetails/TaskRunDetails.test.jsx @@ -247,4 +247,31 @@ describe('TaskRunDetails', () => { expect(queryByText('Resource')).toBeFalsy(); expect(queryByText(waitingMessage)).toBeTruthy(); }); + + it('renders skipped task', () => { + const reason = 'When Expressions evaluated to false'; + const podName = 'fake_pod'; + const pod = { metadata: { name: podName } }; + const taskRun = { + metadata: { name: 'task-run-name' }, + spec: {}, + status: {} + }; + const { queryByText } = render( + + ); + expect(queryByText('Pod')).toBeFalsy(); + expect(queryByText(reason)).toBeTruthy(); + }); }); diff --git a/packages/components/src/components/TaskTree/TaskTree.jsx b/packages/components/src/components/TaskTree/TaskTree.jsx index a38393f50d..09e6944803 100644 --- a/packages/components/src/components/TaskTree/TaskTree.jsx +++ b/packages/components/src/components/TaskTree/TaskTree.jsx @@ -15,6 +15,7 @@ import { getStatus, labels as labelConstants } from '@tektoncd/dashboard-utils'; import Task from '../Task'; const defaults = { + skippedTasks: [], taskRuns: [] }; @@ -26,6 +27,7 @@ const TaskTree = ({ selectedStepId, selectedTaskId, selectedTaskRunName, + skippedTasks = defaults.skippedTasks, taskRuns = defaults.taskRuns }) => { if (!taskRuns) { @@ -62,7 +64,9 @@ const TaskTree = ({ }; } - const { reason, status } = getStatus(taskRunToUse); + const taskRunStatus = getStatus(taskRunToUse); + let { reason } = taskRunStatus; + const { status } = taskRunStatus; const { steps } = taskRunToUse.status || {}; const expanded = // should only have 1 expanded task at a time (may change in a future design) @@ -82,6 +86,15 @@ const TaskTree = ({ hasExpandedTask = true; } + if ( + !reason && + skippedTasks.find( + skippedTask => skippedTask.name === pipelineTaskName + ) + ) { + reason = 'tkn-dashboard:skipped'; + } + const selectDefaultStep = !selectedTaskId || (isSelectedTaskMatrix && !selectedTaskRunName); return ( diff --git a/packages/components/src/components/TaskTree/TaskTree.stories.jsx b/packages/components/src/components/TaskTree/TaskTree.stories.jsx index 3f1a7fa1ea..2edeb995a9 100644 --- a/packages/components/src/components/TaskTree/TaskTree.stories.jsx +++ b/packages/components/src/components/TaskTree/TaskTree.stories.jsx @@ -19,6 +19,7 @@ export default { args: { selectedStepId: undefined, selectedTaskId: undefined, + skippedTasks: [{ name: 'Task 2' }], taskRuns: [ { metadata: { @@ -30,8 +31,8 @@ export default { { reason: 'Completed', status: 'True', type: 'Succeeded' } ], steps: [ - { name: 'build', terminated: { reason: 'Completed' } }, - { name: 'test', terminated: { reason: 'Completed' } } + { name: 'build', terminated: { exitCode: 0, reason: 'Completed' } }, + { name: 'test', terminated: { exitCode: 1, reason: 'Completed' } } ] } }, @@ -40,6 +41,16 @@ export default { labels: { 'tekton.dev/pipelineTask': 'Task 2' }, uid: 'task2' }, + status: { + conditions: [], + steps: [{ name: 'build' }, { name: 'test' }] + } + }, + { + metadata: { + labels: { 'tekton.dev/pipelineTask': 'Task 3' }, + uid: 'task3' + }, status: { conditions: [ { reason: 'Failed', status: 'False', type: 'Succeeded' } @@ -53,10 +64,10 @@ export default { }, { metadata: { - labels: { 'tekton.dev/pipelineTask': 'Task 3' }, - uid: 'task3' + labels: { 'tekton.dev/pipelineTask': 'Task 4' }, + uid: 'task4' }, - pipelineTaskName: 'Task 3', + pipelineTaskName: 'Task 4', status: { conditions: [ { reason: 'Running', status: 'Unknown', type: 'Succeeded' } diff --git a/packages/components/src/components/TaskTree/TaskTree.test.jsx b/packages/components/src/components/TaskTree/TaskTree.test.jsx index c0e67f78b2..55e68bf369 100644 --- a/packages/components/src/components/TaskTree/TaskTree.test.jsx +++ b/packages/components/src/components/TaskTree/TaskTree.test.jsx @@ -84,7 +84,7 @@ it('TaskTree renders when taskRuns contains a falsy run', () => { render(); }); -it('TaskTree renders and expands first Task in TaskRun with no error', () => { +it('TaskTree renders and expands first Task in run with no error', () => { const { queryByText } = render(); // Selected Task should have two child elements. The anchor and ordered list // of steps in expanded task @@ -99,7 +99,7 @@ it('TaskTree renders and expands first Task in TaskRun with no error', () => { ).toHaveLength(1); }); -it('TaskTree renders and expands error Task in TaskRun', () => { +it('TaskTree renders and expands error Task', () => { const props = getProps(); props.taskRuns[1].status.conditions[0].status = 'False'; @@ -117,7 +117,7 @@ it('TaskTree renders and expands error Task in TaskRun', () => { ).toHaveLength(1); }); -it('TaskTree renders and expands first error Task in TaskRun', () => { +it('TaskTree renders and expands first error Task', () => { const props = getProps(); props.taskRuns[1].status.conditions[0].status = 'False'; props.taskRuns[2].status.conditions[0].status = 'False'; @@ -136,6 +136,23 @@ it('TaskTree renders and expands first error Task in TaskRun', () => { ).toHaveLength(1); }); +it('TaskTree renders skipped Task', () => { + const { queryByText } = render( + + ); + // Selected Task should have two child elements. The anchor and ordered list + // of steps in expanded task + expect(queryByText('A Task').parentNode.parentNode.childNodes).toHaveLength( + 2 + ); + expect( + queryByText('A Second Task').parentNode.parentNode.childNodes + ).toHaveLength(1); + expect( + queryByText('A Third Task').parentNode.parentNode.childNodes + ).toHaveLength(1); +}); + it('TaskTree handles click event on Task', () => { const onSelect = vi.fn(); const { getByText } = render( diff --git a/src/containers/CustomRun/CustomRun.jsx b/src/containers/CustomRun/CustomRun.jsx index 63e1afcddd..9fbe9ba096 100644 --- a/src/containers/CustomRun/CustomRun.jsx +++ b/src/containers/CustomRun/CustomRun.jsx @@ -16,7 +16,7 @@ import { useState } from 'react'; import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'; import { useIntl } from 'react-intl'; import { InlineNotification } from '@carbon/react'; -import { UndefinedFilled as UndefinedIcon } from '@carbon/react/icons'; +import { UnknownFilled as UnknownIcon } from '@carbon/react/icons'; import { ActionableNotification, Actions, @@ -69,7 +69,7 @@ function getRunStatusIcon(run) { const { reason, status } = getStatus(run); return ( } + DefaultIcon={props => } isCustomTask reason={reason} status={status} diff --git a/src/nls/messages_de.json b/src/nls/messages_de.json index 38d1aa16b4..6b9f57148d 100644 --- a/src/nls/messages_de.json +++ b/src/nls/messages_de.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "Schritt abgeschlossen", "dashboard.pipelineRun.stepCompleted.exitCode": "", "dashboard.pipelineRun.stepFailed": "Schritt fehlgeschlagen", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "Fehler beim Laden von PipelineRuns", "dashboard.pipelines.errorLoading": "", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "", "dashboard.tableHeader.value": "", "dashboard.taskRun.logs": "Protokolle", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "", "dashboard.taskRun.results": "", "dashboard.taskRun.status": "Status", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "Nicht ausgeführt", "dashboard.taskRun.status.pending": "Anstehend", "dashboard.taskRun.status.running": "Wird ausgeführt", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "Abgeschlossen", "dashboard.taskRun.status.succeeded.warning": "", "dashboard.taskRun.status.waiting": "Wartestatus", diff --git a/src/nls/messages_en.json b/src/nls/messages_en.json index 11f6381cdd..50d6368748 100644 --- a/src/nls/messages_en.json +++ b/src/nls/messages_en.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "Step completed successfully", "dashboard.pipelineRun.stepCompleted.exitCode": "Step completed with exit code {exitCode}", "dashboard.pipelineRun.stepFailed": "Step failed", + "dashboard.pipelineRun.stepSkipped": "Step skipped", "dashboard.pipelineRuns.error": "Error loading PipelineRuns", "dashboard.pipelines.errorLoading": "Error loading Pipelines", "dashboard.pipelines.v1Resources.label": "Use Tekton Pipelines API version v1", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "Task", "dashboard.tableHeader.value": "Value", "dashboard.taskRun.logs": "Logs", + "dashboard.taskRun.logs.skipped": "This step did not run as the task was skipped. See task status for more details.", "dashboard.taskRun.params": "Parameters", "dashboard.taskRun.results": "Results", "dashboard.taskRun.status": "Status", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "Not run", "dashboard.taskRun.status.pending": "Pending", "dashboard.taskRun.status.running": "Running", + "dashboard.taskRun.status.skipped": "Skipped", "dashboard.taskRun.status.succeeded": "Completed", "dashboard.taskRun.status.succeeded.warning": "Completed with exit code {exitCode}", "dashboard.taskRun.status.waiting": "Waiting", diff --git a/src/nls/messages_es.json b/src/nls/messages_es.json index db5d7f4666..75bd5f9726 100644 --- a/src/nls/messages_es.json +++ b/src/nls/messages_es.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "Paso completado", "dashboard.pipelineRun.stepCompleted.exitCode": "", "dashboard.pipelineRun.stepFailed": "Paso fallido", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "Error al cargar PipelineRuns", "dashboard.pipelines.errorLoading": "", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "", "dashboard.tableHeader.value": "", "dashboard.taskRun.logs": "Anotaciones", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "", "dashboard.taskRun.results": "", "dashboard.taskRun.status": "Estado", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "No ejecutado", "dashboard.taskRun.status.pending": "Pendiente", "dashboard.taskRun.status.running": "En ejecución", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "Completado", "dashboard.taskRun.status.succeeded.warning": "", "dashboard.taskRun.status.waiting": "En espera", diff --git a/src/nls/messages_fr.json b/src/nls/messages_fr.json index 7585031b32..b3d4046d53 100644 --- a/src/nls/messages_fr.json +++ b/src/nls/messages_fr.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "Etape terminée", "dashboard.pipelineRun.stepCompleted.exitCode": "", "dashboard.pipelineRun.stepFailed": "Echec de l'étape", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "Une erreur s'est produite lors du chargement des ressources PipelineRun", "dashboard.pipelines.errorLoading": "", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "", "dashboard.tableHeader.value": "", "dashboard.taskRun.logs": "Journaux", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "", "dashboard.taskRun.results": "", "dashboard.taskRun.status": "Statut", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "Non exécuté", "dashboard.taskRun.status.pending": "En attente", "dashboard.taskRun.status.running": "En cours d'exécution", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "Terminé", "dashboard.taskRun.status.succeeded.warning": "", "dashboard.taskRun.status.waiting": "En attente", diff --git a/src/nls/messages_it.json b/src/nls/messages_it.json index 2f31225ade..a591aca33a 100644 --- a/src/nls/messages_it.json +++ b/src/nls/messages_it.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "Passo completato", "dashboard.pipelineRun.stepCompleted.exitCode": "", "dashboard.pipelineRun.stepFailed": "Passo non riuscito", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "Errore nel caricamento delle esecuzioni pipeline", "dashboard.pipelines.errorLoading": "", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "", "dashboard.tableHeader.value": "", "dashboard.taskRun.logs": "Log", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "", "dashboard.taskRun.results": "", "dashboard.taskRun.status": "Stato", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "Non eseguito", "dashboard.taskRun.status.pending": "In attesa", "dashboard.taskRun.status.running": "In esecuzione", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "Completato", "dashboard.taskRun.status.succeeded.warning": "", "dashboard.taskRun.status.waiting": "In attesa", diff --git a/src/nls/messages_ja.json b/src/nls/messages_ja.json index 6eaa312401..0b40b3095c 100644 --- a/src/nls/messages_ja.json +++ b/src/nls/messages_ja.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "ステップが完了しました", "dashboard.pipelineRun.stepCompleted.exitCode": "", "dashboard.pipelineRun.stepFailed": "ステップが失敗しました", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "PipelineRunのロード中にエラーが発生しました", "dashboard.pipelines.errorLoading": "Pipelineのロード中にエラーが発生しました", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "", "dashboard.tableHeader.value": "値", "dashboard.taskRun.logs": "ログ", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "パラメータ", "dashboard.taskRun.results": "結果", "dashboard.taskRun.status": "ステータス", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "未実行", "dashboard.taskRun.status.pending": "保留中", "dashboard.taskRun.status.running": "実行中", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "完了", "dashboard.taskRun.status.succeeded.warning": "", "dashboard.taskRun.status.waiting": "待機中", diff --git a/src/nls/messages_ko.json b/src/nls/messages_ko.json index 5e2eb56542..5e519bfc9b 100644 --- a/src/nls/messages_ko.json +++ b/src/nls/messages_ko.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "단계 완료", "dashboard.pipelineRun.stepCompleted.exitCode": "{exitCode} 종료 코드와 함께 단계가 완료됨", "dashboard.pipelineRun.stepFailed": "단계 실패", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "PipelineRun 로드 중 오류 발생", "dashboard.pipelines.errorLoading": "Pipelines 로드하는 중 오류가 발생했습니다.", "dashboard.pipelines.v1Resources.label": "Tekton Pipelines API 버전 v1 사용", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "작업", "dashboard.tableHeader.value": "값", "dashboard.taskRun.logs": "로그", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "매개변수", "dashboard.taskRun.results": "결과", "dashboard.taskRun.status": "상태", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "실행하지 않음", "dashboard.taskRun.status.pending": "보류 중", "dashboard.taskRun.status.running": "실행 중", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "완료됨", "dashboard.taskRun.status.succeeded.warning": "종료 코드 {exitCode}로 완료됨", "dashboard.taskRun.status.waiting": "대기 중", diff --git a/src/nls/messages_pt.json b/src/nls/messages_pt.json index b60bd1df2f..babfcffb32 100644 --- a/src/nls/messages_pt.json +++ b/src/nls/messages_pt.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "Etapa concluída", "dashboard.pipelineRun.stepCompleted.exitCode": "", "dashboard.pipelineRun.stepFailed": "Etapa com falha", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "Erro ao carregar os PipelineRuns", "dashboard.pipelines.errorLoading": "", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "", "dashboard.tableHeader.value": "", "dashboard.taskRun.logs": "Logs", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "", "dashboard.taskRun.results": "", "dashboard.taskRun.status": "Status", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "Não executado", "dashboard.taskRun.status.pending": "Pendente", "dashboard.taskRun.status.running": "Executando", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "Concluído", "dashboard.taskRun.status.succeeded.warning": "Completado com exit code {exitCode}", "dashboard.taskRun.status.waiting": "Aguardando", diff --git a/src/nls/messages_zh-Hans.json b/src/nls/messages_zh-Hans.json index 6138fa5f59..13612239d5 100644 --- a/src/nls/messages_zh-Hans.json +++ b/src/nls/messages_zh-Hans.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "步骤已完成", "dashboard.pipelineRun.stepCompleted.exitCode": "步骤已完成,退出代码为 {exitCode}", "dashboard.pipelineRun.stepFailed": "步骤失败", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "加载 PipelineRun 时出错", "dashboard.pipelines.errorLoading": "加载 Pipelines 时出错", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "Task", "dashboard.tableHeader.value": "值", "dashboard.taskRun.logs": "日志", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "参数", "dashboard.taskRun.results": "结果", "dashboard.taskRun.status": "状态", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "未运行", "dashboard.taskRun.status.pending": "暂挂中", "dashboard.taskRun.status.running": "运行中", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "已完成", "dashboard.taskRun.status.succeeded.warning": "已完成,退出代码 {exitCode}", "dashboard.taskRun.status.waiting": "等待中", diff --git a/src/nls/messages_zh-Hant.json b/src/nls/messages_zh-Hant.json index 8807eb19b6..7dd0f66d9c 100644 --- a/src/nls/messages_zh-Hant.json +++ b/src/nls/messages_zh-Hant.json @@ -187,6 +187,7 @@ "dashboard.pipelineRun.stepCompleted": "步驟已完成", "dashboard.pipelineRun.stepCompleted.exitCode": "", "dashboard.pipelineRun.stepFailed": "步驟失敗", + "dashboard.pipelineRun.stepSkipped": "", "dashboard.pipelineRuns.error": "載入 PipelineRuns 時發生錯誤", "dashboard.pipelines.errorLoading": "", "dashboard.pipelines.v1Resources.label": "", @@ -234,6 +235,7 @@ "dashboard.tableHeader.task": "", "dashboard.tableHeader.value": "", "dashboard.taskRun.logs": "日誌", + "dashboard.taskRun.logs.skipped": "", "dashboard.taskRun.params": "", "dashboard.taskRun.results": "", "dashboard.taskRun.status": "狀態", @@ -242,6 +244,7 @@ "dashboard.taskRun.status.notRun": "未執行", "dashboard.taskRun.status.pending": "擱置中", "dashboard.taskRun.status.running": "執行中", + "dashboard.taskRun.status.skipped": "", "dashboard.taskRun.status.succeeded": "已完成", "dashboard.taskRun.status.succeeded.warning": "", "dashboard.taskRun.status.waiting": "等待中",