Skip to content

Commit 13d3fef

Browse files
committed
fix: Progress Sync Unknown in UI (argoproj#24202)
Signed-off-by: Atif Ali <atali@redhat.com>
1 parent bf9f927 commit 13d3fef

4 files changed

Lines changed: 73 additions & 21 deletions

File tree

ui/src/app/applications/components/application-status-panel/application-status-panel.tsx

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,44 +58,75 @@ const sectionHeader = (info: SectionInfo, onClick?: () => any) => {
5858
);
5959
};
6060

61-
const hasRollingSyncEnabled = (application: models.Application): boolean => {
62-
return application.metadata.ownerReferences?.some(ref => ref.kind === 'ApplicationSet') || false;
61+
const getApplicationSetOwnerRef = (application: models.Application) => {
62+
return application.metadata.ownerReferences?.find(ref => ref.kind === 'ApplicationSet');
6363
};
6464

6565
const ProgressiveSyncStatus = ({application}: {application: models.Application}) => {
66-
if (!hasRollingSyncEnabled(application)) {
67-
return null;
68-
}
69-
70-
const appSetRef = application.metadata.ownerReferences.find(ref => ref.kind === 'ApplicationSet');
66+
const appSetRef = getApplicationSetOwnerRef(application);
7167
if (!appSetRef) {
7268
return null;
7369
}
7470

7571
return (
7672
<DataLoader
7773
input={application}
74+
errorRenderer={() => {
75+
// For any errors, show a minimal error state
76+
return (
77+
<div className='application-status-panel__item'>
78+
{sectionHeader({
79+
title: 'PROGRESSIVE SYNC',
80+
helpContent: 'Shows the current status of progressive sync for applications managed by an ApplicationSet.'
81+
})}
82+
<div className='application-status-panel__item-value'>
83+
<i className='fa fa-exclamation-triangle' style={{color: COLORS.sync.unknown}} /> Error
84+
</div>
85+
<div className='application-status-panel__item-name'>Unable to load Progressive Sync status</div>
86+
</div>
87+
);
88+
}}
7889
load={async () => {
79-
const appSet = await services.applications.getApplicationSet(appSetRef.name, application.metadata.namespace);
80-
return appSet?.spec?.strategy?.type === 'RollingSync' ? appSet : null;
81-
}}>
82-
{(appSet: models.ApplicationSet) => {
90+
// Check if user has permission to read ApplicationSets
91+
const canReadApplicationSets = await services.accounts.canI('applicationsets', 'get', application.spec.project + '/' + application.metadata.name);
92+
93+
// Find ApplicationSet by searching all namespaces dynamically
94+
const appSetList = await services.applications.listApplicationSets();
95+
const appSet = appSetList.items?.find(item => item.metadata.name === appSetRef.name);
96+
8397
if (!appSet) {
98+
throw new Error(`ApplicationSet ${appSetRef.name} not found in any namespace`);
99+
}
100+
101+
return {canReadApplicationSets, appSet};
102+
}}>
103+
{({canReadApplicationSets, appSet}: {canReadApplicationSets: boolean; appSet: models.ApplicationSet}) => {
104+
// Hide panel if: Progressive Sync disabled, no permission, or not RollingSync strategy
105+
if (!appSet.status?.applicationStatus || appSet?.spec?.strategy?.type !== 'RollingSync' || !canReadApplicationSets) {
106+
return null;
107+
}
108+
109+
// Get the current application's status from the ApplicationSet applicationStatus
110+
const appResource = appSet.status?.applicationStatus?.find(status => status.application === application.metadata.name);
111+
112+
// If no application status is found, show a default status
113+
if (!appResource) {
84114
return (
85115
<div className='application-status-panel__item'>
86116
{sectionHeader({
87117
title: 'PROGRESSIVE SYNC',
88118
helpContent: 'Shows the current status of progressive sync for applications managed by an ApplicationSet with RollingSync strategy.'
89119
})}
90120
<div className='application-status-panel__item-value'>
91-
<i className='fa fa-question-circle' style={{color: COLORS.sync.unknown}} /> Unknown
121+
<i className='fa fa-clock' style={{color: COLORS.sync.out_of_sync}} /> Waiting
92122
</div>
123+
<div className='application-status-panel__item-name'>Application status not yet available from ApplicationSet</div>
93124
</div>
94125
);
95126
}
96127

97-
// Get the current application's status from the ApplicationSet resources
98-
const appResource = appSet.status?.applicationStatus?.find(status => status.application === application.metadata.name);
128+
// Get last transition time from application status
129+
const lastTransitionTime = appResource?.lastTransitionTime;
99130

100131
return (
101132
<div className='application-status-panel__item'>
@@ -106,12 +137,14 @@ const ProgressiveSyncStatus = ({application}: {application: models.Application})
106137
<div className='application-status-panel__item-value' style={{color: getProgressiveSyncStatusColor(appResource.status)}}>
107138
{getProgressiveSyncStatusIcon({status: appResource.status})}&nbsp;{appResource.status}
108139
</div>
109-
<div className='application-status-panel__item-value'>Wave: {appResource.step}</div>
110-
<div className='application-status-panel__item-name' style={{marginBottom: '0.5em'}}>
111-
Last Transition: <br />
112-
<Timestamp date={appResource.lastTransitionTime} />
113-
</div>
114-
{appResource.message && <div className='application-status-panel__item-name'>{appResource.message}</div>}
140+
{appResource?.step && <div className='application-status-panel__item-value'>Wave: {appResource.step}</div>}
141+
{lastTransitionTime && (
142+
<div className='application-status-panel__item-name' style={{marginBottom: '0.5em'}}>
143+
Last Transition: <br />
144+
<Timestamp date={lastTransitionTime} />
145+
</div>
146+
)}
147+
{appResource?.message && <div className='application-status-panel__item-name'>{appResource.message}</div>}
115148
</div>
116149
);
117150
}}
@@ -123,7 +156,9 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh
123156
const [showProgressiveSync, setShowProgressiveSync] = React.useState(false);
124157

125158
React.useEffect(() => {
126-
setShowProgressiveSync(hasRollingSyncEnabled(application));
159+
// Only show Progressive Sync if the application has an ApplicationSet parent
160+
// The actual strategy validation will be done inside ProgressiveSyncStatus component
161+
setShowProgressiveSync(!!getApplicationSetOwnerRef(application));
127162
}, [application]);
128163

129164
const today = new Date();

ui/src/app/applications/components/utils.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,6 +1716,10 @@ export const getProgressiveSyncStatusIcon = ({status, isButton}: {status: string
17161716
return {icon: 'fa-clock', color: COLORS.sync.out_of_sync};
17171717
case 'Error':
17181718
return {icon: 'fa-times-circle', color: COLORS.health.degraded};
1719+
case 'Synced':
1720+
return {icon: 'fa-check-circle', color: COLORS.sync.synced};
1721+
case 'OutOfSync':
1722+
return {icon: 'fa-exclamation-triangle', color: COLORS.sync.out_of_sync};
17191723
default:
17201724
return {icon: 'fa-question-circle', color: COLORS.sync.unknown};
17211725
}
@@ -1738,6 +1742,10 @@ export const getProgressiveSyncStatusColor = (status: string): string => {
17381742
return COLORS.health.healthy;
17391743
case 'Error':
17401744
return COLORS.health.degraded;
1745+
case 'Synced':
1746+
return COLORS.sync.synced;
1747+
case 'OutOfSync':
1748+
return COLORS.sync.out_of_sync;
17411749
default:
17421750
return COLORS.sync.unknown;
17431751
}

ui/src/app/shared/models.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,3 +1134,8 @@ export interface ApplicationSet {
11341134
resources?: ApplicationSetResource[];
11351135
};
11361136
}
1137+
1138+
export interface ApplicationSetList {
1139+
metadata: models.ListMeta;
1140+
items: ApplicationSet[];
1141+
}

ui/src/app/shared/services/applications-service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,4 +550,8 @@ export class ApplicationsService {
550550
.query({appsetNamespace: namespace})
551551
.then(res => res.body as models.ApplicationSet);
552552
}
553+
554+
public async listApplicationSets(): Promise<models.ApplicationSetList> {
555+
return requests.get(`/applicationsets`).then(res => res.body as models.ApplicationSetList);
556+
}
553557
}

0 commit comments

Comments
 (0)