@@ -8,12 +8,12 @@ import {
88 MultiComboBoxItem ,
99} from '@ui5/webcomponents-react' ;
1010import useResource from '../../lib/api/useApiResource' ;
11- import '@ui5/webcomponents-icons/dist/sys-enter-2' ;
12- import '@ui5/webcomponents-icons/dist/sys-cancel-2' ;
1311import { ListNamespaces } from '../../lib/api/types/k8s/listNamespaces' ;
1412import { useEffect , useState , useContext } from 'react' ;
1513import { resourcesInterval } from '../../lib/shared/constants' ;
1614import { InstalationsRequest } from '../../lib/api/types/landscaper/listInstallations' ;
15+ import { ExecutionsRequest } from '../../lib/api/types/landscaper/listExecutions' ;
16+ import { DeployItemsRequest } from '../../lib/api/types/landscaper/listDeployItems' ;
1717import { ApiConfigContext } from '../../components/Shared/k8s' ;
1818import { fetchApiServerJson } from '../../lib/api/fetch' ;
1919
@@ -27,6 +27,8 @@ export function Landscapers() {
2727
2828 const [ selectedNamespaces , setSelectedNamespaces ] = useState < string [ ] > ( [ ] ) ;
2929 const [ installations , setInstallations ] = useState < any [ ] > ( [ ] ) ;
30+ const [ executions , setExecutions ] = useState < any [ ] > ( [ ] ) ;
31+ const [ deployItems , setDeployItems ] = useState < any [ ] > ( [ ] ) ;
3032 const [ loading , setLoading ] = useState ( false ) ;
3133
3234 const handleSelectionChange = ( e : CustomEvent ) => {
@@ -36,34 +38,67 @@ export function Landscapers() {
3638 } ;
3739
3840 useEffect ( ( ) => {
39- const fetchInstallations = async ( ) => {
41+ const fetchAllResources = async ( ) => {
4042 if ( selectedNamespaces . length === 0 ) {
4143 setInstallations ( [ ] ) ;
44+ setExecutions ( [ ] ) ;
45+ setDeployItems ( [ ] ) ;
4246 return ;
4347 }
4448
4549 setLoading ( true ) ;
4650
4751 try {
48- const paths = selectedNamespaces
52+ // === INSTALLATIONS ===
53+ const installationPaths = selectedNamespaces
4954 . map ( ( ns ) => InstalationsRequest ( ns ) . path )
5055 . filter ( ( p ) : p is string => p !== null && p !== undefined ) ;
5156
52- const allResponses = await Promise . all (
53- paths . map ( ( path ) => fetchApiServerJson ( path , apiConfig ) ) ,
57+ const installationResponses = await Promise . all (
58+ installationPaths . map ( ( path ) => fetchApiServerJson ( path , apiConfig ) ) ,
5459 ) ;
5560
56- const allItems = allResponses . flatMap ( ( res ) => res . items || [ ] ) ;
57- setInstallations ( allItems ) ;
61+ const installationsData = installationResponses . flatMap (
62+ ( res ) => res . items || [ ] ,
63+ ) ;
64+ setInstallations ( installationsData ) ;
65+
66+ // === EXECUTIONS ===
67+ const executionPaths = selectedNamespaces
68+ . map ( ( ns ) => ExecutionsRequest ( ns ) . path )
69+ . filter ( ( p ) : p is string => p !== null && p !== undefined ) ;
70+
71+ const executionResponses = await Promise . all (
72+ executionPaths . map ( ( path ) => fetchApiServerJson ( path , apiConfig ) ) ,
73+ ) ;
74+
75+ const executionsData = executionResponses . flatMap (
76+ ( res ) => res . items || [ ] ,
77+ ) ;
78+ setExecutions ( executionsData ) ;
79+
80+ // === DEPLOY ITEMS ===
81+ const deployPaths = selectedNamespaces
82+ . map ( ( ns ) => DeployItemsRequest ( ns ) . path )
83+ . filter ( ( p ) : p is string => p !== null && p !== undefined ) ;
84+
85+ const deployResponses = await Promise . all (
86+ deployPaths . map ( ( path ) => fetchApiServerJson ( path , apiConfig ) ) ,
87+ ) ;
88+
89+ const deployItemsData = deployResponses . flatMap ( ( res ) => res . items || [ ] ) ;
90+ setDeployItems ( deployItemsData ) ;
5891 } catch ( error ) {
5992 console . error ( error ) ;
6093 setInstallations ( [ ] ) ;
94+ setExecutions ( [ ] ) ;
95+ setDeployItems ( [ ] ) ;
6196 } finally {
6297 setLoading ( false ) ;
6398 }
6499 } ;
65100
66- fetchInstallations ( ) ;
101+ fetchAllResources ( ) ;
67102 } , [ selectedNamespaces , apiConfig ] ) ;
68103
69104 const columns : AnalyticalTableColumnDefinition [ ] = [
@@ -85,6 +120,52 @@ export function Landscapers() {
85120 } ,
86121 ] ;
87122
123+ const renderRowSubComponent = ( row : any ) => {
124+ const installation = row . original ;
125+
126+ const relatedExecutions = executions . filter ( ( execution ) =>
127+ execution . metadata . ownerReferences ?. some (
128+ ( ref ) => ref . uid === installation . metadata . uid ,
129+ ) ,
130+ ) ;
131+
132+ const relatedDeployItems = deployItems . filter ( ( deploy ) =>
133+ deploy . metadata . ownerReferences ?. some (
134+ ( ref ) => ref . uid === installation . metadata . uid ,
135+ ) ,
136+ ) ;
137+
138+ return (
139+ < div style = { { padding : '10px' , backgroundColor : '#f4f4f4' } } >
140+ < h5 > { t ( 'Executions' ) } </ h5 >
141+ { relatedExecutions . length > 0 ? (
142+ < ul >
143+ { relatedExecutions . map ( ( execution : any ) => (
144+ < li key = { execution . metadata . uid } >
145+ { execution . metadata . name } – { execution . status . phase }
146+ </ li >
147+ ) ) }
148+ </ ul >
149+ ) : (
150+ < p > { t ( 'No executions found' ) } </ p >
151+ ) }
152+
153+ < h5 style = { { marginTop : '1rem' } } > { t ( 'Deploy Items' ) } </ h5 >
154+ { relatedDeployItems . length > 0 ? (
155+ < ul >
156+ { relatedDeployItems . map ( ( deploy : any ) => (
157+ < li key = { deploy . metadata . uid } >
158+ { deploy . metadata . name } – { deploy . status . phase }
159+ </ li >
160+ ) ) }
161+ </ ul >
162+ ) : (
163+ < p > { t ( 'No deploy items found' ) } </ p >
164+ ) }
165+ </ div >
166+ ) ;
167+ } ;
168+
88169 return (
89170 < >
90171 < Title level = "H4" > { t ( 'Providers.headerProviders' ) } </ Title >
@@ -109,6 +190,8 @@ export function Landscapers() {
109190 scaleWidthMode = { AnalyticalTableScaleWidthMode . Smart }
110191 filterable
111192 retainColumnWidth
193+ renderRowSubComponent = { renderRowSubComponent }
194+ subComponentsBehavior = "IncludeHeightExpandable"
112195 reactTableOptions = { {
113196 autoResetHiddenColumns : false ,
114197 autoResetPage : false ,
0 commit comments