11import * as React from 'react' ;
22import { RouteComponentProps } from 'react-router' ;
3- import { Timestamp } from '@openshift-console/dynamic-plugin-sdk' ;
4- import { ApplicationSetKind } from '../../models/ApplicationSetModel' ;
3+ import { ApplicationSetKind , ApplicationSetModel } from '../../models/ApplicationSetModel' ;
54import {
65 Badge ,
76 PageSection ,
87 Title ,
98 DescriptionList ,
9+ DescriptionListGroup ,
10+ DescriptionListDescription ,
11+ DescriptionListTermHelpText ,
12+ DescriptionListTermHelpTextButton ,
13+ Popover ,
1014 Grid ,
1115 GridItem ,
1216} from '@patternfly/react-core' ;
13- import ResourceDetailsAttributes from '../../utils/components/ResourceDetails/ResourceDetailsAttributes' ;
17+ import BaseDetailsSummary from '../shared/BaseDetailsSummary/BaseDetailsSummary' ;
18+ import { getAppSetGeneratorCount , getAppSetStatus } from '../../utils/gitops' ;
19+ import { ApplicationSetStatus } from '../../utils/constants' ;
20+ import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk' ;
21+ import { ApplicationKind , ApplicationModel } from '../../models/ApplicationModel' ;
22+ import {
23+ HealthHealthyIcon ,
24+ HealthDegradedIcon ,
25+ HealthUnknownIcon ,
26+ } from '../../utils/components/Icons/Icons' ;
27+ import { Conditions } from '../../utils/components/Conditions/Conditions' ;
1428import './AppSetDetailsTab.scss' ;
1529
1630type AppSetDetailsTabProps = RouteComponentProps < { ns : string ; name : string } > & {
@@ -19,69 +33,174 @@ type AppSetDetailsTabProps = RouteComponentProps<{ ns: string; name: string }> &
1933 name ?: string ;
2034} ;
2135
22- const AppSetDetailsTab : React . FC < AppSetDetailsTabProps > = ( { obj } ) => {
36+ const AppSetDetailsTab : React . FC < AppSetDetailsTabProps > = ( { obj, namespace } ) => {
2337 if ( ! obj ) return null ;
2438
25- const metadata = obj . metadata || { } ;
2639 const status = obj . status || { } ;
40+ const spec = obj . spec || { } ;
41+ const totalGenerators = getAppSetGeneratorCount ( obj ) ;
42+ const appSetStatus = getAppSetStatus ( obj ) ;
43+
44+ // Get applications to count generated apps
45+ const [ applications ] = useK8sWatchResource < ApplicationKind [ ] > ( {
46+ groupVersionKind : {
47+ group : ApplicationModel . apiGroup ,
48+ version : ApplicationModel . apiVersion ,
49+ kind : ApplicationModel . kind ,
50+ } ,
51+ namespace : namespace || obj . metadata ?. namespace ,
52+ isList : true ,
53+ } ) ;
54+
55+ // Count applications owned by this ApplicationSet
56+ const generatedAppsCount = applications ?. filter ( app =>
57+ app . metadata ?. ownerReferences ?. some ( owner =>
58+ owner . kind === obj . kind && owner . name === obj . metadata ?. name
59+ )
60+ ) . length || 0 ;
2761
2862 return (
2963 < >
3064 < PageSection >
3165 < Title headingLevel = "h2" className = "co-section-heading" >
32- ApplicationSet details
66+ Argo CD ApplicationSet details
3367 </ Title >
34- < Grid hasGutter = { true } span = { 2 } sm = { 3 } md = { 6 } lg = { 6 } xl = { 6 } xl2 = { 6 } >
35- < GridItem >
36- < DescriptionList >
37- < ResourceDetailsAttributes
38- metadata = { metadata }
39- resource = { obj }
40- showOwner = { true }
41- showStatus = { true }
42- showGeneratedApps = { true }
43- showGenerators = { true }
44- showAppProject = { true }
45- showRepository = { true }
46- />
68+ < Grid hasGutter = { true } >
69+ < GridItem span = { 12 } sm = { 12 } md = { 6 } lg = { 6 } xl = { 6 } xl2 = { 6 } >
70+ < BaseDetailsSummary obj = { obj } model = { ApplicationSetModel } />
71+ </ GridItem >
72+ < GridItem span = { 12 } sm = { 12 } md = { 6 } lg = { 6 } xl = { 6 } xl2 = { 6 } >
73+ < DescriptionList className = "pf-c-description-list" >
74+ { /* Status */ }
75+ < DescriptionListGroup >
76+ < DescriptionListTermHelpText >
77+ < Popover
78+ headerContent = { < div > Status</ div > }
79+ bodyContent = {
80+ < div >
81+ < div > Current status of the ApplicationSet</ div >
82+ < div style = { { fontSize : '14px' , color : '#ffffff' , borderTop : '1px solid #4f5255' , paddingTop : '8px' , marginTop : '8px' , fontWeight : '500' } } >
83+ ApplicationSet { '>' } status
84+ </ div >
85+ </ div >
86+ }
87+ >
88+ < DescriptionListTermHelpTextButton > Status</ DescriptionListTermHelpTextButton >
89+ </ Popover >
90+ </ DescriptionListTermHelpText >
91+ < DescriptionListDescription >
92+ < span >
93+ { appSetStatus === ApplicationSetStatus . HEALTHY && < HealthHealthyIcon /> }
94+ { appSetStatus === ApplicationSetStatus . ERROR && < HealthDegradedIcon /> }
95+ { appSetStatus === ApplicationSetStatus . UNKNOWN && < HealthUnknownIcon /> }
96+ { ' ' } { appSetStatus === ApplicationSetStatus . HEALTHY ? 'Healthy' :
97+ appSetStatus === ApplicationSetStatus . ERROR ? 'Error' : 'Unknown' }
98+ </ span >
99+ </ DescriptionListDescription >
100+ </ DescriptionListGroup >
101+
102+ { /* Generated Apps */ }
103+ < DescriptionListGroup >
104+ < DescriptionListTermHelpText >
105+ < Popover
106+ headerContent = { < div > Generated Apps</ div > }
107+ bodyContent = {
108+ < div >
109+ < div > Number of applications generated by this ApplicationSet</ div >
110+ < div style = { { fontSize : '14px' , color : '#ffffff' , borderTop : '1px solid #4f5255' , paddingTop : '8px' , marginTop : '8px' , fontWeight : '500' } } >
111+ ApplicationSet { '>' } status { '>' } applications
112+ </ div >
113+ </ div >
114+ }
115+ >
116+ < DescriptionListTermHelpTextButton > Generated Apps</ DescriptionListTermHelpTextButton >
117+ </ Popover >
118+ </ DescriptionListTermHelpText >
119+ < DescriptionListDescription >
120+ < Badge isRead color = "blue" > { generatedAppsCount } application{ generatedAppsCount !== 1 ? 's' : '' } </ Badge >
121+ </ DescriptionListDescription >
122+ </ DescriptionListGroup >
123+
124+ { /* Generators */ }
125+ < DescriptionListGroup >
126+ < DescriptionListTermHelpText >
127+ < Popover
128+ headerContent = { < div > Generators</ div > }
129+ bodyContent = {
130+ < div >
131+ < div > Number of generators configured in this ApplicationSet</ div >
132+ < div style = { { fontSize : '14px' , color : '#ffffff' , borderTop : '1px solid #4f5255' , paddingTop : '8px' , marginTop : '8px' , fontWeight : '500' } } >
133+ ApplicationSet { '>' } spec { '>' } generators
134+ </ div >
135+ </ div >
136+ }
137+ >
138+ < DescriptionListTermHelpTextButton > Generators</ DescriptionListTermHelpTextButton >
139+ </ Popover >
140+ </ DescriptionListTermHelpText >
141+ < DescriptionListDescription >
142+ < Badge isRead color = "grey" > { totalGenerators } generator{ totalGenerators !== 1 ? 's' : '' } </ Badge >
143+ </ DescriptionListDescription >
144+ </ DescriptionListGroup >
145+
146+ { /* App Project */ }
147+ < DescriptionListGroup >
148+ < DescriptionListTermHelpText >
149+ < Popover
150+ headerContent = { < div > App Project</ div > }
151+ bodyContent = {
152+ < div >
153+ < div > Argo CD project that this ApplicationSet belongs to</ div >
154+ < div style = { { fontSize : '14px' , color : '#ffffff' , borderTop : '1px solid #4f5255' , paddingTop : '8px' , marginTop : '8px' , fontWeight : '500' } } >
155+ ApplicationSet { '>' } spec { '>' } template { '>' } spec { '>' } project
156+ </ div >
157+ </ div >
158+ }
159+ >
160+ < DescriptionListTermHelpTextButton > App Project</ DescriptionListTermHelpTextButton >
161+ </ Popover >
162+ </ DescriptionListTermHelpText >
163+ < DescriptionListDescription >
164+ < Badge isRead color = "blue" style = { { backgroundColor : '#73bcf7' , color : '#003a70' } } > AP</ Badge > { spec . template ?. spec ?. project || 'default' }
165+ </ DescriptionListDescription >
166+ </ DescriptionListGroup >
167+
168+ { /* Repository */ }
169+ { spec . template ?. spec ?. source ?. repoURL && (
170+ < DescriptionListGroup >
171+ < DescriptionListTermHelpText >
172+ < Popover
173+ headerContent = { < div > Repository</ div > }
174+ bodyContent = {
175+ < div >
176+ < div > Git repository URL where the ApplicationSet configuration is stored</ div >
177+ < div style = { { fontSize : '14px' , color : '#ffffff' , borderTop : '1px solid #4f5255' , paddingTop : '8px' , marginTop : '8px' , fontWeight : '500' } } >
178+ ApplicationSet { '>' } spec { '>' } template { '>' } spec { '>' } source { '>' } repoURL
179+ </ div >
180+ </ div >
181+ }
182+ >
183+ < DescriptionListTermHelpTextButton > Repository</ DescriptionListTermHelpTextButton >
184+ </ Popover >
185+ </ DescriptionListTermHelpText >
186+ < DescriptionListDescription >
187+ < a href = { spec . template . spec . source . repoURL } target = "_blank" rel = "noopener noreferrer" >
188+ { spec . template . spec . source . repoURL }
189+ </ a >
190+ </ DescriptionListDescription >
191+ </ DescriptionListGroup >
192+ ) }
47193 </ DescriptionList >
48194 </ GridItem >
49195 </ Grid >
50196 </ PageSection >
51-
52- { status . conditions && status . conditions . length > 0 && (
53- < PageSection >
54- < Title headingLevel = "h2" className = "co-section-heading" >
55- Conditions
56- </ Title >
57- < div className = "application-set-details-page__conditions-table" >
58- < div className = "application-set-details-page__conditions-table-header" >
59- < div className = "application-set-details-page__conditions-table-header-cell application-set-details-page__conditions-table-header-cell--type" > Type</ div >
60- < div className = "application-set-details-page__conditions-table-header-cell application-set-details-page__conditions-table-header-cell--status" > Status</ div >
61- < div className = "application-set-details-page__conditions-table-header-cell application-set-details-page__conditions-table-header-cell--updated" > Updated</ div >
62- < div className = "application-set-details-page__conditions-table-header-cell application-set-details-page__conditions-table-header-cell--reason" > Reason</ div >
63- < div className = "application-set-details-page__conditions-table-header-cell application-set-details-page__conditions-table-header-cell--message" > Message</ div >
64- </ div >
65- { status . conditions . map ( ( condition : any , index : number ) => (
66- < React . Fragment key = { index } >
67- < div className = "application-set-details-page__conditions-table-row" >
68- < div className = "application-set-details-page__conditions-table-row-cell application-set-details-page__conditions-table-row-cell--type" > { condition . type } </ div >
69- < div className = "application-set-details-page__conditions-table-row-cell application-set-details-page__conditions-table-row-cell--status" >
70- < Badge isRead color = { condition . status === 'True' ? 'green' : 'red' } >
71- { condition . status }
72- </ Badge >
73- </ div >
74- < div className = "application-set-details-page__conditions-table-row-cell application-set-details-page__conditions-table-row-cell--updated" >
75- < Timestamp timestamp = { condition . lastTransitionTime } />
76- </ div >
77- < div className = "application-set-details-page__conditions-table-row-cell application-set-details-page__conditions-table-row-cell--reason" > { condition . reason || '' } </ div >
78- < div className = "application-set-details-page__conditions-table-row-cell application-set-details-page__conditions-table-row-cell--message" > { condition . message || '' } </ div >
79- </ div >
80- </ React . Fragment >
81- ) ) }
82- </ div >
83- </ PageSection >
84- ) }
197+
198+ < PageSection >
199+ < Title headingLevel = "h2" className = "co-section-heading" >
200+ Conditions
201+ </ Title >
202+ < Conditions conditions = { status . conditions } />
203+ </ PageSection >
85204 </ >
86205 ) ;
87206} ;
0 commit comments