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 6efbd6062a988..e0ee2b95e7d9c 100644
--- a/ui/src/app/applications/components/applications-list/applications-filter.tsx
+++ b/ui/src/app/applications/components/applications-list/applications-filter.tsx
@@ -1,6 +1,8 @@
+import {Checkbox} from 'argo-ui';
import {useData} from 'argo-ui/v2';
import * as minimatch from 'minimatch';
import * as React from 'react';
+import {Context} from '../../../shared/context';
import {Application, ApplicationDestination, Cluster, HealthStatusCode, HealthStatuses, SyncStatusCode, SyncStatuses} from '../../../shared/models';
import {AppsListPreferences, services} from '../../../shared/services';
import {Filter, FiltersGroup} from '../filter/filter';
@@ -13,6 +15,7 @@ export interface FilterResult {
health: boolean;
namespaces: boolean;
clusters: boolean;
+ favourite: boolean;
labels: boolean;
}
@@ -28,6 +31,7 @@ export function getFilterResults(applications: Application[], pref: AppsListPref
sync: pref.syncFilter.length === 0 || pref.syncFilter.includes(app.status.sync.status),
health: pref.healthFilter.length === 0 || pref.healthFilter.includes(app.status.health.status),
namespaces: pref.namespacesFilter.length === 0 || pref.namespacesFilter.some(ns => app.spec.destination.namespace && minimatch(app.spec.destination.namespace, ns)),
+ favourite: !pref.showFavorites || pref.favoritesAppList.includes(app.metadata.name),
clusters:
pref.clustersFilter.length === 0 ||
pref.clustersFilter.some(filterString => {
@@ -211,6 +215,23 @@ const NamespaceFilter = (props: AppFilterProps) => {
);
};
+const FavoriteFilter = (props: AppFilterProps) => {
+ const ctx = React.useContext(Context);
+ return (
+
+ {
+ ctx.navigation.goto('.', {showFavorites: val}, {replace: true});
+ services.viewPreferences.updatePreferences({appList: {...props.pref, showFavorites: val}});
+ }}
+ />{' '}
+
+
+ );
+};
+
export const ApplicationsFilter = (props: AppFilterProps) => {
const setShown = (val: boolean) => {
services.viewPreferences.updatePreferences({appList: {...props.pref, hideFilters: !val}});
@@ -218,6 +239,7 @@ export const ApplicationsFilter = (props: AppFilterProps) => {
return (
+
diff --git a/ui/src/app/applications/components/applications-list/applications-list.scss b/ui/src/app/applications/components/applications-list/applications-list.scss
index 6d34822f9ab33..e731619d51ce8 100644
--- a/ui/src/app/applications/components/applications-list/applications-list.scss
+++ b/ui/src/app/applications/components/applications-list/applications-list.scss
@@ -172,7 +172,6 @@
&__external-links-icon-container {
position: relative;
display: inline-block;
- width: 28px;
}
.filters-group__panel {
diff --git a/ui/src/app/applications/components/applications-list/applications-list.tsx b/ui/src/app/applications/components/applications-list/applications-list.tsx
index 5303780c22334..133695d08436a 100644
--- a/ui/src/app/applications/components/applications-list/applications-list.tsx
+++ b/ui/src/app/applications/components/applications-list/applications-list.tsx
@@ -122,6 +122,9 @@ const ViewPref = ({children}: {children: (pref: AppsListPreferences & {page: num
.split(',')
.filter(item => !!item);
}
+ if (params.get('showFavorites') != null) {
+ viewPref.showFavorites = params.get('showFavorites') === 'true';
+ }
if (params.get('view') != null) {
viewPref.view = params.get('view') as AppsListViewType;
} else {
diff --git a/ui/src/app/applications/components/applications-list/applications-table.tsx b/ui/src/app/applications/components/applications-list/applications-table.tsx
index cf8e4e80dbf46..1f3c14bbe34bc 100644
--- a/ui/src/app/applications/components/applications-list/applications-table.tsx
+++ b/ui/src/app/applications/components/applications-list/applications-table.tsx
@@ -1,4 +1,4 @@
-import {DropDownMenu} from 'argo-ui';
+import {DataLoader, DropDownMenu, Tooltip} from 'argo-ui';
import * as React from 'react';
import {Key, KeybindingContext, useNav} from 'argo-ui/v2';
import {Cluster} from '../../../shared/components';
@@ -9,6 +9,7 @@ import * as AppUtils from '../utils';
import {OperationState} from '../utils';
import {ApplicationsLabels} from './applications-labels';
import {ApplicationsSource} from './applications-source';
+import {services} from '../../../shared/services';
require('./applications-table.scss');
export const ApplicationsTable = (props: {
@@ -34,66 +35,98 @@ export const ApplicationsTable = (props: {
return (
{ctx => (
-
- {props.applications.map((app, i) => (
-
services.viewPreferences.getPreferences()}>
+ {pref => {
+ const favList = pref.appList.favoritesAppList || [];
+ return (
+
+ {props.applications.map((app, i) => (
+
-
ctx.navigation.goto(`/applications/${app.metadata.name}`, {}, {event: e})}>
-
-
-
Project:
-
{app.spec.project}
-
-
-
-
-
-
Source:
-
-
-
+
ctx.navigation.goto(`/applications/${app.metadata.name}`, {}, {event: e})}>
+
+
+
+
+
+
+
+
+
+
+
Project:
+
{app.spec.project}
+
+
+
+
Name:
+
{app.metadata.name}
+
-
-
+
+
+
+
+
Destination:
+
+ /{app.spec.destination.namespace}
+
+
+
+
+
{app.status.health.status}
+
+
{app.status.sync.status}
+
(
+
+ )}
+ items={[
+ {title: 'Sync', action: () => props.syncApplication(app.metadata.name)},
+ {title: 'Refresh', action: () => props.refreshApplication(app.metadata.name)},
+ {title: 'Delete', action: () => props.deleteApplication(app.metadata.name)}
+ ]}
+ />
-
-
Destination:
-
- /{app.spec.destination.namespace}
-
-
-
-
-
{app.status.health.status}
-
-
-
{app.status.sync.status}
-
(
-
- )}
- items={[
- {title: 'Sync', action: () => props.syncApplication(app.metadata.name)},
- {title: 'Refresh', action: () => props.refreshApplication(app.metadata.name)},
- {title: 'Delete', action: () => props.deleteApplication(app.metadata.name)}
- ]}
- />
-
+ ))}
-
- ))}
-
+ );
+ }}
+
)}
);
diff --git a/ui/src/app/applications/components/applications-list/applications-tiles.tsx b/ui/src/app/applications/components/applications-list/applications-tiles.tsx
index b22158a679ac7..6f7509f9ef4ee 100644
--- a/ui/src/app/applications/components/applications-list/applications-tiles.tsx
+++ b/ui/src/app/applications/components/applications-list/applications-tiles.tsx
@@ -102,158 +102,178 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
{ctx => (
services.viewPreferences.getPreferences()}>
- {pref => (
-
- {applications.map((app, i) => (
-
-
-
ctx.navigation.goto(`/applications/${app.metadata.name}`, {view: pref.appDetails.view}, {event: e})}>
-
-
-
-
-
- {app.metadata.name}
-
-
-
-
- Project:
-
-
{app.spec.project}
-
-
-
- Labels:
-
-
-
- {Object.keys(app.metadata.labels || {})
- .map(label => ({label, value: app.metadata.labels[label]}))
- .map(item => (
-
- {item.label}={item.value}
-
- ))}
-
- }>
-
- {Object.keys(app.metadata.labels || {})
- .map(label => `${label}=${app.metadata.labels[label]}`)
- .join(', ')}
-
+ {pref => {
+ const favList = pref.appList.favoritesAppList || [];
+ return (
+
+ {applications.map((app, i) => (
+
+
+
ctx.navigation.goto(`/applications/${app.metadata.name}`, {view: pref.appDetails.view}, {event: e})}>
+
+
+
+
+
-
-
-
- Status:
-
-
-
{app.status.health.status}
-
-
{app.status.sync.status}
-
-
-
-
-
-
- Repository:
+
+
+
+ {app.metadata.name}
+
-
-
- {app.spec.source.repoURL}
-
+
+
+ Project:
+
+
{app.spec.project}
-
-
-
- Target Revision:
+
+
+ Labels:
+
+
+
+ {Object.keys(app.metadata.labels || {})
+ .map(label => ({label, value: app.metadata.labels[label]}))
+ .map(item => (
+
+ {item.label}={item.value}
+
+ ))}
+
+ }>
+
+ {Object.keys(app.metadata.labels || {})
+ .map(label => `${label}=${app.metadata.labels[label]}`)
+ .join(', ')}
+
+
+
-
{app.spec.source.targetRevision}
-
- {app.spec.source.path && (
-
- Path:
+
+ Status:
+
+
+
{app.status.health.status}
+
+
{app.status.sync.status}
+
+
-
{app.spec.source.path}
- )}
- {app.spec.source.chart && (
-
- Chart:
+
+ Repository:
+
+
+
+ {app.spec.source.repoURL}
+
-
{app.spec.source.chart}
- )}
-
-
- Destination:
+
+
+ Target Revision:
+
+
{app.spec.source.targetRevision}
-
-
+ {app.spec.source.path && (
+
+
+ Path:
+
+
{app.spec.source.path}
+
+ )}
+ {app.spec.source.chart && (
+
+
+ Chart:
+
+
{app.spec.source.chart}
+
+ )}
+
-
-
-
- Namespace:
+
+
+ Namespace:
+
+
{app.spec.destination.namespace}
-
{app.spec.destination.namespace}
-
-
-
- ))}
-
- )}
+ ))}
+
+ );
+ }}
)}
diff --git a/ui/src/app/shared/services/view-preferences-service.ts b/ui/src/app/shared/services/view-preferences-service.ts
index 7251305913b13..6a8f2dfcff763 100644
--- a/ui/src/app/shared/services/view-preferences-service.ts
+++ b/ui/src/app/shared/services/view-preferences-service.ts
@@ -63,6 +63,7 @@ export class AppsListPreferences {
pref.projectsFilter = [];
pref.reposFilter = [];
pref.syncFilter = [];
+ pref.showFavorites = false;
}
public labelsFilter: string[];
@@ -75,6 +76,8 @@ export class AppsListPreferences {
public view: AppsListViewType;
public hideFilters: boolean;
public statusBarView: HealthStatusBarPreferences;
+ public showFavorites: boolean;
+ public favoritesAppList: string[];
}
export interface ViewPreferences {
@@ -117,6 +120,8 @@ const DEFAULT_PREFERENCES: ViewPreferences = {
syncFilter: new Array
(),
healthFilter: new Array(),
hideFilters: false,
+ showFavorites: false,
+ favoritesAppList: new Array(),
statusBarView: {
showHealthStatusBar: true
}