Skip to content

Commit 4c465b0

Browse files
committed
Add modal message, layout issues, check undefined
Signed-off-by: Keith Chong <kykchong@redhat.com>
1 parent 7e17f29 commit 4c465b0

File tree

3 files changed

+203
-144
lines changed

3 files changed

+203
-144
lines changed

src/gitops/components/application/ApplicationDetailsTab.tsx

Lines changed: 196 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,23 @@ import SyncStatus from '@gitops/Statuses/SyncStatus';
1414
import { ArgoServer, getArgoServer, getFriendlyClusterName } from '@gitops/utils/gitops';
1515
import { useGitOpsTranslation } from '@gitops/utils/hooks/useGitOpsTranslation';
1616
import { useObjectModifyPermissions } from '@gitops/utils/utils';
17-
import { k8sUpdate, ResourceLink, useK8sModel } from '@openshift-console/dynamic-plugin-sdk';
18-
import { Label as PfLabel, ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
17+
import {
18+
k8sUpdate,
19+
ResourceLink,
20+
useK8sModel,
21+
useModal,
22+
} from '@openshift-console/dynamic-plugin-sdk';
23+
import { ModalComponent } from '@openshift-console/dynamic-plugin-sdk/lib/app/modal-support/ModalProvider';
24+
import {
25+
Button,
26+
Label as PfLabel,
27+
Modal,
28+
ModalBody,
29+
ModalFooter,
30+
ModalHeader,
31+
ToggleGroup,
32+
ToggleGroupItem,
33+
} from '@patternfly/react-core';
1934
import {
2035
DescriptionList,
2136
Flex,
@@ -47,7 +62,7 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
4762
const [canPatch, canUpdate] = useObjectModifyPermissions(obj, ApplicationModel);
4863

4964
const [argoServer, setArgoServer] = React.useState<ArgoServer>({ host: '', protocol: '' });
50-
65+
const launchModal = useModal();
5166
React.useEffect(() => {
5267
(async () => {
5368
getArgoServer(model, obj)
@@ -60,9 +75,39 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
6075
})();
6176
}, [model, obj]);
6277

78+
const modalStyle: React.CSSProperties = {
79+
padding: '1rem 1rem',
80+
textAlign: 'left',
81+
zIndex: 9999,
82+
width: '500px',
83+
};
84+
85+
const syncErrorModal: ModalComponent = (props) => {
86+
return (
87+
<Modal
88+
isOpen
89+
onClose={props?.closeModal}
90+
style={modalStyle}
91+
aria-describedby="modal-title-icon-description"
92+
aria-labelledby="title-icon-modal-title"
93+
>
94+
<ModalHeader title="Error" titleIconVariant="danger" labelId="title-icon-modal-title" />
95+
<ModalBody>
96+
<span id="modal-title-icon-description">
97+
Sync policy change failed. Check your application/logs and try again.
98+
</span>
99+
</ModalBody>
100+
<ModalFooter>
101+
<Button key="cancel" variant="primary" onClick={props?.closeModal}>
102+
Close
103+
</Button>
104+
</ModalFooter>
105+
</Modal>
106+
);
107+
};
108+
63109
const onChangeAutomated = (event: React.MouseEvent<any> | React.KeyboardEvent | MouseEvent) => {
64110
const id = event.currentTarget.id;
65-
66111
switch (id) {
67112
case 'automated': {
68113
if (obj.spec.syncPolicy?.automated) {
@@ -73,7 +118,7 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
73118
break;
74119
}
75120
case 'self-heal': {
76-
if (obj.spec.syncPolicy.automated.selfHeal) {
121+
if (obj.spec.syncPolicy?.automated?.selfHeal) {
77122
obj.spec.syncPolicy.automated.selfHeal = false;
78123
} else {
79124
obj.spec.syncPolicy.automated = {
@@ -84,7 +129,7 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
84129
break;
85130
}
86131
case 'prune': {
87-
if (obj.spec.syncPolicy.automated.prune) {
132+
if (obj.spec.syncPolicy?.automated?.prune) {
88133
obj.spec.syncPolicy.automated.prune = false;
89134
} else {
90135
obj.spec.syncPolicy.automated = { ...obj.spec.syncPolicy.automated, ...{ prune: true } };
@@ -95,7 +140,13 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
95140
k8sUpdate({
96141
model: ApplicationModel,
97142
data: obj,
98-
});
143+
})
144+
.then(() => {
145+
// ignore
146+
})
147+
.catch((e) => {
148+
launchModal(syncErrorModal, { errorMessage: e.message });
149+
});
99150
};
100151

101152
let sources: ApplicationSource[];
@@ -119,146 +170,153 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
119170
<Title headingLevel="h2" className="co-section-heading">
120171
{t('Application details')}
121172
</Title>
122-
<div className="row">
123-
<div className="col-sm-6">
124-
<BaseDetailsSummary
125-
obj={obj}
126-
model={ApplicationModel}
127-
nameLink={
128-
<>
129-
<ArgoCDLink
130-
href={
131-
argoServer.protocol +
132-
'://' +
133-
argoServer.host +
134-
'/applications/' +
135-
obj?.metadata?.namespace +
136-
'/' +
137-
obj?.metadata?.name
138-
}
139-
/>
140-
</>
141-
}
142-
/>
143-
</div>
173+
<Flex
174+
justifyContent={{ default: 'justifyContentSpaceEvenly' }}
175+
direction={{ default: 'column', lg: 'row' }}
176+
>
177+
<Flex flex={{ default: 'flex_2' }}>
178+
<FlexItem>
179+
<BaseDetailsSummary
180+
obj={obj}
181+
model={ApplicationModel}
182+
nameLink={
183+
<>
184+
<ArgoCDLink
185+
href={
186+
argoServer.protocol +
187+
'://' +
188+
argoServer.host +
189+
'/applications/' +
190+
obj?.metadata?.namespace +
191+
'/' +
192+
obj?.metadata?.name
193+
}
194+
/>
195+
</>
196+
}
197+
/>
198+
</FlexItem>
199+
</Flex>
200+
<Flex flex={{ default: 'flex_2' }} direction={{ default: 'column' }}>
201+
<FlexItem>
202+
<DescriptionList className="pf-c-description-list">
203+
<DetailsDescriptionGroup
204+
title={t('Health Status')}
205+
help={t('Health status represents the overall health of the application.')}
206+
>
207+
<HealthStatus status={obj.status?.health?.status || ''} />
208+
</DetailsDescriptionGroup>
144209

145-
<div className="col-sm-6">
146-
<DescriptionList className="pf-c-description-list">
147-
<DetailsDescriptionGroup
148-
title={t('Health Status')}
149-
help={t('Health status represents the overall health of the application.')}
150-
>
151-
<HealthStatus status={obj.status?.health?.status || ''} />
152-
</DetailsDescriptionGroup>
153-
154-
<DetailsDescriptionGroup
155-
title={t('Current Sync Status')}
156-
help={t(
157-
'Sync status represents the current synchronized state for the application.',
158-
)}
159-
>
160-
<Flex>
161-
<FlexItem>
162-
<SyncStatus status={obj.status?.sync?.status || ''} />
163-
</FlexItem>
164-
<FlexItem>
165-
<PfLabel>
166-
<Revision
167-
revision={revisions[0] || ''}
168-
repoURL={sources[0].repoURL}
169-
helm={obj.status?.sourceType == 'Helm' && sources[0].chart ? true : false}
170-
revisionExtra={
171-
revisions.length > 1 && ' and ' + (revisions.length - 1) + ' more'
172-
}
173-
/>
174-
</PfLabel>
175-
</FlexItem>
176-
</Flex>
177-
</DetailsDescriptionGroup>
178-
179-
<DetailsDescriptionGroup
180-
title={t('Last Sync Status')}
181-
help={t('The result of the last sync status.')}
182-
>
183-
<Flex>
184-
{obj?.status?.operationState && (
210+
<DetailsDescriptionGroup
211+
title={t('Current Sync Status')}
212+
help={t(
213+
'Sync status represents the current synchronized state for the application.',
214+
)}
215+
>
216+
<Flex>
185217
<FlexItem>
186-
<OperationState app={obj} />
218+
<SyncStatus status={obj.status?.sync?.status || ''} />
187219
</FlexItem>
188-
)}
189-
{obj?.status?.conditions && (
190220
<FlexItem>
191-
<ConditionsPopover conditions={obj.status?.conditions} />
221+
<PfLabel>
222+
<Revision
223+
revision={revisions[0] || ''}
224+
repoURL={sources[0].repoURL}
225+
helm={obj.status?.sourceType == 'Helm' && sources[0].chart ? true : false}
226+
revisionExtra={
227+
revisions.length > 1 && ' and ' + (revisions.length - 1) + ' more'
228+
}
229+
/>
230+
</PfLabel>
192231
</FlexItem>
193-
)}
194-
</Flex>
195-
</DetailsDescriptionGroup>
232+
</Flex>
233+
</DetailsDescriptionGroup>
196234

197-
<DetailsDescriptionGroup
198-
title={t('Target Revision')}
199-
help={t('The specified revision for the Application.')}
200-
>
201-
{sources[0].targetRevision ? sources[0].targetRevision : 'HEAD'}
202-
</DetailsDescriptionGroup>
235+
<DetailsDescriptionGroup
236+
title={t('Last Sync Status')}
237+
help={t('The result of the last sync status.')}
238+
>
239+
<Flex>
240+
{obj?.status?.operationState && (
241+
<FlexItem>
242+
<OperationState app={obj} />
243+
</FlexItem>
244+
)}
245+
{obj?.status?.conditions && (
246+
<FlexItem>
247+
<ConditionsPopover conditions={obj.status?.conditions} />
248+
</FlexItem>
249+
)}
250+
</Flex>
251+
</DetailsDescriptionGroup>
203252

204-
<DetailsDescriptionGroup
205-
title={t('Project')}
206-
help={t('The Argo CD Project that this application belongs to.')}
207-
>
208-
{/* TODO - Update to handle App in Any Namespace when controller namespace is in status */}
209-
<ResourceLink
210-
namespace={obj?.metadata?.namespace}
211-
groupVersionKind={{
212-
group: 'argoproj.io',
213-
version: 'v1alpha1',
214-
kind: 'AppProject',
215-
}}
216-
name={obj?.spec?.project}
217-
/>
218-
</DetailsDescriptionGroup>
253+
<DetailsDescriptionGroup
254+
title={t('Target Revision')}
255+
help={t('The specified revision for the Application.')}
256+
>
257+
{sources[0].targetRevision ? sources[0].targetRevision : 'HEAD'}
258+
</DetailsDescriptionGroup>
219259

220-
<DetailsDescriptionGroup
221-
title={t('Destination')}
222-
help={t('The cluster and namespace where the application is targeted')}
223-
>
224-
{getFriendlyClusterName(obj?.spec?.destination.server)}/
225-
{obj?.spec?.destination.namespace}
226-
</DetailsDescriptionGroup>
227-
228-
<DetailsDescriptionGroup
229-
title={t('Sync Policy')}
230-
help={t('Provides options to determine application synchronization behavior')}
231-
>
232-
<ToggleGroup isCompact areAllGroupsDisabled={!canPatch || !canUpdate}>
233-
<ToggleGroupItem
234-
text={t('Automated')}
235-
buttonId="automated"
236-
onChange={onChangeAutomated}
237-
isSelected={obj?.spec?.syncPolicy?.automated ? true : false}
238-
/>
239-
<ToggleGroupItem
240-
text={t('Prune')}
241-
buttonId="prune"
242-
onChange={onChangeAutomated}
243-
isSelected={
244-
obj?.spec?.syncPolicy?.automated && obj?.spec?.syncPolicy?.automated.prune
245-
}
246-
isDisabled={obj?.spec?.syncPolicy?.automated ? false : true}
247-
/>
248-
<ToggleGroupItem
249-
text={t('Self Heal')}
250-
buttonId="self-heal"
251-
onChange={onChangeAutomated}
252-
isSelected={
253-
obj?.spec?.syncPolicy?.automated && obj?.spec?.syncPolicy?.automated.selfHeal
254-
}
255-
isDisabled={obj?.spec?.syncPolicy?.automated ? false : true}
260+
<DetailsDescriptionGroup
261+
title={t('Project')}
262+
help={t('The Argo CD Project that this application belongs to.')}
263+
>
264+
{/* TODO - Update to handle App in Any Namespace when controller namespace is in status */}
265+
<ResourceLink
266+
namespace={obj?.metadata?.namespace}
267+
groupVersionKind={{
268+
group: 'argoproj.io',
269+
version: 'v1alpha1',
270+
kind: 'AppProject',
271+
}}
272+
name={obj?.spec?.project}
256273
/>
257-
</ToggleGroup>
258-
</DetailsDescriptionGroup>
259-
</DescriptionList>
260-
</div>
261-
</div>
274+
</DetailsDescriptionGroup>
275+
276+
<DetailsDescriptionGroup
277+
title={t('Destination')}
278+
help={t('The cluster and namespace where the application is targeted')}
279+
>
280+
{getFriendlyClusterName(obj?.spec?.destination.server)}/
281+
{obj?.spec?.destination.namespace}
282+
</DetailsDescriptionGroup>
283+
284+
<DetailsDescriptionGroup
285+
title={t('Sync Policy')}
286+
help={t('Provides options to determine application synchronization behavior')}
287+
>
288+
<ToggleGroup isCompact areAllGroupsDisabled={!canPatch || !canUpdate}>
289+
<ToggleGroupItem
290+
text={t('Automated')}
291+
buttonId="automated"
292+
onChange={onChangeAutomated}
293+
isSelected={obj?.spec?.syncPolicy?.automated ? true : false}
294+
/>
295+
<ToggleGroupItem
296+
text={t('Prune')}
297+
buttonId="prune"
298+
onChange={onChangeAutomated}
299+
isSelected={
300+
obj?.spec?.syncPolicy?.automated && obj?.spec?.syncPolicy?.automated.prune
301+
}
302+
isDisabled={obj?.spec?.syncPolicy?.automated ? false : true}
303+
/>
304+
<ToggleGroupItem
305+
text={t('Self Heal')}
306+
buttonId="self-heal"
307+
onChange={onChangeAutomated}
308+
isSelected={
309+
obj?.spec?.syncPolicy?.automated &&
310+
obj?.spec?.syncPolicy?.automated.selfHeal
311+
}
312+
isDisabled={obj?.spec?.syncPolicy?.automated ? false : true}
313+
/>
314+
</ToggleGroup>
315+
</DetailsDescriptionGroup>
316+
</DescriptionList>
317+
</FlexItem>
318+
</Flex>
319+
</Flex>
262320
</PageSection>
263321
</div>
264322
);

0 commit comments

Comments
 (0)