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}
-
-
-
Name:
-
- {app.metadata.name} -
-
-
-
-
-
Source:
-
-
- +
ctx.navigation.goto(`/applications/${app.metadata.name}`, {}, {event: e})}> +
+
+
+
+ + + + +
+
+
Project:
+
{app.spec.project}
+
+
+
+
Name:
+
{app.metadata.name}
+
-
- + +
+
+
Source:
+
+
+ +
+
+ +
+
+
+
+
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}
+
+ )} +
+
+ Destination: +
+
+ +
-
-
-
- ))} -
- )} + ))} +
+ ); + }} )} 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 }