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): support display sync wave #20614

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Checkbox, DropDown, Duration, NotificationType, Ticker, HelpIcon} from 'argo-ui';
import {Checkbox, DropDown, Duration, NotificationType, Ticker, HelpIcon, DataLoader} from 'argo-ui';
import * as moment from 'moment';
import * as PropTypes from 'prop-types';
import * as React from 'react';
Expand All @@ -15,7 +15,8 @@ interface Props {
application: models.Application;
operationState: models.OperationState;
}
const buildResourceUniqueId = (res: Omit<models.ResourceRef, 'uid'>) => `${res.group}-${res.kind}-${res.version}-${res.namespace}-${res.name}`;
const buildResourceUniqueId = (res: Omit<models.ResourceRef, 'uid'>) =>
`${res.group || ''}-${res.kind || ''}-${res.version || ''}-${res.kind === 'Namespace' ? res.name : res.kind}-${res.name}`;

const Filter = (props: {filters: string[]; setFilters: (f: string[]) => void; options: string[]; title: string; style?: React.CSSProperties}) => {
const {filters, setFilters, options, title, style} = props;
Expand Down Expand Up @@ -138,13 +139,19 @@ export const ApplicationOperationState: React.StatelessComponent<Props> = ({appl
// const hookPhases = ['Running', 'Terminating', 'Failed', 'Error', 'Succeeded'];
const resourceHealth = application.status.resources.reduce(
(acc, res) => {
if (res.health) {
acc[buildResourceUniqueId(res)] = res.health;
}

acc[buildResourceUniqueId(res)] = {
health: res.health,
syncWave: res.syncWave
};
return acc;
},
{} as Record<string, models.HealthStatus>
{} as Record<
string,
{
health: models.HealthStatus;
syncWave: number;
}
>
);

const combinedHealthSyncResult: models.SyncResourceResult[] = syncResult?.resources?.map(syncResultItem => {
Expand All @@ -156,10 +163,12 @@ export const ApplicationOperationState: React.StatelessComponent<Props> = ({appl
...syncResultItem
};

if (healthStatus) {
syncResultWithHealth.health = healthStatus;
if (healthStatus?.health) {
syncResultWithHealth.health = healthStatus.health;
}

syncResultWithHealth.syncWave = healthStatus?.syncWave;

return syncResultWithHealth;
});
let filtered: models.SyncResourceResult[] = [];
Expand Down Expand Up @@ -195,72 +204,132 @@ export const ApplicationOperationState: React.StatelessComponent<Props> = ({appl
))}
</div>
</div>
{syncResult && syncResult.resources && syncResult.resources.length > 0 && (
<React.Fragment>
<div style={{display: 'flex'}}>
<label style={{display: 'block', marginBottom: '1em'}}>RESULT</label>
<div style={{marginLeft: 'auto'}}>
<Filter options={Healths} filters={healthFilters} setFilters={setHealthFilters} title='HEALTH' style={{marginRight: '5px'}} />
<Filter options={Statuses} filters={filters} setFilters={setFilters} title='STATUS' style={{marginRight: '5px'}} />
<Filter options={OperationPhases} filters={filters} setFilters={setFilters} title='HOOK' />
</div>
</div>
<div className='argo-table-list'>
<div className='argo-table-list__head'>
<div className='row'>
<div className='columns large-1 show-for-large application-operation-state__icons_container_padding'>KIND</div>
<div className='columns large-2 show-for-large'>NAMESPACE</div>
<div className='columns large-2 small-2'>NAME</div>
<div className='columns large-1 small-2'>STATUS</div>
<div className='columns large-1 small-2'>HEALTH</div>
<div className='columns large-1 show-for-large'>HOOK</div>
<div className='columns large-4 small-8'>MESSAGE</div>
</div>
</div>
{filtered.length > 0 ? (
filtered.map((resource, i) => (
<div className='argo-table-list__row' key={i}>
<div className='row'>
<div className='columns large-1 show-for-large application-operation-state__icons_container_padding'>
<div className='application-operation-state__icons_container'>
{resource.hookType && <i title='Resource lifecycle hook' className='fa fa-anchor' />}
</div>
<span title={getKind(resource)}>{getKind(resource)}</span>
</div>
<div className='columns large-2 show-for-large' title={resource.namespace}>
{resource.namespace}
</div>
<div className='columns large-2 small-2' title={resource.name}>
{resource.name}
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{pref => {
const showSyncWave = pref.appDetails?.syncResult?.showSyncWave ?? false;

return (
<>
{syncResult && syncResult.resources && syncResult.resources.length > 0 && (
<React.Fragment>
<div style={{display: 'flex'}}>
<label style={{display: 'block', marginBottom: '1em'}}>RESULT</label>
<div style={{marginLeft: 'auto'}}>
<span style={{marginRight: '5px'}}>
<Checkbox
id='show_sync_wave'
checked={showSyncWave}
onChange={() =>
services.viewPreferences.updatePreferences({
...pref,
appDetails: {
...pref.appDetails,
syncResult: {
...pref.appDetails.syncResult,
showSyncWave: !showSyncWave
}
}
})
}></Checkbox>
<label htmlFor='show_sync_wave'>SHOW SYNC WAVE</label>
</span>
<Filter options={Healths} filters={healthFilters} setFilters={setHealthFilters} title='HEALTH' style={{marginRight: '5px'}} />
<Filter options={Statuses} filters={filters} setFilters={setFilters} title='STATUS' style={{marginRight: '5px'}} />
<Filter options={OperationPhases} filters={filters} setFilters={setFilters} title='HOOK' />
</div>
<div className='columns large-1 small-2' title={getStatus(resource)}>
<utils.ResourceResultIcon resource={resource} /> {getStatus(resource)}
</div>
<div className='argo-table-list'>
<div className='argo-table-list__head'>
<div className='row'>
{showSyncWave ? (
<>
<div className='columns large-1 small-1 application-operation-state__icons_container_padding'>SYNC WAVE</div>
<div className='columns large-1 show-for-large'>KIND</div>
<div className='columns large-1 show-for-large'>NAMESPACE</div>
</>
) : (
<>
<div className='columns large-1 show-for-large application-operation-state__icons_container_padding'>KIND</div>
<div className='columns large-2 show-for-large'>NAMESPACE</div>
</>
)}

<div className='columns large-2 small-2'>NAME</div>
<div className='columns large-1 small-2'>STATUS</div>
<div className='columns large-1 small-2'>HEALTH</div>
<div className='columns large-1 show-for-large'>HOOK</div>
<div className='columns large-4 small-8'>MESSAGE</div>
</div>
</div>
<div className='columns large-1 small-2'>
{resource.health ? (
<div>
<utils.HealthStatusIcon state={resource?.health} /> {resource.health?.status}
{resource.health.message && <HelpIcon title={resource.health.message} />}
{filtered.length > 0 ? (
filtered.map((resource, i) => (
<div className='argo-table-list__row' key={i}>
<div className='row'>
{showSyncWave ? (
<>
<div
className='columns large-1 small-1 application-operation-state__icons_container_padding'
title={`${resource.syncWave || '0'}`}>
{resource.syncWave || '0'}
</div>
<div className='columns large-1 show-for-large'>
<div className='application-operation-state__icons_container'>
{resource.hookType && <i title='Resource lifecycle hook' className='fa fa-anchor' />}
</div>
<span title={getKind(resource)}>{getKind(resource)}</span>
</div>
<div className='columns large-1 show-for-large' title={resource.namespace}>
{resource.namespace}
</div>
</>
) : (
<>
<div className='columns large-1 show-for-large application-operation-state__icons_container_padding'>
<div className='application-operation-state__icons_container'>
{resource.hookType && <i title='Resource lifecycle hook' className='fa fa-anchor' />}
</div>
<span title={getKind(resource)}>{getKind(resource)}</span>
</div>
<div className='columns large-2 show-for-large' title={resource.namespace}>
{resource.namespace}
</div>
</>
)}
<div className='columns large-2 small-2' title={resource.name}>
{resource.name}
</div>
<div className='columns large-1 small-2' title={getStatus(resource)}>
<utils.ResourceResultIcon resource={resource} /> {getStatus(resource)}
</div>
<div className='columns large-1 small-2'>
{resource.health ? (
<div>
<utils.HealthStatusIcon state={resource?.health} /> {resource.health?.status}
{resource.health.message && <HelpIcon title={resource.health.message} />}
</div>
) : (
<>{'-'}</>
)}
</div>
<div className='columns large-1 show-for-large' title={resource.hookType}>
{resource.hookType}
</div>
<div className='columns large-4 small-8' title={resource.message}>
<div className='application-operation-state__message'>{resource.message}</div>
</div>
</div>
</div>
) : (
<>{'-'}</>
)}
</div>
<div className='columns large-1 show-for-large' title={resource.hookType}>
{resource.hookType}
</div>
<div className='columns large-4 small-8' title={resource.message}>
<div className='application-operation-state__message'>{resource.message}</div>
</div>
))
) : (
<div style={{textAlign: 'center', marginTop: '2em', fontSize: '20px'}}>No Sync Results match filter</div>
)}
</div>
</div>
))
) : (
<div style={{textAlign: 'center', marginTop: '2em', fontSize: '20px'}}>No Sync Results match filter</div>
)}
</div>
</React.Fragment>
)}
</React.Fragment>
)}
</>
);
}}
</DataLoader>
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions ui/src/app/shared/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export interface ResourceResult {

export type SyncResourceResult = ResourceResult & {
health?: HealthStatus;
syncWave?: number;
};

export const AnnotationRefreshKey = 'argocd.argoproj.io/refresh';
Expand Down
8 changes: 7 additions & 1 deletion ui/src/app/shared/services/view-preferences-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export interface AppDetailsPreferences {
zoom: number;
podGroupCount: number;
userHelpTipMsgs: UserMessages[];
syncResult?: {
showSyncWave?: boolean;
};
}

export interface PodViewPreferences {
Expand Down Expand Up @@ -126,7 +129,10 @@ const DEFAULT_PREFERENCES: ViewPreferences = {
wrapLines: false,
zoom: 1.0,
podGroupCount: 15.0,
userHelpTipMsgs: []
userHelpTipMsgs: [],
syncResult: {
showSyncWave: false
}
},
appList: {
view: 'tiles' as AppsListViewType,
Expand Down