From d3fb7a80168c099235998b7dd8047de3edf89eab Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Mon, 27 Apr 2020 13:18:22 -0700 Subject: [PATCH 1/4] feat(ui): Add pagination to workflow list. Fixes #1080 and #976 --- .../archived-workflow-list.tsx | 21 +++- .../app/shared/services/workflows-service.ts | 10 +- ui/src/app/workflows/components/index.ts | 1 - .../workflow-list-item.scss | 97 ------------------- .../workflow-list-item/workflow-list-item.tsx | 77 --------------- .../workflows-list/workflows-list.tsx | 79 +++++++++++---- 6 files changed, 85 insertions(+), 200 deletions(-) delete mode 100644 ui/src/app/workflows/components/workflow-list-item/workflow-list-item.scss delete mode 100644 ui/src/app/workflows/components/workflow-list-item/workflow-list-item.tsx diff --git a/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx b/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx index 299a174221e6..5bdc15b5e40d 100644 --- a/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx +++ b/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx @@ -1,7 +1,9 @@ import {Page, SlidingPanel} from 'argo-ui'; +import {Ticker} from 'argo-ui/src/index'; import * as classNames from 'classnames'; import {isNaN} from 'formik'; +import * as moment from 'moment'; import * as React from 'react'; import {Link, RouteComponentProps} from 'react-router-dom'; import * as models from '../../../../models'; @@ -13,6 +15,7 @@ import {ResourceSubmit} from '../../../shared/components/resource-submit'; import {Timestamp} from '../../../shared/components/timestamp'; import {ZeroState} from '../../../shared/components/zero-state'; import {Consumer} from '../../../shared/context'; +import {formatDuration} from '../../../shared/duration'; import {exampleWorkflow} from '../../../shared/examples'; import {services} from '../../../shared/services'; import {Utils} from '../../../shared/utils'; @@ -219,25 +222,33 @@ export class ArchivedWorkflowList extends BasePage, Sta ); } + function wfDuration(workflow: models.WorkflowStatus, now: moment.Moment) { + const endTime = workflow.finishedAt ? moment(workflow.finishedAt) : now; + return endTime.diff(moment(workflow.startedAt)) / 1000; + } return ( <>
-
NAME
+
NAME
NAMESPACE
-
CREATED
+
STARTED
+
DURATION
{this.state.workflows.map(w => (
-
{w.metadata.name}
+
{w.metadata.name}
{w.metadata.namespace}
-
- +
+ +
+
+ {now => formatDuration(wfDuration(w.status, now))}
))} diff --git a/ui/src/app/shared/services/workflows-service.ts b/ui/src/app/shared/services/workflows-service.ts index 34588df00b34..5c4e2bc9802c 100644 --- a/ui/src/app/shared/services/workflows-service.ts +++ b/ui/src/app/shared/services/workflows-service.ts @@ -6,6 +6,8 @@ import {Workflow, WorkflowList} from '../../../models'; import requests from './requests'; import {WorkflowDeleteResponse} from './responses'; +const fieldsFilter = `fields=items.metadata.name,items.metadata.namespace,items.status.phase,items.status.finishedAt,items.status.startedAt`; + export class WorkflowsService { public create(workflow: Workflow, namespace: string) { return requests @@ -14,8 +16,10 @@ export class WorkflowsService { .then(res => res.body as Workflow); } - public list(namespace: string, phases: string[], labels: string[]) { - return requests.get(`api/v1/workflows/${namespace}?${this.queryParams({phases, labels}).join('&')}`).then(res => res.body as WorkflowList); + public list(namespace: string, phases: string[], labels: string[], offset: string) { + return requests + .get(`api/v1/workflows/${namespace}?${fieldsFilter}&listOptions.continue=${offset}${this.queryParams({phases, labels}).join('&')}`) + .then(res => res.body as WorkflowList); } public get(namespace: string, name: string) { @@ -23,7 +27,7 @@ export class WorkflowsService { } public watch(filter: {namespace?: string; name?: string; phases?: Array; labels?: Array}): Observable> { - const url = `api/v1/workflow-events/${filter.namespace || ''}?${this.queryParams(filter).join('&')}`; + const url = `api/v1/workflow-events/${filter.namespace || ''}?${fieldsFilter}&${this.queryParams(filter).join('&')}`; return requests.loadEventSource(url, true).map(data => JSON.parse(data).result as models.kubernetes.WatchEvent); } diff --git a/ui/src/app/workflows/components/index.ts b/ui/src/app/workflows/components/index.ts index 67a05ac577c0..fd4af830fcb6 100644 --- a/ui/src/app/workflows/components/index.ts +++ b/ui/src/app/workflows/components/index.ts @@ -1,5 +1,4 @@ export * from './workflow-dag/workflow-dag'; -export * from './workflow-list-item/workflow-list-item'; export * from './workflow-logs-viewer/workflow-logs-viewer'; export * from './workflow-node-info/workflow-node-info'; export * from './workflow-timeline/workflow-timeline'; diff --git a/ui/src/app/workflows/components/workflow-list-item/workflow-list-item.scss b/ui/src/app/workflows/components/workflow-list-item/workflow-list-item.scss deleted file mode 100644 index 5b924c887c25..000000000000 --- a/ui/src/app/workflows/components/workflow-list-item/workflow-list-item.scss +++ /dev/null @@ -1,97 +0,0 @@ -@import 'node_modules/argo-ui/src/styles/config'; - -$ax-job-height: 150px; -$ax-job-status-width: 220px; - -.workflow-list-item { - margin: 10px 0 20px 0; - - &__top { - position: relative; - display: block; - font-size: 0.8em; - height: 36px; - } - - &__content { - border-radius: $border-radius; - background-color: white; - box-shadow: 1px 1px 3px $argo-color-gray-5; - cursor: pointer; - position: relative; - - &-menu { - position: absolute; - top: 20px; - right: 20px; - - .ax-button--radius-2 { - i { - padding-bottom: 0; - } - } - } - - &:hover { - box-shadow: 1px 2px 3px rgba($argo-color-gray-9, .1), 0 0 0 1px rgba($argo-color-teal-5, .5); - } - - &-box { - flex: 4; - border-top-left-radius: $border-radius; - border-bottom-left-radius: $border-radius; - } - - &-details { - padding: 20px; - border-top-right-radius: $border-radius; - border-bottom-right-radius: $border-radius; - overflow-y: hidden; - height: 100%; - background-color: $argo-color-teal-1; - - &-row { - margin-top: 10px; - font-size: .75em; - color: $argo-color-gray-6; - - &-job-id { - margin-right: 50px; - } - } - - &--additional-space { - overflow: hidden; - padding-left: 20px; - padding-right: 20px; - } - } - } - - &__status { - display: inline-block; - line-height: 18px; - width: 100%; - margin-top: 8px; - white-space: nowrap; - - &-icon { - font-size: 18px; - display: inline-block; - height: 18px; - width: 18px; - } - - &-message { - display: inline-block; - vertical-align: top; - color: $argo-color-gray-5; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - padding-left: 5px; - padding-right: 20px; - } - } -} diff --git a/ui/src/app/workflows/components/workflow-list-item/workflow-list-item.tsx b/ui/src/app/workflows/components/workflow-list-item/workflow-list-item.tsx deleted file mode 100644 index 192e0b762e6a..000000000000 --- a/ui/src/app/workflows/components/workflow-list-item/workflow-list-item.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import {Duration, Ticker} from 'argo-ui'; -import * as classNames from 'classnames'; -import * as moment from 'moment'; -import * as React from 'react'; - -import * as models from '../../../../models'; -import {Utils} from '../../../shared/utils'; - -import {Timestamp} from '../../../shared/components/timestamp'; -import {WorkflowSteps} from '../workflow-steps/workflow-steps'; - -require('./workflow-list-item.scss'); - -export interface WorkflowListItemProps { - workflow: models.Workflow; - archived: boolean; -} - -function wfDuration(workflow: models.WorkflowStatus, now: moment.Moment) { - const endTime = workflow.finishedAt ? moment(workflow.finishedAt) : now; - return endTime.diff(moment(workflow.startedAt)) / 1000; -} - -export const WorkflowListItem = (props: WorkflowListItemProps) => ( -
-
-
-
-