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(ui): Add label filter to workflow list page. Fixes #802 #2196

Merged
merged 11 commits into from
Feb 11, 2020

Conversation

whynowy
Copy link
Member

@whynowy whynowy commented Feb 7, 2020

Fixes: #802

Checklist:

  • Either (a) I've created an enhancement proposal and discussed it with the community, (b) this is a bug fix, or (c) this is a chore.
  • The title of the PR is (a) conventional, (b) states what changed, and (c) suffixes the related issues number. E.g. "fix(controller): Updates such and such. Fixes #1234".
  • I have written unit and/or e2e tests for my change. PRs without these are unlike to be merged.
  • Optional. I've added My organization is added to the README.
  • I've signed the CLA and required builds are green.

@whynowy whynowy changed the title feat(ui): Add label filter to workflow list page. Fixes#802 feat(ui): Add label filter to workflow list page. Fixes #802 Feb 7, 2020
@whynowy whynowy requested review from alexec and simster7 February 7, 2020 22:21
error?: Error;
}

export class InputFilter extends React.Component<InputProps, InputState> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is abstracted from original NamespaceFilter to make it a generic input box with local cache.

<i className='fa fa-times-circle' />
</a>
</>
<InputFilter
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reference to abstracted InputFilter

</>
<InputFilter
value={this.namespace}
placeholder='Namespace'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use placeholder to replace Namespace text.

@@ -0,0 +1,16 @@
import * as React from 'react';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tags-input is introduced from argo-cd.

@@ -0,0 +1,53 @@
import * as React from 'react';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkbox-filter introduces a list of checkboxes with counts displayed for for each item.

return (
<Consumer>
{ctx => (
<Page
title='Workflows'
toolbar={{
filter,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phase filter is now part of workflow-filters.

@@ -104,9 +96,20 @@ export class WorkflowsList extends BasePage<RouteComponentProps<any>, State> {
}
]
},
tools: [<NamespaceFilter key='namespace-filter' value={this.namespace} onChange={namespace => (this.namespace = namespace)} />]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Namespace filter is now also part of workflow-filters

@codecov
Copy link

codecov bot commented Feb 7, 2020

Codecov Report

Merging #2196 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@          Coverage Diff           @@
##           master   #2196   +/-   ##
======================================
  Coverage    11.7%   11.7%           
======================================
  Files          52      52           
  Lines       26313   26313           
======================================
  Hits         3081    3081           
  Misses      22837   22837           
  Partials      395     395

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2d3416b...0381986. Read the comment docs.

Copy link
Contributor

@alexec alexec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks pretty good so for - some minor comments - it might be good to do a side-by-side review on Monday - maybe include @simster7 ?

ui/src/app/shared/components/input-filter.tsx Outdated Show resolved Hide resolved
@@ -30,17 +28,7 @@ export class NamespaceFilter extends React.Component<Props, State> {
}

private set namespace(namespace: string) {
this.setState(state => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with this code removed - how do entries get saved into local storage?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's moved to generic component input-filter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If all these getters and setters do is modify and read from state I would recommend not using them and simply modifying and reading state directly. Way more explicit and React-y


interface InputState {
input: string;
localInputs: string[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this name - would something like previousValue be good?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to localCache

ui/src/app/shared/components/input-filter.tsx Outdated Show resolved Hide resolved
interface InputProps {
value: string;
placeholder: string;
type: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is "type"? is in select or checkbox?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used to generate the local storage key. I renamed it to name.


require('./tags-input.scss');

export class TagsInput extends React.Component<TagsInputProps, {tags: string[]; input: string; focused: boolean}> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexmt should we be pushing this into the shared Argo UI code? does that still exist?

ui/src/app/shared/components/tags-input/tags-input.tsx Outdated Show resolved Hide resolved
error?: Error;
}

export class WorkflowFilters extends React.Component<WorkflowFilterProps, WorkflowFilterState> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like how we have one big component that comprises of smaller ones

Copy link
Member

@simster7 simster7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work for your first React PR! Jotted down some initial comments, but this should have a more in-depth review soon. A couple of things:

  1. The design is not responsive:

image

  1. It might be just my build, but it seems like this is very broken and slow. See: https://cl.ly/4d454b27345a. This will need some reworking and actual testing before it's ready.

  2. This needs a make lint

namespace={this.namespace}
phases={this.phases}
labels={this.labels}
onChange={(namespace, phases, labels) => this.handleChanges(namespace, phases, labels)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could simply pass in the function here

Suggested change
onChange={(namespace, phases, labels) => this.handleChanges(namespace, phases, labels)}
onChange={this.handleChanges}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow it doesn't work.....

Comment on lines 36 to 38
namespace: props.namespace,
phases: props.phases,
labels: props.labels
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too sure about this pattern... there should only be one source of truth about what the current namespace, phases, and labels are. Right now we are storing it in three different places: the URL, state in workflows-list, and this state. It should all be consolidated in one. Why store state here if you pass in an onChange that changes the state of the parent component... forcing a re-render here anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Realized the same thing, removed the state and used the props.

}
}}
renderInput={props => (
<input
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole <input> field doesn't seem like it is the correct way to do this. Can you check how we take input elsewhere in the codebase?

Comment on lines 93 to 101
}
if (filter.labels && filter.labels.length > 0) {
if (labelSelector.length > 0) {
labelSelector += ',';
}
labelSelector += filter.labels.join(',');
}
if (labelSelector.length > 0) {
queryParams.push(`listOptions.labelSelector=${labelSelector}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The labelSelector logic should be extracted as a utility function

@whynowy
Copy link
Member Author

whynowy commented Feb 9, 2020

Good work for your first React PR! Jotted down some initial comments, but this should have a more in-depth review soon. A couple of things:

  1. The design is not responsive:
image
  1. It might be just my build, but it seems like this is very broken and slow. See: https://cl.ly/4d454b27345a. This will need some reworking and actual testing before it's ready.
  2. This needs a make lint

I noticed the slow responsive issue, it seems like the API call /api/v1/workflow-events/ is stuck, there must be some issue on the server side. I'll take a further look.

Copy link
Member

@simster7 simster7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work! This is a great PR. Conditional approval: please fix the un-responsive design. I.e. the site doesn't resize well with different screen sizes. See: https://cl.ly/bd0c78ca10df

import {Autocomplete} from '../../../../node_modules/argo-ui';

interface InputProps {
value: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: maybe call this initialValue?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

I feel like value would be better, since it's still a <input type="text">, using value to be consistent with it.

};
}

private set value(value: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setter should be converted to a function and renamed something like setValueAndCache

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

require('./tags-input.scss');

export class TagsInput extends React.Component<TagsInputProps, {tags: string[]; input: string; focused: boolean}> {
private inputEl: HTMLInputElement;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick:

Suggested change
private inputEl: HTMLInputElement;
private inputElement: HTMLInputElement;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

<NamespaceFilter
value={this.props.namespace}
onChange={ns => {
this.props.onChange(ns, this.props.selectedPhases, this.props.selectedLabels);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

const value = wf.metadata.labels[label];
const suggestedLabel = `${label}=${value}`;
if (!suggestions.some(v => v === suggestedLabel)) {
suggestions.push(`${label}=${value}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe don't include labels that denote phase because the check boxes already provide that functionality? Up to you

image

@whynowy
Copy link
Member Author

whynowy commented Feb 11, 2020

Excellent work! This is a great PR. Conditional approval: please fix the un-responsive design. I.e. the site doesn't resize well with different screen sizes. See: https://cl.ly/bd0c78ca10df

Thanks! Fixed.

@whynowy whynowy merged commit e30b77f into argoproj:master Feb 11, 2020
@whynowy whynowy deleted the labelselector branch February 11, 2020 06:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[UI] Feature Request: Show and filter by labels in the UI
4 participants