feat: add MariaDB tuning support and internationalization for application UI
This commit is contained in:
@@ -16,6 +16,7 @@ innodb_doublewrite=0
|
||||
innodb_lock_wait_timeout=600
|
||||
innodb_strict_mode=0
|
||||
innodb_default_row_format=DYNAMIC
|
||||
{{EXTRA_CONFIG}}
|
||||
|
||||
[client]
|
||||
port={{PORT}}
|
||||
|
||||
+53
-1
@@ -484,11 +484,13 @@ export function registerIpcHandlers(): void {
|
||||
const sanitizedServiceName = serviceName.replace(/:/g, '_')
|
||||
const logFile = path.join(configService.getBasePath(), 'logs', `${sanitizedServiceName}_error.log`)
|
||||
|
||||
const tuning = settings.mariaDbTuning?.[dbId] || ''
|
||||
const configPath = await configService.generateConfig('mariadb.ini.template', `mariadb_${dbId || 'default'}.ini`, {
|
||||
PORT: dbPort,
|
||||
DATADIR: dataDir.replace(/\\/g, '/'),
|
||||
SOCKET: `/tmp/${sanitizedServiceName}.sock`,
|
||||
LOG_FILE: logFile.replace(/\\/g, '/')
|
||||
LOG_FILE: logFile.replace(/\\/g, '/'),
|
||||
EXTRA_CONFIG: tuning
|
||||
})
|
||||
|
||||
const success = await processManager.startService(serviceName, binPath, ['--defaults-file=' + configPath], false)
|
||||
@@ -627,6 +629,56 @@ export function registerIpcHandlers(): void {
|
||||
return { success: false, message: `MariaDB hatası: ${error.message}` }
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('mariadb:config:get', async (_event, versionId: string) => {
|
||||
const settings = configService.getSettings()
|
||||
const tuning = settings.mariaDbTuning?.[versionId] || ''
|
||||
return { content: tuning }
|
||||
})
|
||||
|
||||
ipcMain.handle('mariadb:config:save', async (_event, { versionId, content }) => {
|
||||
const settings = configService.getSettings()
|
||||
const mariaDbTuning = settings.mariaDbTuning || {}
|
||||
mariaDbTuning[versionId] = content
|
||||
configService.updateSettings({ ...settings, mariaDbTuning })
|
||||
|
||||
const serviceName = `mariadb:${versionId.replace('mariadb-', '')}`
|
||||
if (processManager.isServiceRunning(serviceName)) {
|
||||
await processManager.stopService(serviceName)
|
||||
}
|
||||
|
||||
return { success: true, message: 'Tuning configuration saved.' }
|
||||
})
|
||||
|
||||
ipcMain.handle('php:versions:all', async () => {
|
||||
return phpManagerService.getVersions()
|
||||
})
|
||||
|
||||
ipcMain.handle('php:config:get', async (_event, version: string) => {
|
||||
const phpIniPath = path.join(configService.getBasePath(), 'generated_configs', `php_${version}.ini`)
|
||||
if (fs.existsSync(phpIniPath)) {
|
||||
return { content: fs.readFileSync(phpIniPath, 'utf8') }
|
||||
}
|
||||
return { content: '' }
|
||||
})
|
||||
|
||||
ipcMain.handle('php:config:save', async (_event, { version, content }) => {
|
||||
const phpIniPath = path.join(configService.getBasePath(), 'generated_configs', `php_${version}.ini`)
|
||||
// Add manual edit marker to prevent overwriting
|
||||
let finalContent = content
|
||||
if (!finalContent.includes('; MANUAL_EDIT')) {
|
||||
finalContent = `; MANUAL_EDIT\n${finalContent}`
|
||||
}
|
||||
fs.writeFileSync(phpIniPath, finalContent, 'utf8')
|
||||
|
||||
// Restart PHP if running
|
||||
const serviceName = `php:${version}`
|
||||
if (processManager.isServiceRunning(serviceName)) {
|
||||
await processManager.stopService(serviceName)
|
||||
// It will be started again later or manually
|
||||
}
|
||||
return { success: true }
|
||||
})
|
||||
|
||||
// Apache Versions
|
||||
ipcMain.handle('apache:versions', async () => {
|
||||
|
||||
@@ -17,7 +17,8 @@ export class ConfigService {
|
||||
language: 'tr',
|
||||
cliEnvEnabled: true,
|
||||
defaultPhpVersion: '',
|
||||
defaultMariaDbVersion: ''
|
||||
defaultMariaDbVersion: '',
|
||||
mariaDbTuning: {} as Record<string, string>
|
||||
}
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -78,7 +78,8 @@ import {
|
||||
Launch as LaunchIcon,
|
||||
Handyman as ToolsIcon,
|
||||
Restore as ResetIcon,
|
||||
Search as SearchIcon
|
||||
Search as SearchIcon,
|
||||
Tune as TuningIcon
|
||||
} from '@mui/icons-material'
|
||||
import Swal from 'sweetalert2'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -88,6 +89,7 @@ import MariaDbExportWizard from './components/MariaDbExportWizard'
|
||||
import NginxCodeEditor from './components/NginxCodeEditor'
|
||||
import ApacheCodeEditor from './components/ApacheCodeEditor'
|
||||
import PhpExtensionManager from './components/PhpExtensionManager'
|
||||
import ServerTuning from './components/ServerTuning'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -1105,6 +1107,12 @@ function App(): JSX.Element {
|
||||
<ListItemText primary={t('projects.title')} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton selected={activeTab === 'tuning'} onClick={() => setActiveTab('tuning')}>
|
||||
<ListItemIcon><TuningIcon color={activeTab === 'tuning' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||
<ListItemText primary={t('tuning.title')} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton selected={activeTab === 'tools'} onClick={() => setActiveTab('tools')}>
|
||||
<ListItemIcon><ToolsIcon color={activeTab === 'tools' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||
@@ -1133,6 +1141,7 @@ function App(): JSX.Element {
|
||||
<Box component="main" sx={{ flexGrow: 1, p: 3 }}>
|
||||
<Toolbar />
|
||||
<Container maxWidth={false} sx={{ py: 2 }}>
|
||||
{activeTab === 'tuning' && <ServerTuning />}
|
||||
{activeTab === 'settings' && (
|
||||
<Box>
|
||||
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Grid,
|
||||
Paper,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Slider,
|
||||
TextField,
|
||||
Stack,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Alert,
|
||||
CircularProgress,
|
||||
Card,
|
||||
CardContent,
|
||||
CardActionArea,
|
||||
Chip
|
||||
} from '@mui/material'
|
||||
import {
|
||||
Tune as TuneIcon,
|
||||
Close as CloseIcon,
|
||||
Save as SaveIcon,
|
||||
Code as PhpIcon,
|
||||
Storage as DbIcon,
|
||||
InfoOutlined as InfoIcon
|
||||
} from '@mui/icons-material'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface TuningParam {
|
||||
key: string
|
||||
label: string
|
||||
description: string
|
||||
min: number
|
||||
max: number
|
||||
step: number
|
||||
unit: string
|
||||
type: 'php' | 'mariadb'
|
||||
transform?: (val: number) => string
|
||||
parse?: (val: string) => number
|
||||
}
|
||||
|
||||
const PHP_PARAMS: TuningParam[] = [
|
||||
{
|
||||
key: 'memory_limit',
|
||||
label: 'memory_limit',
|
||||
description: 'tuning.parameters.memory_limit_desc',
|
||||
min: 64,
|
||||
max: 4096,
|
||||
step: 64,
|
||||
unit: 'M',
|
||||
type: 'php',
|
||||
transform: (v) => `${v}M`,
|
||||
parse: (v) => parseInt(v.replace('M', '')) || 128
|
||||
},
|
||||
{
|
||||
key: 'max_execution_time',
|
||||
label: 'max_execution_time',
|
||||
description: 'tuning.parameters.max_execution_time_desc',
|
||||
min: 30,
|
||||
max: 3600,
|
||||
step: 30,
|
||||
unit: 's',
|
||||
type: 'php',
|
||||
transform: (v) => `${v}`,
|
||||
parse: (v) => parseInt(v) || 30
|
||||
},
|
||||
{
|
||||
key: 'post_max_size',
|
||||
label: 'post_max_size',
|
||||
description: 'tuning.parameters.post_max_size_desc',
|
||||
min: 8,
|
||||
max: 2048,
|
||||
step: 8,
|
||||
unit: 'M',
|
||||
type: 'php',
|
||||
transform: (v) => `${v}M`,
|
||||
parse: (v) => parseInt(v.replace('M', '')) || 8
|
||||
},
|
||||
{
|
||||
key: 'upload_max_filesize',
|
||||
label: 'upload_max_filesize',
|
||||
description: 'tuning.parameters.upload_max_filesize_desc',
|
||||
min: 2,
|
||||
max: 2048,
|
||||
step: 2,
|
||||
unit: 'M',
|
||||
type: 'php',
|
||||
transform: (v) => `${v}M`,
|
||||
parse: (v) => parseInt(v.replace('M', '')) || 2
|
||||
},
|
||||
{
|
||||
key: 'max_input_vars',
|
||||
label: 'max_input_vars',
|
||||
description: 'tuning.parameters.max_input_vars_desc',
|
||||
min: 1000,
|
||||
max: 100000,
|
||||
step: 1000,
|
||||
unit: '',
|
||||
type: 'php',
|
||||
transform: (v) => `${v}`,
|
||||
parse: (v) => parseInt(v) || 1000
|
||||
}
|
||||
]
|
||||
|
||||
const MARIADB_PARAMS: TuningParam[] = [
|
||||
{
|
||||
key: 'max_connections',
|
||||
label: 'max_connections',
|
||||
description: 'tuning.parameters.max_connections_desc',
|
||||
min: 10,
|
||||
max: 5000,
|
||||
step: 10,
|
||||
unit: '',
|
||||
type: 'mariadb',
|
||||
transform: (v) => `${v}`,
|
||||
parse: (v) => parseInt(v) || 151
|
||||
},
|
||||
{
|
||||
key: 'innodb_buffer_pool_size',
|
||||
label: 'innodb_buffer_pool_size',
|
||||
description: 'tuning.parameters.innodb_buffer_pool_size_desc',
|
||||
min: 128,
|
||||
max: 16384,
|
||||
step: 128,
|
||||
unit: 'M',
|
||||
type: 'mariadb',
|
||||
transform: (v) => `${v}M`,
|
||||
parse: (v) => {
|
||||
if (v.endsWith('G')) return parseInt(v) * 1024
|
||||
return parseInt(v) || 128
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'key_buffer_size',
|
||||
label: 'key_buffer_size',
|
||||
description: 'tuning.parameters.key_buffer_size_desc',
|
||||
min: 8,
|
||||
max: 1024,
|
||||
step: 8,
|
||||
unit: 'M',
|
||||
type: 'mariadb',
|
||||
transform: (v) => `${v}M`,
|
||||
parse: (v) => parseInt(v) || 16
|
||||
},
|
||||
{
|
||||
key: 'max_allowed_packet',
|
||||
label: 'max_allowed_packet',
|
||||
description: 'tuning.parameters.max_allowed_packet_desc',
|
||||
min: 1,
|
||||
max: 1024,
|
||||
step: 1,
|
||||
unit: 'M',
|
||||
type: 'mariadb',
|
||||
transform: (v) => `${v}M`,
|
||||
parse: (v) => {
|
||||
if (v.endsWith('G')) return parseInt(v) * 1024
|
||||
return parseInt(v) || 16
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
export default function ServerTuning() {
|
||||
const { t } = useTranslation()
|
||||
const [phpVersions, setPhpVersions] = useState<any[]>([])
|
||||
const [mariaDbVersions, setMariaDbVersions] = useState<any[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [selectedVersion, setSelectedVersion] = useState<any>(null)
|
||||
const [configContent, setConfigContent] = useState('')
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [tuningValues, setTuningValues] = useState<Record<string, number>>({})
|
||||
|
||||
const fetchVersions = async () => {
|
||||
setLoading(true)
|
||||
if (window.api) {
|
||||
const phps = await window.api.getPhpVersions()
|
||||
const dbs = await window.api.getMariaDbVersions()
|
||||
setPhpVersions(phps.filter((v: any) => v.status === 'installed'))
|
||||
setMariaDbVersions(dbs.filter((v: any) => v.status === 'installed'))
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchVersions()
|
||||
}, [])
|
||||
|
||||
const handleOpenTuning = async (version: any, type: 'php' | 'mariadb') => {
|
||||
setSelectedVersion({ ...version, type })
|
||||
let content = ''
|
||||
if (type === 'php') {
|
||||
const res = await window.api.invoke('php:config:get', version.version)
|
||||
content = res.content
|
||||
} else {
|
||||
const res = await window.api.invoke('mariadb:config:get', version.id)
|
||||
content = res.content
|
||||
}
|
||||
setConfigContent(content)
|
||||
|
||||
// Parse current values
|
||||
const params = type === 'php' ? PHP_PARAMS : MARIADB_PARAMS
|
||||
const values: Record<string, number> = {}
|
||||
params.forEach(p => {
|
||||
const regex = type === 'php'
|
||||
? new RegExp(`^\\s*${p.key}\\s*=\\s*(.+)$`, 'm')
|
||||
: new RegExp(`^\\s*${p.key}\\s*=\\s*(.+)$`, 'm')
|
||||
|
||||
const match = content.match(regex)
|
||||
if (match && p.parse) {
|
||||
values[p.key] = p.parse(match[1].trim())
|
||||
} else {
|
||||
values[p.key] = p.min // Default to min if not found
|
||||
}
|
||||
})
|
||||
setTuningValues(values)
|
||||
setIsModalOpen(true)
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
setSaving(true)
|
||||
let updatedContent = configContent
|
||||
const params = selectedVersion.type === 'php' ? PHP_PARAMS : MARIADB_PARAMS
|
||||
|
||||
params.forEach(p => {
|
||||
const newValue = p.transform ? p.transform(tuningValues[p.key]) : tuningValues[p.key].toString()
|
||||
const regex = new RegExp(`^(\\s*${p.key}\\s*=\\s*)(.+)$`, 'm')
|
||||
|
||||
if (updatedContent.match(regex)) {
|
||||
updatedContent = updatedContent.replace(regex, `$1${newValue}`)
|
||||
} else {
|
||||
updatedContent += `\n${p.key}=${newValue}`
|
||||
}
|
||||
})
|
||||
|
||||
if (selectedVersion.type === 'php') {
|
||||
await window.api.invoke('php:config:save', { version: selectedVersion.version, content: updatedContent })
|
||||
} else {
|
||||
await window.api.invoke('mariadb:config:save', { versionId: selectedVersion.id, content: updatedContent })
|
||||
}
|
||||
|
||||
setSaving(false)
|
||||
setIsModalOpen(false)
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', p: 10 }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<Typography variant="h4" sx={{ fontWeight: 800, mb: 1, color: 'primary.light' }}>
|
||||
{t('tuning.title')}
|
||||
</Typography>
|
||||
<Typography variant="body1" sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
||||
{t('tuning.desc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={4}>
|
||||
{/* PHP Section */}
|
||||
<Grid item xs={12} md={6}>
|
||||
<Paper sx={{ p: 3, height: '100%', bgcolor: 'rgba(255,255,255,0.02)', borderRadius: 4, border: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3, gap: 2 }}>
|
||||
<Box sx={{ p: 1.5, borderRadius: 2, bgcolor: 'primary.main', display: 'flex' }}>
|
||||
<PhpIcon sx={{ color: 'white' }} />
|
||||
</Box>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>PHP Tuning</Typography>
|
||||
<Chip label={phpVersions.length} size="small" variant="outlined" />
|
||||
</Box>
|
||||
|
||||
<Stack spacing={2}>
|
||||
{phpVersions.map(v => (
|
||||
<Card key={v.id} sx={{ bgcolor: 'rgba(255,255,255,0.03)', backgroundImage: 'none', border: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<CardActionArea onClick={() => handleOpenTuning(v, 'php')}>
|
||||
<CardContent sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Box>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>PHP {v.version}</Typography>
|
||||
<Typography variant="caption" color="text.secondary">php.ini optimization</Typography>
|
||||
</Box>
|
||||
<Button variant="contained" size="small" startIcon={<TuneIcon />}>
|
||||
{t('tuning.tune_btn')}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
</Card>
|
||||
))}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
||||
{/* MariaDB Section */}
|
||||
<Grid item xs={12} md={6}>
|
||||
<Paper sx={{ p: 3, height: '100%', bgcolor: 'rgba(255,255,255,0.02)', borderRadius: 4, border: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3, gap: 2 }}>
|
||||
<Box sx={{ p: 1.5, borderRadius: 2, bgcolor: 'secondary.main', display: 'flex' }}>
|
||||
<DbIcon sx={{ color: 'white' }} />
|
||||
</Box>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>MariaDB Tuning</Typography>
|
||||
<Chip label={mariaDbVersions.length} size="small" variant="outlined" />
|
||||
</Box>
|
||||
|
||||
<Stack spacing={2}>
|
||||
{mariaDbVersions.map(v => (
|
||||
<Card key={v.id} sx={{ bgcolor: 'rgba(255,255,255,0.03)', backgroundImage: 'none', border: '1px solid rgba(255,255,255,0.05)' }}>
|
||||
<CardActionArea onClick={() => handleOpenTuning(v, 'mariadb')}>
|
||||
<CardContent sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Box>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>MariaDB {v.version}</Typography>
|
||||
<Typography variant="caption" color="text.secondary">Performance variables</Typography>
|
||||
</Box>
|
||||
<Button variant="contained" color="secondary" size="small" startIcon={<TuneIcon />}>
|
||||
{t('tuning.tune_btn')}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
</Card>
|
||||
))}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Tuning Modal */}
|
||||
<Dialog
|
||||
open={isModalOpen}
|
||||
onClose={() => !saving && setIsModalOpen(false)}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
sx: {
|
||||
bgcolor: '#1a1d21',
|
||||
backgroundImage: 'none',
|
||||
color: '#fff',
|
||||
borderRadius: 4,
|
||||
border: '1px solid rgba(255,255,255,0.1)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{ borderBottom: '1px solid rgba(255,255,255,0.1)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||
<TuneIcon color={selectedVersion?.type === 'php' ? 'primary' : 'secondary'} />
|
||||
<Typography variant="h6" sx={{ fontWeight: 800 }}>
|
||||
{selectedVersion?.type === 'php' ? `PHP ${selectedVersion?.version}` : `MariaDB ${selectedVersion?.version}`} Tuning
|
||||
</Typography>
|
||||
</Box>
|
||||
<IconButton onClick={() => setIsModalOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box sx={{ pt: 2 }}>
|
||||
<Alert severity="info" sx={{ mb: 4, bgcolor: 'rgba(2, 136, 209, 0.1)', color: 'info.light', border: '1px solid rgba(2, 136, 209, 0.2)' }}>
|
||||
{t('tuning.restart_notice')}
|
||||
</Alert>
|
||||
|
||||
<Stack spacing={5}>
|
||||
{(selectedVersion?.type === 'php' ? PHP_PARAMS : MARIADB_PARAMS).map(p => (
|
||||
<Box key={p.key}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1, alignItems: 'center' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 'bold' }}>{p.label}</Typography>
|
||||
<Tooltip title={t(p.description)}>
|
||||
<InfoIcon sx={{ fontSize: 16, color: 'rgba(255,255,255,0.3)', cursor: 'help' }} />
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<TextField
|
||||
size="small"
|
||||
value={tuningValues[p.key]}
|
||||
onChange={(e) => setTuningValues({ ...tuningValues, [p.key]: parseInt(e.target.value) || p.min })}
|
||||
InputProps={{
|
||||
endAdornment: <Typography variant="caption" sx={{ ml: 1, opacity: 0.5 }}>{p.unit}</Typography>
|
||||
} as any}
|
||||
sx={{ width: 120, '& .MuiOutlinedInput-root': { height: 32 } }}
|
||||
/>
|
||||
</Box>
|
||||
<Slider
|
||||
value={tuningValues[p.key]}
|
||||
min={p.min}
|
||||
max={p.max}
|
||||
step={p.step}
|
||||
onChange={(_e, v) => setTuningValues({ ...tuningValues, [p.key]: v as number })}
|
||||
sx={{
|
||||
color: selectedVersion?.type === 'php' ? 'primary.main' : 'secondary.main',
|
||||
'& .MuiSlider-thumb': {
|
||||
width: 14,
|
||||
height: 14,
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.4)', mt: -1, display: 'block' }}>
|
||||
{t(p.description)}
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Stack>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ p: 3, borderTop: '1px solid rgba(255,255,255,0.1)' }}>
|
||||
<Button onClick={() => setIsModalOpen(false)} disabled={saving}>
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color={selectedVersion?.type === 'php' ? 'primary' : 'secondary'}
|
||||
onClick={handleSave}
|
||||
startIcon={saving ? <CircularProgress size={20} color="inherit" /> : <SaveIcon />}
|
||||
disabled={saving}
|
||||
sx={{ px: 4, borderRadius: 2 }}
|
||||
>
|
||||
{saving ? t('tuning.saving') : t('common.save')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -276,5 +276,34 @@
|
||||
"info": "Info",
|
||||
"progress": "Progress"
|
||||
}
|
||||
},
|
||||
"tuning": {
|
||||
"title": "Server Tuning",
|
||||
"desc": "Optimize performance of PHP and MariaDB servers with key resource limits.",
|
||||
"php_total": "PHP Instances",
|
||||
"mariadb_total": "MariaDB Instances",
|
||||
"tune_btn": "TUNE",
|
||||
"saving": "Applying changes...",
|
||||
"restart_notice": "Some changes require a service restart to take effect.",
|
||||
"parameters": {
|
||||
"memory_limit": "Memory Limit",
|
||||
"memory_limit_desc": "Maximum amount of memory a script may consume.",
|
||||
"max_execution_time": "Max Execution Time",
|
||||
"max_execution_time_desc": "Maximum time in seconds a script is allowed to run.",
|
||||
"post_max_size": "Post Max Size",
|
||||
"post_max_size_desc": "Maximum size of POST data that PHP will accept.",
|
||||
"upload_max_filesize": "Upload Max Filesize",
|
||||
"upload_max_filesize_desc": "Maximum size of an uploaded file.",
|
||||
"max_input_vars": "Max Input Vars",
|
||||
"max_input_vars_desc": "How many input variables may be accepted.",
|
||||
"max_connections": "Max Connections",
|
||||
"max_connections_desc": "Maximum number of simultaneous client connections.",
|
||||
"innodb_buffer_pool_size": "InnoDB Buffer Pool",
|
||||
"innodb_buffer_pool_size_desc": "Crucial for performance. Holds indexes and data from memory.",
|
||||
"key_buffer_size": "Key Buffer Size",
|
||||
"key_buffer_size_desc": "Index blocks for MyISAM tables (shared by all threads).",
|
||||
"max_allowed_packet": "Max Allowed Packet",
|
||||
"max_allowed_packet_desc": "Maximum size of one packet or any generated/intermediate string."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,5 +271,34 @@
|
||||
"info": "Bilgi",
|
||||
"progress": "İlerleme"
|
||||
}
|
||||
},
|
||||
"tuning": {
|
||||
"title": "Sunucu Optimizasyonu",
|
||||
"desc": "PHP ve MariaDB sunucularının performansını kritik kaynak sınırlarıyla optimize edin.",
|
||||
"php_total": "PHP Örneği",
|
||||
"mariadb_total": "MariaDB Örneği",
|
||||
"tune_btn": "AYARLA",
|
||||
"saving": "Değişiklikler uygulanıyor...",
|
||||
"restart_notice": "Bazı değişikliklerin geçerli olması için servislerin yeniden başlatılması gerekir.",
|
||||
"parameters": {
|
||||
"memory_limit": "Bellek Limiti",
|
||||
"memory_limit_desc": "Bir betiğin tüketebileceği maksimum bellek miktarı.",
|
||||
"max_execution_time": "Maksimum Çalışma Süresi",
|
||||
"max_execution_time_desc": "Bir betiğin çalışmasına izin verilen maksimum süre (saniye).",
|
||||
"post_max_size": "Post Maksimum Boyutu",
|
||||
"post_max_size_desc": "PHP'nin kabul edeceği maksimum POST verisi boyutu.",
|
||||
"upload_max_filesize": "Dosya Yükleme Limiti",
|
||||
"upload_max_filesize_desc": "Yüklenebilecek maksimum dosya boyutu.",
|
||||
"max_input_vars": "Maksimum Girdi Değişkeni",
|
||||
"max_input_vars_desc": "Kaç tane girdi değişkeninin (GET/POST/Cookie) kabul edilebileceği.",
|
||||
"max_connections": "Maksimum Bağlantı",
|
||||
"max_connections_desc": "Eşzamanlı maksimum istemci bağlantısı sayısı.",
|
||||
"innodb_buffer_pool_size": "InnoDB Tampon Havuzu",
|
||||
"innodb_buffer_pool_size_desc": "Performans için kritiktir. İndeksleri ve verileri bellekte tutar.",
|
||||
"key_buffer_size": "Anahtar Tampon Boyutu",
|
||||
"key_buffer_size_desc": "MyISAM tabloları için indeks blokları (tüm iş parçacıkları tarafından paylaşılır).",
|
||||
"max_allowed_packet": "Maksimum Paket Boyutu",
|
||||
"max_allowed_packet_desc": "Bir paketin veya oluşturulan herhangi bir dizenin maksimum boyutu."
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user