diff --git a/ui/src/app/applications/components/applications-list/applications-filter.tsx b/ui/src/app/applications/components/applications-list/applications-filter.tsx index ee74c27329f50..14194a9164d3f 100644 --- a/ui/src/app/applications/components/applications-list/applications-filter.tsx +++ b/ui/src/app/applications/components/applications-list/applications-filter.tsx @@ -1,4 +1,4 @@ -import {Checkbox, DataLoader} from 'argo-ui'; +import {Checkbox, DataLoader, Tooltip} from 'argo-ui'; import * as classNames from 'classnames'; import * as React from 'react'; @@ -105,16 +105,38 @@ export class ApplicationsFilter extends React.Component - this.setState({expanded: !this.state.expanded})} - className={classNames('fa applications-list__filters-expander', {'fa-chevron-up': this.state.expanded, 'fa-chevron-down': !this.state.expanded})} - /> -

Filter By:

-
+
+ + + +
+
+ {filtersCount} Filter{filtersCount === 1 ? '' : 's'} + + { + AppsListPreferences.clearFilters(this.props.pref); + this.props.onChange(this.props.pref); + }} + /> + +
+ + this.setState({expanded: !this.state.expanded})} + /> + +
+
-

Sync

+
Sync
onChange({...pref, syncFilter: selected})} @@ -123,7 +145,7 @@ export class ApplicationsFilter extends React.Component
-

Health

+
Health
onChange({...pref, healthFilter: selected})} @@ -133,7 +155,7 @@ export class ApplicationsFilter extends React.Component
-

Labels

+
Labels
-

Projects

+
Projects
  • services.projects.list('items.metadata.name')}> @@ -164,7 +186,7 @@ export class ApplicationsFilter extends React.Component
-

Clusters

+
Clusters
-

Namespaces

+
Namespaces
  • ) => { services.applications.get(appName, 'normal'); } + function onFilterPrefChanged(ctx: ContextApis, newPref: AppsListPreferences) { + services.viewPreferences.updatePreferences({appList: newPref}); + ctx.navigation.goto('.', { + proj: newPref.projectsFilter.join(','), + sync: newPref.syncFilter.join(','), + health: newPref.healthFilter.join(','), + namespace: newPref.namespacesFilter.join(','), + cluster: newPref.clustersFilter.join(','), + labels: newPref.labelsFilter.map(encodeURIComponent).join(',') + }); + } + return ( @@ -274,6 +286,7 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => { } }} className='argo-field' + placeholder='Search applications...' /> )} renderItem={item => ( @@ -298,21 +311,12 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => { clusters={clusterList} applications={applications} pref={pref} - onChange={newPref => { - services.viewPreferences.updatePreferences({appList: newPref}); - ctx.navigation.goto('.', { - proj: newPref.projectsFilter.join(','), - sync: newPref.syncFilter.join(','), - health: newPref.healthFilter.join(','), - namespace: newPref.namespacesFilter.join(','), - cluster: newPref.clustersFilter.join(','), - labels: newPref.labelsFilter.map(encodeURIComponent).join(',') - }); - }} + onChange={newPref => onFilterPrefChanged(ctx, newPref)} /> ); }} + {syncAppsInput && ( ) => { page={pref.page} emptyState={() => ( -

    No applications found

    -
    Try to change filter criteria
    +

    No matching applications found

    +
    + Change filter criteria or  + { + AppsListPreferences.clearFilters(pref); + onFilterPrefChanged(ctx, pref); + }}> + clear filters + +
    )} data={filterApps(applications, pref, pref.search)} diff --git a/ui/src/app/shared/components/paginate/paginate.tsx b/ui/src/app/shared/components/paginate/paginate.tsx index 9f0bce9a83c3e..09ce8838ad2a0 100644 --- a/ui/src/app/shared/components/paginate/paginate.tsx +++ b/ui/src/app/shared/components/paginate/paginate.tsx @@ -43,7 +43,7 @@ export function Paginate({page, onPageChange, children, data, emptyState, pre ( - page size: {pageSize === -1 ? 'all' : pageSize} + Items per page: {pageSize === -1 ? 'all' : pageSize} )} items={[5, 10, 15, 20, -1].map(count => ({ diff --git a/ui/src/app/shared/components/tags-input/tags-input.scss b/ui/src/app/shared/components/tags-input/tags-input.scss index ad235373d2166..5e9dfc4c0647c 100644 --- a/ui/src/app/shared/components/tags-input/tags-input.scss +++ b/ui/src/app/shared/components/tags-input/tags-input.scss @@ -35,8 +35,7 @@ background: $argo-color-gray-3; box-shadow: 1px 1px 3px $argo-color-gray-5; border-radius: 5px; - padding: 4px; - padding: 4px 15px 4px 4px; + padding: 4px 18px 4px 4px; margin: 0.2em 0.75em 0.2em 0; cursor: default; max-width: 100%; diff --git a/ui/src/app/shared/components/tags-input/tags-input.tsx b/ui/src/app/shared/components/tags-input/tags-input.tsx index eaa8cb6a0538c..040efdfa8a269 100644 --- a/ui/src/app/shared/components/tags-input/tags-input.tsx +++ b/ui/src/app/shared/components/tags-input/tags-input.tsx @@ -10,9 +10,20 @@ export interface TagsInputProps { placeholder?: string; } +interface TagsInputState { + tags: string[]; + input: string; + focused: boolean; +} + require('./tags-input.scss'); -export class TagsInput extends React.Component { +export class TagsInput extends React.Component { + public static getDerivedStateFromProps(props: TagsInputProps, state: TagsInputState) { + state.tags = props.tags; + return state; + } + private inputEl: HTMLInputElement; private autocompleteApi: AutocompleteApi; diff --git a/ui/src/app/shared/services/view-preferences-service.ts b/ui/src/app/shared/services/view-preferences-service.ts index 859660c0c7812..531bd05823b04 100644 --- a/ui/src/app/shared/services/view-preferences-service.ts +++ b/ui/src/app/shared/services/view-preferences-service.ts @@ -13,15 +13,45 @@ export interface AppDetailsPreferences { export type AppsListViewType = 'tiles' | 'list' | 'summary'; -export interface AppsListPreferences { - labelsFilter: string[]; - projectsFilter: string[]; - reposFilter: string[]; - syncFilter: string[]; - healthFilter: string[]; - namespacesFilter: string[]; - clustersFilter: string[]; - view: AppsListViewType; +export class AppsListPreferences { + public static countEnabledFilters(pref: AppsListPreferences) { + // tslint:disable-next-line: prettier + return [ + pref.clustersFilter, + pref.healthFilter, + pref.labelsFilter, + pref.namespacesFilter, + pref.projectsFilter, + pref.reposFilter, + pref.syncFilter + ].reduce((count, filter) => { + if (filter && filter.length > 0) { + return count + 1; + } + return count; + }, + 0 + ); + } + + public static clearFilters(pref: AppsListPreferences) { + pref.clustersFilter = []; + pref.healthFilter = []; + pref.labelsFilter = []; + pref.namespacesFilter = []; + pref.projectsFilter = []; + pref.reposFilter = []; + pref.syncFilter = []; + } + + public labelsFilter: string[]; + public projectsFilter: string[]; + public reposFilter: string[]; + public syncFilter: string[]; + public healthFilter: string[]; + public namespacesFilter: string[]; + public clustersFilter: string[]; + public view: AppsListViewType; } export interface ViewPreferences {