Skip to content

Commit 916634d

Browse files
committed
[grid] Session can be deleted via Grid UI
1 parent ce8faa7 commit 916634d

File tree

2 files changed

+400
-10
lines changed

2 files changed

+400
-10
lines changed

javascript/grid-ui/src/components/RunningSessions/RunningSessions.tsx

Lines changed: 152 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ const Transition = React.forwardRef(function Transition (
175175
function RunningSessions (props) {
176176
const [rowOpen, setRowOpen] = useState('')
177177
const [rowLiveViewOpen, setRowLiveViewOpen] = useState('')
178+
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false)
179+
const [sessionToDelete, setSessionToDelete] = useState('')
180+
const [deleteLocation, setDeleteLocation] = useState('') // 'info' or 'liveview'
181+
const [feedbackMessage, setFeedbackMessage] = useState('')
182+
const [feedbackOpen, setFeedbackOpen] = useState(false)
183+
const [feedbackSeverity, setFeedbackSeverity] = useState('success')
178184
const [order, setOrder] = useState<Order>('asc')
179185
const [orderBy, setOrderBy] = useState<keyof SessionData>('sessionDurationMillis')
180186
const [selected, setSelected] = useState<string[]>([])
@@ -244,6 +250,79 @@ function RunningSessions (props) {
244250

245251
const isSelected = (name: string): boolean => selected.includes(name)
246252

253+
const handleDeleteConfirmation = (sessionId: string, location: string) => {
254+
setSessionToDelete(sessionId)
255+
setDeleteLocation(location)
256+
setConfirmDeleteOpen(true)
257+
}
258+
259+
const handleDeleteSession = async () => {
260+
try {
261+
const session = sessions.find(s => s.id === sessionToDelete)
262+
if (!session) {
263+
setFeedbackMessage('Session not found')
264+
setFeedbackSeverity('error')
265+
setConfirmDeleteOpen(false)
266+
setFeedbackOpen(true)
267+
return
268+
}
269+
270+
let deleteUrl = ''
271+
272+
const parsed = JSON.parse(session.capabilities)
273+
let wsUrl = parsed['webSocketUrl'] ?? ''
274+
if (wsUrl.length > 0) {
275+
try {
276+
const url = new URL(origin)
277+
const sessionUrl = new URL(wsUrl)
278+
url.pathname = sessionUrl.pathname.split('/se/')[0] // Remove /se/ and everything after
279+
url.protocol = sessionUrl.protocol === 'wss:' ? 'https:' : 'http:'
280+
deleteUrl = url.href
281+
} catch (error) {
282+
deleteUrl = ''
283+
}
284+
}
285+
286+
if (!deleteUrl) {
287+
const currentUrl = window.location.href
288+
const baseUrl = currentUrl.split('/ui/')[0] // Remove /ui/ and everything after
289+
deleteUrl = `${baseUrl}/session/${sessionToDelete}`
290+
}
291+
292+
const response = await fetch(deleteUrl, {
293+
method: 'DELETE'
294+
})
295+
296+
if (response.ok) {
297+
setFeedbackMessage('Session deleted successfully')
298+
setFeedbackSeverity('success')
299+
if (deleteLocation === 'liveview') {
300+
handleDialogClose()
301+
} else {
302+
setRowOpen('')
303+
}
304+
} else {
305+
setFeedbackMessage('Failed to delete session')
306+
setFeedbackSeverity('error')
307+
}
308+
} catch (error) {
309+
console.error('Error deleting session:', error)
310+
setFeedbackMessage('Error deleting session')
311+
setFeedbackSeverity('error')
312+
}
313+
314+
setConfirmDeleteOpen(false)
315+
setFeedbackOpen(true)
316+
setSessionToDelete('')
317+
setDeleteLocation('')
318+
}
319+
320+
const handleCancelDelete = () => {
321+
setConfirmDeleteOpen(false)
322+
setSessionToDelete('')
323+
setDeleteLocation('')
324+
}
325+
247326
const displaySessionInfo = (id: string): JSX.Element => {
248327
const handleInfoIconClick = (): void => {
249328
setRowOpen(id)
@@ -280,15 +359,15 @@ function RunningSessions (props) {
280359
try {
281360
const capabilities = JSON.parse(capabilitiesStr as string)
282361
const value = capabilities[key]
283-
362+
284363
if (value === undefined || value === null) {
285364
return ''
286365
}
287-
366+
288367
if (typeof value === 'object') {
289368
return JSON.stringify(value)
290369
}
291-
370+
292371
return String(value)
293372
} catch (e) {
294373
return ''
@@ -307,11 +386,11 @@ function RunningSessions (props) {
307386
session.slot,
308387
origin
309388
)
310-
389+
311390
selectedColumns.forEach(column => {
312391
sessionData[column] = getCapabilityValue(session.capabilities, column)
313392
})
314-
393+
315394
return sessionData
316395
})
317396
const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage)
@@ -328,14 +407,14 @@ function RunningSessions (props) {
328407
setRowLiveViewOpen(s)
329408
}
330409
}, [sessionId, sessions])
331-
410+
332411
useEffect(() => {
333412
const dynamicHeadCells = selectedColumns.map(column => ({
334413
id: column,
335414
numeric: false,
336415
label: column
337416
}))
338-
417+
339418
setHeadCells([...fixedHeadCells, ...dynamicHeadCells])
340419
}, [selectedColumns])
341420

@@ -346,7 +425,7 @@ function RunningSessions (props) {
346425
<Paper sx={{ width: '100%', marginBottom: 2 }}>
347426
<EnhancedTableToolbar title='Running'>
348427
<Box display="flex" alignItems="center">
349-
<ColumnSelector
428+
<ColumnSelector
350429
sessions={sessions}
351430
selectedColumns={selectedColumns}
352431
onColumnSelectionChange={(columns) => {
@@ -532,6 +611,14 @@ function RunningSessions (props) {
532611
</Typography>
533612
</DialogContent>
534613
<DialogActions>
614+
<Button
615+
onClick={() => handleDeleteConfirmation(row.id as string, 'info')}
616+
color='error'
617+
variant='contained'
618+
sx={{ marginRight: 1 }}
619+
>
620+
Delete
621+
</Button>
535622
<Button
536623
onClick={() => setRowOpen('')}
537624
color='primary'
@@ -586,6 +673,63 @@ function RunningSessions (props) {
586673
/>
587674
</div>
588675
)}
676+
{/* Confirmation Dialog */}
677+
<Dialog
678+
open={confirmDeleteOpen}
679+
onClose={handleCancelDelete}
680+
aria-labelledby='delete-confirmation-dialog'
681+
>
682+
<DialogTitle id='delete-confirmation-dialog'>
683+
Confirm Session Deletion
684+
</DialogTitle>
685+
<DialogContent>
686+
<Typography>
687+
Are you sure you want to delete this session? This action cannot be undone.
688+
</Typography>
689+
</DialogContent>
690+
<DialogActions>
691+
<Button
692+
onClick={handleCancelDelete}
693+
color='primary'
694+
variant='outlined'
695+
>
696+
Cancel
697+
</Button>
698+
<Button
699+
onClick={handleDeleteSession}
700+
color='error'
701+
variant='contained'
702+
autoFocus
703+
>
704+
Delete
705+
</Button>
706+
</DialogActions>
707+
</Dialog>
708+
709+
{/* Feedback Dialog */}
710+
<Dialog
711+
open={feedbackOpen}
712+
onClose={() => setFeedbackOpen(false)}
713+
aria-labelledby='feedback-dialog'
714+
>
715+
<DialogTitle id='feedback-dialog'>
716+
{feedbackSeverity === 'success' ? 'Success' : 'Error'}
717+
</DialogTitle>
718+
<DialogContent>
719+
<Typography color={feedbackSeverity === 'success' ? 'success.main' : 'error.main'}>
720+
{feedbackMessage}
721+
</Typography>
722+
</DialogContent>
723+
<DialogActions>
724+
<Button
725+
onClick={() => setFeedbackOpen(false)}
726+
color='primary'
727+
variant='contained'
728+
>
729+
OK
730+
</Button>
731+
</DialogActions>
732+
</Dialog>
589733
</Box>
590734
)
591735
}

0 commit comments

Comments
 (0)