From 02c864d0f609d9131326659637e5fe709c4b17e4 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 | 34 +++++++++--- .../DetailsHeader/DetailsHeader.stories.js | 33 +++++++++++- .../DetailsHeader/DetailsHeader.test.jsx | 39 ++++++++++++++ .../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 | 16 +++++- .../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 | 8 +++ .../src/components/Task/Task.test.jsx | 6 +++ .../TaskRunDetails/TaskRunDetails.jsx | 29 ++++++---- .../TaskRunDetails/TaskRunDetails.stories.jsx | 10 ++++ .../TaskRunDetails/TaskRunDetails.test.jsx | 27 ++++++++++ .../src/components/TaskTree/TaskTree.jsx | 21 +++++++- .../components/TaskTree/TaskTree.stories.jsx | 21 ++++++-- .../src/components/TaskTree/TaskTree.test.jsx | 23 ++++++-- packages/utils/src/utils/constants.js | 4 +- 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 ++ 40 files changed, 513 insertions(+), 53 deletions(-) diff --git a/packages/components/src/components/Actions/Actions.jsx b/packages/components/src/components/Actions/Actions.jsx index 70b169e8e..39b6e9821 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 41727cfd1..fa3ee800b 100644 --- a/packages/components/src/components/DetailsHeader/DetailsHeader.jsx +++ b/packages/components/src/components/DetailsHeader/DetailsHeader.jsx @@ -13,7 +13,7 @@ limitations under the License. import { Pending as DefaultIcon } from '@carbon/react/icons'; import { useIntl } from 'react-intl'; -import { getStatus } from '@tektoncd/dashboard-utils'; +import { dashboardReasonSkipped, getStatus } from '@tektoncd/dashboard-utils'; import FormattedDuration from '../FormattedDuration'; import StatusIcon from '../StatusIcon'; @@ -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 === dashboardReasonSkipped + ? 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 === dashboardReasonSkipped ? 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 93edccc86..49b391195 100644 --- a/packages/components/src/components/DetailsHeader/DetailsHeader.stories.js +++ b/packages/components/src/components/DetailsHeader/DetailsHeader.stories.js @@ -11,14 +11,16 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { dashboardReasonSkipped } from '@tektoncd/dashboard-utils'; import DetailsHeader from './DetailsHeader'; -const getTaskRun = ({ reason, status }) => ({ +const getTaskRun = ({ reason, status, terminationReason }) => ({ status: { conditions: [ { reason, status, + terminationReason, type: 'Succeeded' } ] @@ -71,6 +73,35 @@ export const CompletedWithWarning = { name: 'Completed with warning' }; +export const SkippedTask = { + args: { + reason: dashboardReasonSkipped, + 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 81e932f86..ad7445f54 100644 --- a/packages/components/src/components/DetailsHeader/DetailsHeader.test.jsx +++ b/packages/components/src/components/DetailsHeader/DetailsHeader.test.jsx @@ -11,6 +11,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { dashboardReasonSkipped } from '@tektoncd/dashboard-utils'; + import DetailsHeader from './DetailsHeader'; import { render } from '../../utils/test'; @@ -104,6 +106,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 dbe5ee18a..6ccfeba37 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 a40511522..b3348b63b 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 8a1eb1f09..20b0c543a 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 aefe896ca..725fc7b6d 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 cbaf912f1..56acd23a4 100644 --- a/packages/components/src/components/StatusIcon/StatusIcon.jsx +++ b/packages/components/src/components/StatusIcon/StatusIcon.jsx @@ -18,9 +18,15 @@ import { CloseFilled, CloseOutline, Time as Pending, + Undefined, + UndefinedFilled, WarningAltFilled as WarningFilled } from '@carbon/react/icons'; -import { classNames, isRunning } from '@tektoncd/dashboard-utils'; +import { + classNames, + dashboardReasonSkipped, + isRunning +} from '@tektoncd/dashboard-utils'; import Spinner from '../Spinner'; @@ -30,6 +36,7 @@ const icons = { error: CloseOutline, pending: Pending, running: Spinner, + skipped: Undefined, success: CheckmarkOutline, warning: WarningFilled }, @@ -38,6 +45,7 @@ const icons = { error: CloseFilled, pending: Pending, running: Spinner, + skipped: UndefinedFilled, success: CheckmarkFilled, warning: CheckmarkFilledWarning } @@ -63,11 +71,17 @@ export default function StatusIcon({ isCustomTask, reason, status, + terminationReason, title, type = 'normal' }) { let statusClass; if ( + (!status && reason === dashboardReasonSkipped) || + 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 97814d705..e121301f5 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 67e07b7ce..184c2a783 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 c3fa96a76..f60d933ee 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 63cafbb50..0a7affc6c 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 f53c49689..c7cfdbe48 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 faea39293..34af8b9f0 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 b7cf5e918..80657cd04 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 b65d52dbe..7cef08880 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 72002bcfa..412d8412f 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 6b24cda1b..8be9057b9 100644 --- a/packages/components/src/components/Task/Task.stories.jsx +++ b/packages/components/src/components/Task/Task.stories.jsx @@ -11,6 +11,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { dashboardReasonSkipped } from '@tektoncd/dashboard-utils'; import { action } from '@storybook/addon-actions'; import { useArgs } from '@storybook/preview-api'; @@ -51,6 +52,8 @@ export const Pending = { args: { ...Unknown.args, reason: 'Pending' } }; export const Running = { args: { ...Unknown.args, reason: 'Running' } }; +export const Skipped = { args: { reason: dashboardReasonSkipped } }; + export const Expanded = args => { const [, updateArgs] = useArgs(); @@ -64,6 +67,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 d2e3ad4ab..9d1040a8a 100644 --- a/packages/components/src/components/Task/Task.test.jsx +++ b/packages/components/src/components/Task/Task.test.jsx @@ -11,7 +11,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { dashboardReasonSkipped } from '@tektoncd/dashboard-utils'; import { fireEvent } from '@testing-library/react'; + import Task from './Task'; import { render } from '../../utils/test'; @@ -147,6 +149,10 @@ describe('Task', () => { render(); }); + it('renders skipped state', () => { + render(); + }); + it('renders cancelled state', () => { render( + {intl.formatMessage({ id: 'dashboard.taskRun.params', defaultMessage: 'Parameters' @@ -180,7 +185,7 @@ const TaskRunDetails = ({ ); tabPanels.push( - + {selectedTabIndex === tabPanels.length && (
      {paramsTable}
      )} @@ -189,7 +194,7 @@ const TaskRunDetails = ({ } if (resultsTable) { tabList.push( - + {intl.formatMessage({ id: 'dashboard.taskRun.results', defaultMessage: 'Results' @@ -197,7 +202,7 @@ const TaskRunDetails = ({ ); tabPanels.push( - + {selectedTabIndex === tabPanels.length && (
      {resultsTable}
      )} @@ -205,7 +210,7 @@ const TaskRunDetails = ({ ); } tabList.push( - + {intl.formatMessage({ id: 'dashboard.taskRun.status', defaultMessage: 'Status' @@ -213,13 +218,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 +278,7 @@ const TaskRunDetails = ({ diff --git a/packages/components/src/components/TaskRunDetails/TaskRunDetails.stories.jsx b/packages/components/src/components/TaskRunDetails/TaskRunDetails.stories.jsx index 77bff4649..d5d36b16f 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 607377e37..c510574c1 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 a38393f50..2a1c57e21 100644 --- a/packages/components/src/components/TaskTree/TaskTree.jsx +++ b/packages/components/src/components/TaskTree/TaskTree.jsx @@ -11,10 +11,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { getStatus, labels as labelConstants } from '@tektoncd/dashboard-utils'; +import { + dashboardReasonSkipped, + getStatus, + labels as labelConstants +} from '@tektoncd/dashboard-utils'; import Task from '../Task'; const defaults = { + skippedTasks: [], taskRuns: [] }; @@ -26,6 +31,7 @@ const TaskTree = ({ selectedStepId, selectedTaskId, selectedTaskRunName, + skippedTasks = defaults.skippedTasks, taskRuns = defaults.taskRuns }) => { if (!taskRuns) { @@ -62,7 +68,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 +90,15 @@ const TaskTree = ({ hasExpandedTask = true; } + if ( + !reason && + skippedTasks.find( + skippedTask => skippedTask.name === pipelineTaskName + ) + ) { + reason = dashboardReasonSkipped; + } + 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 3f1a7fa1e..2edeb995a 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 c0e67f78b..55e68bf36 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/packages/utils/src/utils/constants.js b/packages/utils/src/utils/constants.js index 2820678f3..17e0b46d6 100644 --- a/packages/utils/src/utils/constants.js +++ b/packages/utils/src/utils/constants.js @@ -1,5 +1,5 @@ /* -Copyright 2020-2023 The Tekton Authors +Copyright 2020-2024 The Tekton Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -11,6 +11,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +export const dashboardReasonSkipped = 'tkn-dashboard:skipped'; + export const labels = { CLUSTER_TASK: 'tekton.dev/clusterTask', DASHBOARD_DESCRIPTION: 'dashboard.tekton.dev/description', diff --git a/src/containers/CustomRun/CustomRun.jsx b/src/containers/CustomRun/CustomRun.jsx index 63e1afcdd..9fbe9ba09 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 38d1aa16b..6b9f57148 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 11f6381cd..50d636874 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 db5d7f466..75bd5f972 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 7585031b3..b3d4046d5 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 2f31225ad..a591aca33 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 6eaa31240..0b40b3095 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 5e2eb5654..5e519bfc9 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 b60bd1df2..babfcffb3 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 6138fa5f5..13612239d 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 8807eb19b..7dd0f66d9 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": "等待中",