feat: implement MariaDB management, PHP extension control, and project details UI components

This commit is contained in:
Ümit Tunç
2026-04-03 16:02:14 +03:00
parent fe25ec5b38
commit 815e01004e
8 changed files with 220 additions and 162 deletions
+24 -19
View File
@@ -860,11 +860,11 @@ function App(): JSX.Element {
size="small" size="small"
color="success" color="success"
onClick={handleStartAll} onClick={handleStartAll}
startIcon={<StartIcon sx={{ fontSize: '1rem !important' }} />} startIcon={<StartIcon sx={{ fontSize: 'var(--font-size-base) !important' }} />}
sx={{ sx={{
borderRadius: 1.5, borderRadius: 'var(--radius-md)',
fontSize: '0.7rem', fontSize: 'var(--font-size-xs)',
fontWeight: 800, fontWeight: 'var(--font-weight-black)',
textTransform: 'none', textTransform: 'none',
borderColor: 'rgba(76, 175, 80, 0.3)', borderColor: 'rgba(76, 175, 80, 0.3)',
px: 1.5, px: 1.5,
@@ -879,11 +879,11 @@ function App(): JSX.Element {
size="small" size="small"
color="error" color="error"
onClick={handleStopAll} onClick={handleStopAll}
startIcon={<StopIcon sx={{ fontSize: '1rem !important' }} />} startIcon={<StopIcon sx={{ fontSize: 'var(--font-size-base) !important' }} />}
sx={{ sx={{
borderRadius: 1.5, borderRadius: 'var(--radius-md)',
fontSize: '0.7rem', fontSize: 'var(--font-size-xs)',
fontWeight: 800, fontWeight: 'var(--font-weight-black)',
textTransform: 'none', textTransform: 'none',
borderColor: 'rgba(244, 67, 54, 0.3)', borderColor: 'rgba(244, 67, 54, 0.3)',
px: 1.5, px: 1.5,
@@ -912,7 +912,7 @@ function App(): JSX.Element {
}} }}
> >
{supportedLngs.map(lang => ( {supportedLngs.map(lang => (
<MenuItem key={lang} value={lang} sx={{ fontSize: '0.75rem' }}> <MenuItem key={lang} value={lang} className="text-sm">
{lang.toUpperCase()} {lang.toUpperCase()}
</MenuItem> </MenuItem>
))} ))}
@@ -937,7 +937,12 @@ function App(): JSX.Element {
sx={{ sx={{
width: drawerWidth, width: drawerWidth,
flexShrink: 0, flexShrink: 0,
[`& .MuiDrawer-paper`]: { width: drawerWidth, boxSizing: 'border-box', bgcolor: 'rgba(18, 18, 18, 0.95)', borderRight: '1px solid rgba(255, 255, 255, 0.05)' }, [`& .MuiDrawer-paper`]: {
width: drawerWidth,
boxSizing: 'border-box',
bgcolor: 'rgba(18, 18, 18, 0.95)',
borderRight: '1px solid var(--color-border-soft)'
},
}} }}
> >
<Box sx={{ p: 2, display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '120px' }}> <Box sx={{ p: 2, display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '120px' }}>
@@ -949,37 +954,37 @@ function App(): JSX.Element {
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'dashboard'} onClick={() => setActiveTab('dashboard')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'dashboard'} onClick={() => setActiveTab('dashboard')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><DashboardIcon fontSize="small" color={activeTab === 'dashboard' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><DashboardIcon fontSize="small" color={activeTab === 'dashboard' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('dashboard.title')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('dashboard.title')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'projects'} onClick={() => setActiveTab('projects')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'projects'} onClick={() => setActiveTab('projects')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><ProjectIcon fontSize="small" color={activeTab === 'projects' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><ProjectIcon fontSize="small" color={activeTab === 'projects' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('projects.title')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('projects.title')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'tuning'} onClick={() => setActiveTab('tuning')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'tuning'} onClick={() => setActiveTab('tuning')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><TuningIcon fontSize="small" color={activeTab === 'tuning' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><TuningIcon fontSize="small" color={activeTab === 'tuning' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('tuning.title')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('tuning.title')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'tools'} onClick={() => setActiveTab('tools')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'tools'} onClick={() => setActiveTab('tools')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><ToolsIcon fontSize="small" color={activeTab === 'tools' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><ToolsIcon fontSize="small" color={activeTab === 'tools' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('common.tools')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('common.tools')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'db_manager'} onClick={() => setActiveTab('db_manager')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'db_manager'} onClick={() => setActiveTab('db_manager')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><DbIcon fontSize="small" color={activeTab === 'db_manager' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><DbIcon fontSize="small" color={activeTab === 'db_manager' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('mariadb_manager.title')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('mariadb_manager.title')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'db_monitor'} onClick={() => setActiveTab('db_monitor')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'db_monitor'} onClick={() => setActiveTab('db_monitor')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><TerminalIcon fontSize="small" color={activeTab === 'db_monitor' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><TerminalIcon fontSize="small" color={activeTab === 'db_monitor' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('mariadb_process_monitor.title')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('mariadb_process_monitor.title')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
</List> </List>
@@ -988,19 +993,19 @@ function App(): JSX.Element {
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'user_guide'} onClick={() => setActiveTab('user_guide')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'user_guide'} onClick={() => setActiveTab('user_guide')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><GuideIcon fontSize="small" color={activeTab === 'user_guide' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><GuideIcon fontSize="small" color={activeTab === 'user_guide' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('common.user_guide')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('common.user_guide')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'settings'} onClick={() => setActiveTab('settings')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'settings'} onClick={() => setActiveTab('settings')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><SettingsIcon fontSize="small" color={activeTab === 'settings' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><SettingsIcon fontSize="small" color={activeTab === 'settings' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('settings.general')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('settings.general')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton selected={activeTab === 'event_monitor'} onClick={() => setActiveTab('event_monitor')} sx={{ py: 0.5 }}> <ListItemButton selected={activeTab === 'event_monitor'} onClick={() => setActiveTab('event_monitor')} sx={{ py: 0.5 }}>
<ListItemIcon sx={{ minWidth: 40 }}><HistoryIcon fontSize="small" color={activeTab === 'event_monitor' ? 'primary' : 'inherit'} /></ListItemIcon> <ListItemIcon sx={{ minWidth: 40 }}><HistoryIcon fontSize="small" color={activeTab === 'event_monitor' ? 'primary' : 'inherit'} /></ListItemIcon>
<ListItemText primary={t('service_monitor.title')} primaryTypographyProps={{ fontSize: '0.75rem', fontWeight: 500 }} /> <ListItemText primary={t('service_monitor.title')} primaryTypographyProps={{ className: 'text-sm font-medium' }} />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
</List> </List>
@@ -178,31 +178,32 @@ const MariaDbDatabaseManager: React.FC<MariaDbDatabaseManagerProps> = ({ version
<Stack direction="row" spacing={2} alignItems="center" justifyContent="space-between" sx={{ mb: 3 }}> <Stack direction="row" spacing={2} alignItems="center" justifyContent="space-between" sx={{ mb: 3 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<DbIcon color="primary" /> <DbIcon color="primary" />
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>{t('mariadb_manager.title')}</Typography> <Typography variant="h6" className="font-bold">{t('mariadb_manager.title')}</Typography>
</Box> </Box>
<Stack direction="row" spacing={1.5}> <Stack direction="row" spacing={1.5}>
<FormControl size="small" sx={{ minWidth: 160 }}> <FormControl size="small" sx={{ minWidth: 160 }}>
<InputLabel id="version-select-label" sx={{ fontSize: '0.75rem' }}>{t('mariadb.version')}</InputLabel> <InputLabel id="version-select-label" className="text-sm">{t('mariadb.version')}</InputLabel>
<Select <Select
labelId="version-select-label" labelId="version-select-label"
value={selectedVersion} value={selectedVersion}
label={t('mariadb.version')} label={t('mariadb.version')}
onChange={(e) => setSelectedVersion(e.target.value)} onChange={(e) => setSelectedVersion(e.target.value)}
sx={{ fontSize: '0.75rem', height: 32 }} sx={{ height: 32 }}
className="text-sm"
> >
{installedVersions.map(v => ( {installedVersions.map(v => (
<MenuItem key={v.id} value={v.id} sx={{ fontSize: '0.75rem' }}>MariaDB {v.version}</MenuItem> <MenuItem key={v.id} value={v.id} className="text-sm">MariaDB {v.version}</MenuItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>
<Button variant="outlined" size="small" startIcon={<RefreshIcon sx={{ fontSize: '1rem' }} />} onClick={fetchData} disabled={loading} sx={{ fontSize: '0.7rem', height: 32, borderRadius: 2 }}> <Button variant="outlined" size="small" startIcon={<RefreshIcon sx={{ fontSize: 'var(--font-size-base)' }} />} onClick={fetchData} disabled={loading} sx={{ height: 32 }} className="text-xs rounded-md">
{t('common.refresh')} {t('common.refresh')}
</Button> </Button>
</Stack> </Stack>
</Stack> </Stack>
{!selectedVersion && ( {!selectedVersion && (
<Alert severity="info" sx={{ mt: 2, fontSize: '0.75rem' }}>{t('mariadb_manager.no_active_version')}</Alert> <Alert severity="info" sx={{ mt: 2 }} className="text-sm">{t('mariadb_manager.no_active_version')}</Alert>
)} )}
{selectedVersion && ( {selectedVersion && (
@@ -210,10 +211,10 @@ const MariaDbDatabaseManager: React.FC<MariaDbDatabaseManagerProps> = ({ version
{/* Databases Section */} {/* Databases Section */}
<Box> <Box>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1.5 }}> <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1.5 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 800, color: 'primary.light', fontSize: '0.8rem' }}> <Typography variant="subtitle2" sx={{ color: 'primary.light' }} className="font-black text-md">
{t('mariadb_manager.databases_title')} {t('mariadb_manager.databases_title')}
</Typography> </Typography>
<Button variant="outlined" size="small" startIcon={<AddIcon sx={{ fontSize: '1rem' }} />} onClick={handleCreateDb} sx={{ fontSize: '0.7rem', height: 28, borderRadius: 1.5 }}> <Button variant="outlined" size="small" startIcon={<AddIcon sx={{ fontSize: 'var(--font-size-base)' }} />} onClick={handleCreateDb} sx={{ height: 28 }} className="text-xs rounded-md">
{t('mariadb_manager.create_db_btn')} {t('mariadb_manager.create_db_btn')}
</Button> </Button>
</Box> </Box>
@@ -221,20 +222,20 @@ const MariaDbDatabaseManager: React.FC<MariaDbDatabaseManagerProps> = ({ version
<Table stickyHeader size="small"> <Table stickyHeader size="small">
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell sx={{ bgcolor: '#1a1d21', fontWeight: 800, fontSize: '0.7rem', py: 1 }}>{t('mariadb_manager.db_name')}</TableCell> <TableCell sx={{ bgcolor: '#1a1d21', py: 1 }} className="font-black text-xs">{t('mariadb_manager.db_name')}</TableCell>
<TableCell sx={{ bgcolor: '#1a1d21', fontWeight: 800, fontSize: '0.7rem', py: 1 }}>{t('mariadb_manager.db_size')}</TableCell> <TableCell sx={{ bgcolor: '#1a1d21', py: 1 }} className="font-black text-xs">{t('mariadb_manager.db_size')}</TableCell>
<TableCell sx={{ bgcolor: '#1a1d21', fontWeight: 800, fontSize: '0.7rem', py: 1, textAlign: 'right' }}>{t('common.actions')}</TableCell> <TableCell sx={{ bgcolor: '#1a1d21', py: 1, textAlign: 'right' }} className="font-black text-xs">{t('common.actions')}</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{loading ? ( {loading ? (
<TableRow><TableCell colSpan={3} align="center"><CircularProgress size={20} sx={{ my: 1 }} /></TableCell></TableRow> <TableRow><TableCell colSpan={3} align="center"><CircularProgress size={20} sx={{ my: 1 }} /></TableCell></TableRow>
) : databases.length === 0 ? ( ) : databases.length === 0 ? (
<TableRow><TableCell colSpan={3} align="center" sx={{ py: 2, color: 'text.secondary', fontSize: '0.7rem' }}>{t('common.no_data')}</TableCell></TableRow> <TableRow><TableCell colSpan={3} align="center" sx={{ py: 2 }} className="text-secondary text-xs">{t('common.no_data')}</TableCell></TableRow>
) : databases.map(db => ( ) : databases.map(db => (
<TableRow key={db.name}> <TableRow key={db.name}>
<TableCell sx={{ fontWeight: 600, fontSize: '0.75rem' }}>{db.name}</TableCell> <TableCell className="font-semibold text-sm">{db.name}</TableCell>
<TableCell sx={{ fontSize: '0.7rem', opacity: 0.8 }}>{db.size.toFixed(2)} MB</TableCell> <TableCell className="text-xs" sx={{ opacity: 0.8 }}>{db.size.toFixed(2)} MB</TableCell>
<TableCell align="right" sx={{ py: 0.5 }}> <TableCell align="right" sx={{ py: 0.5 }}>
<Tooltip title={t('common.delete')}> <Tooltip title={t('common.delete')}>
<IconButton color="error" size="small" onClick={() => handleDeleteDb(db.name)} sx={{ p: 0.5 }}> <IconButton color="error" size="small" onClick={() => handleDeleteDb(db.name)} sx={{ p: 0.5 }}>
@@ -257,7 +258,7 @@ const MariaDbDatabaseManager: React.FC<MariaDbDatabaseManagerProps> = ({ version
<Typography variant="subtitle2" sx={{ fontWeight: 800, color: 'secondary.light', fontSize: '0.8rem' }}> <Typography variant="subtitle2" sx={{ fontWeight: 800, color: 'secondary.light', fontSize: '0.8rem' }}>
{t('mariadb_manager.users_title')} {t('mariadb_manager.users_title')}
</Typography> </Typography>
<Button variant="outlined" color="secondary" size="small" startIcon={<AddIcon sx={{ fontSize: '1rem' }} />} onClick={handleCreateUser} sx={{ fontSize: '0.7rem', height: 28, borderRadius: 1.5 }}> <Button variant="outlined" color="secondary" size="small" startIcon={<AddIcon sx={{ fontSize: 'var(--font-size-base)' }} />} onClick={handleCreateUser} sx={{ height: 28 }} className="text-xs rounded-md">
{t('mariadb_manager.create_user_btn')} {t('mariadb_manager.create_user_btn')}
</Button> </Button>
</Box> </Box>
@@ -265,27 +266,27 @@ const MariaDbDatabaseManager: React.FC<MariaDbDatabaseManagerProps> = ({ version
<Table stickyHeader size="small"> <Table stickyHeader size="small">
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell sx={{ bgcolor: '#1a1d21', fontWeight: 800, fontSize: '0.7rem', py: 1 }}>{t('mariadb_manager.user_label')}</TableCell> <TableCell sx={{ bgcolor: '#1a1d21', py: 1 }} className="font-black text-xs">{t('mariadb_manager.user_label')}</TableCell>
<TableCell sx={{ bgcolor: '#1a1d21', fontWeight: 800, fontSize: '0.7rem', py: 1 }}>Host</TableCell> <TableCell sx={{ bgcolor: '#1a1d21', py: 1 }} className="font-black text-xs">Host</TableCell>
<TableCell sx={{ bgcolor: '#1a1d21', fontWeight: 800, fontSize: '0.7rem', py: 1, textAlign: 'right' }}>{t('common.actions')}</TableCell> <TableCell sx={{ bgcolor: '#1a1d21', py: 1, textAlign: 'right' }} className="font-black text-xs">{t('common.actions')}</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{loading ? ( {loading ? (
<TableRow><TableCell colSpan={3} align="center"><CircularProgress size={20} sx={{ my: 1 }} /></TableCell></TableRow> <TableRow><TableCell colSpan={3} align="center"><CircularProgress size={20} sx={{ my: 1 }} /></TableCell></TableRow>
) : users.length === 0 ? ( ) : users.length === 0 ? (
<TableRow><TableCell colSpan={3} align="center" sx={{ py: 2, color: 'text.secondary', fontSize: '0.7rem' }}>{t('common.no_data')}</TableCell></TableRow> <TableRow><TableCell colSpan={3} align="center" sx={{ py: 2 }} className="text-secondary text-xs">{t('common.no_data')}</TableCell></TableRow>
) : users.map(user => ( ) : users.map(user => (
<TableRow key={`${user.user}-${user.host}`}> <TableRow key={`${user.user}-${user.host}`}>
<TableCell sx={{ fontWeight: 600, fontSize: '0.75rem' }}> <TableCell className="font-semibold text-sm">
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> <Box className="flex-align-center" sx={{ gap: 1 }}>
<UserIcon sx={{ opacity: 0.5, fontSize: '0.9rem' }} /> <UserIcon sx={{ fontSize: 'var(--font-size-md)' }} className="text-secondary" />
{user.user} {user.user}
</Box> </Box>
</TableCell> </TableCell>
<TableCell sx={{ fontSize: '0.7rem', opacity: 0.8 }}> <TableCell className="text-xs" sx={{ opacity: 0.8 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> <Box className="flex-align-center" sx={{ gap: 1 }}>
<HostIcon sx={{ opacity: 0.5, fontSize: '0.9rem' }} /> <HostIcon sx={{ fontSize: 'var(--font-size-md)' }} className="text-secondary" />
{user.host} {user.host}
</Box> </Box>
</TableCell> </TableCell>
@@ -219,9 +219,9 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
{!exportResult ? ( {!exportResult ? (
<> <>
<Paper sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.05)', borderRadius: 2 }}> <Paper sx={{ p: 2, bgcolor: 'var(--color-bg-soft)', border: '1px solid var(--color-border-soft)' }} className="rounded-md">
<Typography variant="subtitle2" color="primary" sx={{ fontWeight: 'bold' }}>{t('mariadb.import.summary')}</Typography> <Typography variant="subtitle2" color="primary" className="font-bold">{t('mariadb.import.summary')}</Typography>
<Divider sx={{ my: 1 }} /> <Divider sx={{ my: 1, opacity: 0.05 }} />
<Stack spacing={1}> <Stack spacing={1}>
<Typography variant="body2"><strong>{t('mariadb.import.server')}:</strong> {selectedVersion}</Typography> <Typography variant="body2"><strong>{t('mariadb.import.server')}:</strong> {selectedVersion}</Typography>
<Typography variant="body2"><strong>{t('mariadb.import.db')}:</strong> {selectedDb}</Typography> <Typography variant="body2"><strong>{t('mariadb.import.db')}:</strong> {selectedDb}</Typography>
@@ -230,7 +230,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
</Stack> </Stack>
</Paper> </Paper>
{loading && ( {loading && (
<Box sx={{ mt: 3, p: 2, bgcolor: '#000', borderRadius: 2, maxHeight: '200px', overflowY: 'auto', fontFamily: 'monospace' }}> <Box sx={{ mt: 3, p: 2, bgcolor: 'var(--color-bg-medium)', maxHeight: '200px', overflowY: 'auto', fontFamily: 'monospace' }} className="rounded-md border-soft">
{logs.map((log, i) => ( {logs.map((log, i) => (
<Typography key={i} variant="caption" sx={{ display: 'block', color: log.includes('error') ? 'error.main' : 'success.main' }}> <Typography key={i} variant="caption" sx={{ display: 'block', color: log.includes('error') ? 'error.main' : 'success.main' }}>
{log} {log}
@@ -260,9 +260,9 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
{!importResult ? ( {!importResult ? (
<> <>
<Paper sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.05)', borderRadius: 2 }}> <Paper sx={{ p: 2, bgcolor: 'var(--color-bg-soft)', border: '1px solid var(--color-border-soft)' }} className="rounded-md">
<Typography variant="subtitle2" color="primary" sx={{ fontWeight: 'bold' }}>{t('mariadb.import.summary')}</Typography> <Typography variant="subtitle2" color="primary" className="font-bold">{t('mariadb.import.summary')}</Typography>
<Divider sx={{ my: 1 }} /> <Divider sx={{ my: 1, opacity: 0.05 }} />
<Stack spacing={1}> <Stack spacing={1}>
<Typography variant="body2"><strong>{t('mariadb.import.file')}:</strong> {filePath.split(/[/\\]/).pop()}</Typography> <Typography variant="body2"><strong>{t('mariadb.import.file')}:</strong> {filePath.split(/[/\\]/).pop()}</Typography>
<Typography variant="body2"><strong>{t('mariadb.import.server')}:</strong> {selectedVersion}</Typography> <Typography variant="body2"><strong>{t('mariadb.import.server')}:</strong> {selectedVersion}</Typography>
@@ -271,7 +271,7 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
</Stack> </Stack>
</Paper> </Paper>
{loading && ( {loading && (
<Box sx={{ mt: 3, p: 2, bgcolor: '#000', borderRadius: 2, maxHeight: '200px', overflowY: 'auto', fontFamily: 'monospace' }}> <Box sx={{ mt: 3, p: 2, bgcolor: 'var(--color-bg-medium)', maxHeight: '200px', overflowY: 'auto', fontFamily: 'monospace' }} className="rounded-md border-soft">
{logs.map((log, i) => ( {logs.map((log, i) => (
<Typography key={i} variant="caption" sx={{ display: 'block', color: log.includes('fail') ? 'error.main' : 'success.main' }}> <Typography key={i} variant="caption" sx={{ display: 'block', color: log.includes('fail') ? 'error.main' : 'success.main' }}>
{log} {log}
@@ -288,8 +288,8 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
<SuccessIcon color="success" sx={{ fontSize: 60 }} /> <SuccessIcon color="success" sx={{ fontSize: 60 }} />
<Typography variant="h6" sx={{ mt: 2 }}>{t('mariadb.import.success_title')}</Typography> <Typography variant="h6" sx={{ mt: 2 }}>{t('mariadb.import.success_title')}</Typography>
<Typography variant="body2" color="text.secondary">{importResult.message}</Typography> <Typography variant="body2" color="text.secondary">{importResult.message}</Typography>
<Paper sx={{ p: 2, mt: 3, textAlign: 'left', bgcolor: 'rgba(0,180,0,0.1)' }}> <Paper sx={{ p: 2, mt: 3, textAlign: 'left', bgcolor: 'rgba(0,180,0,0.1)', border: '1px solid rgba(0,180,0,0.2)' }} className="rounded-md">
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>{t('mariadb.import.access_info')}:</Typography> <Typography variant="caption" className="font-bold">{t('mariadb.import.access_info')}:</Typography>
<Typography variant="body2"><strong>{t('mariadb.import.host')}:</strong> localhost</Typography> <Typography variant="body2"><strong>{t('mariadb.import.host')}:</strong> localhost</Typography>
<Typography variant="body2"><strong>{t('mariadb.import.db')}:</strong> {dbConfig.dbName}</Typography> <Typography variant="body2"><strong>{t('mariadb.import.db')}:</strong> {dbConfig.dbName}</Typography>
<Typography variant="body2"><strong>{t('mariadb.import.user')}:</strong> {dbConfig.user}</Typography> <Typography variant="body2"><strong>{t('mariadb.import.user')}:</strong> {dbConfig.user}</Typography>
@@ -168,8 +168,8 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
> >
<DialogTitle sx={{ m: 0, p: 1.5, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> <DialogTitle sx={{ m: 0, p: 1.5, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Box> <Box>
<Typography variant="subtitle2" sx={{ fontWeight: 800 }}>{t('php.extensions.title', { version: phpVersion })}</Typography> <Typography variant="subtitle2" className="font-black">{t('php.extensions.title', { version: phpVersion })}</Typography>
<Typography variant="caption" color="text.secondary" sx={{ fontSize: '0.65rem' }}>{t('php.extensions.desc')}</Typography> <Typography variant="caption" color="text.secondary" className="text-xs">{t('php.extensions.desc')}</Typography>
</Box> </Box>
<IconButton onClick={onClose} size="small" sx={{ color: 'text.secondary' }}> <IconButton onClick={onClose} size="small" sx={{ color: 'text.secondary' }}>
<CloseIcon fontSize="small" /> <CloseIcon fontSize="small" />
@@ -186,18 +186,20 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
InputProps={{ InputProps={{
startAdornment: ( startAdornment: (
<InputAdornment position="start"> <InputAdornment position="start">
<SearchIcon sx={{ color: 'text.secondary', fontSize: '1rem' }} /> <SearchIcon sx={{ color: 'text.secondary', fontSize: 'var(--font-size-base)' }} />
</InputAdornment> </InputAdornment>
), ),
sx: { color: '#fff', bgcolor: 'rgba(0,0,0,0.2)', fontSize: '0.75rem', height: 32 } className: 'text-sm',
sx: { color: '#fff', bgcolor: 'rgba(0,0,0,0.2)', height: 32 }
}} }}
/> />
<Button <Button
variant="outlined" variant="outlined"
size="small" size="small"
startIcon={<RawIcon sx={{ fontSize: '1rem' }} />} startIcon={<RawIcon sx={{ fontSize: 'var(--font-size-base)' }} />}
onClick={fetchRawConfig} onClick={fetchRawConfig}
sx={{ whiteSpace: 'nowrap', borderColor: 'rgba(255,255,255,0.1)', color: 'rgba(255,255,255,0.7)', fontSize: '0.7rem', height: 32, borderRadius: 1.5 }} sx={{ whiteSpace: 'nowrap', borderColor: 'var(--color-border-medium)', color: 'var(--color-text-secondary)', height: 32 }}
className="text-xs rounded-md"
> >
{t('php.extensions.raw_editor')} {t('php.extensions.raw_editor')}
</Button> </Button>
@@ -213,7 +215,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
<ListItem> <ListItem>
<ListItemText <ListItemText
primary={searchTerm ? t('php.extensions.not_found') : t('php.extensions.none')} primary={searchTerm ? t('php.extensions.not_found') : t('php.extensions.none')}
primaryTypographyProps={{ sx: { textAlign: 'center', color: 'text.secondary', fontSize: '0.75rem' } }} primaryTypographyProps={{ className: 'text-sm text-secondary', sx: { textAlign: 'center' } }}
/> />
</ListItem> </ListItem>
) : ( ) : (
@@ -238,13 +240,13 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
> >
<ListItemText <ListItemText
primary={ primary={
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, fontSize: '0.75rem', fontWeight: 600 }}> <Box className="flex-align-center font-semibold text-sm" sx={{ gap: 1 }}>
{ext.name} {ext.name}
{ext.enabled && <Chip label={t('php.extensions.active')} size="small" color="success" sx={{ height: 16, fontSize: '0.55rem', fontWeight: 900 }} />} {ext.enabled && <Chip label={t('php.extensions.active')} size="small" color="success" className="font-black text-xs" sx={{ height: 16 }} />}
</Box> </Box>
} }
secondary={ext.dll} secondary={ext.dll}
secondaryTypographyProps={{ sx: { color: 'text.secondary', fontSize: '0.65rem', opacity: 0.5 } }} secondaryTypographyProps={{ className: 'text-xs text-secondary', sx: { opacity: 0.5 } }}
/> />
</ListItem> </ListItem>
)) ))
@@ -253,10 +255,10 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
)} )}
</DialogContent> </DialogContent>
<DialogActions sx={{ p: 1.5, bgcolor: 'rgba(255,255,255,0.01)' }}> <DialogActions sx={{ p: 1.5, bgcolor: 'rgba(255,255,255,0.01)' }}>
<Button onClick={fetchExtensions} size="small" startIcon={<RefreshIcon sx={{ fontSize: '0.9rem' }} />} sx={{ mr: 'auto', fontSize: '0.7rem' }}> <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>
<Button onClick={onClose} variant="outlined" size="small" sx={{ fontSize: '0.7rem', borderRadius: 1.5 }}> <Button onClick={onClose} variant="outlined" size="small" className="text-xs rounded-md">
{t('common.close').toUpperCase()} {t('common.close').toUpperCase()}
</Button> </Button>
</DialogActions> </DialogActions>
@@ -273,18 +275,18 @@ 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" sx={{ fontWeight: 800 }}>{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: 'rgba(255,255,255,0.5)' }}>
<CloseIcon fontSize="small" /> <CloseIcon fontSize="small" />
</IconButton> </IconButton>
</Box> </Box>
<Typography <Typography
variant="caption" variant="caption"
className="text-xs"
sx={{ sx={{
color: 'primary.main', color: 'primary.main',
wordBreak: 'break-all', wordBreak: 'break-all',
cursor: 'pointer', cursor: 'pointer',
fontSize: '0.6rem',
opacity: 0.7, opacity: 0.7,
'&:hover': { textDecoration: 'underline', color: 'primary.light' } '&:hover': { textDecoration: 'underline', color: 'primary.light' }
}} }}
@@ -304,15 +306,15 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
InputProps={{ InputProps={{
startAdornment: ( startAdornment: (
<InputAdornment position="start"> <InputAdornment position="start">
<SearchIcon sx={{ color: 'text.secondary', fontSize: '1rem' }} /> <SearchIcon sx={{ color: 'text.secondary', fontSize: 'var(--font-size-base)' }} />
</InputAdornment> </InputAdornment>
), ),
className: 'text-sm',
sx: { sx: {
color: '#fff', color: '#fff',
bgcolor: 'rgba(255,255,255,0.03)', bgcolor: 'rgba(255,255,255,0.03)',
fontSize: '0.75rem',
height: 32, height: 32,
'& fieldset': { borderColor: 'rgba(255,255,255,0.05)' } '& fieldset': { borderColor: 'var(--color-border-soft)' }
} }
}} }}
/> />
@@ -324,7 +326,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
/> />
</DialogContent> </DialogContent>
<DialogActions sx={{ p: 1.5, bgcolor: 'rgba(0,0,0,0.1)' }}> <DialogActions sx={{ p: 1.5, bgcolor: 'rgba(0,0,0,0.1)' }}>
<Button onClick={() => setIsRawEditorOpen(false)} size="small" sx={{ color: 'rgba(255,255,255,0.4)', fontSize: '0.7rem' }}> <Button onClick={() => setIsRawEditorOpen(false)} size="small" className="text-secondary text-xs">
{t('common.cancel').toUpperCase()} {t('common.cancel').toUpperCase()}
</Button> </Button>
<Button <Button
@@ -332,9 +334,10 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
variant="outlined" variant="outlined"
color="primary" color="primary"
size="small" size="small"
startIcon={isSavingRaw ? <CircularProgress size={14} color="inherit" /> : <SaveIcon sx={{ fontSize: '1rem' }} />} startIcon={isSavingRaw ? <CircularProgress size={14} color="inherit" /> : <SaveIcon sx={{ fontSize: 'var(--font-size-base)' }} />}
disabled={isSavingRaw} disabled={isSavingRaw}
sx={{ fontSize: '0.7rem', borderRadius: 1.5, px: 2 }} className="text-xs rounded-md"
sx={{ px: 2 }}
> >
{isSavingRaw ? t('php.extensions.saving_btn') : t('php.extensions.save_restart_btn')} {isSavingRaw ? t('php.extensions.saving_btn') : t('php.extensions.save_restart_btn')}
</Button> </Button>
@@ -201,7 +201,7 @@ export default function ProjectDetails({
return ( return (
<Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', opacity: 0.3 }}> <Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', opacity: 0.3 }}>
<ProjectIcon sx={{ fontSize: 80, mb: 2 }} /> <ProjectIcon sx={{ fontSize: 80, mb: 2 }} />
<Typography variant="h6">{t('projects.no_project_selected')}</Typography> <Typography variant="h6" className="font-semibold">{t('projects.no_project_selected')}</Typography>
</Box> </Box>
); );
} }
@@ -218,14 +218,14 @@ export default function ProjectDetails({
<Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column', bgcolor: 'rgba(255,255,255,0.01)', height: '100%', overflow: 'hidden', position: 'relative' }}> <Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column', bgcolor: 'rgba(255,255,255,0.01)', height: '100%', overflow: 'hidden', position: 'relative' }}>
{/* Header */} {/* Header */}
<Box sx={{ p: 4, borderBottom: '1px solid rgba(255,255,255,0.05)', display: 'flex', alignItems: 'flex-start', gap: 3, position: 'relative' }}> <Box sx={{ p: 4, borderBottom: '1px solid rgba(255,255,255,0.05)', display: 'flex', alignItems: 'flex-start', gap: 3, position: 'relative' }}>
<Avatar sx={{ bgcolor: 'rgba(57, 167, 255, 0.1)', color: 'primary.main', width: 64, height: 64, borderRadius: 3, border: '1px solid rgba(57, 167, 255, 0.2)' }}> <Avatar sx={{ bgcolor: 'rgba(57, 167, 255, 0.1)', color: 'primary.main', width: 64, height: 64, border: '1px solid var(--color-border-soft)' }} className="rounded-lg">
<ProjectIcon sx={{ fontSize: 32 }} /> <ProjectIcon sx={{ fontSize: 32 }} />
</Avatar> </Avatar>
<Box sx={{ flexGrow: 1 }}> <Box sx={{ flexGrow: 1 }}>
<Box sx={{ mb: 2.5 }}> <Box sx={{ mb: 2.5 }}>
<Typography variant="h4" sx={{ fontWeight: 800, letterSpacing: '-0.02em', mb: 0.5 }}>{p.name}</Typography> <Typography variant="h4" sx={{ letterSpacing: '-0.02em', mb: 0.5 }} className="font-black">{p.name}</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.4)', fontFamily: 'monospace' }}> <Typography variant="body2" sx={{ fontFamily: 'monospace' }} className="text-secondary">
{p.path} {p.path}
</Typography> </Typography>
<Tooltip title={t('projects.open_folder')}> <Tooltip title={t('projects.open_folder')}>
@@ -263,7 +263,8 @@ export default function ProjectDetails({
size="small" size="small"
startIcon={<LaunchIcon sx={{ fontSize: '1rem !important' }} />} startIcon={<LaunchIcon sx={{ fontSize: '1rem !important' }} />}
onClick={() => onOpenSite(isHostMapped)} onClick={() => onOpenSite(isHostMapped)}
sx={{ px: 2, height: 32, borderRadius: 1.5, fontWeight: 600, fontSize: '0.75rem', borderColor: 'rgba(255,255,255,0.1)', '&:hover': { borderColor: 'primary.main', bgcolor: 'rgba(57, 167, 255, 0.05)' } }} sx={{ px: 2, height: 32, borderColor: 'var(--color-border-medium)', '&:hover': { borderColor: 'primary.main', bgcolor: 'rgba(57, 167, 255, 0.05)' } }}
className="rounded-md font-semibold text-sm"
> >
{t('projects.open_site').toUpperCase()} {t('projects.open_site').toUpperCase()}
</Button> </Button>
@@ -320,9 +321,9 @@ export default function ProjectDetails({
{/* Tabs */} {/* Tabs */}
<Box sx={{ borderBottom: 1, borderColor: 'rgba(255,255,255,0.05)', px: 4, bgcolor: 'rgba(255,255,255,0.01)' }}> <Box sx={{ borderBottom: 1, borderColor: 'rgba(255,255,255,0.05)', px: 4, bgcolor: 'rgba(255,255,255,0.01)' }}>
<Tabs value={projectDetailTab} onChange={(_e, v) => setProjectDetailTab(v)} textColor="primary" indicatorColor="primary"> <Tabs value={projectDetailTab} onChange={(_e, v) => setProjectDetailTab(v)} textColor="primary" indicatorColor="primary">
<Tab label={t('projects.overview')} sx={{ fontWeight: 700, py: 2.5, minWidth: 120, fontSize: '0.8rem' }} /> <Tab label={t('projects.overview').toUpperCase()} className="font-bold text-md" sx={{ py: 2.5, minWidth: 120 }} />
<Tab label={t('projects.database')} sx={{ fontWeight: 700, py: 2.5, minWidth: 120, fontSize: '0.8rem' }} /> <Tab label={t('projects.database').toUpperCase()} className="font-bold text-md" sx={{ py: 2.5, minWidth: 120 }} />
<Tab label={t('projects.server_settings')} sx={{ fontWeight: 700, py: 2.5, minWidth: 120, fontSize: '0.8rem' }} /> <Tab label={t('projects.server_settings').toUpperCase()} className="font-bold text-md" sx={{ py: 2.5, minWidth: 120 }} />
</Tabs> </Tabs>
</Box> </Box>
+14 -14
View File
@@ -258,10 +258,10 @@ export default function ServerTuning() {
return ( return (
<Box> <Box>
<Box sx={{ mb: 4 }}> <Box sx={{ mb: 4 }}>
<Typography variant="h4" sx={{ fontWeight: 800, mb: 1, color: 'primary.light' }}> <Typography variant="h4" sx={{ mb: 1, color: 'primary.light' }} className="font-black">
{t('tuning.title')} {t('tuning.title')}
</Typography> </Typography>
<Typography variant="body1" sx={{ color: 'rgba(255,255,255,0.6)' }}> <Typography variant="body1" className="text-secondary">
{t('tuning.desc')} {t('tuning.desc')}
</Typography> </Typography>
</Box> </Box>
@@ -269,22 +269,22 @@ export default function ServerTuning() {
<Grid container spacing={4}> <Grid container spacing={4}>
{/* PHP Section */} {/* PHP Section */}
<Grid item xs={12} md={6}> <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)' }}> <Paper sx={{ p: 3, height: '100%', bgcolor: 'var(--color-bg-soft)', border: '1px solid var(--color-border-soft)' }} className="rounded-xl">
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3, gap: 2 }}> <Box sx={{ display: 'flex', alignItems: 'center', mb: 3, gap: 2 }}>
<Box sx={{ p: 1.5, borderRadius: 2, bgcolor: 'primary.main', display: 'flex' }}> <Box sx={{ p: 1.5, borderRadius: 2, bgcolor: 'primary.main', display: 'flex' }}>
<PhpIcon sx={{ color: 'white' }} /> <PhpIcon sx={{ color: 'white' }} />
</Box> </Box>
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>PHP Tuning</Typography> <Typography variant="h6" className="font-bold">PHP Tuning</Typography>
<Chip label={phpVersions.length} size="small" variant="outlined" /> <Chip label={phpVersions.length} size="small" variant="outlined" />
</Box> </Box>
<Stack spacing={2}> <Stack spacing={2}>
{phpVersions.map(v => ( {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)' }}> <Card key={v.id} sx={{ bgcolor: 'var(--color-bg-soft)', backgroundImage: 'none', border: '1px solid var(--color-border-soft)' }}>
<CardActionArea onClick={() => handleOpenTuning(v, 'php')}> <CardActionArea onClick={() => handleOpenTuning(v, 'php')}>
<CardContent sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> <CardContent sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Box> <Box>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>PHP {v.version}</Typography> <Typography variant="subtitle1" className="font-bold">PHP {v.version}</Typography>
<Typography variant="caption" color="text.secondary">php.ini optimization</Typography> <Typography variant="caption" color="text.secondary">php.ini optimization</Typography>
</Box> </Box>
<Button variant="outlined" size="small" startIcon={<TuneIcon />}> <Button variant="outlined" size="small" startIcon={<TuneIcon />}>
@@ -300,22 +300,22 @@ export default function ServerTuning() {
{/* MariaDB Section */} {/* MariaDB Section */}
<Grid item xs={12} md={6}> <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)' }}> <Paper sx={{ p: 3, height: '100%', bgcolor: 'var(--color-bg-soft)', border: '1px solid var(--color-border-soft)' }} className="rounded-xl">
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3, gap: 2 }}> <Box sx={{ display: 'flex', alignItems: 'center', mb: 3, gap: 2 }}>
<Box sx={{ p: 1.5, borderRadius: 2, bgcolor: 'secondary.main', display: 'flex' }}> <Box sx={{ p: 1.5, borderRadius: 2, bgcolor: 'secondary.main', display: 'flex' }}>
<DbIcon sx={{ color: 'white' }} /> <DbIcon sx={{ color: 'white' }} />
</Box> </Box>
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>MariaDB Tuning</Typography> <Typography variant="h6" className="font-bold">MariaDB Tuning</Typography>
<Chip label={mariaDbVersions.length} size="small" variant="outlined" /> <Chip label={mariaDbVersions.length} size="small" variant="outlined" />
</Box> </Box>
<Stack spacing={2}> <Stack spacing={2}>
{mariaDbVersions.map(v => ( {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)' }}> <Card key={v.id} sx={{ bgcolor: 'var(--color-bg-soft)', backgroundImage: 'none', border: '1px solid var(--color-border-soft)' }}>
<CardActionArea onClick={() => handleOpenTuning(v, 'mariadb')}> <CardActionArea onClick={() => handleOpenTuning(v, 'mariadb')}>
<CardContent sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> <CardContent sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Box> <Box>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>MariaDB {v.version}</Typography> <Typography variant="subtitle1" className="font-bold">MariaDB {v.version}</Typography>
<Typography variant="caption" color="text.secondary">Performance variables</Typography> <Typography variant="caption" color="text.secondary">Performance variables</Typography>
</Box> </Box>
<Button variant="outlined" color="secondary" size="small" startIcon={<TuneIcon />}> <Button variant="outlined" color="secondary" size="small" startIcon={<TuneIcon />}>
@@ -343,7 +343,7 @@ export default function ServerTuning() {
<DialogTitle sx={{ borderBottom: '1px solid rgba(255,255,255,0.1)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> <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 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
<TuneIcon color={selectedVersion?.type === 'php' ? 'primary' : 'secondary'} /> <TuneIcon color={selectedVersion?.type === 'php' ? 'primary' : 'secondary'} />
<Typography variant="h6" sx={{ fontWeight: 800 }}> <Typography variant="h6" className="font-black">
{selectedVersion?.type === 'php' ? `PHP ${selectedVersion?.version}` : `MariaDB ${selectedVersion?.version}`} Tuning {selectedVersion?.type === 'php' ? `PHP ${selectedVersion?.version}` : `MariaDB ${selectedVersion?.version}`} Tuning
</Typography> </Typography>
</Box> </Box>
@@ -362,7 +362,7 @@ export default function ServerTuning() {
<Box key={p.key}> <Box key={p.key}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1, alignItems: 'center' }}> <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1, alignItems: 'center' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 'bold' }}>{p.label}</Typography> <Typography variant="subtitle2" className="font-bold">{p.label}</Typography>
<Tooltip title={t(p.description)}> <Tooltip title={t(p.description)}>
<InfoIcon sx={{ fontSize: 16, color: 'rgba(255,255,255,0.3)', cursor: 'help' }} /> <InfoIcon sx={{ fontSize: 16, color: 'rgba(255,255,255,0.3)', cursor: 'help' }} />
</Tooltip> </Tooltip>
@@ -372,7 +372,7 @@ export default function ServerTuning() {
value={tuningValues[p.key]} value={tuningValues[p.key]}
onChange={(e) => setTuningValues({ ...tuningValues, [p.key]: parseInt(e.target.value) || p.min })} onChange={(e) => setTuningValues({ ...tuningValues, [p.key]: parseInt(e.target.value) || p.min })}
InputProps={{ InputProps={{
endAdornment: <Typography variant="caption" sx={{ ml: 1, opacity: 0.5 }}>{p.unit}</Typography> endAdornment: <Typography variant="caption" sx={{ ml: 1 }} className="text-secondary">{p.unit}</Typography>
} as any} } as any}
sx={{ width: 120, '& .MuiOutlinedInput-root': { height: 32 } }} sx={{ width: 120, '& .MuiOutlinedInput-root': { height: 32 } }}
/> />
@@ -391,7 +391,7 @@ export default function ServerTuning() {
} }
}} }}
/> />
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.4)', mt: -1, display: 'block' }}> <Typography variant="caption" className="text-muted" sx={{ mt: -1, display: 'block' }}>
{t(p.description)} {t(p.description)}
</Typography> </Typography>
</Box> </Box>
+48
View File
@@ -1,6 +1,54 @@
import { GlobalStyles as MuiGlobalStyles } from '@mui/material' import { GlobalStyles as MuiGlobalStyles } from '@mui/material'
const styles = { const styles = {
':root': {
'--font-size-xs': '0.65rem',
'--font-size-sm': '1rem',
'--font-size-md': '0.85rem',
'--font-size-base': '1rem',
'--font-size-lg': '1.25rem',
'--font-size-xl': '1.5rem',
'--font-weight-thin': '300',
'--font-weight-normal': '400',
'--font-weight-medium': '500',
'--font-weight-semibold': '600',
'--font-weight-bold': '700',
'--font-weight-black': '800',
'--radius-sm': '4px',
'--radius-md': '8px',
'--radius-lg': '12px',
'--radius-xl': '16px',
'--color-border-soft': 'rgba(255, 255, 255, 0.05)',
'--color-border-medium': 'rgba(255, 255, 255, 0.1)',
'--color-text-secondary': 'rgba(255, 255, 255, 0.5)',
'--color-text-muted': 'rgba(255, 255, 255, 0.3)',
'--color-bg-soft': 'rgba(255, 255, 255, 0.03)',
'--color-bg-medium': 'rgba(0, 0, 0, 0.2)',
},
'.text-xs': { fontSize: 'var(--font-size-xs) !important' },
'.text-sm': { fontSize: 'var(--font-size-sm) !important' },
'.text-md': { fontSize: 'var(--font-size-md) !important' },
'.text-base': { fontSize: 'var(--font-size-base) !important' },
'.text-lg': { fontSize: 'var(--font-size-lg) !important' },
'.text-xl': { fontSize: 'var(--font-size-xl) !important' },
'.font-normal': { fontWeight: 'var(--font-weight-normal) !important' },
'.font-medium': { fontWeight: 'var(--font-weight-medium) !important' },
'.font-semibold': { fontWeight: 'var(--font-weight-semibold) !important' },
'.font-bold': { fontWeight: 'var(--font-weight-bold) !important' },
'.font-black': { fontWeight: 'var(--font-weight-black) !important' },
'.text-secondary': { color: 'var(--color-text-secondary) !important' },
'.text-muted': { color: 'var(--color-text-muted) !important' },
'.border-soft': { border: '1px solid var(--color-border-soft) !important' },
'.border-medium': { border: '1px solid var(--color-border-medium) !important' },
'.bg-soft': { backgroundColor: 'var(--color-bg-soft) !important' },
'.bg-medium': { backgroundColor: 'var(--color-bg-medium) !important' },
'.rounded-sm': { borderRadius: 'var(--radius-sm) !important' },
'.rounded-md': { borderRadius: 'var(--radius-md) !important' },
'.rounded-lg': { borderRadius: 'var(--radius-lg) !important' },
'.rounded-xl': { borderRadius: 'var(--radius-xl) !important' },
'.flex-center': { display: 'flex', alignItems: 'center', justifyContent: 'center' },
'.flex-between': { display: 'flex', alignItems: 'center', justifyContent: 'space-between' },
'.flex-align-center': { display: 'flex', alignItems: 'center' },
'html, body, #root': { 'html, body, #root': {
margin: 0, margin: 0,
padding: 0, padding: 0,