Compare commits

...

5 Commits

Author SHA1 Message Date
argo-bot
7d7eed4932 Bump version to 2.3.0-rc1 2022-01-30 21:42:54 +00:00
argo-bot
af8c5eb07a Bump version to 2.3.0-rc1 2022-01-30 21:42:41 +00:00
Alexander Matyushentsev
1a476f7564 fix: argocd build fails on windows (#8319)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-30 13:02:01 -08:00
Saumeya Katyal
7f15389c72 feat: favourite ui feature (#8210)
* feat: favourite ui feature (#8210)

Signed-off-by: saumeya <saumeyakatyal@gmail.com>
2022-01-28 12:55:23 -08:00
Alexander Matyushentsev
1a3556e1cc fix: add missing steps in release workflow to setup docker buildx (#8311)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-01-28 12:04:34 -08:00
19 changed files with 340 additions and 225 deletions

View File

@@ -197,6 +197,8 @@ jobs:
if: ${{ env.DRY_RUN != 'true' }}
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- name: Build and push Docker image for release
run: |
set -ue

View File

@@ -1 +1 @@
2.3.0
2.3.0-rc1

View File

@@ -9,7 +9,6 @@ import (
"os/exec"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/argoproj/pkg/rand"
@@ -68,7 +67,7 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
cmd.Stderr = &stderr
// Make sure the command is killed immediately on timeout. https://stackoverflow.com/a/38133948/684776
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
cmd.SysProcAttr = newSysProcAttr(true)
start := time.Now()
err = cmd.Start()
@@ -80,7 +79,7 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
<-ctx.Done()
// Kill by group ID to make sure child processes are killed. The - tells `kill` that it's a group ID.
// Since we didn't set Pgid in SysProcAttr, the group ID is the same as the process ID. https://pkg.go.dev/syscall#SysProcAttr
_ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
_ = sysCallKill(-cmd.Process.Pid)
}()
err = cmd.Wait()

View File

@@ -0,0 +1,16 @@
//go:build !windows
// +build !windows
package plugin
import (
"syscall"
)
func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
return &syscall.SysProcAttr{Setpgid: setpgid}
}
func sysCallKill(pid int) error {
return syscall.Kill(pid, syscall.SIGKILL)
}

View File

@@ -0,0 +1,16 @@
//go:build windows
// +build windows
package plugin
import (
"syscall"
)
func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
return &syscall.SysProcAttr{}
}
func sysCallKill(pid int) error {
return nil
}

View File

@@ -5,7 +5,7 @@ kind: Kustomization
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v2.3.0-rc1
resources:
- ./application-controller
- ./dex

View File

@@ -3033,7 +3033,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -3082,7 +3082,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
name: copyutil
volumeMounts:
- mountPath: /var/run/argocd
@@ -3247,7 +3247,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -11,4 +11,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v2.3.0-rc1

View File

@@ -11,7 +11,7 @@ patchesStrategicMerge:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v2.3.0-rc1
resources:
- ../../base/application-controller
- ../../base/dex

View File

@@ -10348,7 +10348,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -10381,7 +10381,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -10614,7 +10614,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -10663,7 +10663,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
name: copyutil
volumeMounts:
- mountPath: /var/run/argocd
@@ -10890,7 +10890,7 @@ spec:
key: server.http.cookie.maxnumber
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -11086,7 +11086,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -7644,7 +7644,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -7677,7 +7677,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -7910,7 +7910,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -7959,7 +7959,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
name: copyutil
volumeMounts:
- mountPath: /var/run/argocd
@@ -8186,7 +8186,7 @@ spec:
key: server.http.cookie.maxnumber
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -8382,7 +8382,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -9718,7 +9718,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -9751,7 +9751,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -9948,7 +9948,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -9997,7 +9997,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
name: copyutil
volumeMounts:
- mountPath: /var/run/argocd
@@ -10220,7 +10220,7 @@ spec:
key: server.http.cookie.maxnumber
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -10410,7 +10410,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -7014,7 +7014,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -7047,7 +7047,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -7244,7 +7244,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -7293,7 +7293,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
name: copyutil
volumeMounts:
- mountPath: /var/run/argocd
@@ -7516,7 +7516,7 @@ spec:
key: server.http.cookie.maxnumber
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -7706,7 +7706,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.3.0-rc1
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -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 (
<div className='filter'>
<Checkbox
checked={!!props.pref.showFavorites}
id='favouriteFilter'
onChange={val => {
ctx.navigation.goto('.', {showFavorites: val}, {replace: true});
services.viewPreferences.updatePreferences({appList: {...props.pref, showFavorites: val}});
}}
/>{' '}
<label htmlFor='favouriteFilter'>FAVORITES ONLY</label>
</div>
);
};
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 (
<FiltersGroup setShown={setShown} expanded={!props.pref.hideFilters} content={props.children}>
<FavoriteFilter {...props} />
<SyncFilter {...props} />
<HealthFilter {...props} />
<LabelsFilter {...props} />

View File

@@ -172,7 +172,6 @@
&__external-links-icon-container {
position: relative;
display: inline-block;
width: 28px;
}
.filters-group__panel {

View File

@@ -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 {

View File

@@ -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 (
<Consumer>
{ctx => (
<div className='applications-table argo-table-list argo-table-list--clickable'>
{props.applications.map((app, i) => (
<div
key={app.metadata.name}
className={`argo-table-list__row
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{pref => {
const favList = pref.appList.favoritesAppList || [];
return (
<div className='applications-table argo-table-list argo-table-list--clickable'>
{props.applications.map((app, i) => (
<div
key={app.metadata.name}
className={`argo-table-list__row
applications-list__entry applications-list__entry--health-${app.status.health.status} ${selectedApp === i ? 'applications-tiles__selected' : ''}`}>
<div className={`row applications-list__table-row`} onClick={e => ctx.navigation.goto(`/applications/${app.metadata.name}`, {}, {event: e})}>
<div className='columns small-4'>
<div className='row'>
<div className='show-for-xxlarge columns small-3'>Project:</div>
<div className='columns small-12 xxlarge-9'>{app.spec.project}</div>
</div>
<div className='row'>
<div className='show-for-xxlarge columns small-3'>Name:</div>
<div className='columns small-12 xxlarge-9'>
{app.metadata.name} <ApplicationURLs urls={AppUtils.getExternalUrls(app.metadata.annotations, app.status.summary.externalURLs)} />
</div>
</div>
</div>
<div className='columns small-6'>
<div className='row'>
<div className='show-for-xxlarge columns small-2'>Source:</div>
<div className='columns small-12 xxlarge-10 applications-table-source' style={{position: 'relative'}}>
<div className='applications-table-source__link'>
<ApplicationsSource source={app.spec.source} />
<div
className={`row applications-list__table-row`}
onClick={e => ctx.navigation.goto(`/applications/${app.metadata.name}`, {}, {event: e})}>
<div className='columns small-4'>
<div className='row'>
<div className=' columns small-2'>
<div>
<Tooltip content={favList?.includes(app.metadata.name) ? 'Remove Favorite' : 'Add Favorite'}>
<button
onClick={e => {
e.stopPropagation();
favList?.includes(app.metadata.name)
? favList.splice(favList.indexOf(app.metadata.name), 1)
: favList.push(app.metadata.name);
services.viewPreferences.updatePreferences({appList: {...pref.appList, favoritesAppList: favList}});
}}>
<i
className={'fas fa-star'}
style={{
cursor: 'pointer',
marginRight: '7px',
color: favList?.includes(app.metadata.name) ? '#1FBDD0' : 'grey'
}}
/>
</button>
</Tooltip>
<ApplicationURLs urls={AppUtils.getExternalUrls(app.metadata.annotations, app.status.summary.externalURLs)} />
</div>
</div>
<div className='show-for-xxlarge columns small-4'>Project:</div>
<div className='columns small-12 xxlarge-6'>{app.spec.project}</div>
</div>
<div className='row'>
<div className=' columns small-2' />
<div className='show-for-xxlarge columns small-4'>Name:</div>
<div className='columns small-12 xxlarge-6'>{app.metadata.name}</div>
</div>
</div>
<div className='applications-table-source__labels'>
<ApplicationsLabels app={app} />
<div className='columns small-6'>
<div className='row'>
<div className='show-for-xxlarge columns small-2'>Source:</div>
<div className='columns small-12 xxlarge-10 applications-table-source' style={{position: 'relative'}}>
<div className='applications-table-source__link'>
<ApplicationsSource source={app.spec.source} />
</div>
<div className='applications-table-source__labels'>
<ApplicationsLabels app={app} />
</div>
</div>
</div>
<div className='row'>
<div className='show-for-xxlarge columns small-2'>Destination:</div>
<div className='columns small-12 xxlarge-10'>
<Cluster server={app.spec.destination.server} name={app.spec.destination.name} />/{app.spec.destination.namespace}
</div>
</div>
</div>
<div className='columns small-2'>
<AppUtils.HealthStatusIcon state={app.status.health} /> <span>{app.status.health.status}</span> <br />
<AppUtils.ComparisonStatusIcon status={app.status.sync.status} />
<span>{app.status.sync.status}</span> <OperationState app={app} quiet={true} />
<DropDownMenu
anchor={() => (
<button className='argo-button argo-button--light argo-button--lg argo-button--short'>
<i className='fa fa-ellipsis-v' />
</button>
)}
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)}
]}
/>
</div>
</div>
</div>
<div className='row'>
<div className='show-for-xxlarge columns small-2'>Destination:</div>
<div className='columns small-12 xxlarge-10'>
<Cluster server={app.spec.destination.server} name={app.spec.destination.name} />/{app.spec.destination.namespace}
</div>
</div>
</div>
<div className='columns small-2'>
<AppUtils.HealthStatusIcon state={app.status.health} /> <span>{app.status.health.status}</span>
<br />
<AppUtils.ComparisonStatusIcon status={app.status.sync.status} />
<span>{app.status.sync.status}</span> <OperationState app={app} quiet={true} />
<DropDownMenu
anchor={() => (
<button className='argo-button argo-button--light argo-button--lg argo-button--short'>
<i className='fa fa-ellipsis-v' />
</button>
)}
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)}
]}
/>
</div>
))}
</div>
</div>
))}
</div>
);
}}
</DataLoader>
)}
</Consumer>
);

View File

@@ -102,158 +102,178 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
<Consumer>
{ctx => (
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{pref => (
<div className='applications-tiles argo-table-list argo-table-list--clickable row small-up-1 medium-up-2 large-up-3 xxxlarge-up-4' ref={appContainerRef}>
{applications.map((app, i) => (
<div key={app.metadata.name} className='column column-block'>
<div
ref={appRef.set ? null : appRef.ref}
className={`argo-table-list__row applications-list__entry applications-list__entry--health-${app.status.health.status} ${
selectedApp === i ? 'applications-tiles__selected' : ''
}`}>
<div className='row' onClick={e => ctx.navigation.goto(`/applications/${app.metadata.name}`, {view: pref.appDetails.view}, {event: e})}>
<div className={`columns small-12 applications-list__info qe-applications-list-${app.metadata.name}`}>
<div className='applications-list__external-link'>
<ApplicationURLs urls={AppUtils.getExternalUrls(app.metadata.annotations, app.status.summary.externalURLs)} />
</div>
<div className='row'>
<div className='columns small-12'>
<i className={'icon argo-icon-' + (app.spec.source.chart != null ? 'helm' : 'git')} />
<span className='applications-list__title'>{app.metadata.name}</span>
{pref => {
const favList = pref.appList.favoritesAppList || [];
return (
<div
className='applications-tiles argo-table-list argo-table-list--clickable row small-up-1 medium-up-2 large-up-3 xxxlarge-up-4'
ref={appContainerRef}>
{applications.map((app, i) => (
<div key={app.metadata.name} className='column column-block'>
<div
ref={appRef.set ? null : appRef.ref}
className={`argo-table-list__row applications-list__entry applications-list__entry--health-${app.status.health.status} ${
selectedApp === i ? 'applications-tiles__selected' : ''
}`}>
<div className='row' onClick={e => ctx.navigation.goto(`/applications/${app.metadata.name}`, {view: pref.appDetails.view}, {event: e})}>
<div className={`columns small-12 applications-list__info qe-applications-list-${app.metadata.name}`}>
<div className='applications-list__external-link'>
<ApplicationURLs urls={AppUtils.getExternalUrls(app.metadata.annotations, app.status.summary.externalURLs)} />
<Tooltip content={favList?.includes(app.metadata.name) ? 'Remove Favorite' : 'Add Favorite'}>
<button
onClick={e => {
e.stopPropagation();
favList?.includes(app.metadata.name)
? favList.splice(favList.indexOf(app.metadata.name), 1)
: favList.push(app.metadata.name);
services.viewPreferences.updatePreferences({appList: {...pref.appList, favoritesAppList: favList}});
}}>
<i
className={'fas fa-star fa-lg'}
style={{cursor: 'pointer', marginLeft: '7px', color: favList?.includes(app.metadata.name) ? '#1FBDD0' : 'grey'}}
/>
</button>
</Tooltip>
</div>
</div>
<div className='row'>
<div className='columns small-3' title='Project:'>
Project:
<div className='row'>
<div className='columns small-12'>
<i className={'icon argo-icon-' + (app.spec.source.chart != null ? 'helm' : 'git')} />
<span className='applications-list__title'>{app.metadata.name}</span>
</div>
</div>
<div className='columns small-9'>{app.spec.project}</div>
</div>
<div className='row'>
<div className='columns small-3' title='Labels:'>
Labels:
<div className='row'>
<div className='columns small-3' title='Project:'>
Project:
</div>
<div className='columns small-9'>{app.spec.project}</div>
</div>
<div className='columns small-9'>
<Tooltip
zIndex={4}
content={
<div>
<div className='row'>
<div className='columns small-3' title='Labels:'>
Labels:
</div>
<div className='columns small-9'>
<Tooltip
zIndex={4}
content={
<div>
{Object.keys(app.metadata.labels || {})
.map(label => ({label, value: app.metadata.labels[label]}))
.map(item => (
<div key={item.label}>
{item.label}={item.value}
</div>
))}
</div>
}>
<span>
{Object.keys(app.metadata.labels || {})
.map(label => ({label, value: app.metadata.labels[label]}))
.map(item => (
<div key={item.label}>
{item.label}={item.value}
</div>
))}
</div>
}>
<span>
{Object.keys(app.metadata.labels || {})
.map(label => `${label}=${app.metadata.labels[label]}`)
.join(', ')}
</span>
</Tooltip>
</div>
</div>
<div className='row'>
<div className='columns small-3' title='Status:'>
Status:
</div>
<div className='columns small-9' qe-id='applications-tiles-health-status'>
<AppUtils.HealthStatusIcon state={app.status.health} /> {app.status.health.status}
&nbsp;
<AppUtils.ComparisonStatusIcon status={app.status.sync.status} /> {app.status.sync.status}
&nbsp;
<OperationState app={app} quiet={true} />
</div>
</div>
<div className='row'>
<div className='columns small-3' title='Repository:'>
Repository:
</div>
<div className='columns small-9'>
<Tooltip content={app.spec.source.repoURL} zIndex={4}>
<span>{app.spec.source.repoURL}</span>
</Tooltip>
</div>
</div>
<div className='row'>
<div className='columns small-3' title='Target Revision:'>
Target Revision:
</div>
<div className='columns small-9'>{app.spec.source.targetRevision}</div>
</div>
{app.spec.source.path && (
<div className='row'>
<div className='columns small-3' title='Path:'>
Path:
.map(label => `${label}=${app.metadata.labels[label]}`)
.join(', ')}
</span>
</Tooltip>
</div>
<div className='columns small-9'>{app.spec.source.path}</div>
</div>
)}
{app.spec.source.chart && (
<div className='row'>
<div className='columns small-3' title='Chart:'>
Chart:
<div className='columns small-3' title='Status:'>
Status:
</div>
<div className='columns small-9' qe-id='applications-tiles-health-status'>
<AppUtils.HealthStatusIcon state={app.status.health} /> {app.status.health.status}
&nbsp;
<AppUtils.ComparisonStatusIcon status={app.status.sync.status} /> {app.status.sync.status}
&nbsp;
<OperationState app={app} quiet={true} />
</div>
<div className='columns small-9'>{app.spec.source.chart}</div>
</div>
)}
<div className='row'>
<div className='columns small-3' title='Destination:'>
Destination:
<div className='row'>
<div className='columns small-3' title='Repository:'>
Repository:
</div>
<div className='columns small-9'>
<Tooltip content={app.spec.source.repoURL} zIndex={4}>
<span>{app.spec.source.repoURL}</span>
</Tooltip>
</div>
</div>
<div className='columns small-9'>
<Cluster server={app.spec.destination.server} name={app.spec.destination.name} />
<div className='row'>
<div className='columns small-3' title='Target Revision:'>
Target Revision:
</div>
<div className='columns small-9'>{app.spec.source.targetRevision}</div>
</div>
</div>
<div className='row'>
<div className='columns small-3' title='Namespace:'>
Namespace:
{app.spec.source.path && (
<div className='row'>
<div className='columns small-3' title='Path:'>
Path:
</div>
<div className='columns small-9'>{app.spec.source.path}</div>
</div>
)}
{app.spec.source.chart && (
<div className='row'>
<div className='columns small-3' title='Chart:'>
Chart:
</div>
<div className='columns small-9'>{app.spec.source.chart}</div>
</div>
)}
<div className='row'>
<div className='columns small-3' title='Destination:'>
Destination:
</div>
<div className='columns small-9'>
<Cluster server={app.spec.destination.server} name={app.spec.destination.name} />
</div>
</div>
<div className='columns small-9'>{app.spec.destination.namespace}</div>
</div>
<div className='row'>
<div className='columns applications-list__entry--actions'>
<a
className='argo-button argo-button--base'
qe-id='applications-tiles-button-sync'
onClick={e => {
e.stopPropagation();
syncApplication(app.metadata.name);
}}>
<i className='fa fa-sync' /> Sync
</a>
&nbsp;
<a
className='argo-button argo-button--base'
qe-id='applications-tiles-button-refresh'
{...AppUtils.refreshLinkAttrs(app)}
onClick={e => {
e.stopPropagation();
refreshApplication(app.metadata.name);
}}>
<i className={classNames('fa fa-redo', {'status-icon--spin': AppUtils.isAppRefreshing(app)})} />{' '}
<span className='show-for-xxlarge'>Refresh</span>
</a>
&nbsp;
<a
className='argo-button argo-button--base'
qe-id='applications-tiles-button-delete'
onClick={e => {
e.stopPropagation();
deleteApplication(app.metadata.name);
}}>
<i className='fa fa-times-circle' /> <span className='show-for-xxlarge'>Delete</span>
</a>
<div className='row'>
<div className='columns small-3' title='Namespace:'>
Namespace:
</div>
<div className='columns small-9'>{app.spec.destination.namespace}</div>
</div>
<div className='row'>
<div className='columns applications-list__entry--actions'>
<a
className='argo-button argo-button--base'
qe-id='applications-tiles-button-sync'
onClick={e => {
e.stopPropagation();
syncApplication(app.metadata.name);
}}>
<i className='fa fa-sync' /> Sync
</a>
&nbsp;
<a
className='argo-button argo-button--base'
qe-id='applications-tiles-button-refresh'
{...AppUtils.refreshLinkAttrs(app)}
onClick={e => {
e.stopPropagation();
refreshApplication(app.metadata.name);
}}>
<i className={classNames('fa fa-redo', {'status-icon--spin': AppUtils.isAppRefreshing(app)})} />{' '}
<span className='show-for-xxlarge'>Refresh</span>
</a>
&nbsp;
<a
className='argo-button argo-button--base'
qe-id='applications-tiles-button-delete'
onClick={e => {
e.stopPropagation();
deleteApplication(app.metadata.name);
}}>
<i className='fa fa-times-circle' /> <span className='show-for-xxlarge'>Delete</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</div>
)}
))}
</div>
);
}}
</DataLoader>
)}
</Consumer>

View File

@@ -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<string>(),
healthFilter: new Array<string>(),
hideFilters: false,
showFavorites: false,
favoritesAppList: new Array<string>(),
statusBarView: {
showHealthStatusBar: true
}