Skip to content

Commit

Permalink
Add created time column on all resource list pages
Browse files Browse the repository at this point in the history
- Add column showing creationTimestamp on all list views
- Add column showing duration on PipelineRuns and TaskRuns views
  - `now - creationTimestamp` for in progress runs
  - `lastUpdate - creationTimestamp` for completed runs
  • Loading branch information
AlanGreene authored and tekton-robot committed Jan 6, 2020
1 parent 256137d commit 08ab6e6
Show file tree
Hide file tree
Showing 22 changed files with 269 additions and 65 deletions.
8 changes: 5 additions & 3 deletions .storybook/Container.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019 The Tekton Authors
Copyright 2019-2020 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
Expand All @@ -12,13 +12,15 @@ limitations under the License.
*/

import React from 'react';
import { IntlProvider } from "react-intl";

import messages from '../src/nls/messages_en.json';

import './Container.scss';
import { IntlProvider } from "react-intl";

export default function Container({ story }) {
return (
<IntlProvider locale='en' defaultLocale='en'>
<IntlProvider locale="en" defaultLocale="en" messages={messages['en']}>
<div
data-floating-menu-container
role="main"
Expand Down
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"elkjs": "^0.5.1",
"js-yaml": "^3.13.0",
"prop-types": "^15.7.2",
"react-intl-formatted-duration": "^3.1.0",
"react-window": "^1.8.5"
},
"peerDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright 2019-2020 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import { defineMessages } from 'react-intl';
import FormattedDuration from 'react-intl-formatted-duration';

defineMessages({
duration: {
id: 'react-intl-formatted-duration.duration',
defaultMessage: '{value} {unit}'
},
daysUnit: {
id: 'react-intl-formatted-duration.daysUnit',
defaultMessage: '{value, plural, one {day} other {days}}'
},
hoursUnit: {
id: 'react-intl-formatted-duration.hoursUnit',
defaultMessage: '{value, plural, one {hour} other {hours}}'
},
minutesUnit: {
id: 'react-intl-formatted-duration.minutesUnit',
defaultMessage: '{value, plural, one {minute} other {minutes}}'
},
secondsUnit: {
id: 'react-intl-formatted-duration.secondsUnit',
defaultMessage: '{value, plural, one {second} other {seconds}}'
}
});

const FormattedDurationWrapper = ({ milliseconds }) => {
return (
<FormattedDuration
seconds={milliseconds / 1000}
format="{days} {hours} {minutes} {seconds}"
/>
);
};

export default FormattedDurationWrapper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright 2019-2020 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import { storiesOf } from '@storybook/react';
import { number } from '@storybook/addon-knobs';

import FormattedDuration from './FormattedDuration';

storiesOf('FormattedDuration', module)
.add('1 second', () => <FormattedDuration milliseconds={1000} />)
.add('1 minute 1 second', () => <FormattedDuration milliseconds={61000} />)
.add('other', () => (
<FormattedDuration
milliseconds={number(
'milliseconds',
2 * 60 * 60 * 1000 + 1 * 60 * 1000 + 10 * 1000 // 2h 1m 10s
)}
/>
));
14 changes: 14 additions & 0 deletions packages/components/src/components/FormattedDuration/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
Copyright 2019-2020 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

export { default } from './FormattedDuration';
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { urls } from '@tektoncd/dashboard-utils';

import { RunDropdown, Table } from '..';
import { FormattedDate, RunDropdown, Table } from '..';

const PipelineResources = ({
createPipelineResourcesURL = urls.pipelineResources.byName,
Expand Down Expand Up @@ -50,6 +50,13 @@ const PipelineResources = ({
defaultMessage: 'Type'
})
},
{
key: 'createdTime',
header: intl.formatMessage({
id: 'dashboard.tableHeader.createdTime',
defaultMessage: 'Created'
})
},
{
key: 'dropdown',
header: ''
Expand Down Expand Up @@ -77,6 +84,12 @@ const PipelineResources = ({
),
namespace,
type: pipelineResource.spec.type,
createdTime: (
<FormattedDate
date={pipelineResource.metadata.creationTimestamp}
relative
/>
),
dropdown: (
<RunDropdown
items={pipelineResourceActions}
Expand Down
41 changes: 27 additions & 14 deletions packages/components/src/components/PipelineRuns/PipelineRuns.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ import { Table } from '@tektoncd/dashboard-components';
import 'carbon-components-react';
import { getStatus, getStatusIcon, urls } from '@tektoncd/dashboard-utils';

import { FormattedDate, RunDropdown } from '..';
import { FormattedDate, FormattedDuration, RunDropdown } from '..';

import './PipelineRuns.scss';

const PipelineRuns = ({
createPipelineRunURL = urls.pipelineRuns.byName,
createPipelineRunDisplayName = ({ pipelineRunMetadata }) =>
pipelineRunMetadata.name,
createPipelineRunTimestamp = pipelineRun =>
getStatus(pipelineRun).lastTransitionTime,
createPipelineRunsByPipelineURL = urls.pipelineRuns.byPipeline,
getPipelineRunStatus = (pipelineRun, intl) =>
pipelineRun.status && pipelineRun.status.conditions
Expand Down Expand Up @@ -78,10 +76,17 @@ const PipelineRuns = ({
})
},
{
key: 'transitionTime',
key: 'createdTime',
header: intl.formatMessage({
id: 'dashboard.tableHeader.transitionTime',
defaultMessage: 'Last Transition Time'
id: 'dashboard.tableHeader.createdTime',
defaultMessage: 'Created'
})
},
{
key: 'duration',
header: intl.formatMessage({
id: 'dashboard.tableHeader.duration',
defaultMessage: 'Duration'
})
},
{
Expand All @@ -98,20 +103,32 @@ const PipelineRuns = ({
});

const pipelineRunsFormatted = pipelineRuns.map(pipelineRun => {
const { namespace, annotations } = pipelineRun.metadata;
const { annotations, creationTimestamp, namespace } = pipelineRun.metadata;
const pipelineRunName = createPipelineRunDisplayName({
pipelineRunMetadata: pipelineRun.metadata
});
const pipelineRefName = pipelineRun.spec.pipelineRef.name;
const pipelineRunType = pipelineRun.spec.type;
const { reason, status } = getStatus(pipelineRun);
const { lastTransitionTime, reason, status } = getStatus(pipelineRun);
const statusIcon = getPipelineRunStatusIcon(pipelineRun);
const pipelineRunStatus = getPipelineRunStatus(pipelineRun, intl);
const url = createPipelineRunURL({
namespace,
pipelineRunName,
annotations
});

let endTime = Date.now();
if (status === 'False' || status === 'True') {
endTime = new Date(lastTransitionTime).getTime();
}

const duration = (
<FormattedDuration
milliseconds={endTime - new Date(creationTimestamp).getTime()}
/>
);

return {
id: `${namespace}:${pipelineRunName}`,
name: url ? (
Expand Down Expand Up @@ -145,12 +162,8 @@ const PipelineRuns = ({
</div>
</div>
),
transitionTime: (
<FormattedDate
date={createPipelineRunTimestamp(pipelineRun)}
relative
/>
),
createdTime: <FormattedDate date={creationTimestamp} relative />,
duration,
type: pipelineRunType,
dropdown: (
<RunDropdown items={pipelineRunActions} resource={pipelineRun} />
Expand Down
36 changes: 27 additions & 9 deletions packages/components/src/components/TaskRuns/TaskRuns.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ import { injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { getStatus, getStatusIcon, urls } from '@tektoncd/dashboard-utils';

import { FormattedDate, RunDropdown, Table } from '..';
import { FormattedDate, FormattedDuration, RunDropdown, Table } from '..';

const TaskRuns = ({
createTaskRunURL = urls.taskRuns.byName,
createTaskRunsDisplayName = ({ taskRunMetadata }) => taskRunMetadata.name,
createTaskRunTimestamp = taskRun => getStatus(taskRun).lastTransitionTime,
createTaskRunsByTaskURL = urls.taskRuns.byTask,
getTaskRunStatus = (taskRun, intl) =>
taskRun.status && taskRun.status.conditions
Expand Down Expand Up @@ -70,10 +69,17 @@ const TaskRuns = ({
})
},
{
key: 'transitionTime',
key: 'createdTime',
header: intl.formatMessage({
id: 'dashboard.tableHeader.transitionTime',
defaultMessage: 'Last Transition Time'
id: 'dashboard.tableHeader.createdTime',
defaultMessage: 'Created'
})
},
{
key: 'duration',
header: intl.formatMessage({
id: 'dashboard.tableHeader.duration',
defaultMessage: 'Duration'
})
},
{
Expand All @@ -83,19 +89,30 @@ const TaskRuns = ({
];

const taskRunsFormatted = taskRuns.map(taskRun => {
const { namespace } = taskRun.metadata;
const { creationTimestamp, namespace } = taskRun.metadata;
const taskRunName = createTaskRunsDisplayName({
taskRunMetadata: taskRun.metadata
});
const taskRefName = taskRun.spec.taskRef && taskRun.spec.taskRef.name;
const { reason, status } = getStatus(taskRun);
const { lastTransitionTime, reason, status } = getStatus(taskRun);
const statusIcon = getTaskRunStatusIcon(taskRun);
const taskRunStatus = getTaskRunStatus(taskRun, intl);
const url = createTaskRunURL({
namespace,
taskRunName
});

let endTime = Date.now();
if (status === 'False' || status === 'True') {
endTime = new Date(lastTransitionTime).getTime();
}

const duration = (
<FormattedDuration
milliseconds={endTime - new Date(creationTimestamp).getTime()}
/>
);

return {
id: taskRun.metadata.uid,
name: url ? (
Expand Down Expand Up @@ -127,9 +144,10 @@ const TaskRuns = ({
</div>
</div>
),
transitionTime: (
<FormattedDate date={createTaskRunTimestamp(taskRun)} relative />
createdTime: (
<FormattedDate date={taskRun.metadata.creationTimestamp} relative />
),
duration,
dropdown: <RunDropdown items={taskRunActions} resource={taskRun} />
};
});
Expand Down
5 changes: 3 additions & 2 deletions packages/components/src/components/TaskRuns/TaskRuns.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019 The Tekton Authors
Copyright 2019-2020 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
Expand Down Expand Up @@ -32,7 +32,8 @@ it('TaskRuns renders headers state', () => {
expect(queryByText(/task/i)).toBeTruthy();
expect(queryByText(/namespace/i)).toBeTruthy();
expect(queryByText(/status/i)).toBeTruthy();
expect(queryByText(/last transition time/i)).toBeTruthy();
expect(queryByText(/created/i)).toBeTruthy();
expect(queryByText(/duration/i)).toBeTruthy();
expect(document.getElementsByClassName('bx--overflow-menu')).toBeTruthy();
});

Expand Down
Loading

0 comments on commit 08ab6e6

Please sign in to comment.