///////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2025, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// import React, { useCallback, useEffect, useMemo } from 'react'; import { styled } from '@mui/material/styles'; import PgTable from 'sources/components/PgTable'; import gettext from 'sources/gettext'; import PropTypes from 'prop-types'; import { BgProcessManagerEvents, BgProcessManagerProcessState } from './BgProcessConstants'; import { PgButtonGroup, PgIconButton } from '../../../../static/js/components/Buttons'; import BlockRoundedIcon from '@mui/icons-material/BlockRounded'; import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; import DeleteIcon from '@mui/icons-material/Delete'; import HelpIcon from '@mui/icons-material/HelpRounded'; import url_for from 'sources/url_for'; import { Box } from '@mui/material'; import { usePgAdmin } from '../../../../static/js/PgAdminProvider'; import { BROWSER_PANELS } from '../../../../browser/static/js/constants'; import ErrorBoundary from '../../../../static/js/helpers/ErrorBoundary'; import ProcessDetails from './ProcessDetails'; const Root = styled('div')(({theme}) => ({ height: '100%', '& .Processes-stopButton': { color: theme.palette.error.main }, '& .Processes-noPadding': { padding: '0 !important', '& .Processes-bgSucess': { backgroundColor: theme.palette.success.light, height: '100%', padding: '4px', }, '& .Processes-bgFailed': { backgroundColor: theme.palette.error.light, height: '100%', padding: '4px', }, '& .Processes-bgTerm': { backgroundColor: theme.palette.warning.light, height: '100%', padding: '4px', }, '& .Processes-bgRunning': { backgroundColor: theme.palette.primary.light, height: '100%', padding: '4px', } }, })); const ProcessStateTextAndColor = { [BgProcessManagerProcessState.PROCESS_NOT_STARTED]: [gettext('Not started'), 'bgRunning'], [BgProcessManagerProcessState.PROCESS_STARTED]: [gettext('Running'), 'bgRunning'], [BgProcessManagerProcessState.PROCESS_FINISHED]: [gettext('Finished'), 'bgSucess'], [BgProcessManagerProcessState.PROCESS_TERMINATED]: [gettext('Terminated'), 'bgTerm'], [BgProcessManagerProcessState.PROCESS_TERMINATING]: [gettext('Terminating...'), 'bgTerm'], [BgProcessManagerProcessState.PROCESS_FAILED]: [gettext('Failed'), 'bgFailed'], }; const cellPropTypes = { row: PropTypes.any, }; function CancelCell({row}) { const pgAdmin = usePgAdmin(); return ( } className='Processes-stopButton' disabled={row.original.process_state != BgProcessManagerProcessState.PROCESS_STARTED || row.original.server_id != null} onClick={(e) => { e.preventDefault(); pgAdmin.Browser.BgProcessManager.stopProcess(row.original.id); }} aria-label="End Process" title={gettext('End Process')} > ); } CancelCell.propTypes = cellPropTypes; function getLogsCell(pgAdmin, onViewDetailsClick) { function LogsCell({ row }) { return ( } noBorder onClick={(e) => { e.preventDefault(); onViewDetailsClick(row.original); }} aria-label="View details" title={gettext('View details')} /> ); } LogsCell.propTypes = cellPropTypes; return LogsCell; } function StatusCell({row}) { const [text, bgcolor] = ProcessStateTextAndColor[row.original.process_state]; return {text}; } StatusCell.propTypes = cellPropTypes; function CustomHeader({selectedRowIDs, setSelectedRows}) { const pgAdmin = usePgAdmin(); return ( } aria-label="Acknowledge and Remove" title={gettext('Acknowledge and Remove')} onClick={() => { pgAdmin.Browser.notifier.confirm(gettext('Remove Processes'), gettext('Are you sure you want to remove the selected processes?'), ()=>{ pgAdmin.Browser.BgProcessManager.acknowledge(selectedRowIDs); setSelectedRows({}); }); }} disabled={selectedRowIDs.length <= 0} > } aria-label="Help" title={gettext('Help')} onClick={() => { window.open(url_for('help.static', {'filename': 'processes.html'})); }} > ); } CustomHeader.propTypes = { selectedRowIDs: PropTypes.array, setSelectedRows: PropTypes.func, }; export default function Processes() { const pgAdmin = usePgAdmin(); const [tableData, setTableData] = React.useState([]); const [selectedRows, setSelectedRows] = React.useState({}); const selectedRowIDs = useMemo(()=>Object.keys(selectedRows).filter((k)=>selectedRows[k]), [selectedRows]); const onViewDetailsClick = useCallback((p)=>{ const panelTitle = gettext('Process Watcher - %s', p.type_desc); const panelId = BROWSER_PANELS.PROCESS_DETAILS+''+p.id; pgAdmin.Browser.docker.default_workspace.openDialog({ id: panelId, title: panelTitle, content: ( ) }, pgAdmin.Browser.stdW.md, pgAdmin.Browser.stdH.md); }, []); const columns = useMemo(()=>{ return [{ header: () => null, enableSorting: false, enableResizing: false, enableFilters: false, size: 35, maxSize: 35, minSize: 35, id: 'btn-stop', cell: CancelCell, }, { header: () => null, enableSorting: false, enableResizing: false, enableFilters: false, size: 35, maxSize: 35, minSize: 35, id: 'btn-logs', cell: getLogsCell(pgAdmin, onViewDetailsClick), }, { header: gettext('PID'), accessorKey: 'utility_pid', enableSorting: true, enableResizing: false, width: 70, minWidth: 70, enableFilters: true, }, { header: gettext('Type'), accessorFn: (row)=>row.details?.type, enableSorting: true, enableResizing: true, width: 100, minWidth: 70, enableFilters: true, }, { header: gettext('Server'), accessorFn: (row)=>row.details?.server, enableSorting: true, enableResizing: true, width: 200, minWidth: 120, enableFilters: true, }, { header: gettext('Object'), accessorFn: (row)=>row.details?.object, enableSorting: true, enableResizing: true, width: 200, minWidth: 120, enableFilters: true, }, { id: 'stime', header: gettext('Start Time'), enableSorting: true, enableResizing: true, enableFilters: false, width: 150, minWidth: 150, accessorFn: (row)=>(new Date(row.stime)), cell: (info)=>(info.getValue().toLocaleString()), }, { header: gettext('Status'), enableSorting: true, enableResizing: false, enableFilters: true, width: 120, minWidth: 120, accessorFn: (row)=>ProcessStateTextAndColor[row.process_state][0], dataClassName: 'Processes-noPadding', cell: StatusCell, }, { header: gettext('Time Taken (sec)'), accessorKey: 'execution_time', enableSorting: true, enableResizing: true, enableFilters: false, }]; }, []); const updateList = ()=>{ if(pgAdmin.Browser.BgProcessManager.procList) { setTableData([...pgAdmin.Browser.BgProcessManager.procList]); } }; useEffect(() => { updateList(); pgAdmin.Browser.BgProcessManager.registerListener(BgProcessManagerEvents.LIST_UPDATED, updateList); return ()=>{ pgAdmin.Browser.BgProcessManager.deregisterListener(BgProcessManagerEvents.LIST_UPDATED, updateList); }; }, []); return ( { return row.id; } }} customHeader={} > ); }