feat: add ServiceEventMonitor and PhpExtensionManager components for service tracking and management
This commit is contained in:
@@ -175,8 +175,8 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
<CloseIcon fontSize="small" />
|
<CloseIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers sx={{ borderColor: 'rgba(255,255,255,0.05)', p: 0 }}>
|
<DialogContent dividers sx={{ borderColor: 'var(--color-border-soft)', p: 0 }}>
|
||||||
<Box sx={{ p: 1.5, bgcolor: 'rgba(255,255,255,0.02)', display: 'flex', gap: 1 }}>
|
<Box sx={{ p: 1.5, bgcolor: 'var(--color-bg-soft)', display: 'flex', gap: 1 }}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
@@ -190,7 +190,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
),
|
),
|
||||||
className: 'text-sm',
|
className: 'text-sm',
|
||||||
sx: { color: '#fff', bgcolor: 'rgba(0,0,0,0.2)', height: 32 }
|
sx: { color: 'white', bgcolor: 'var(--color-bg-medium)', height: 32 }
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
@@ -223,7 +223,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
<ListItem
|
<ListItem
|
||||||
key={ext.name}
|
key={ext.name}
|
||||||
divider
|
divider
|
||||||
sx={{ borderColor: 'rgba(255,255,255,0.03)', py: 0.5 }}
|
sx={{ borderColor: 'var(--color-border-soft)', py: 0.5 }}
|
||||||
secondaryAction={
|
secondaryAction={
|
||||||
saving === ext.name ? (
|
saving === ext.name ? (
|
||||||
<CircularProgress size={16} />
|
<CircularProgress size={16} />
|
||||||
@@ -254,7 +254,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
</List>
|
</List>
|
||||||
)}
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions sx={{ p: 1.5, bgcolor: 'rgba(255,255,255,0.01)' }}>
|
<DialogActions sx={{ p: 1.5, bgcolor: 'var(--color-bg-soft)' }}>
|
||||||
<Button onClick={fetchExtensions} size="small" startIcon={<RefreshIcon sx={{ fontSize: 'var(--font-size-md)' }} />} className="text-xs" sx={{ mr: 'auto' }}>
|
<Button onClick={fetchExtensions} size="small" startIcon={<RefreshIcon sx={{ fontSize: 'var(--font-size-md)' }} />} className="text-xs" sx={{ mr: 'auto' }}>
|
||||||
{t('common.refresh').toUpperCase()}
|
{t('common.refresh').toUpperCase()}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -276,7 +276,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
<DialogTitle sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, p: 1.5 }}>
|
<DialogTitle sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, p: 1.5 }}>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<Typography variant="subtitle2" className="font-black">{t('php.extensions.ini_edit', { version: phpVersion })}</Typography>
|
<Typography variant="subtitle2" className="font-black">{t('php.extensions.ini_edit', { version: phpVersion })}</Typography>
|
||||||
<IconButton onClick={() => setIsRawEditorOpen(false)} size="small" sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
<IconButton onClick={() => setIsRawEditorOpen(false)} size="small" sx={{ color: 'var(--color-text-tertiary)' }}>
|
||||||
<CloseIcon fontSize="small" />
|
<CloseIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -311,21 +311,21 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
),
|
),
|
||||||
className: 'text-sm',
|
className: 'text-sm',
|
||||||
sx: {
|
sx: {
|
||||||
color: '#fff',
|
color: 'white',
|
||||||
bgcolor: 'rgba(255,255,255,0.03)',
|
bgcolor: 'var(--color-bg-soft)',
|
||||||
height: 32,
|
height: 32,
|
||||||
'& fieldset': { borderColor: 'var(--color-border-soft)' }
|
'& fieldset': { borderColor: 'var(--color-border-soft)' }
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<DialogContent sx={{ p: 0, minHeight: 350, borderTop: '1px solid rgba(255,255,255,0.05)' }}>
|
<DialogContent sx={{ p: 0, minHeight: 350, borderTop: '1px solid var(--color-border-soft)' }}>
|
||||||
<PhpIniCodeEditor
|
<PhpIniCodeEditor
|
||||||
value={rawConfig}
|
value={rawConfig}
|
||||||
onChange={setRawConfig}
|
onChange={setRawConfig}
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions sx={{ p: 1.5, bgcolor: 'rgba(0,0,0,0.1)' }}>
|
<DialogActions sx={{ p: 1.5, bgcolor: 'var(--color-bg-medium)' }}>
|
||||||
<Button onClick={() => setIsRawEditorOpen(false)} size="small" className="text-secondary text-xs">
|
<Button onClick={() => setIsRawEditorOpen(false)} size="small" className="text-secondary text-xs">
|
||||||
{t('common.cancel').toUpperCase()}
|
{t('common.cancel').toUpperCase()}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ export default function ServiceEventMonitor({ onClose }: { onClose?: () => void
|
|||||||
renderCell: (params) => {
|
renderCell: (params) => {
|
||||||
const status = params.value as string
|
const status = params.value as string
|
||||||
return status === 'success' ? (
|
return status === 'success' ? (
|
||||||
<SuccessIcon sx={{ color: 'success.main', fontSize: 'var(--font-size-md)' }} />
|
<SuccessIcon sx={{ color: 'var(--color-success)', fontSize: 'var(--font-size-md)' }} />
|
||||||
) : status === 'failure' ? (
|
) : status === 'failure' ? (
|
||||||
<ErrorIcon sx={{ color: 'error.main', fontSize: 'var(--font-size-md)' }} />
|
<ErrorIcon sx={{ color: 'var(--color-error)', fontSize: 'var(--font-size-md)' }} />
|
||||||
) : (
|
) : (
|
||||||
<InfoIcon sx={{ color: 'info.main', fontSize: 'var(--font-size-md)' }} />
|
<InfoIcon sx={{ color: 'var(--color-primary)', fontSize: 'var(--font-size-md)' }} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -160,7 +160,7 @@ export default function ServiceEventMonitor({ onClose }: { onClose?: () => void
|
|||||||
return (
|
return (
|
||||||
<Box sx={{ height: '100%', display: 'flex', flexDirection: 'column', bgcolor: 'var(--color-bg-dark)', color: 'var(--color-text-primary)' }}>
|
<Box sx={{ height: '100%', display: 'flex', flexDirection: 'column', bgcolor: 'var(--color-bg-dark)', color: 'var(--color-text-primary)' }}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Box sx={{ p: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
|
<Box sx={{ p: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: '1px solid var(--color-border-soft)' }}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||||
<HistoryIcon color="primary" />
|
<HistoryIcon color="primary" />
|
||||||
<Box>
|
<Box>
|
||||||
@@ -176,7 +176,7 @@ export default function ServiceEventMonitor({ onClose }: { onClose?: () => void
|
|||||||
<IconButton onClick={fetchEvents} size="small" sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
<IconButton onClick={fetchEvents} size="small" sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||||
<RefreshIcon fontSize="small" />
|
<RefreshIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton onClick={handleClear} size="small" sx={{ color: '#f44336' }}>
|
<IconButton onClick={handleClear} size="small" sx={{ color: 'var(--color-error)' }}>
|
||||||
<ClearIcon fontSize="small" />
|
<ClearIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{onClose && (
|
{onClose && (
|
||||||
@@ -194,7 +194,7 @@ export default function ServiceEventMonitor({ onClose }: { onClose?: () => void
|
|||||||
<CircularProgress size={30} />
|
<CircularProgress size={30} />
|
||||||
</Box>
|
</Box>
|
||||||
) : events.length === 0 ? (
|
) : events.length === 0 ? (
|
||||||
<Alert severity="info" sx={{ bgcolor: 'rgba(2, 136, 209, 0.05)', color: 'info.light' }}>
|
<Alert severity="info" sx={{ bgcolor: 'var(--color-primary-soft)', color: 'var(--color-primary)' }}>
|
||||||
{t('service_monitor.no_events')}
|
{t('service_monitor.no_events')}
|
||||||
</Alert>
|
</Alert>
|
||||||
) : (
|
) : (
|
||||||
@@ -209,9 +209,9 @@ export default function ServiceEventMonitor({ onClose }: { onClose?: () => void
|
|||||||
dataset={chartData}
|
dataset={chartData}
|
||||||
xAxis={[{ scaleType: 'band', dataKey: 'service' }]}
|
xAxis={[{ scaleType: 'band', dataKey: 'service' }]}
|
||||||
series={[
|
series={[
|
||||||
{ dataKey: 'start', label: t('common.start'), color: '#4caf50' },
|
{ dataKey: 'start', label: t('common.start'), color: 'var(--color-success)' },
|
||||||
{ dataKey: 'stop', label: t('common.stop'), color: '#f44336' },
|
{ dataKey: 'stop', label: t('common.stop'), color: 'var(--color-error)' },
|
||||||
{ dataKey: 'error', label: t('common.error'), color: '#ff9800' }
|
{ dataKey: 'error', label: t('common.error'), color: 'var(--color-warning)' }
|
||||||
]}
|
]}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
legend: {
|
legend: {
|
||||||
@@ -221,10 +221,10 @@ export default function ServiceEventMonitor({ onClose }: { onClose?: () => void
|
|||||||
}}
|
}}
|
||||||
margin={{ top: 10, bottom: 50, left: 30, right: 10 }}
|
margin={{ top: 10, bottom: 50, left: 30, right: 10 }}
|
||||||
sx={{
|
sx={{
|
||||||
'& .MuiChartsAxis-left .MuiChartsAxis-tickLabel': { fill: 'rgba(255,255,255,0.3)' },
|
'& .MuiChartsAxis-left .MuiChartsAxis-tickLabel': { fill: 'var(--color-text-muted)' },
|
||||||
'& .MuiChartsAxis-bottom .MuiChartsAxis-tickLabel': { fill: 'rgba(255,255,255,0.3)', fontSize: 10 },
|
'& .MuiChartsAxis-bottom .MuiChartsAxis-tickLabel': { fill: 'var(--color-text-muted)', fontSize: 10 },
|
||||||
'& .MuiChartsAxis-line': { stroke: 'rgba(255,255,255,0.1)' },
|
'& .MuiChartsAxis-line': { stroke: 'var(--color-border-soft)' },
|
||||||
'& .MuiChartsAxis-tick': { stroke: 'rgba(255,255,255,0.1)' }
|
'& .MuiChartsAxis-tick': { stroke: 'var(--color-border-soft)' }
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -242,7 +242,7 @@ export default function ServiceEventMonitor({ onClose }: { onClose?: () => void
|
|||||||
border: 'none',
|
border: 'none',
|
||||||
color: 'var(--color-text-primary)',
|
color: 'var(--color-text-primary)',
|
||||||
'& .MuiDataGrid-cell': { borderBottom: '1px solid var(--color-border-soft)', fontSize: 'var(--font-size-xs)' },
|
'& .MuiDataGrid-cell': { borderBottom: '1px solid var(--color-border-soft)', fontSize: 'var(--font-size-xs)' },
|
||||||
'& .MuiDataGrid-columnHeaders': { bgcolor: 'rgba(255,255,255,0.03)', borderBottom: '1px solid var(--color-border-medium)' },
|
'& .MuiDataGrid-columnHeaders': { bgcolor: 'var(--color-bg-soft)', borderBottom: '1px solid var(--color-border-medium)' },
|
||||||
'& .MuiDataGrid-columnHeaderTitle': { fontWeight: 'bold', fontSize: 'var(--font-size-xs)', opacity: 0.5 },
|
'& .MuiDataGrid-columnHeaderTitle': { fontWeight: 'bold', fontSize: 'var(--font-size-xs)', opacity: 0.5 },
|
||||||
'& .MuiDataGrid-virtualScroller': { bgcolor: 'transparent' },
|
'& .MuiDataGrid-virtualScroller': { bgcolor: 'transparent' },
|
||||||
'& .MuiDataGrid-footerContainer': { borderTop: '1px solid var(--color-border-soft)' }
|
'& .MuiDataGrid-footerContainer': { borderTop: '1px solid var(--color-border-soft)' }
|
||||||
|
|||||||
Reference in New Issue
Block a user