Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Unified workflows list UI and API #11121

Merged
merged 27 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
234b09f
feat: wip
terrytangyuan May 19, 2023
86c4102
fix: return complete wfs
terrytangyuan May 22, 2023
0ab6747
fix: add archived column
terrytangyuan May 22, 2023
2988184
fix: true or false
terrytangyuan May 22, 2023
3d9185e
fix: remove archived-wf from UI
terrytangyuan May 22, 2023
d267bab
fix: fix wf detail
terrytangyuan May 23, 2023
9cbdb59
fix: fix
terrytangyuan May 24, 2023
5e2f5eb
feat: Add delete popup
terrytangyuan Jun 1, 2023
ed6542a
fix: check if wf is in both
terrytangyuan Jun 5, 2023
fb4fd14
fix: redirect after deletion
terrytangyuan Jun 5, 2023
50b2e08
fix: edge cases
terrytangyuan Jun 5, 2023
ae040e8
fix: wip
terrytangyuan Jun 5, 2023
5f67f7b
fix: wip
terrytangyuan Jun 9, 2023
add32f3
fix: wip
terrytangyuan Jun 9, 2023
351cc5c
fix: blank page
terrytangyuan Jun 9, 2023
8a89cb5
fix: couple of fixes and TODO
terrytangyuan Jun 10, 2023
b51d810
fix: working with global var instead of state
terrytangyuan Jun 11, 2023
544aefb
fix: feedback
terrytangyuan Jun 17, 2023
cb9ca5c
fix: Address feedback
terrytangyuan Jun 17, 2023
a92363f
fix: undo temporary changes
terrytangyuan Jun 18, 2023
a4be657
fix: print error
terrytangyuan Jun 19, 2023
a4ed8ad
fix: correct pagination and handle unmarshalling errors
terrytangyuan Jun 29, 2023
84d778f
fix: use 0 instead of -1
terrytangyuan Jun 29, 2023
4e53ada
fix: Add missing list meta
terrytangyuan Jun 29, 2023
b6b15ec
fix: simplify
terrytangyuan Jun 29, 2023
f6df909
fix: keep sorting
terrytangyuan Jul 2, 2023
2461b7c
fix: Consistent result and test correctness
terrytangyuan Jul 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 10 additions & 18 deletions persist/sqldb/workflow_archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import (

log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"upper.io/db.v3"
"upper.io/db.v3/lib/sqlbuilder"

Expand Down Expand Up @@ -144,7 +142,7 @@ func (r *workflowArchive) ArchiveWorkflow(wf *wfv1.Workflow) error {
}

func (r *workflowArchive) ListWorkflows(namespace string, name string, namePrefix string, minStartedAt, maxStartedAt time.Time, labelRequirements labels.Requirements, limit int, offset int) (wfv1.Workflows, error) {
var archivedWfs []archivedWorkflowMetadata
var archivedWfs []archivedWorkflowRecord
clause, err := labelsClause(r.dbType, labelRequirements)
if err != nil {
return nil, err
Expand All @@ -158,7 +156,7 @@ func (r *workflowArchive) ListWorkflows(namespace string, name string, namePrefi
}

err = r.session.
Select("name", "namespace", "uid", "phase", "startedat", "finishedat").
agilgur5 marked this conversation as resolved.
Show resolved Hide resolved
Select("workflow").
From(archiveTableName).
Where(r.clusterManagedNamespaceAndInstanceID()).
And(namespaceEqual(namespace)).
Expand All @@ -173,20 +171,14 @@ func (r *workflowArchive) ListWorkflows(namespace string, name string, namePrefi
if err != nil {
return nil, err
}
wfs := make(wfv1.Workflows, len(archivedWfs))
for i, md := range archivedWfs {
wfs[i] = wfv1.Workflow{
ObjectMeta: v1.ObjectMeta{
Name: md.Name,
Namespace: md.Namespace,
UID: types.UID(md.UID),
CreationTimestamp: v1.Time{Time: md.StartedAt},
},
Status: wfv1.WorkflowStatus{
Phase: md.Phase,
StartedAt: v1.Time{Time: md.StartedAt},
FinishedAt: v1.Time{Time: md.FinishedAt},
},
wfs := make(wfv1.Workflows, 0)
for _, archivedWf := range archivedWfs {
wf := wfv1.Workflow{}
err = json.Unmarshal([]byte(archivedWf.Workflow), &wf)
if err != nil {
log.WithFields(log.Fields{"workflowUID": archivedWf.UID, "workflowName": archivedWf.Name}).Errorln("unable to unmarshal workflow from database")
} else {
wfs = append(wfs, wf)
}
}
return wfs, nil
Expand Down
39 changes: 36 additions & 3 deletions server/workflow/workflow_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
workflowpkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflow"
workflowarchivepkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflowarchive"
"github.com/argoproj/argo-workflows/v3/pkg/apis/workflow"
"github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
"github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned"
"github.com/argoproj/argo-workflows/v3/server/auth"
Expand Down Expand Up @@ -128,6 +129,28 @@ func (s *workflowServer) GetWorkflow(ctx context.Context, req *workflowpkg.Workf
return wf, nil
}

func mergeWithArchivedWorkflows(liveWfs v1alpha1.WorkflowList, archivedWfs v1alpha1.WorkflowList, numWfsToKeep int) *v1alpha1.WorkflowList {
var finalWfs []v1alpha1.Workflow
var uidToWfs = map[types.UID][]v1alpha1.Workflow{}
for _, item := range liveWfs.Items {
uidToWfs[item.UID] = append(uidToWfs[item.UID], item)
}
for _, item := range archivedWfs.Items {
uidToWfs[item.UID] = append(uidToWfs[item.UID], item)
}
numWfs := 0
for _, v := range uidToWfs {
if numWfsToKeep == 0 || numWfs < numWfsToKeep {
finalWfs = append(finalWfs, v[0])
numWfs += 1
}
}
jessesuen marked this conversation as resolved.
Show resolved Hide resolved
finalWfsList := v1alpha1.WorkflowList{Items: finalWfs, ListMeta: liveWfs.ListMeta}
sort.Sort(finalWfsList.Items)

return &finalWfsList
terrytangyuan marked this conversation as resolved.
Show resolved Hide resolved
}

func (s *workflowServer) ListWorkflows(ctx context.Context, req *workflowpkg.WorkflowListRequest) (*wfv1.WorkflowList, error) {
wfClient := auth.GetWfClient(ctx)

Expand All @@ -140,6 +163,19 @@ func (s *workflowServer) ListWorkflows(ctx context.Context, req *workflowpkg.Wor
if err != nil {
return nil, sutils.ToStatusError(err, codes.Internal)
}
archivedWfList, err := s.wfArchiveServer.ListArchivedWorkflows(ctx, &workflowarchivepkg.ListArchivedWorkflowsRequest{
ListOptions: listOption,
NamePrefix: "",
Namespace: req.Namespace,
})
if err != nil {
log.Warnf("unable to list archived workflows:%v", err)
} else {
if archivedWfList != nil {
wfList = mergeWithArchivedWorkflows(*wfList, *archivedWfList, int(listOption.Limit))
}
}

cleaner := fields.NewCleaner(req.Fields)
if s.offloadNodeStatusRepo.IsEnabled() && !cleaner.WillExclude("items.status.nodes") {
offloadedNodes, err := s.offloadNodeStatusRepo.List(req.Namespace)
Expand All @@ -157,9 +193,6 @@ func (s *workflowServer) ListWorkflows(ctx context.Context, req *workflowpkg.Wor
}
}

// we make no promises about the overall list sorting, we just sort each page
sort.Sort(wfList.Items)

res := &wfv1.WorkflowList{ListMeta: metav1.ListMeta{Continue: wfList.Continue, ResourceVersion: wfList.ResourceVersion}, Items: wfList.Items}
newRes := &wfv1.WorkflowList{}
if ok, err := cleaner.Clean(res, &newRes); err != nil {
Expand Down
25 changes: 25 additions & 0 deletions server/workflow/workflow_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,31 @@ func (t testWatchWorkflowServer) Send(*workflowpkg.WorkflowWatchEvent) error {
panic("implement me")
}

func TestMergeWithArchivedWorkflows(t *testing.T) {
liveWfList := v1alpha1.WorkflowList{
Items: []v1alpha1.Workflow{
{ObjectMeta: metav1.ObjectMeta{UID: "1"}},
{ObjectMeta: metav1.ObjectMeta{UID: "2"}},
},
}
archivedWfList := v1alpha1.WorkflowList{
Items: []v1alpha1.Workflow{
{ObjectMeta: metav1.ObjectMeta{UID: "1"}},
{ObjectMeta: metav1.ObjectMeta{UID: "3"}},
{ObjectMeta: metav1.ObjectMeta{UID: "2"}},
},
}
expectedWfList := v1alpha1.WorkflowList{
Items: []v1alpha1.Workflow{
{ObjectMeta: metav1.ObjectMeta{UID: "3"}},
{ObjectMeta: metav1.ObjectMeta{UID: "2"}},
{ObjectMeta: metav1.ObjectMeta{UID: "1"}},
},
}
assert.Len(t, mergeWithArchivedWorkflows(liveWfList, archivedWfList, 0).Items, len(expectedWfList.Items))
assert.Len(t, mergeWithArchivedWorkflows(liveWfList, archivedWfList, 2).Items, 2)
}

func TestWatchWorkflows(t *testing.T) {
server, ctx := getWorkflowServer()
wf := &v1alpha1.Workflow{
Expand Down
8 changes: 0 additions & 8 deletions ui/src/app/app-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {useEffect, useState} from 'react';
import {Redirect, Route, Router, Switch} from 'react-router';
import {Version} from '../models';
import apidocs from './apidocs';
import archivedWorkflows from './archived-workflows';
import clusterWorkflowTemplates from './cluster-workflow-templates';
import cronWorkflows from './cron-workflows';
import eventflow from './event-flow';
Expand Down Expand Up @@ -35,7 +34,6 @@ const workflowsEventBindingsUrl = uiUrl('workflow-event-bindings');
const workflowTemplatesUrl = uiUrl('workflow-templates');
const clusterWorkflowTemplatesUrl = uiUrl('cluster-workflow-templates');
const cronWorkflowsUrl = uiUrl('cron-workflows');
const archivedWorkflowsUrl = uiUrl('archived-workflows');
const eventSourceUrl = uiUrl('event-sources');
const pluginsUrl = uiUrl('plugins');
const helpUrl = uiUrl('help');
Expand Down Expand Up @@ -130,11 +128,6 @@ export const AppRouter = ({popupManager, history, notificationsManager}: {popupM
path: workflowsEventBindingsUrl + namespaceSuffix,
iconClassName: 'fa fa-link'
},
{
title: 'Archived Workflows',
path: archivedWorkflowsUrl + namespaceSuffix,
iconClassName: 'fa fa-archive'
},
{
title: 'Reports',
path: reportsUrl + namespaceSuffix,
Expand Down Expand Up @@ -176,7 +169,6 @@ export const AppRouter = ({popupManager, history, notificationsManager}: {popupM
<Route path={workflowTemplatesUrl} component={workflowTemplates.component} />
<Route path={clusterWorkflowTemplatesUrl} component={clusterWorkflowTemplates.component} />
<Route path={cronWorkflowsUrl} component={cronWorkflows.component} />
<Route path={archivedWorkflowsUrl} component={archivedWorkflows.component} />
<Route path={reportsUrl} component={reports.component} />
<Route path={pluginsUrl} component={plugins.component} />
<Route exact={true} strict={true} path={helpUrl} component={help.component} />
Expand Down

This file was deleted.

Loading