@@ -3,9 +3,13 @@ import {
33 AnalyticalTable ,
44 AnalyticalTableColumnDefinition ,
55 AnalyticalTableScaleWidthMode ,
6+ Button ,
67 Title ,
8+ Menu ,
9+ MenuItem ,
10+ MenuDomRef ,
711} from '@ui5/webcomponents-react' ;
8- import { useApiResource } from '../../lib/api/useApiResource' ;
12+ import { useApiResource , useCRDItemsMapping } from '../../lib/api/useApiResource' ;
913import { ManagedResourcesRequest } from '../../lib/api/types/crossplane/listManagedResources' ;
1014import { formatDateAsTimeAgo } from '../../utils/i18n/timeAgo' ;
1115import IllustratedError from '../Shared/IllustratedError' ;
@@ -14,10 +18,37 @@ import '@ui5/webcomponents-icons/dist/sys-cancel-2';
1418import { resourcesInterval } from '../../lib/shared/constants' ;
1519
1620import { YamlViewButton } from '../Yaml/YamlViewButton.tsx' ;
17- import { useMemo } from 'react' ;
21+ import { FC , useMemo , useRef , useState } from 'react' ;
1822import StatusFilter from '../Shared/StatusFilter/StatusFilter.tsx' ;
1923import { ResourceStatusCell } from '../Shared/ResourceStatusCell.tsx' ;
2024import { Resource } from '../../utils/removeManagedFieldsAndFilterData.ts' ;
25+ import { ManagedResourceItem } from '../../lib/shared/types.ts' ;
26+ import { ManagedResourceDeleteDialog } from '../Dialogs/ManagedResourceDeleteDialog.tsx' ;
27+
28+ const getItemKey = ( item : ManagedResourceItem ) : string => `${ item . kind } -${ item . metadata . name } ` ;
29+
30+ const RowActionsMenu : FC < {
31+ item : ManagedResourceItem ;
32+ onOpen : ( item : ManagedResourceItem ) => void ;
33+ isDeleting : boolean ;
34+ } > = ( { item, onOpen, isDeleting } ) => {
35+ const { t } = useTranslation ( ) ;
36+ const popoverRef = useRef < MenuDomRef > ( null ) ;
37+
38+ return (
39+ < >
40+ < Button icon = "overflow" icon-end disabled = { isDeleting } onClick = { ( ) => onOpen ( item ) } />
41+ < Menu
42+ ref = { popoverRef }
43+ onItemClick = { ( ) => {
44+ onOpen ( item ) ;
45+ } }
46+ >
47+ < MenuItem text = { t ( 'ManagedResources.deleteAction' ) } icon = "delete" />
48+ </ Menu >
49+ </ >
50+ ) ;
51+ } ;
2152
2253interface CellData < T > {
2354 cell : {
@@ -43,13 +74,30 @@ type ResourceRow = {
4374
4475export function ManagedResources ( ) {
4576 const { t } = useTranslation ( ) ;
77+ const [ deleteDialogOpen , setDeleteDialogOpen ] = useState ( false ) ;
78+ const [ selectedItem , setSelectedItem ] = useState < ManagedResourceItem | null > ( null ) ;
79+ const [ deletingItems , setDeletingItems ] = useState < Set < string > > ( new Set ( ) ) ;
4680
4781 const {
4882 data : managedResources ,
4983 error,
5084 isLoading,
5185 } = useApiResource ( ManagedResourcesRequest , {
52- refreshInterval : resourcesInterval , // Resources are quite expensive to fetch, so we refresh every 30 seconds
86+ refreshInterval : resourcesInterval ,
87+ } ) ;
88+
89+ const openDeleteDialog = ( item : ManagedResourceItem ) => {
90+ setSelectedItem ( item ) ;
91+ setDeleteDialogOpen ( true ) ;
92+ } ;
93+
94+ const handleDeleteStart = ( item : ManagedResourceItem ) => {
95+ const itemKey = getItemKey ( item ) ;
96+ setDeletingItems ( ( prev ) => new Set ( prev . add ( itemKey ) ) ) ;
97+ } ;
98+
99+ const { data : kindMapping } = useCRDItemsMapping ( {
100+ refreshInterval : resourcesInterval ,
53101 } ) ;
54102
55103 const columns : AnalyticalTableColumnDefinition [ ] = useMemo (
@@ -106,20 +154,39 @@ export function ManagedResources() {
106154 width : 75 ,
107155 accessor : 'yaml' ,
108156 disableFilters : true ,
109- Cell : ( cellData : CellData < ResourceRow > ) =>
110- cellData . cell . row . original ?. item ? (
157+ Cell : ( cellData : CellData < ResourceRow > ) => {
158+ return cellData . cell . row . original ?. item ? (
111159 < YamlViewButton variant = "resource" resource = { cellData . cell . row . original ?. item as Resource } />
112- ) : undefined ,
160+ ) : undefined ;
161+ } ,
162+ } ,
163+ {
164+ Header : ' ' ,
165+ hAlign : 'Center' ,
166+ width : 60 ,
167+ disableFilters : true ,
168+ Cell : ( cellData : CellData < ResourceRow > ) => {
169+ const item = cellData . cell . row . original ?. item as ManagedResourceItem ;
170+ const itemKey = item ? getItemKey ( item ) : '' ;
171+ const isDeleting = deletingItems . has ( itemKey ) ;
172+
173+ return cellData . cell . row . original ?. item ? (
174+ < RowActionsMenu item = { item } isDeleting = { isDeleting } onOpen = { openDeleteDialog } />
175+ ) : undefined ;
176+ } ,
113177 } ,
114178 ] ,
115- [ t ] ,
179+ [ t , deletingItems ] ,
116180 ) ;
117181
118182 const rows : ResourceRow [ ] =
119183 managedResources
120184 ?. filter ( ( managedResource ) => managedResource . items )
121185 . flatMap ( ( managedResource ) =>
122186 managedResource . items ?. map ( ( item ) => {
187+ const itemKey = getItemKey ( item ) ;
188+ const isDeleting = deletingItems . has ( itemKey ) ;
189+
123190 const conditionSynced = item . status ?. conditions ?. find ( ( condition ) => condition . type === 'Synced' ) ;
124191 const conditionReady = item . status ?. conditions ?. find ( ( condition ) => condition . type === 'Ready' ) ;
125192
@@ -134,6 +201,7 @@ export function ManagedResources() {
134201 item : item ,
135202 conditionSyncedMessage : conditionSynced ?. message ?? conditionSynced ?. reason ?? '' ,
136203 conditionReadyMessage : conditionReady ?. message ?? conditionReady ?. reason ?? '' ,
204+ style : isDeleting ? { opacity : 0.5 , pointerEvents : 'none' } : undefined ,
137205 } ;
138206 } ) ,
139207 ) ?? [ ] ;
@@ -145,28 +213,36 @@ export function ManagedResources() {
145213 { error && < IllustratedError details = { error . message } /> }
146214
147215 { ! error && (
148- < AnalyticalTable
149- columns = { columns }
150- data = { rows }
151- minRows = { 1 }
152- groupBy = { [ 'kind' ] }
153- scaleWidthMode = { AnalyticalTableScaleWidthMode . Smart }
154- loading = { isLoading }
155- filterable
156- // Prevent the table from resetting when the data changes
157- retainColumnWidth
158- reactTableOptions = { {
159- autoResetHiddenColumns : false ,
160- autoResetPage : false ,
161- autoResetExpanded : false ,
162- autoResetGroupBy : false ,
163- autoResetSelectedRows : false ,
164- autoResetSortBy : false ,
165- autoResetFilters : false ,
166- autoResetRowState : false ,
167- autoResetResize : false ,
168- } }
169- />
216+ < >
217+ < AnalyticalTable
218+ columns = { columns }
219+ data = { rows }
220+ minRows = { 1 }
221+ groupBy = { [ 'kind' ] }
222+ scaleWidthMode = { AnalyticalTableScaleWidthMode . Smart }
223+ loading = { isLoading }
224+ filterable
225+ retainColumnWidth
226+ reactTableOptions = { {
227+ autoResetHiddenColumns : false ,
228+ autoResetPage : false ,
229+ autoResetExpanded : false ,
230+ autoResetGroupBy : false ,
231+ autoResetSelectedRows : false ,
232+ autoResetSortBy : false ,
233+ autoResetFilters : false ,
234+ autoResetRowState : false ,
235+ autoResetResize : false ,
236+ } }
237+ />
238+ < ManagedResourceDeleteDialog
239+ kindMapping = { kindMapping }
240+ open = { deleteDialogOpen }
241+ item = { selectedItem }
242+ onClose = { ( ) => setDeleteDialogOpen ( false ) }
243+ onDeleteStart = { handleDeleteStart }
244+ />
245+ </ >
170246 ) }
171247 </ >
172248 ) ;
0 commit comments