feat: implement MariaDB export wizard and add localization support
This commit is contained in:
+181
-193
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useState, useEffect, useRef, useMemo } from 'react'
|
||||
import logo from './assets/logo.svg'
|
||||
import {
|
||||
Box,
|
||||
@@ -72,6 +72,7 @@ import {
|
||||
} from '@mui/icons-material'
|
||||
import Swal from 'sweetalert2'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { supportedLngs } from './i18n'
|
||||
import MariaDbImportWizard from './components/MariaDbImportWizard'
|
||||
import MariaDbExportWizard from './components/MariaDbExportWizard'
|
||||
import NginxCodeEditor from './components/NginxCodeEditor'
|
||||
@@ -346,10 +347,10 @@ function App(): JSX.Element {
|
||||
|
||||
if (!result.success) {
|
||||
Swal.fire({
|
||||
title: 'Hata!',
|
||||
title: t('common.error'),
|
||||
text: result.message,
|
||||
icon: 'error',
|
||||
confirmButtonText: 'Tamam',
|
||||
confirmButtonText: t('common.ok'),
|
||||
background: '#1e1e1e',
|
||||
color: '#fff',
|
||||
confirmButtonColor: '#153E5E',
|
||||
@@ -374,12 +375,12 @@ function App(): JSX.Element {
|
||||
|
||||
const handleResetData = async (service: string) => {
|
||||
const confirmResult = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: `${service} verilerini sıfırlamak istiyor musunuz? Bu işlem tüm verileri siler ve temiz kurulum yapar.`,
|
||||
title: t('common.reset_confirm_title'),
|
||||
text: t('common.reset_confirm_text', { service }),
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Sıfırla',
|
||||
cancelButtonText: 'Vazgeç',
|
||||
confirmButtonText: t('common.reset_btn'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
background: '#1e1e1e',
|
||||
color: '#fff',
|
||||
confirmButtonColor: '#d33',
|
||||
@@ -389,7 +390,7 @@ function App(): JSX.Element {
|
||||
if (confirmResult.isConfirmed) {
|
||||
const result = await window.api.invoke('services:reset-data', service)
|
||||
Swal.fire({
|
||||
title: result.success ? 'Başarılı!' : 'Hata!',
|
||||
title: result.success ? t('common.success') : t('common.error'),
|
||||
text: result.message,
|
||||
icon: result.success ? 'success' : 'error',
|
||||
background: '#1e1e1e',
|
||||
@@ -403,14 +404,15 @@ function App(): JSX.Element {
|
||||
if (window.api && window.api.saveSettings) {
|
||||
const result = await window.api.saveSettings(settings)
|
||||
if (result.success) {
|
||||
setNotification({ open: true, message: 'Ayarlar kaydedildi.', severity: 'success' })
|
||||
setNotification({ open: true, message: t('settings.saved'), severity: 'success' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const toggleLanguage = () => {
|
||||
const newLang = i18n.language === 'tr' ? 'en' : i18n.language === 'en' ? 'de' : 'tr'
|
||||
const handleLanguageChange = (event: any) => {
|
||||
const newLang = event.target.value
|
||||
i18n.changeLanguage(newLang)
|
||||
setSettings(prev => ({ ...prev, language: newLang }))
|
||||
}
|
||||
|
||||
const handleStartAll = async () => {
|
||||
@@ -437,7 +439,7 @@ function App(): JSX.Element {
|
||||
])
|
||||
|
||||
fetchStatus()
|
||||
setNotification({ open: true, message: 'Tüm servisler başlatıldı.', severity: 'success' })
|
||||
setNotification({ open: true, message: t('dashboard.all_started'), severity: 'success' })
|
||||
}
|
||||
|
||||
const handleStopAll = async () => {
|
||||
@@ -454,12 +456,12 @@ function App(): JSX.Element {
|
||||
])
|
||||
|
||||
fetchStatus()
|
||||
setNotification({ open: true, message: 'Tüm servisler durduruldu.', severity: 'success' })
|
||||
setNotification({ open: true, message: t('dashboard.all_stopped'), severity: 'success' })
|
||||
}
|
||||
|
||||
const getStatusChip = (s: string) => {
|
||||
if (s === 'starting') {
|
||||
return <Chip label="BAŞLATILIYOR..." color="warning" size="small" sx={{ fontWeight: 'bold' }} icon={<CircularProgress size={14} color="inherit" />} />
|
||||
return <Chip label={t('common.starting')} color="warning" size="small" sx={{ fontWeight: 'bold' }} icon={<CircularProgress size={14} color="inherit" />} />
|
||||
}
|
||||
const color = s === 'running' ? 'success' : s === 'stopped' ? 'error' : 'warning'
|
||||
return <Chip label={s.toUpperCase()} color={color} size="small" sx={{ fontWeight: 'bold' }} />
|
||||
@@ -474,28 +476,28 @@ function App(): JSX.Element {
|
||||
}
|
||||
setIsProjectDialogOpen(false)
|
||||
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost' })
|
||||
setNotification({ open: true, message: newProject.id ? 'Proje güncellendi.' : 'Proje başarıyla eklendi.', severity: 'success' })
|
||||
setNotification({ open: true, message: newProject.id ? t('projects.updated') : t('projects.added'), severity: 'success' })
|
||||
fetchProjects()
|
||||
}
|
||||
|
||||
const handleRemoveProject = async (id: string) => {
|
||||
if (!window.api) return
|
||||
const result = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: "Bu projeyi silmek istediğinize emin misiniz? Nginx ayarları otomatik olarak güncellenecektir.",
|
||||
title: t('common.are_you_sure'),
|
||||
text: t('projects.delete_confirm'),
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#ff4444',
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Evet, sil!',
|
||||
cancelButtonText: 'İptal',
|
||||
confirmButtonText: t('common.yes_delete'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
background: '#1e1e1e',
|
||||
color: '#fff'
|
||||
})
|
||||
|
||||
if (result.isConfirmed) {
|
||||
await window.api.removeProject(id)
|
||||
setNotification({ open: true, message: 'Proje silindi. Nginx yeniden yüklendi.', severity: 'success' })
|
||||
setNotification({ open: true, message: t('projects.deleted'), severity: 'success' })
|
||||
fetchProjects()
|
||||
}
|
||||
}
|
||||
@@ -512,7 +514,7 @@ function App(): JSX.Element {
|
||||
if (window.api && window.api.invoke) {
|
||||
const result = await window.api.invoke('nginx:config:save', nginxConfig)
|
||||
if (result.success) {
|
||||
setNotification({ open: true, message: 'Nginx yapılandırması kaydedildi ve yeniden yüklendi.', severity: 'success' })
|
||||
setNotification({ open: true, message: t('server.nginx.config_saved'), severity: 'success' })
|
||||
setIsNginxConfigOpen(false)
|
||||
}
|
||||
}
|
||||
@@ -530,7 +532,7 @@ function App(): JSX.Element {
|
||||
if (window.api && window.api.invoke) {
|
||||
const result = await window.api.invoke('apache:config:save', apacheConfig)
|
||||
if (result.success) {
|
||||
setNotification({ open: true, message: 'Apache yapılandırması kaydedildi ve yeniden yüklendi.', severity: 'success' })
|
||||
setNotification({ open: true, message: t('server.apache.config_saved'), severity: 'success' })
|
||||
setIsApacheConfigOpen(false)
|
||||
}
|
||||
}
|
||||
@@ -577,15 +579,15 @@ function App(): JSX.Element {
|
||||
${errorInfo?.host ? `
|
||||
<div style="margin-top: 15px; text-align: center;">
|
||||
<p style="font-size: 0.9rem; color: #ffb142;">
|
||||
<b>Sorunlu Proje:</b> ${errorInfo.host} (Satır: ${errorInfo.line})
|
||||
<b>{t('common.error')}:</b> ${errorInfo.host} (Satır: ${errorInfo.line})
|
||||
</p>
|
||||
</div>
|
||||
` : ''}
|
||||
`,
|
||||
icon: result.success ? 'success' : 'error',
|
||||
showCancelButton: !result.success && !!errorInfo?.host,
|
||||
confirmButtonText: !result.success && errorInfo?.host ? 'Düzeltmeye Git' : 'Tamam',
|
||||
cancelButtonText: 'Kapat',
|
||||
confirmButtonText: !result.success && errorInfo?.host ? t('common.go_to_fix') : t('common.ok'),
|
||||
cancelButtonText: t('common.close'),
|
||||
background: '#1e1e1e',
|
||||
color: '#fff',
|
||||
width: '600px'
|
||||
@@ -611,7 +613,7 @@ function App(): JSX.Element {
|
||||
if (window.api && window.api.invoke) {
|
||||
const result = await window.api.invoke('project:nginx:save', selectedProjectHost, projectNginxConfig)
|
||||
if (result.success) {
|
||||
setNotification({ open: true, message: `${selectedProjectHost} için Nginx yapılandırması kaydedildi.`, severity: 'success' })
|
||||
setNotification({ open: true, message: t('server.nginx.config_saved'), severity: 'success' })
|
||||
setIsProjectNginxConfigOpen(false)
|
||||
}
|
||||
}
|
||||
@@ -668,10 +670,9 @@ function App(): JSX.Element {
|
||||
try {
|
||||
const success = await window.api.pmaSetup()
|
||||
if (success) {
|
||||
setPmaInstalled(true)
|
||||
setNotification({ open: true, message: 'phpMyAdmin başarıyla kuruldu.', severity: 'success' })
|
||||
setNotification({ open: true, message: t('server.phpmyadmin.installed_success'), severity: 'success' })
|
||||
} else {
|
||||
setNotification({ open: true, message: 'phpMyAdmin kurulumu sırasında hata oluştu.', severity: 'error' })
|
||||
setNotification({ open: true, message: t('server.phpmyadmin.installed_error'), severity: 'error' })
|
||||
}
|
||||
} finally {
|
||||
setPmaLoading(false)
|
||||
@@ -718,12 +719,28 @@ function App(): JSX.Element {
|
||||
backdropFilter: 'blur(10px)'
|
||||
}}
|
||||
>
|
||||
<Toolbar sx={{ justifyContent: 'flex-end' }}>
|
||||
<Tooltip title="Dil Değiştir">
|
||||
<IconButton onClick={toggleLanguage} color="inherit">
|
||||
<LanguageIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Toolbar sx={{ gap: 2 }}>
|
||||
<FormControl size="small" variant="outlined" sx={{ minWidth: 120 }}>
|
||||
<Select
|
||||
value={i18n.language}
|
||||
onChange={handleLanguageChange}
|
||||
displayEmpty
|
||||
IconComponent={LanguageIcon}
|
||||
sx={{
|
||||
color: 'white',
|
||||
'.MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.3)' },
|
||||
'&:hover .MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.5)' },
|
||||
'&.Mui-focused .MuiOutlinedInput-notchedOutline': { borderColor: 'primary.main' },
|
||||
'.MuiSelect-icon': { color: 'white' }
|
||||
}}
|
||||
>
|
||||
{supportedLngs.map(lang => (
|
||||
<MenuItem key={lang} value={lang}>
|
||||
{lang.toUpperCase()}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<IconButton color="inherit" onClick={() => setActiveTab('settings')}>
|
||||
<SettingsIcon />
|
||||
</IconButton>
|
||||
@@ -747,19 +764,19 @@ function App(): JSX.Element {
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton selected={activeTab === 'dashboard'} onClick={() => setActiveTab('dashboard')}>
|
||||
<ListItemIcon><DashboardIcon color={activeTab === 'dashboard' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||
<ListItemText primary="Dashboard" />
|
||||
<ListItemText primary={t('dashboard.title')} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton selected={activeTab === 'projects'} onClick={() => setActiveTab('projects')}>
|
||||
<ListItemIcon><ProjectIcon color={activeTab === 'projects' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||
<ListItemText primary="Projeler" />
|
||||
<ListItemText primary={t('projects.title')} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton selected={activeTab === 'tools'} onClick={() => setActiveTab('tools')}>
|
||||
<ListItemIcon><ToolsIcon color={activeTab === 'tools' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||
<ListItemText primary="Araçlar" />
|
||||
<ListItemText primary={t('common.tools')} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
@@ -768,7 +785,7 @@ function App(): JSX.Element {
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton selected={activeTab === 'settings'} onClick={() => setActiveTab('settings')}>
|
||||
<ListItemIcon><SettingsIcon color={activeTab === 'settings' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||
<ListItemText primary="Genel Ayarlar" />
|
||||
<ListItemText primary={t('settings.general')} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
@@ -788,19 +805,19 @@ function App(): JSX.Element {
|
||||
<Tab label="MariaDB" icon={<DbIcon />} iconPosition="start" />
|
||||
<Tab label="Nginx" icon={<WebIcon />} iconPosition="start" />
|
||||
<Tab label="Apache" icon={<ServerIcon />} iconPosition="start" />
|
||||
<Tab label="Sunucu Ayarları" icon={<ServerIcon />} iconPosition="start" />
|
||||
<Tab label={t('settings.server_settings')} icon={<ServerIcon />} iconPosition="start" />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
{settingsTab === 0 && (
|
||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
||||
<Box sx={{ p: 2, borderBottom: '1px solid rgba(255, 255, 255, 0.05)' }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>PHP Sürümleri</Typography>
|
||||
<Typography variant="body2" color="text.secondary">Gereken PHP sürümlerini buradan indirebilir ve yönetebilirsiniz.</Typography>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.php_versions')}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">{t('settings.php_versions_desc')}</Typography>
|
||||
</Box>
|
||||
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||
{phpVersions.length === 0 && (
|
||||
<ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem>
|
||||
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||
)}
|
||||
{phpVersions.map((v) => (
|
||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||
@@ -809,13 +826,13 @@ function App(): JSX.Element {
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={`PHP ${v.version}`}
|
||||
secondary={v.status === 'downloading' ? `İndiriliyor... %${Math.round(v.progress)}` : v.status === 'installed' ? 'Kurulu' : 'İndirilebilir'}
|
||||
secondary={v.status === 'downloading' ? `${t('common.loading')} %${Math.round(v.progress)}` : v.status === 'installed' ? t('php.extensions.active') : t('common.available')}
|
||||
sx={{ flexGrow: 1 }}
|
||||
/>
|
||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||
{v.status === 'available' && (
|
||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadPhp(v.id)}>
|
||||
İNDİR
|
||||
{t('common.download')}
|
||||
</Button>
|
||||
)}
|
||||
{v.status === 'downloading' && (
|
||||
@@ -826,9 +843,9 @@ function App(): JSX.Element {
|
||||
{v.status === 'installed' && (
|
||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||
<Button variant="outlined" size="small" startIcon={<ToolsIcon />} onClick={() => handleOpenPhpExtensions(v.version)}>
|
||||
EKLENTİLER
|
||||
{t('php.extensions.title', { version: '' }).replace(' ', ' ')}
|
||||
</Button>
|
||||
<Chip label="HAZIR" color="success" variant="outlined" size="small" />
|
||||
<Chip label={t('common.ok').toUpperCase()} color="success" variant="outlined" size="small" />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
@@ -841,12 +858,12 @@ function App(): JSX.Element {
|
||||
{settingsTab === 1 && (
|
||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
||||
<Box sx={{ p: 2, borderBottom: '1px solid rgba(255, 255, 255, 0.05)' }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>MariaDB Sürümleri</Typography>
|
||||
<Typography variant="body2" color="text.secondary">Farklı MariaDB sürümlerini indirebilir ve sunucunuzda kullanabilirsiniz.</Typography>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.mariadb_versions')}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">{t('settings.mariadb_versions_desc')}</Typography>
|
||||
</Box>
|
||||
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||
{mariaDbVersions.length === 0 && (
|
||||
<ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem>
|
||||
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||
)}
|
||||
{mariaDbVersions.map((v) => (
|
||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||
@@ -854,15 +871,8 @@ function App(): JSX.Element {
|
||||
{v.status === 'installed' ? <InstalledIcon color="success" /> : <AvailableIcon color="action" />}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{`MariaDB ${v.version} (${v.cycle})`}
|
||||
{v.description && (
|
||||
<Chip label={v.description} size="small" variant="outlined" sx={{ fontSize: '0.7rem', height: 20 }} />
|
||||
)}
|
||||
</Box>
|
||||
}
|
||||
secondary={v.status === 'downloading' ? `İndiriliyor... %${Math.round(v.progress)}` : v.status === 'installed' ? 'Kurulu' : 'İndirilebilir'}
|
||||
primary={`MariaDB ${v.version}`}
|
||||
secondary={v.status === 'downloading' ? `${t('common.loading')} %${Math.round(v.progress)}` : v.status === 'installed' ? t('php.extensions.active') : t('common.available')}
|
||||
sx={{ flexGrow: 1 }}
|
||||
/>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
@@ -883,7 +893,7 @@ function App(): JSX.Element {
|
||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||
{v.status === 'available' && (
|
||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadMariaDb(v.id)}>
|
||||
İNDİR
|
||||
{t('common.download')}
|
||||
</Button>
|
||||
)}
|
||||
{v.status === 'downloading' && (
|
||||
@@ -892,7 +902,7 @@ function App(): JSX.Element {
|
||||
</Box>
|
||||
)}
|
||||
{v.status === 'installed' && (
|
||||
<Chip label="HAZIR" color="success" variant="outlined" size="small" />
|
||||
<Chip label={t('common.ok').toUpperCase()} color="success" variant="outlined" size="small" />
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -905,24 +915,27 @@ function App(): JSX.Element {
|
||||
{settingsTab === 2 && (
|
||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
||||
<Box sx={{ p: 2, borderBottom: '1px solid rgba(255, 255, 255, 0.05)' }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>Nginx Web Sunucusu</Typography>
|
||||
<Typography variant="body2" color="text.secondary">Sunucu için gerekli Nginx binary dosyalarını buradan indirebilirsiniz.</Typography>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.nginx_versions')}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">{t('settings.nginx_versions_desc')}</Typography>
|
||||
</Box>
|
||||
<List>
|
||||
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||
{nginxVersions.length === 0 && (
|
||||
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||
)}
|
||||
{nginxVersions.map((v) => (
|
||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||
<ListItemIcon>
|
||||
{v.status === 'installed' ? <InstalledIcon color="success" /> : <AvailableIcon color="action" />}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={`Nginx ${v.version} (Stable)`}
|
||||
secondary={v.status === 'downloading' ? `İndiriliyor... %${Math.round(v.progress)}` : v.status === 'installed' ? 'Kurulu' : 'İndirilebilir'}
|
||||
primary={`Nginx ${v.version}`}
|
||||
secondary={v.status === 'downloading' ? `${t('common.loading')} %${Math.round(v.progress)}` : v.status === 'installed' ? t('php.extensions.active') : t('common.available')}
|
||||
sx={{ flexGrow: 1 }}
|
||||
/>
|
||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||
{v.status === 'available' && (
|
||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadNginx(v.id)}>
|
||||
İNDİR
|
||||
{t('common.download')}
|
||||
</Button>
|
||||
)}
|
||||
{v.status === 'downloading' && (
|
||||
@@ -931,7 +944,7 @@ function App(): JSX.Element {
|
||||
</Box>
|
||||
)}
|
||||
{v.status === 'installed' && (
|
||||
<Chip label="HAZIR" color="success" variant="outlined" size="small" />
|
||||
<Chip label={t('common.ok').toUpperCase()} color="success" variant="outlined" size="small" />
|
||||
)}
|
||||
</Box>
|
||||
</ListItem>
|
||||
@@ -943,10 +956,13 @@ function App(): JSX.Element {
|
||||
{settingsTab === 3 && (
|
||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
||||
<Box sx={{ p: 2, borderBottom: '1px solid rgba(255, 255, 255, 0.05)' }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>Apache Web Sunucusu</Typography>
|
||||
<Typography variant="body2" color="text.secondary">Apache HTTP Server binary dosyalarını buradan yönetebilirsiniz.</Typography>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.apache_versions')}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">{t('settings.apache_versions_desc')}</Typography>
|
||||
</Box>
|
||||
<List>
|
||||
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||
{apacheVersions.length === 0 && (
|
||||
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||
)}
|
||||
{apacheVersions.map((v) => (
|
||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||
<ListItemIcon>
|
||||
@@ -954,13 +970,13 @@ function App(): JSX.Element {
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={`Apache ${v.version}`}
|
||||
secondary={v.status === 'downloading' ? `İndiriliyor... %${Math.round(v.progress)}` : v.status === 'installed' ? 'Kurulu' : 'İndirilebilir'}
|
||||
secondary={v.status === 'downloading' ? `${t('common.loading')} %${Math.round(v.progress)}` : v.status === 'installed' ? t('php.extensions.active') : t('common.available')}
|
||||
sx={{ flexGrow: 1 }}
|
||||
/>
|
||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||
{v.status === 'available' && (
|
||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadApache(v.id)}>
|
||||
İNDİR
|
||||
{t('common.download')}
|
||||
</Button>
|
||||
)}
|
||||
{v.status === 'downloading' && (
|
||||
@@ -971,9 +987,9 @@ function App(): JSX.Element {
|
||||
{v.status === 'installed' && (
|
||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||
<Button variant="outlined" size="small" startIcon={<SettingsIcon />} onClick={handleOpenApacheConfig}>
|
||||
YAPILANDIRMA
|
||||
{t('common.settings').toUpperCase()}
|
||||
</Button>
|
||||
<Chip label="HAZIR" color="success" variant="outlined" size="small" />
|
||||
<Chip label={t('common.ok').toUpperCase()} color="success" variant="outlined" size="small" />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
@@ -984,78 +1000,50 @@ function App(): JSX.Element {
|
||||
)}
|
||||
|
||||
{settingsTab === 4 && (
|
||||
<Box component={Stack} spacing={3}>
|
||||
<Paper sx={{ p: 3, bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
||||
<Typography variant="h6" gutterBottom>Port Ayarları</Typography>
|
||||
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 3, mt: 2 }}>
|
||||
<FormControl variant="filled" size="small" fullWidth>
|
||||
<InputLabel>Varsayılan Web Sunucusu</InputLabel>
|
||||
<Paper sx={{ p: 4, bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
||||
<Typography variant="h6" gutterBottom sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<SettingsIcon color="primary" />
|
||||
{t('settings.server')}
|
||||
</Typography>
|
||||
<Grid container spacing={3} sx={{ mt: 1 }}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField variant="outlined" fullWidth label={t('settings.nginx_port')} value={settings.nginxPort} onChange={(e) => setSettings({ ...settings, nginxPort: e.target.value })} />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField variant="outlined" fullWidth label={t('settings.apache_port')} value={settings.apachePort} onChange={(e) => setSettings({ ...settings, apachePort: e.target.value })} />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField variant="outlined" fullWidth label={t('settings.php_port')} value={settings.phpPort} onChange={(e) => setSettings({ ...settings, phpPort: e.target.value })} />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField variant="outlined" fullWidth label={t('settings.mariadb_port')} value={settings.mariaDbPort} onChange={(e) => setSettings({ ...settings, mariaDbPort: e.target.value })} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>{t('settings.server_type_select')}</InputLabel>
|
||||
<Select
|
||||
value={settings.serverType || 'nginx'}
|
||||
value={settings.serverType}
|
||||
label={t('settings.server_type_select')}
|
||||
onChange={(e) => setSettings({ ...settings, serverType: e.target.value as any })}
|
||||
>
|
||||
<MenuItem value="nginx">Nginx (Performans)</MenuItem>
|
||||
<MenuItem value="apache">Apache (htaccess Desteği)</MenuItem>
|
||||
<MenuItem value="nginx">Nginx</MenuItem>
|
||||
<MenuItem value="apache">Apache</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
label="Nginx Portu"
|
||||
value={settings.nginxPort}
|
||||
onChange={(e) => setSettings({ ...settings, nginxPort: e.target.value })}
|
||||
variant="filled"
|
||||
size="small"
|
||||
helperText="Varsayılan: 80"
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={settings.allowRemoteAccess} onChange={(e) => setSettings({ ...settings, allowRemoteAccess: e.target.checked })} />}
|
||||
label={t('settings.remote_access')}
|
||||
/>
|
||||
<TextField
|
||||
label="Apache Portu"
|
||||
value={settings.apachePort}
|
||||
onChange={(e) => setSettings({ ...settings, apachePort: e.target.value })}
|
||||
variant="filled"
|
||||
size="small"
|
||||
helperText="Varsayılan: 8080"
|
||||
/>
|
||||
<TextField
|
||||
label="PHP FastCGI Portu"
|
||||
value={settings.phpPort}
|
||||
onChange={(e) => setSettings({ ...settings, phpPort: e.target.value })}
|
||||
variant="filled"
|
||||
size="small"
|
||||
helperText="Varsayılan: 9001"
|
||||
/>
|
||||
<TextField
|
||||
label="MariaDB Portu"
|
||||
value={settings.mariaDbPort}
|
||||
onChange={(e) => setSettings({ ...settings, mariaDbPort: e.target.value })}
|
||||
variant="filled"
|
||||
size="small"
|
||||
helperText="Varsayılan: 3306"
|
||||
/>
|
||||
</Box>
|
||||
<Divider sx={{ my: 2, bgcolor: 'rgba(255,255,255,0.05)' }} />
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={settings.allowRemoteAccess}
|
||||
onChange={(e) => {
|
||||
const newSettings = { ...settings, allowRemoteAccess: e.target.checked }
|
||||
setSettings(newSettings)
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Dış Erişime İzin Ver (0.0.0.0)"
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block' }}>
|
||||
{settings.allowRemoteAccess
|
||||
? "Sunucu yerel ağdaki diğer cihazlardan erişilebilir."
|
||||
: "Sunucu sadece bu bilgisayardan (127.0.0.1) erişilebilir."}
|
||||
</Typography>
|
||||
</Paper>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<Button variant="contained" startIcon={<SaveIcon />} size="large" onClick={handleSaveSettings}>
|
||||
Ayarları Kaydet
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{ mt: 2 }}>
|
||||
<Button variant="contained" color="primary" size="large" startIcon={<SaveIcon />} onClick={handleSaveSettings} fullWidth>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
@@ -1094,12 +1082,12 @@ function App(): JSX.Element {
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>Port: {settings.nginxPort}</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<IconButton onClick={() => handleOpenLogs('nginx')} title="Hata Logları" size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}>
|
||||
<IconButton onClick={() => handleOpenLogs('nginx')} title={t('diagnostics.logs')} size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}>
|
||||
<TerminalIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleOpenNginxConfig}
|
||||
title="Nginx Yapılandırması"
|
||||
title={t('server.nginx.config')}
|
||||
size="small"
|
||||
sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'primary.main' } }}
|
||||
>
|
||||
@@ -1111,7 +1099,7 @@ function App(): JSX.Element {
|
||||
setNotification({ open: true, message: res.message, severity: res.success ? 'success' : 'error' })
|
||||
})
|
||||
}}
|
||||
title="Yapılandırmayı Yeniden Yükle"
|
||||
title={t('server.nginx.save_reload')}
|
||||
size="small"
|
||||
disabled={status.nginx !== 'running'}
|
||||
sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'primary.main' } }}
|
||||
@@ -1148,12 +1136,12 @@ function App(): JSX.Element {
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>Port: {settings.apachePort}</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<IconButton onClick={() => handleOpenLogs('apache')} title="Hata Logları" size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}>
|
||||
<IconButton onClick={() => handleOpenLogs('apache')} title={t('diagnostics.logs')} size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}>
|
||||
<TerminalIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleOpenApacheConfig}
|
||||
title="Apache Yapılandırması"
|
||||
title={t('server.apache.config')}
|
||||
size="small"
|
||||
sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'primary.main' } }}
|
||||
>
|
||||
@@ -1220,10 +1208,10 @@ function App(): JSX.Element {
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>Port: {settings.mariaDbPorts?.[v.id] || v.port}</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<IconButton onClick={() => handleOpenLogs(`mariadb:${v.version}`)} title="Hata Logları" size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}>
|
||||
<IconButton onClick={() => handleOpenLogs(`mariadb:${v.version}`)} title={t('diagnostics.logs')} size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}>
|
||||
<TerminalIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton onClick={() => handleResetData(`mariadb:${v.version}`)} title="Verileri Sıfırla" size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'error.main' } }}>
|
||||
<IconButton onClick={() => handleResetData(`mariadb:${v.version}`)} title={t('common.reset')} size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'error.main' } }}>
|
||||
<ResetIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
@@ -1262,7 +1250,7 @@ function App(): JSX.Element {
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>phpMyAdmin</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{pmaInstalled ? 'Veritabanı yönetimi için phpMyAdmin hazır.' : 'Veritabanlarını web üzerinden yönetmek için phpMyAdmin kurun.'}
|
||||
{pmaInstalled ? t('pma.ready_desc') : t('pma.install_desc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
@@ -1275,7 +1263,7 @@ function App(): JSX.Element {
|
||||
startIcon={pmaLoading ? <CircularProgress size={20} /> : <DownloadIcon />}
|
||||
sx={{ borderRadius: 2 }}
|
||||
>
|
||||
{pmaLoading ? 'KURULUYOR...' : 'KURULUMU BAŞLAT'}
|
||||
{pmaLoading ? t('pma.installing') : t('pma.install_button')}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
@@ -1285,7 +1273,7 @@ function App(): JSX.Element {
|
||||
startIcon={<OpenIcon />}
|
||||
sx={{ borderRadius: 2 }}
|
||||
>
|
||||
AÇ
|
||||
{t('pma.open')}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
@@ -1294,7 +1282,7 @@ function App(): JSX.Element {
|
||||
<Box sx={{ mt: 3 }}>
|
||||
<LinearProgress variant="determinate" value={pmaProgress} sx={{ height: 8, borderRadius: 4 }} />
|
||||
<Typography variant="caption" sx={{ mt: 1, display: 'block', textAlign: 'center', color: 'primary.main', fontWeight: 'bold' }}>
|
||||
İndiriliyor... %{Math.round(pmaProgress)}
|
||||
{t('pma.progress', { progress: Math.round(pmaProgress) })}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
@@ -1306,9 +1294,9 @@ function App(): JSX.Element {
|
||||
<DbIcon color="primary" sx={{ fontSize: 32 }} />
|
||||
</Box>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>MariaDB Veri İçe Aktar</Typography>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>{t('mariadb.import.title')}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Seçtiğiniz bir .sql veya arşiv dosyasını hızlıca veritabanına yükleyin.
|
||||
{t('mariadb.import.desc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
@@ -1319,7 +1307,7 @@ function App(): JSX.Element {
|
||||
startIcon={<DbIcon />}
|
||||
sx={{ borderRadius: 2 }}
|
||||
>
|
||||
İÇE AKTAR
|
||||
{t('mariadb.import.button')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -1331,9 +1319,9 @@ function App(): JSX.Element {
|
||||
<DbIcon color="secondary" sx={{ fontSize: 32 }} />
|
||||
</Box>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>MariaDB Veri Dışa Aktar</Typography>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>{t('mariadb.export.title')}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Veritabanlarını .sql veya .sql.gz olarak güvenle yedekleyin.
|
||||
{t('mariadb.export.desc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
@@ -1345,7 +1333,7 @@ function App(): JSX.Element {
|
||||
startIcon={<DbIcon />}
|
||||
sx={{ borderRadius: 2 }}
|
||||
>
|
||||
DIŞA AKTAR
|
||||
{t('mariadb.export.button')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -1358,16 +1346,16 @@ function App(): JSX.Element {
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
||||
<Typography variant="h5" sx={{ fontWeight: 'medium' }}>
|
||||
Projelerim
|
||||
{t('projects.title')}
|
||||
</Typography>
|
||||
<Button variant="contained" startIcon={<ProjectIcon />} onClick={() => setIsProjectDialogOpen(true)}>
|
||||
Yeni Proje Ekle
|
||||
{t('projects.add_new')}
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{projects.length === 0 ? (
|
||||
<Paper sx={{ p: 4, textAlign: 'center', bgcolor: 'rgba(255, 255, 255, 0.03)' }}>
|
||||
<Typography variant="body1" color="text.secondary">Henüz bir proje eklenmemiş.</Typography>
|
||||
<Typography variant="body1" color="text.secondary">{t('projects.empty')}</Typography>
|
||||
</Paper>
|
||||
) : (
|
||||
<Grid container spacing={3}>
|
||||
@@ -1405,7 +1393,7 @@ function App(): JSX.Element {
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 0.5, flexShrink: 0 }}>
|
||||
<Tooltip title="Düzenle">
|
||||
<Tooltip title={t('common.edit')}>
|
||||
<IconButton size="small" onClick={() => {
|
||||
setNewProject(project)
|
||||
setIsProjectDialogOpen(true)
|
||||
@@ -1414,7 +1402,7 @@ function App(): JSX.Element {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{project.serverType !== 'apache' && (
|
||||
<Tooltip title="Nginx Ayarları">
|
||||
<Tooltip title={t('server.nginx.config')}>
|
||||
<IconButton size="small" onClick={() => handleOpenProjectNginxConfig(project.host)} sx={{ color: 'rgba(255,255,255,0.4)', '&:hover': { color: '#39A7FF' } }}>
|
||||
<TerminalIcon fontSize="small" />
|
||||
</IconButton>
|
||||
@@ -1474,7 +1462,7 @@ function App(): JSX.Element {
|
||||
'&:hover': { bgcolor: 'rgba(57, 167, 255, 0.1)' }
|
||||
}}
|
||||
>
|
||||
Gözat
|
||||
{t('projects.browse')}
|
||||
</Button>
|
||||
</Paper>
|
||||
</Stack>
|
||||
@@ -1614,17 +1602,17 @@ function App(): JSX.Element {
|
||||
setIsProjectDialogOpen(false)
|
||||
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost', serverType: 'nginx' })
|
||||
}} fullWidth maxWidth="sm">
|
||||
<DialogTitle>{newProject.id ? 'Proje Düzenle' : 'Yeni Proje Ekle'}</DialogTitle>
|
||||
<DialogTitle>{newProject.id ? t('projects.edit') : t('projects.add_new')}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
<TextField
|
||||
label="Proje Adı"
|
||||
label={t('projects.name')}
|
||||
fullWidth
|
||||
value={newProject.name}
|
||||
onChange={(e) => setNewProject({ ...newProject, name: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
label="Dosya Yolu"
|
||||
label={t('projects.path')}
|
||||
fullWidth
|
||||
value={newProject.path}
|
||||
InputProps={{
|
||||
@@ -1639,17 +1627,17 @@ function App(): JSX.Element {
|
||||
onChange={(e) => setNewProject({ ...newProject, path: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
label="Hostname (örn: local.test)"
|
||||
label={t('projects.hostname_placeholder')}
|
||||
fullWidth
|
||||
value={newProject.host}
|
||||
onChange={(e) => setNewProject({ ...newProject, host: e.target.value })}
|
||||
/>
|
||||
<FormControl fullWidth disabled={installedPhpVersions.length === 0}>
|
||||
<InputLabel id="php-version-label">PHP Sürümü</InputLabel>
|
||||
<InputLabel id="php-version-label">{t('projects.php_version')}</InputLabel>
|
||||
<Select
|
||||
labelId="php-version-label"
|
||||
value={newProject.phpVersion}
|
||||
label="PHP Sürümü"
|
||||
label={t('projects.php_version')}
|
||||
onChange={(e) => setNewProject({ ...newProject, phpVersion: e.target.value })}
|
||||
>
|
||||
{installedPhpVersions.length > 0 ? (
|
||||
@@ -1657,20 +1645,20 @@ function App(): JSX.Element {
|
||||
<MenuItem key={v.id} value={v.version}>PHP {v.version}</MenuItem>
|
||||
))
|
||||
) : (
|
||||
<MenuItem disabled value="">Önce PHP sürümü indirmelisiniz</MenuItem>
|
||||
<MenuItem disabled value="">{t('projects.no_php_warning')}</MenuItem>
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="server-type-label">Web Sunucusu</InputLabel>
|
||||
<InputLabel id="server-type-label">{t('projects.server_type')}</InputLabel>
|
||||
<Select
|
||||
labelId="server-type-label"
|
||||
value={newProject.serverType || 'nginx'}
|
||||
label="Web Sunucusu"
|
||||
label={t('projects.server_type')}
|
||||
onChange={(e) => setNewProject({ ...newProject, serverType: e.target.value as any })}
|
||||
>
|
||||
<MenuItem value="nginx">Nginx</MenuItem>
|
||||
<MenuItem value="apache">Apache (htaccess desteği)</MenuItem>
|
||||
<MenuItem value="apache">{t('projects.apache_htaccess')}</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
@@ -1679,13 +1667,13 @@ function App(): JSX.Element {
|
||||
<Button onClick={() => {
|
||||
setIsProjectDialogOpen(false)
|
||||
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost', serverType: 'nginx' })
|
||||
}}>İptal</Button>
|
||||
}}>{t('common.cancel')}</Button>
|
||||
<Button
|
||||
onClick={handleAddProject}
|
||||
variant="contained"
|
||||
disabled={!newProject.name || !newProject.path || installedPhpVersions.length === 0}
|
||||
>
|
||||
{newProject.id ? 'Güncelle' : 'Ekle'}
|
||||
{newProject.id ? t('common.save') : t('common.save')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
@@ -1717,14 +1705,14 @@ function App(): JSX.Element {
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="h6">Nginx Yapılandırması (nginx.conf)</Typography>
|
||||
<Typography variant="h6">{t('server.nginx.config_title')}</Typography>
|
||||
<IconButton onClick={() => setIsNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent dividers sx={{ borderColor: 'rgba(255,255,255,0.1)' }}>
|
||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.4)', mb: 2, display: 'block' }}>
|
||||
Dikkat: Hatalı yapılandırma Nginx'in çalışmasını durdurabilir. Değişiklik yapmadan önce test edin.
|
||||
{t('server.nginx.config_warning')}
|
||||
</Typography>
|
||||
<NginxCodeEditor
|
||||
value={nginxConfig}
|
||||
@@ -1738,17 +1726,17 @@ function App(): JSX.Element {
|
||||
startIcon={<RefreshIcon />}
|
||||
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
||||
>
|
||||
Yapılandırmayı Test Et
|
||||
{t('server.nginx.test_config')}
|
||||
</Button>
|
||||
<Button onClick={() => setIsNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
||||
İptal
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSaveNginxConfig}
|
||||
variant="contained"
|
||||
startIcon={<SaveIcon />}
|
||||
>
|
||||
Kaydet ve Yeniden Yükle
|
||||
{t('server.nginx.save_reload')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
@@ -1768,14 +1756,14 @@ function App(): JSX.Element {
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="h6">{selectedProjectHost} Nginx Yapılandırması</Typography>
|
||||
<Typography variant="h6">{t('server.project_nginx.title', { host: selectedProjectHost })}</Typography>
|
||||
<IconButton onClick={() => setIsProjectNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent dividers sx={{ borderColor: 'rgba(255,255,255,0.1)' }}>
|
||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.4)', mb: 2, display: 'block' }}>
|
||||
İpucu: Bu yapılandırma sadece {selectedProjectHost} projesi için geçerlidir.
|
||||
{t('server.project_nginx.tip', { host: selectedProjectHost })}
|
||||
</Typography>
|
||||
<NginxCodeEditor
|
||||
value={projectNginxConfig}
|
||||
@@ -1798,7 +1786,7 @@ function App(): JSX.Element {
|
||||
.replace(/successful/g, '<span style="color: #33d9b2;">successful</span>')
|
||||
|
||||
Swal.fire({
|
||||
title: result.success ? 'Başarılı' : 'Yapılandırma Hatası',
|
||||
title: result.success ? t('common.success') : t('server.nginx.test_failed'),
|
||||
html: `
|
||||
<div class="nginx-error-container">
|
||||
${formattedMessage}
|
||||
@@ -1806,7 +1794,7 @@ function App(): JSX.Element {
|
||||
${!result.success && errorInfo ? `
|
||||
<div style="margin-top: 15px; text-align: center;">
|
||||
<p style="font-size: 0.9rem; color: #ffb142;">
|
||||
<b>Hata Satırı:</b> ${errorInfo.line}
|
||||
<b>{t('server.project_nginx.error_line', { line: errorInfo.line })}</b>
|
||||
</p>
|
||||
</div>
|
||||
` : ''}
|
||||
@@ -1822,17 +1810,17 @@ function App(): JSX.Element {
|
||||
startIcon={<RefreshIcon />}
|
||||
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
||||
>
|
||||
Yapılandırmayı Test Et
|
||||
{t('server.nginx.test_config')}
|
||||
</Button>
|
||||
<Button onClick={() => setIsProjectNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
||||
İptal
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSaveProjectNginxConfig}
|
||||
variant="contained"
|
||||
startIcon={<SaveIcon />}
|
||||
>
|
||||
Kaydet ve Yeniden Yükle
|
||||
{t('server.nginx.save_reload')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
@@ -1851,14 +1839,14 @@ function App(): JSX.Element {
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="h6">Apache (httpd.conf) Yapılandırması</Typography>
|
||||
<Typography variant="h6">{t('server.apache.config_title')}</Typography>
|
||||
<IconButton onClick={() => setIsApacheConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent dividers sx={{ borderColor: 'rgba(255,255,255,0.1)' }}>
|
||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.4)', mb: 2, display: 'block' }}>
|
||||
Düzenlediğiniz bu dosya Apache sunucusunun ana (global) yapılandırma dosyasıdır.
|
||||
{t('server.apache.config_desc')}
|
||||
</Typography>
|
||||
<ApacheCodeEditor
|
||||
value={apacheConfig}
|
||||
@@ -1872,13 +1860,13 @@ function App(): JSX.Element {
|
||||
startIcon={<RefreshIcon />}
|
||||
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
||||
>
|
||||
Yapılandırmayı Test Et
|
||||
{t('server.apache.test_config')}
|
||||
</Button>
|
||||
<Button onClick={() => setIsApacheConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
||||
İptal
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button onClick={handleSaveApacheConfig} variant="contained" color="primary" startIcon={<SaveIcon />}>
|
||||
Kaydet ve Yeniden Yükle
|
||||
{t('server.apache.save_reload')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
Save as SaveIcon
|
||||
} from '@mui/icons-material'
|
||||
import Swal from 'sweetalert2'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface MariaDbExportWizardProps {
|
||||
open: boolean
|
||||
@@ -36,14 +37,15 @@ interface MariaDbExportWizardProps {
|
||||
mariaDbVersions: any[]
|
||||
}
|
||||
|
||||
const steps = [
|
||||
'Sunucu Seçimi',
|
||||
'Veritabanı Seçimi',
|
||||
'Dışa Aktarma Ayarları',
|
||||
'Özet ve İşlem'
|
||||
]
|
||||
|
||||
const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose, mariaDbVersions }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const steps = [
|
||||
t('mariadb.export.step1'),
|
||||
t('mariadb.export.step2'),
|
||||
t('mariadb.export.step3'),
|
||||
t('mariadb.export.step4')
|
||||
]
|
||||
const [activeStep, setActiveStep] = useState(0)
|
||||
const [selectedVersion, setSelectedVersion] = useState('')
|
||||
const [databases, setDatabases] = useState<string[]>([])
|
||||
@@ -79,7 +81,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
|
||||
const handleStep1Next = async () => {
|
||||
if (!selectedVersion) {
|
||||
Swal.fire('Hata', 'Lütfen bir MariaDB sunucusu seçin.', 'error')
|
||||
Swal.fire(t('common.error'), t('mariadb.export.step1_desc'), 'error')
|
||||
return
|
||||
}
|
||||
setLoading(true)
|
||||
@@ -88,7 +90,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
setDatabases(dbs)
|
||||
nextStep()
|
||||
} catch (err: any) {
|
||||
Swal.fire('Hata', 'Veritabanları listelenemedi: ' + err.message, 'error')
|
||||
Swal.fire(t('common.error'), t('mariadb.export.list_error') + err.message, 'error')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
@@ -103,7 +105,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
|
||||
const startExport = async () => {
|
||||
setLoading(true)
|
||||
setLogs(['[Sistem] Dışa aktarma işlemi başlatılıyor...'])
|
||||
setLogs([t('mariadb.export.starting')])
|
||||
|
||||
const removeListener = window.api.onMariaDbExportLog((msg: string) => {
|
||||
setLogs(prev => [...prev, msg])
|
||||
@@ -131,12 +133,12 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
case 0:
|
||||
return (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="body1" gutterBottom>Veritabanın hangi MariaDB sunucusunda olduğunu seçin.</Typography>
|
||||
<Typography variant="body1" gutterBottom>{t('mariadb.export.step1_desc')}</Typography>
|
||||
<FormControl fullWidth sx={{ mt: 2 }}>
|
||||
<InputLabel>MariaDB Sunucusu</InputLabel>
|
||||
<InputLabel>{t('mariadb.import.server')}</InputLabel>
|
||||
<Select
|
||||
value={selectedVersion}
|
||||
label="MariaDB Sunucusu"
|
||||
label={t('mariadb.import.server')}
|
||||
onChange={(e) => setSelectedVersion(e.target.value)}
|
||||
>
|
||||
{mariaDbVersions.filter(v => v.status === 'installed').map(v => (
|
||||
@@ -147,25 +149,25 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
label="Root Şifresi (Eğer varsa)"
|
||||
label={t('mariadb.import.root_pass')}
|
||||
fullWidth
|
||||
sx={{ mt: 3 }}
|
||||
value={rootPass}
|
||||
type="password"
|
||||
onChange={(e) => setRootPass(e.target.value)}
|
||||
helperText="MariaDB 'root' kullanıcısının şifresi. Boşsa boş bırakın."
|
||||
helperText={t('mariadb.import.root_pass_helper')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
case 1:
|
||||
return (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="body1" gutterBottom>Dışa aktarmak istediğiniz veritabanını seçin.</Typography>
|
||||
<Typography variant="body1" gutterBottom>{t('mariadb.export.step2_desc')}</Typography>
|
||||
<FormControl fullWidth sx={{ mt: 2 }}>
|
||||
<InputLabel>Veritabanı</InputLabel>
|
||||
<InputLabel>{t('mariadb.export.db')}</InputLabel>
|
||||
<Select
|
||||
value={selectedDb}
|
||||
label="Veritabanı"
|
||||
label={t('mariadb.export.db')}
|
||||
onChange={(e) => setSelectedDb(e.target.value)}
|
||||
>
|
||||
{databases.map(db => (
|
||||
@@ -175,7 +177,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
</FormControl>
|
||||
{databases.length === 0 && (
|
||||
<Typography variant="caption" color="error" sx={{ mt: 1, display: 'block' }}>
|
||||
Seçili sunucuda erişilebilir veritabanı bulunamadı.
|
||||
{t('mariadb.export.no_db_found')}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
@@ -183,17 +185,17 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
case 2:
|
||||
return (
|
||||
<Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||
<Typography variant="body1">Dosyanın kaydedileceği yeri ve formatını belirleyin.</Typography>
|
||||
<Typography variant="body1">{t('mariadb.export.step3_desc')}</Typography>
|
||||
<FormControlLabel
|
||||
control={<Checkbox checked={compress} onChange={(e) => setCompress(e.target.checked)} />}
|
||||
label="Gzip ile Sıkıştır (.sql.gz)"
|
||||
label={t('mariadb.export.compress')}
|
||||
/>
|
||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={savePath}
|
||||
placeholder="Kaydedilecek dosya..."
|
||||
placeholder={t('mariadb.export.placeholder')}
|
||||
disabled
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
@@ -203,7 +205,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Button variant="contained" onClick={handleSelectSavePath} sx={{ minWidth: '120px' }}>SEÇ</Button>
|
||||
<Button variant="contained" onClick={handleSelectSavePath} sx={{ minWidth: '120px' }}>{t('common.select')}</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
@@ -213,13 +215,13 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
{!exportResult ? (
|
||||
<>
|
||||
<Paper sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.05)', borderRadius: 2 }}>
|
||||
<Typography variant="subtitle2" color="primary" sx={{ fontWeight: 'bold' }}>Özet Bilgiler</Typography>
|
||||
<Typography variant="subtitle2" color="primary" sx={{ fontWeight: 'bold' }}>{t('mariadb.import.summary')}</Typography>
|
||||
<Divider sx={{ my: 1 }} />
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="body2"><strong>Sunucu:</strong> {selectedVersion}</Typography>
|
||||
<Typography variant="body2"><strong>Veritabanı:</strong> {selectedDb}</Typography>
|
||||
<Typography variant="body2"><strong>Hedef:</strong> {savePath}</Typography>
|
||||
<Typography variant="body2"><strong>Sıkıştırma:</strong> {compress ? 'Açık (.gz)' : 'Kapalı (.sql)'}</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.export.target')}:</strong> {savePath}</Typography>
|
||||
<Typography variant="body2"><strong>{t('mariadb.export.compression')}:</strong> {compress ? t('mariadb.export.on') : t('mariadb.export.off')}</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
{loading && (
|
||||
@@ -238,20 +240,20 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
{exportResult.success ? (
|
||||
<>
|
||||
<SuccessIcon color="success" sx={{ fontSize: 60 }} />
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>İşlem Başarılı!</Typography>
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>{t('mariadb.import.success_title')}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">{exportResult.message}</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
sx={{ mt: 3 }}
|
||||
onClick={() => window.api.invoke('shell:open-path', savePath.substring(0, savePath.lastIndexOf('\\')))}
|
||||
>
|
||||
DOSYAYI GÖSTER
|
||||
{t('mariadb.export.btn_show_file')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ErrorIcon color="error" sx={{ fontSize: 60 }} />
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>Hata Oluştu!</Typography>
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>{t('mariadb.import.error_title')}</Typography>
|
||||
<Typography variant="body2" color="error">{exportResult.message}</Typography>
|
||||
</>
|
||||
)}
|
||||
@@ -260,13 +262,13 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
</Box>
|
||||
)
|
||||
default:
|
||||
return 'Bilinmeyen adım'
|
||||
return t('common.error')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={loading ? undefined : onClose} maxWidth="sm" fullWidth>
|
||||
<DialogTitle>MariaDB Veritabanı Dışa Aktarma Sihirbazı</DialogTitle>
|
||||
<DialogTitle>{t('mariadb.export.wizard_title')}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stepper activeStep={activeStep} orientation="horizontal" sx={{ pt: 2, pb: 4 }}>
|
||||
{steps.map((label) => (
|
||||
@@ -280,25 +282,25 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
||||
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose} disabled={loading}>KAPAT</Button>
|
||||
<Button onClick={onClose} disabled={loading}>{t('common.close')}</Button>
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
{activeStep > 0 && activeStep < 3 && !exportResult && (
|
||||
<Button onClick={prevStep} disabled={loading}>GERİ</Button>
|
||||
<Button onClick={prevStep} disabled={loading}>{t('common.back')}</Button>
|
||||
)}
|
||||
{activeStep === 0 && (
|
||||
<Button variant="contained" onClick={handleStep1Next} disabled={loading}>
|
||||
{loading ? <CircularProgress size={24} /> : 'İLERİ'}
|
||||
{loading ? <CircularProgress size={24} /> : t('common.next')}
|
||||
</Button>
|
||||
)}
|
||||
{activeStep === 1 && (
|
||||
<Button variant="contained" onClick={nextStep} disabled={!selectedDb}>İLERİ</Button>
|
||||
<Button variant="contained" onClick={nextStep} disabled={!selectedDb}>{t('common.next')}</Button>
|
||||
)}
|
||||
{activeStep === 2 && (
|
||||
<Button variant="contained" onClick={nextStep} disabled={!savePath}>İLERİ</Button>
|
||||
<Button variant="contained" onClick={nextStep} disabled={!savePath}>{t('common.next')}</Button>
|
||||
)}
|
||||
{activeStep === 3 && !exportResult && (
|
||||
<Button variant="contained" color="primary" onClick={startExport} disabled={loading}>
|
||||
{loading ? <CircularProgress size={24} /> : 'EXPORTU BAŞLAT'}
|
||||
{loading ? <CircularProgress size={24} /> : t('mariadb.export.btn_start')}
|
||||
</Button>
|
||||
)}
|
||||
</DialogActions>
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
Error as ErrorIcon
|
||||
} from '@mui/icons-material'
|
||||
import Swal from 'sweetalert2'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface MariaDbImportWizardProps {
|
||||
open: boolean
|
||||
@@ -36,14 +37,15 @@ interface MariaDbImportWizardProps {
|
||||
mariaDbVersions: any[]
|
||||
}
|
||||
|
||||
const steps = [
|
||||
'Veri Seçimi',
|
||||
'Sunucu Seçimi',
|
||||
'Veritabanı Yapılandırması',
|
||||
'Özet ve İşlem'
|
||||
]
|
||||
|
||||
const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose, mariaDbVersions }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const steps = [
|
||||
t('mariadb.import.step1'),
|
||||
t('mariadb.import.step2'),
|
||||
t('mariadb.import.step3'),
|
||||
t('mariadb.import.step4')
|
||||
]
|
||||
const [activeStep, setActiveStep] = useState(0)
|
||||
const [filePath, setFilePath] = useState('')
|
||||
const [selectedVersion, setSelectedVersion] = useState('')
|
||||
@@ -103,7 +105,7 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
|
||||
const handleStep2Next = () => {
|
||||
if (!selectedVersion) {
|
||||
Swal.fire('Hata', 'Lütfen bir MariaDB sunucusu seçin.', 'error')
|
||||
Swal.fire(t('common.error'), t('mariadb.import.step2_desc'), 'error')
|
||||
return
|
||||
}
|
||||
nextStep()
|
||||
@@ -111,7 +113,7 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
|
||||
const handleStep3Next = async () => {
|
||||
if (!dbConfig.dbName || !dbConfig.user) {
|
||||
Swal.fire('Hata', 'Lütfen veritabanı adı ve kullanıcıyı doldurun.', 'error')
|
||||
Swal.fire(t('common.error'), t('mariadb.import.step3_desc'), 'error')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,19 +122,19 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
const { exists } = await window.api.checkMariaDbDb(selectedVersion, dbConfig.dbName, dbConfig.rootPass)
|
||||
if (exists) {
|
||||
const result = await Swal.fire({
|
||||
title: 'Veritabanı Mevcut!',
|
||||
text: `'${dbConfig.dbName}' veritabanı zaten var. Üzerine yazmak istiyor musunuz? Mevcut tüm veriler silinecektir!`,
|
||||
title: t('mariadb.import.overwrite_title'),
|
||||
text: t('mariadb.import.overwrite_desc', { dbName: dbConfig.dbName }),
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Üzerine Yaz',
|
||||
cancelButtonText: 'Hayır, Vazgeç',
|
||||
confirmButtonText: t('common.yes_delete'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
confirmButtonColor: '#d33'
|
||||
})
|
||||
if (!result.isConfirmed) return
|
||||
}
|
||||
nextStep()
|
||||
} catch (err: any) {
|
||||
Swal.fire('Hata', err.message, 'error')
|
||||
Swal.fire(t('common.error'), err.message, 'error')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
@@ -140,7 +142,7 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
|
||||
const startImport = async () => {
|
||||
setLoading(true)
|
||||
setLogs(['[Sistem] İşlem başlatılıyor...'])
|
||||
setLogs([t('mariadb.import.starting')])
|
||||
|
||||
const removeListener = window.api.onMariaDbImportLog((msg: string) => {
|
||||
setLogs(prev => [...prev, msg])
|
||||
@@ -170,13 +172,13 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
case 0:
|
||||
return (
|
||||
<Box sx={{ mt: 2, textAlign: 'center' }}>
|
||||
<Typography variant="body1" gutterBottom>Lütfen yüklenecek olan .sql dosyasını veya arşivini (.zip, .tar.gz) seçin.</Typography>
|
||||
<Typography variant="body1" gutterBottom>{t('mariadb.import.step1_desc')}</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center', mt: 3 }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={filePath}
|
||||
placeholder="Dosya seçilmedi..."
|
||||
placeholder={t('mariadb.import.no_file')}
|
||||
disabled
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
@@ -186,19 +188,19 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Button variant="contained" onClick={handleSelectFile} sx={{ minWidth: '120px' }}>SEÇ</Button>
|
||||
<Button variant="contained" onClick={handleSelectFile} sx={{ minWidth: '120px' }}>{t('common.select')}</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
case 1:
|
||||
return (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="body1" gutterBottom>Dosyanın hangi MariaDB sunucusuna yükleneceğini seçin.</Typography>
|
||||
<Typography variant="body1" gutterBottom>{t('mariadb.import.step2_desc')}</Typography>
|
||||
<FormControl fullWidth sx={{ mt: 2 }}>
|
||||
<InputLabel>MariaDB Sunucusu</InputLabel>
|
||||
<InputLabel>{t('mariadb.import.server')}</InputLabel>
|
||||
<Select
|
||||
value={selectedVersion}
|
||||
label="MariaDB Sunucusu"
|
||||
label={t('mariadb.import.server')}
|
||||
onChange={(e) => setSelectedVersion(e.target.value)}
|
||||
>
|
||||
{mariaDbVersions.filter(v => v.status === 'installed').map(v => (
|
||||
@@ -209,34 +211,34 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
label="Root Şifresi (Eğer varsa)"
|
||||
label={t('mariadb.import.root_pass')}
|
||||
fullWidth
|
||||
sx={{ mt: 3 }}
|
||||
value={dbConfig.rootPass}
|
||||
type="password"
|
||||
onChange={(e) => setDbConfig({ ...dbConfig, rootPass: e.target.value })}
|
||||
helperText="MariaDB 'root' kullanıcısının mevcut şifresini girin. Boşsa boş bırakın."
|
||||
helperText={t('mariadb.import.root_pass_helper')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
case 2:
|
||||
return (
|
||||
<Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||
<Typography variant="body1">Veritabanı ve kullanıcı bilgilerini yapılandırın.</Typography>
|
||||
<Typography variant="body1">{t('mariadb.import.step3_desc')}</Typography>
|
||||
<TextField
|
||||
label="Veritabanı Adı"
|
||||
label={t('mariadb.import.db_name')}
|
||||
fullWidth
|
||||
value={dbConfig.dbName}
|
||||
onChange={(e) => setDbConfig({ ...dbConfig, dbName: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
label="Veritabanı Kullanıcısı"
|
||||
label={t('mariadb.import.db_user')}
|
||||
fullWidth
|
||||
value={dbConfig.user}
|
||||
onChange={(e) => setDbConfig({ ...dbConfig, user: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
label="Kullanıcı Şifresi"
|
||||
label={t('mariadb.import.db_pass')}
|
||||
fullWidth
|
||||
value={dbConfig.pass}
|
||||
type="text"
|
||||
@@ -259,13 +261,13 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
{!importResult ? (
|
||||
<>
|
||||
<Paper sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.05)', borderRadius: 2 }}>
|
||||
<Typography variant="subtitle2" color="primary" sx={{ fontWeight: 'bold' }}>Özet Bilgiler</Typography>
|
||||
<Typography variant="subtitle2" color="primary" sx={{ fontWeight: 'bold' }}>{t('mariadb.import.summary')}</Typography>
|
||||
<Divider sx={{ my: 1 }} />
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="body2"><strong>Dosya:</strong> {filePath.split(/[/\\]/).pop()}</Typography>
|
||||
<Typography variant="body2"><strong>Sunucu:</strong> {selectedVersion}</Typography>
|
||||
<Typography variant="body2"><strong>Veritabanı:</strong> {dbConfig.dbName}</Typography>
|
||||
<Typography variant="body2"><strong>Kullanıcı:</strong> {dbConfig.user}</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.db')}:</strong> {dbConfig.dbName}</Typography>
|
||||
<Typography variant="body2"><strong>{t('mariadb.import.user')}:</strong> {dbConfig.user}</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
{loading && (
|
||||
@@ -284,20 +286,20 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
{importResult.success ? (
|
||||
<>
|
||||
<SuccessIcon color="success" sx={{ fontSize: 60 }} />
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>İşlem Başarılı!</Typography>
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>{t('mariadb.import.success_title')}</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)' }}>
|
||||
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>Erişim Bilgileri:</Typography>
|
||||
<Typography variant="body2"><strong>Host:</strong> localhost</Typography>
|
||||
<Typography variant="body2"><strong>DB:</strong> {dbConfig.dbName}</Typography>
|
||||
<Typography variant="body2"><strong>User:</strong> {dbConfig.user}</Typography>
|
||||
<Typography variant="body2"><strong>Pass:</strong> {dbConfig.pass}</Typography>
|
||||
<Typography variant="caption" sx={{ fontWeight: '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.db')}:</strong> {dbConfig.dbName}</Typography>
|
||||
<Typography variant="body2"><strong>{t('mariadb.import.user')}:</strong> {dbConfig.user}</Typography>
|
||||
<Typography variant="body2"><strong>{t('mariadb.import.db_pass')}:</strong> {dbConfig.pass}</Typography>
|
||||
</Paper>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ErrorIcon color="error" sx={{ fontSize: 60 }} />
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>Hata Oluştu!</Typography>
|
||||
<Typography variant="h6" sx={{ mt: 2 }}>{t('mariadb.import.error_title')}</Typography>
|
||||
<Typography variant="body2" color="error">{importResult.message}</Typography>
|
||||
<Box sx={{ mt: 2, textAlign: 'left', bgcolor: '#000', p: 1, maxHeight: 150, overflowY: 'auto' }}>
|
||||
{logs.slice(-5).map((l, i) => <Typography key={i} variant="caption" sx={{ color: '#fff', display: 'block' }}>{l}</Typography>)}
|
||||
@@ -309,13 +311,13 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
</Box>
|
||||
)
|
||||
default:
|
||||
return 'Bilinmeyen adım'
|
||||
return t('common.error')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={loading ? undefined : onClose} maxWidth="sm" fullWidth>
|
||||
<DialogTitle>MariaDB Hızlı Dump/Import Sihirbazı</DialogTitle>
|
||||
<DialogTitle>{t('mariadb.import.wizard_title')}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stepper activeStep={activeStep} orientation="horizontal" sx={{ pt: 2, pb: 4 }}>
|
||||
{steps.map((label) => (
|
||||
@@ -329,25 +331,25 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
||||
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose} disabled={loading}>KAPAT</Button>
|
||||
<Button onClick={onClose} disabled={loading}>{t('common.close')}</Button>
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
{activeStep > 0 && activeStep < 3 && !importResult && (
|
||||
<Button onClick={prevStep} disabled={loading}>GERİ</Button>
|
||||
<Button onClick={prevStep} disabled={loading}>{t('common.back')}</Button>
|
||||
)}
|
||||
{activeStep === 0 && (
|
||||
<Button variant="contained" onClick={nextStep} disabled={!filePath}>İLERİ</Button>
|
||||
<Button variant="contained" onClick={nextStep} disabled={!filePath}>{t('common.next')}</Button>
|
||||
)}
|
||||
{activeStep === 1 && (
|
||||
<Button variant="contained" onClick={handleStep2Next}>İLERİ</Button>
|
||||
<Button variant="contained" onClick={handleStep2Next}>{t('common.next')}</Button>
|
||||
)}
|
||||
{activeStep === 2 && (
|
||||
<Button variant="contained" onClick={handleStep3Next} disabled={loading}>
|
||||
{loading ? <CircularProgress size={24} /> : 'ÖZETİ GÖR'}
|
||||
{loading ? <CircularProgress size={24} /> : t('mariadb.import.btn_summary')}
|
||||
</Button>
|
||||
)}
|
||||
{activeStep === 3 && !importResult && (
|
||||
<Button variant="contained" color="primary" onClick={startImport} disabled={loading}>
|
||||
{loading ? <CircularProgress size={24} /> : 'IMPORTU BAŞLAT'}
|
||||
{loading ? <CircularProgress size={24} /> : t('mariadb.import.btn_start')}
|
||||
</Button>
|
||||
)}
|
||||
</DialogActions>
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from '@mui/material'
|
||||
import { Search as SearchIcon, Close as CloseIcon, Refresh as RefreshIcon, EditNote as RawIcon, Save as SaveIcon } from '@mui/icons-material'
|
||||
import Swal from 'sweetalert2'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import PhpIniCodeEditor from './PhpIniCodeEditor'
|
||||
|
||||
interface PhpExtension {
|
||||
@@ -34,6 +35,7 @@ interface PhpExtensionManagerProps {
|
||||
}
|
||||
|
||||
const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose, phpVersion }) => {
|
||||
const { t } = useTranslation()
|
||||
const [extensions, setExtensions] = useState<PhpExtension[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
@@ -72,8 +74,8 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
const handleSaveRaw = async () => {
|
||||
setIsSavingRaw(true)
|
||||
Swal.fire({
|
||||
title: 'Yapılandırma Kaydediliyor',
|
||||
text: 'PHP servisi yeniden başlatılıyor...',
|
||||
title: t('php.extensions.saving'),
|
||||
text: t('php.extensions.restarting'),
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading()
|
||||
@@ -89,8 +91,8 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
await window.api.invoke('services:start', `php:${phpVersion}`)
|
||||
|
||||
Swal.fire({
|
||||
title: 'Başarılı',
|
||||
text: 'Yapılandırma kaydedildi ve servis yeniden başlatıldı.',
|
||||
title: t('common.success'),
|
||||
text: t('php.extensions.success_msg'),
|
||||
icon: 'success',
|
||||
timer: 2000,
|
||||
showConfirmButton: false,
|
||||
@@ -121,8 +123,11 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
|
||||
if (wasRunning) {
|
||||
Swal.fire({
|
||||
title: 'Eklenti Ayarlanıyor',
|
||||
text: `${extName} ${enabled ? 'aktif ediliyor' : 'devre dışı bırakılıyor'} ve PHP yeniden başlatılıyor...`,
|
||||
title: t('php.extensions.adjusting'),
|
||||
text: t('php.extensions.adjusting_desc', {
|
||||
extName,
|
||||
mode: enabled ? t('common.starting').toLowerCase() : t('common.stop').toLowerCase()
|
||||
}),
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading()
|
||||
@@ -142,10 +147,10 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
Swal.close()
|
||||
}
|
||||
} else {
|
||||
Swal.fire({ title: 'Hata', text: result.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
||||
Swal.fire({ title: t('common.error'), text: result.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
||||
}
|
||||
} catch (error: any) {
|
||||
Swal.fire({ title: 'Hata', text: error.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
||||
Swal.fire({ title: t('common.error'), text: error.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
||||
} finally {
|
||||
setSaving(null)
|
||||
}
|
||||
@@ -175,8 +180,8 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
>
|
||||
<DialogTitle sx={{ m: 0, p: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Box>
|
||||
<Typography variant="h6">PHP {phpVersion} Eklentileri</Typography>
|
||||
<Typography variant="caption" color="text.secondary">php.ini üzerinden eklentileri yönetin</Typography>
|
||||
<Typography variant="h6">{t('php.extensions.title', { version: phpVersion })}</Typography>
|
||||
<Typography variant="caption" color="text.secondary">{t('php.extensions.desc')}</Typography>
|
||||
</Box>
|
||||
<IconButton onClick={onClose} sx={{ color: 'text.secondary' }}>
|
||||
<CloseIcon />
|
||||
@@ -187,7 +192,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
<TextField
|
||||
fullWidth
|
||||
size="small"
|
||||
placeholder="Eklenti ara... (mysql, gd, mbstring...)"
|
||||
placeholder={t('php.extensions.search_placeholder')}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
InputProps={{
|
||||
@@ -205,7 +210,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
onClick={fetchRawConfig}
|
||||
sx={{ whiteSpace: 'nowrap', borderColor: 'rgba(255,255,255,0.2)', color: '#fff' }}
|
||||
>
|
||||
RAW EDİTÖR
|
||||
{t('php.extensions.raw_editor')}
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
@@ -218,7 +223,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
{filteredExtensions.length === 0 ? (
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary={searchTerm ? "Eklenti bulunamadı." : "Hiç eklenti yok."}
|
||||
primary={searchTerm ? t('php.extensions.not_found') : t('php.extensions.none')}
|
||||
sx={{ textAlign: 'center', color: 'text.secondary' }}
|
||||
/>
|
||||
</ListItem>
|
||||
@@ -245,7 +250,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
primary={
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{ext.name}
|
||||
{ext.enabled && <Chip label="Aktif" size="small" color="success" sx={{ height: 18, fontSize: '0.65rem' }} />}
|
||||
{ext.enabled && <Chip label={t('php.extensions.active')} size="small" color="success" sx={{ height: 18, fontSize: '0.65rem' }} />}
|
||||
</Box>
|
||||
}
|
||||
secondary={ext.dll}
|
||||
@@ -259,10 +264,10 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.02)' }}>
|
||||
<Button onClick={fetchExtensions} startIcon={<RefreshIcon />} sx={{ mr: 'auto' }}>
|
||||
YENİLE
|
||||
{t('common.refresh').toUpperCase()}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant="contained" color="primary">
|
||||
KAPAT
|
||||
{t('common.close').toUpperCase()}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
@@ -282,7 +287,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
>
|
||||
<DialogTitle sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, p: 2 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="h6">php.ini Düzenle ({phpVersion})</Typography>
|
||||
<Typography variant="h6">{t('php.extensions.ini_edit', { version: phpVersion })}</Typography>
|
||||
<IconButton onClick={() => setIsRawEditorOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
@@ -296,7 +301,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
'&:hover': { textDecoration: 'underline', color: 'primary.light' }
|
||||
}}
|
||||
onClick={() => window.api.invoke('shell:open-path', configPath)}
|
||||
title="Dosyayı sistemde aç"
|
||||
title={t('php.extensions.file_open_tip')}
|
||||
>
|
||||
{configPath}
|
||||
</Typography>
|
||||
@@ -305,7 +310,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
<TextField
|
||||
fullWidth
|
||||
size="small"
|
||||
placeholder="Dosya içerisinde ara..."
|
||||
placeholder={t('php.extensions.search_file_placeholder')}
|
||||
value={rawSearchTerm}
|
||||
onChange={(e) => setRawSearchTerm(e.target.value)}
|
||||
InputProps={{
|
||||
@@ -331,7 +336,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ p: 2, bgcolor: 'rgba(0,0,0,0.2)' }}>
|
||||
<Button onClick={() => setIsRawEditorOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||
İPTAL
|
||||
{t('common.cancel').toUpperCase()}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSaveRaw}
|
||||
@@ -340,7 +345,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
||||
startIcon={isSavingRaw ? <CircularProgress size={18} color="inherit" /> : <SaveIcon />}
|
||||
disabled={isSavingRaw}
|
||||
>
|
||||
{isSavingRaw ? 'KAYDEDİLİYOR...' : 'KAYDET VE SUNUCUYU DURDUR'}
|
||||
{isSavingRaw ? t('php.extensions.saving_btn') : t('php.extensions.save_restart_btn')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'prismjs/components/prism-ini'
|
||||
import 'prismjs/themes/prism-tomorrow.css'
|
||||
import { IconButton, Box, Typography, Tooltip } from '@mui/material'
|
||||
import { KeyboardArrowDown as DownIcon, KeyboardArrowUp as UpIcon } from '@mui/icons-material'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface PhpIniCodeEditorProps {
|
||||
value: string
|
||||
@@ -13,6 +14,7 @@ interface PhpIniCodeEditorProps {
|
||||
}
|
||||
|
||||
const PhpIniCodeEditor: React.FC<PhpIniCodeEditorProps> = ({ value, onChange, searchTerm }) => {
|
||||
const { t } = useTranslation()
|
||||
const editorRef = useRef<HTMLDivElement>(null)
|
||||
const [matches, setMatches] = useState<number[]>([])
|
||||
const [currentIndex, setCurrentIndex] = useState(0)
|
||||
@@ -114,12 +116,12 @@ const PhpIniCodeEditor: React.FC<PhpIniCodeEditorProps> = ({ value, onChange, se
|
||||
<Typography variant="caption" sx={{ color: '#aaa', mr: 1, minWidth: '40px', textAlign: 'center', userSelect: 'none' }}>
|
||||
{matches.length > 0 ? `${currentIndex + 1} / ${matches.length}` : '0 / 0'}
|
||||
</Typography>
|
||||
<Tooltip title="Önceki (Shift+Enter)">
|
||||
<Tooltip title={t('php.extensions.prev_match')}>
|
||||
<IconButton size="small" onClick={handlePrev} sx={{ color: '#fff' }}>
|
||||
<UpIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Sonraki (Enter)">
|
||||
<Tooltip title={t('php.extensions.next_match')}>
|
||||
<IconButton size="small" onClick={handleNext} sx={{ color: '#fff' }}>
|
||||
<DownIcon fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
import i18n from 'i18next'
|
||||
import { initReactI18next } from 'react-i18next'
|
||||
import tr from './locales/tr.json'
|
||||
import en from './locales/en.json'
|
||||
import de from './locales/de.json'
|
||||
|
||||
// Dynamically import all json files in the locales directory
|
||||
const modules = import.meta.glob('./locales/*.json', { eager: true })
|
||||
|
||||
const resources = {}
|
||||
const supportedLngs: string[] = []
|
||||
|
||||
for (const path in modules) {
|
||||
const key = path.split('/').pop()?.replace('.json', '')
|
||||
if (key) {
|
||||
resources[key] = { translation: (modules[path] as any).default || modules[path] }
|
||||
supportedLngs.push(key)
|
||||
}
|
||||
}
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
resources: {
|
||||
tr: { translation: tr },
|
||||
en: { translation: en },
|
||||
de: { translation: de }
|
||||
},
|
||||
resources,
|
||||
lng: 'tr',
|
||||
fallbackLng: 'en',
|
||||
supportedLngs,
|
||||
interpolation: {
|
||||
escapeValue: false
|
||||
}
|
||||
})
|
||||
|
||||
export { supportedLngs }
|
||||
export default i18n
|
||||
|
||||
@@ -2,22 +2,228 @@
|
||||
"common": {
|
||||
"start": "Starten",
|
||||
"stop": "Stoppen",
|
||||
"restart": "Neustart",
|
||||
"restart": "Neustarten",
|
||||
"settings": "Einstellungen",
|
||||
"tools": "Werkzeuge",
|
||||
"close": "Schließen",
|
||||
"quit": "Beenden",
|
||||
"save": "Speichern",
|
||||
"port": "Port",
|
||||
"all": "Alle"
|
||||
"all": "Alle",
|
||||
"export": "Exportieren",
|
||||
"import": "Importieren",
|
||||
"ok": "OK",
|
||||
"cancel": "Abbrechen",
|
||||
"error": "Fehler!",
|
||||
"success": "Erfolgreich!",
|
||||
"warning": "Warnung",
|
||||
"info": "Info",
|
||||
"delete": "Löschen",
|
||||
"edit": "Bearbeiten",
|
||||
"refresh": "Aktualisieren",
|
||||
"search": "Suchen",
|
||||
"loading": "Laden...",
|
||||
"starting": "Wird gestartet",
|
||||
"are_you_sure": "Sind Sie sicher?",
|
||||
"yes_delete": "Ja, Löschen",
|
||||
"go_to_fix": "Zur Korrektur gehen",
|
||||
"select": "AUSWÄHLEN",
|
||||
"next": "WEITER",
|
||||
"back": "ZURÜCK",
|
||||
"finish": "FERTIGSTELLEN",
|
||||
"download": "HERUNTERLADEN",
|
||||
"available": "Verfügbar",
|
||||
"reset": "Zurücksetzen",
|
||||
"copy": "Kopieren",
|
||||
"browse": "Durchsuchen",
|
||||
"reset_confirm_title": "Sind Sie sicher?",
|
||||
"reset_confirm_text": "Möchten Sie die {{service}}-Daten zurücksetzen? Dieser Vorgang löscht alle Daten und führt eine Neuinstallation durch.",
|
||||
"reset_btn": "Ja, Zurücksetzen"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Trunçgil Multi-PHP Server",
|
||||
"status": "Serverstatus",
|
||||
"services": "Dienste",
|
||||
"active_version": "Aktive PHP-Version",
|
||||
"quick_look": "Schnellansicht",
|
||||
"quick_look": "Kurzübersicht",
|
||||
"start_all": "Alle starten",
|
||||
"stop_all": "Alle stoppen"
|
||||
"stop_all": "Alle stoppen",
|
||||
"all_started": "Alle Dienste wurden gestartet.",
|
||||
"all_stopped": "Alle Dienste wurden gestoppt."
|
||||
},
|
||||
"projects": {
|
||||
"title": "Meine Projekte",
|
||||
"add_new": "Neues Projekt hinzufügen",
|
||||
"edit": "Projekt bearbeiten",
|
||||
"empty": "Noch keine Projekte hinzugefügt.",
|
||||
"name": "Projektname",
|
||||
"path": "Projektpfad",
|
||||
"host": "Host / Domain",
|
||||
"hostname_placeholder": "Hostname (z.B. local.test)",
|
||||
"php_version": "PHP-Version",
|
||||
"mariadb_version": "MariaDB-Version",
|
||||
"server_type": "Webserver",
|
||||
"apache_htaccess": "Apache (htaccess-Unterstützung)",
|
||||
"actions": "Aktionen",
|
||||
"no_php_warning": "Sie müssen zuerst eine PHP-Version herunterladen",
|
||||
"added": "Projekt erfolgreich hinzugefügt.",
|
||||
"updated": "Projekt erfolgreich aktualisiert.",
|
||||
"deleted": "Projekt wurde gelöscht.",
|
||||
"delete_confirm": "Sind Sie sicher, dass Sie dieses Projekt löschen möchten? Ihre Dateien werden nicht gelöscht, nur aus der Liste entfernt."
|
||||
},
|
||||
"settings": {
|
||||
"general": "Allgemeine Einstellungen",
|
||||
"server": "Server-Einstellungen",
|
||||
"saved": "Einstellungen gespeichert.",
|
||||
"save_failed": "Einstellungen konnten nicht gespeichert werden.",
|
||||
"language": "Sprache",
|
||||
"nginx_port": "Nginx-Port",
|
||||
"apache_port": "Apache-Port",
|
||||
"php_port": "PHP-FPM-Port",
|
||||
"mariadb_port": "MariaDB-Port",
|
||||
"remote_access": "Fernzugriff zulassen",
|
||||
"server_type_select": "Standard-Servertyp",
|
||||
"php_versions": "PHP-Versionen",
|
||||
"mariadb_versions": "MariaDB-Versionen",
|
||||
"nginx_versions": "Nginx-Versionen",
|
||||
"apache_versions": "Apache-Versionen",
|
||||
"php_versions_desc": "Laden Sie hier benötigte PHP-Versionen herunter und verwalten Sie sie.",
|
||||
"mariadb_versions_desc": "MariaDB-Versionen hier verwalten.",
|
||||
"nginx_versions_desc": "Nginx-Versionen hier verwalten.",
|
||||
"apache_versions_desc": "Apache-Versionen hier verwalten.",
|
||||
"server_settings": "Servereinstellungen",
|
||||
"nginx_port_desc": "Port, auf dem Nginx läuft (Standard: 80)"
|
||||
},
|
||||
"server": {
|
||||
"nginx": {
|
||||
"config": "Nginx-Konfiguration",
|
||||
"config_title": "Nginx-Konfiguration (nginx.conf)",
|
||||
"config_warning": "Warnung: Fehlerhafte Konfiguration kann Nginx stoppen. Vor Änderungen testen.",
|
||||
"test": "Konfiguration testen",
|
||||
"save_reload": "Speichern und neu laden",
|
||||
"config_saved": "Nginx-Konfiguration erfolgreich gespeichert.",
|
||||
"title": "Nginx",
|
||||
"test_failed": "Konfigurationsfehler",
|
||||
"test_config": "Konfiguration testen"
|
||||
},
|
||||
"apache": {
|
||||
"config": "Apache-Konfiguration",
|
||||
"config_title": "Apache (httpd.conf) Konfiguration",
|
||||
"config_desc": "Dies ist die globale Konfigurationsdatei für den Apache-Server.",
|
||||
"test": "Konfiguration testen",
|
||||
"save_reload": "Speichern und neu laden",
|
||||
"config_saved": "Apache-Konfiguration gespeichert.",
|
||||
"title": "Apache",
|
||||
"test_config": "Konfiguration testen"
|
||||
},
|
||||
"project_nginx": {
|
||||
"title": "{{host}} Nginx-Konfiguration",
|
||||
"tip": "Tipp: Diese Konfiguration gilt nur für das {{host}}-Projekt.",
|
||||
"error_line": "Fehlerzeile: {{line}}"
|
||||
}
|
||||
},
|
||||
"pma": {
|
||||
"ready_desc": "phpMyAdmin ist bereit für die Datenbankverwaltung.",
|
||||
"install_desc": "phpMyAdmin installieren, um Datenbanken über das Web zu verwalten.",
|
||||
"installing": "INSTALLATION...",
|
||||
"install_button": "INSTALLATION STARTEN",
|
||||
"open": "ÖFFNEN",
|
||||
"progress": "Downloading... %{{progress}}"
|
||||
},
|
||||
"mariadb": {
|
||||
"import": {
|
||||
"title": "MariaDB Daten importieren",
|
||||
"desc": "Schnelles Laden einer .sql- oder Archivdatei in die Datenbank.",
|
||||
"button": "IMPORTIEREN",
|
||||
"wizard_title": "MariaDB-Schnellimport-Assistent",
|
||||
"step1": "Datenauswahl",
|
||||
"step2": "Serverauswahl",
|
||||
"step3": "Datenbankkonfiguration",
|
||||
"step4": "Zusammenfassung & Prozess",
|
||||
"step1_desc": "Bitte wählen Sie die .sql-Datei oder das Archiv (.zip, .tar.gz) aus, das hochgeladen werden soll.",
|
||||
"step2_desc": "Wählen Sie den MariaDB-Server aus, auf den die Datei hochgeladen werden soll.",
|
||||
"step3_desc": "Konfigurieren Sie Datenbank- und Benutzerinformationen.",
|
||||
"no_file": "Keine Datei ausgewählt...",
|
||||
"root_pass": "Root-Passwort (falls vorhanden)",
|
||||
"root_pass_helper": "Geben Sie das vorhandene Passwort für den MariaDB-Benutzer 'root' ein. Leer lassen, wenn kein Passwort vorhanden ist.",
|
||||
"db_name": "Datenbankname",
|
||||
"db_user": "Datenbankbenutzer",
|
||||
"db_pass": "Benutzerpasswort",
|
||||
"summary": "Zusammenfassungsinformationen",
|
||||
"file": "Datei",
|
||||
"server": "Server",
|
||||
"db": "Datenbank",
|
||||
"user": "Benutzer",
|
||||
"success_title": "Vorgang erfolgreich!",
|
||||
"error_title": "Ein Fehler ist aufgetreten!",
|
||||
"access_info": "Zugriffsinformationen",
|
||||
"host": "Host",
|
||||
"starting": "[System] Vorgang wird gestartet...",
|
||||
"overwrite_title": "Datenbank existiert bereits!",
|
||||
"overwrite_desc": "Die Datenbank '{{dbName}}' existiert bereits. Möchten Sie sie überschreiben? Alle vorhandenen Daten werden gelöscht!",
|
||||
"btn_summary": "ZUSAMMENFASSUNG ANZEIGEN",
|
||||
"btn_start": "IMPORT STARTEN"
|
||||
},
|
||||
"export": {
|
||||
"title": "MariaDB Daten exportieren",
|
||||
"desc": "Datenbanken sicher als .sql oder .sql.gz sichern.",
|
||||
"button": "EXPORTIEREN",
|
||||
"wizard_title": "MariaDB-Datenbank-Export-Assistent",
|
||||
"step1": "Serverauswahl",
|
||||
"step2": "Datenbankauswahl",
|
||||
"step3": "Exporteinstellungen",
|
||||
"step4": "Zusammenfassung & Prozess",
|
||||
"step1_desc": "Wählen Sie den MariaDB-Server aus, auf dem sich die Datenbank befindet.",
|
||||
"step2_desc": "Wählen Sie die Datenbank aus, die Sie exportieren möchten.",
|
||||
"step3_desc": "Bestimmen Sie den Speicherort und das Format für die gespeicherte Datei.",
|
||||
"placeholder": "Zu speichernde Datei...",
|
||||
"compress": "Mit Gzip komprimieren (.sql.gz)",
|
||||
"target": "Ziel",
|
||||
"compression": "Komprimierung",
|
||||
"on": "Ein (.gz)",
|
||||
"off": "Aus (.sql)",
|
||||
"btn_show_file": "DATEI ANZEIGEN",
|
||||
"btn_start": "EXPORT STARTEN",
|
||||
"starting": "[System] Exportvorgang wird gestartet...",
|
||||
"no_db_found": "Auf dem ausgewählten Server wurde keine zugängliche Datenbank gefunden.",
|
||||
"list_error": "Datenbanken konnten nicht aufgelistet werden: "
|
||||
},
|
||||
"wizard": {
|
||||
"import_title": "MariaDB-Daten-Import-Assistent",
|
||||
"export_title": "MariaDB-Daten-Export-Assistent",
|
||||
"select_version": "MariaDB-Version wählen",
|
||||
"select_db": "Datenbank wählen",
|
||||
"select_file": "Datei wählen",
|
||||
"import_success": "Datenerfolg beim Importieren.",
|
||||
"export_success": "Datenerfolg beim Exportieren."
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"logs": "Fehlerprotokolle",
|
||||
"noLogs": "Noch keine Protokolle aufgezeichnet."
|
||||
},
|
||||
"php": {
|
||||
"extensions": {
|
||||
"title": "PHP {{version}} Erweiterungen",
|
||||
"desc": "Erweiterungen über php.ini verwalten",
|
||||
"search_placeholder": "Erweiterung suchen... (mysql, gd, mbstring...)",
|
||||
"search_file_placeholder": "In Datei suchen...",
|
||||
"raw_editor": "RAW EDITOR",
|
||||
"none": "Keine Erweiterungen gefunden.",
|
||||
"not_found": "Erweiterung nicht gefunden.",
|
||||
"active": "Aktiv",
|
||||
"ini_edit": "php.ini bearbeiten ({{version}})",
|
||||
"file_open_tip": "Datei im System öffnen",
|
||||
"saving": "Konfiguration wird gespeichert",
|
||||
"restarting": "PHP-Dienst wird neu gestartet...",
|
||||
"adjusting": "Erweiterung wird angepasst",
|
||||
"adjusting_desc": "{{extName}} wird {{mode}} und PHP wird neu gestartet...",
|
||||
"save_restart_btn": "SPEICHERN UND NEU STARTEN",
|
||||
"saving_btn": "SPEICHERN...",
|
||||
"save_error": "Fehler beim Speichern der Erweiterungen.",
|
||||
"success_msg": "Konfiguration gespeichert und Dienst neu gestartet.",
|
||||
"prev_match": "Vorheriges (Shift+Enter)",
|
||||
"next_match": "Nächstes (Enter)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,39 @@
|
||||
"quit": "Quit",
|
||||
"save": "Save",
|
||||
"port": "Port",
|
||||
"all": "All"
|
||||
"all": "All",
|
||||
"export": "Export",
|
||||
"import": "Import",
|
||||
"ok": "OK",
|
||||
"cancel": "Cancel",
|
||||
"error": "Error!",
|
||||
"success": "Success!",
|
||||
"warning": "Warning",
|
||||
"info": "Info",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit",
|
||||
"refresh": "Refresh",
|
||||
"search": "Search",
|
||||
"loading": "Loading...",
|
||||
"starting": "Starting",
|
||||
"are_you_sure": "Are you sure?",
|
||||
"yes_delete": "Yes, delete!",
|
||||
"go_to_fix": "Go to Fix",
|
||||
"select": "SELECT",
|
||||
"next": "NEXT",
|
||||
"back": "BACK",
|
||||
"finish": "FINISH",
|
||||
"download": "DOWNLOAD",
|
||||
"available": "Available",
|
||||
"reset": "Reset",
|
||||
"copy": "Copy",
|
||||
"browse": "Browse",
|
||||
"delete_confirm": "Are you sure you want to delete this project?",
|
||||
"yes_delete_btn": "Yes, Delete",
|
||||
"stopping": "Stopping",
|
||||
"reset_confirm_title": "Are you sure?",
|
||||
"reset_confirm_text": "Do you want to reset {{service}} data? This operation deletes all data and performs a clean installation.",
|
||||
"reset_btn": "Yes, Reset"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Trunçgil Multi-PHP Server",
|
||||
@@ -18,6 +50,186 @@
|
||||
"active_version": "Active PHP Version",
|
||||
"quick_look": "Quick Look",
|
||||
"start_all": "Start All",
|
||||
"stop_all": "Stop All"
|
||||
"stop_all": "Stop All",
|
||||
"all_started": "All services started.",
|
||||
"all_stopped": "All services stopped."
|
||||
},
|
||||
"projects": {
|
||||
"title": "My Projects",
|
||||
"add_new": "Add New Project",
|
||||
"edit": "Edit Project",
|
||||
"empty": "No projects added yet.",
|
||||
"name": "Project Name",
|
||||
"path": "Project Path",
|
||||
"host": "Host / Domain",
|
||||
"hostname_placeholder": "Hostname (e.g., local.test)",
|
||||
"php_version": "PHP Version",
|
||||
"mariadb_version": "MariaDB Version",
|
||||
"server_type": "Web Server",
|
||||
"apache_htaccess": "Apache (htaccess support)",
|
||||
"actions": "Actions",
|
||||
"no_php_warning": "You must download a PHP version first",
|
||||
"added": "Project added successfully.",
|
||||
"updated": "Project updated successfully.",
|
||||
"deleted": "Project deleted.",
|
||||
"delete_confirm": "Are you sure you want to delete this project? Your files will not be deleted, only removed from the list."
|
||||
},
|
||||
"settings": {
|
||||
"general": "General Settings",
|
||||
"server": "Server Settings",
|
||||
"saved": "Settings saved.",
|
||||
"save_failed": "Failed to save settings.",
|
||||
"language": "Language",
|
||||
"nginx_port": "Nginx Port",
|
||||
"apache_port": "Apache Port",
|
||||
"php_port": "PHP-FPM Port",
|
||||
"mariadb_port": "MariaDB Port",
|
||||
"remote_access": "Allow Remote Access",
|
||||
"server_type_select": "Default Server Type",
|
||||
"php_versions": "PHP Versions",
|
||||
"mariadb_versions": "MariaDB Versions",
|
||||
"nginx_versions": "Nginx Versions",
|
||||
"apache_versions": "Apache Versions",
|
||||
"php_versions_desc": "Download and manage required PHP versions here.",
|
||||
"mariadb_versions_desc": "Manage MariaDB versions here.",
|
||||
"nginx_versions_desc": "Manage Nginx versions here.",
|
||||
"apache_versions_desc": "Manage Apache versions here.",
|
||||
"server_settings": "Server Settings",
|
||||
"nginx_port_desc": "Port Nginx will run on (Default: 80)"
|
||||
},
|
||||
"server": {
|
||||
"nginx": {
|
||||
"config": "Nginx Settings",
|
||||
"config_title": "Nginx Configuration (nginx.conf)",
|
||||
"config_warning": "Warning: Incorrect configuration may stop Nginx. Test before making changes.",
|
||||
"test_config": "Test Configuration",
|
||||
"save_reload": "Save and Reload",
|
||||
"config_saved": "Nginx configuration saved successfully.",
|
||||
"test_failed": "Configuration Error"
|
||||
},
|
||||
"apache": {
|
||||
"title": "Apache",
|
||||
"config": "Apache Settings",
|
||||
"config_title": "Apache (httpd.conf) Configuration",
|
||||
"config_desc": "This is the main (global) configuration file for the Apache server.",
|
||||
"test_config": "Test Configuration",
|
||||
"save_reload": "Save and Reload",
|
||||
"config_saved": "Apache configuration saved."
|
||||
},
|
||||
"project_nginx": {
|
||||
"title": "{{host}} Nginx Configuration",
|
||||
"tip": "Tip: This configuration applies only to the {{host}} project.",
|
||||
"error_line": "Error Line: {{line}}"
|
||||
}
|
||||
},
|
||||
"pma": {
|
||||
"ready_desc": "phpMyAdmin is ready for database management.",
|
||||
"install_desc": "Install phpMyAdmin to manage databases via web.",
|
||||
"installing": "INSTALLING...",
|
||||
"install_button": "START INSTALLATION",
|
||||
"open": "OPEN",
|
||||
"progress": "Downloading... %{{progress}}",
|
||||
"title": "phpMyAdmin",
|
||||
"desc": "Web-based database management tool",
|
||||
"open_pma": "Open phpMyAdmin",
|
||||
"install": "Install phpMyAdmin",
|
||||
"installed_success": "phpMyAdmin installed successfully.",
|
||||
"installed_error": "An error occurred during phpMyAdmin installation."
|
||||
},
|
||||
"mariadb": {
|
||||
"import": {
|
||||
"title": "MariaDB Import Data",
|
||||
"desc": "Quickly load a .sql or archive file into the database.",
|
||||
"button": "IMPORT",
|
||||
"wizard_title": "MariaDB Quick Dump/Import Wizard",
|
||||
"step1": "Data Selection",
|
||||
"step2": "Server Selection",
|
||||
"step3": "Database Configuration",
|
||||
"step4": "Summary & Process",
|
||||
"step1_desc": "Please select the .sql file or archive (.zip, .tar.gz) to be uploaded.",
|
||||
"step2_desc": "Select the MariaDB server where the file will be uploaded.",
|
||||
"step3_desc": "Configure database and user information.",
|
||||
"no_file": "No file selected...",
|
||||
"root_pass": "Root Password (If any)",
|
||||
"root_pass_helper": "Enter the existing password for the MariaDB 'root' user. Leave blank if empty.",
|
||||
"db_name": "Database Name",
|
||||
"db_user": "Database User",
|
||||
"db_pass": "User Password",
|
||||
"summary": "Summary Information",
|
||||
"file": "File",
|
||||
"server": "Server",
|
||||
"db": "Database",
|
||||
"user": "User",
|
||||
"success_title": "Operation Successful!",
|
||||
"error_title": "An Error Occurred!",
|
||||
"access_info": "Access Information",
|
||||
"host": "Host",
|
||||
"starting": "[System] Operation is starting...",
|
||||
"overwrite_title": "Database Exists!",
|
||||
"overwrite_desc": "Database '{{dbName}}' already exists. Do you want to overwrite it? All existing data will be deleted!",
|
||||
"btn_summary": "VIEW SUMMARY",
|
||||
"btn_start": "START IMPORT"
|
||||
},
|
||||
"export": {
|
||||
"title": "MariaDB Export Data",
|
||||
"desc": "Securely backup databases as .sql or .sql.gz.",
|
||||
"button": "EXPORT",
|
||||
"wizard_title": "MariaDB Database Export Wizard",
|
||||
"step1": "Server Selection",
|
||||
"step2": "Database Selection",
|
||||
"step3": "Export Settings",
|
||||
"step4": "Summary & Process",
|
||||
"step1_desc": "Select the MariaDB server where the database is located.",
|
||||
"step2_desc": "Select the database you want to export.",
|
||||
"step3_desc": "Determine the location and format for the saved file.",
|
||||
"placeholder": "File to be saved...",
|
||||
"compress": "Compress with Gzip (.sql.gz)",
|
||||
"target": "Target",
|
||||
"compression": "Compression",
|
||||
"on": "On (.gz)",
|
||||
"off": "Off (.sql)",
|
||||
"btn_show_file": "SHOW FILE",
|
||||
"btn_start": "START EXPORT",
|
||||
"starting": "[System] Export operation is starting...",
|
||||
"no_db_found": "No accessible database found on the selected server.",
|
||||
"list_error": "Databases could not be listed: "
|
||||
},
|
||||
"wizard": {
|
||||
"import_title": "MariaDB Data Import Wizard",
|
||||
"export_title": "MariaDB Data Export Wizard",
|
||||
"select_version": "Select MariaDB Version",
|
||||
"select_db": "Select Database",
|
||||
"select_file": "Select File",
|
||||
"import_success": "Data imported successfully.",
|
||||
"export_success": "Data exported successfully."
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"logs": "Error Logs",
|
||||
"noLogs": "No logs recorded yet."
|
||||
},
|
||||
"php": {
|
||||
"extensions": {
|
||||
"title": "PHP {{version}} Extensions",
|
||||
"desc": "Manage extensions via php.ini",
|
||||
"search_placeholder": "Search extension... (mysql, gd, mbstring...)",
|
||||
"search_file_placeholder": "Search inside file...",
|
||||
"raw_editor": "RAW EDITOR",
|
||||
"none": "No extensions found.",
|
||||
"not_found": "Extension not found.",
|
||||
"active": "Active",
|
||||
"ini_edit": "Edit php.ini ({{version}})",
|
||||
"file_open_tip": "Open file in system",
|
||||
"saving": "Configuration Saving",
|
||||
"restarting": "PHP service is restarting...",
|
||||
"adjusting": "Adjusting Extension",
|
||||
"adjusting_desc": "{{extName}} is being {{mode}} and PHP is restarting...",
|
||||
"save_restart_btn": "SAVE AND RESTART",
|
||||
"saving_btn": "SAVING...",
|
||||
"save_error": "Error occurred while saving extensions.",
|
||||
"success_msg": "Configuration saved and service restarted.",
|
||||
"prev_match": "Previous (Shift+Enter)",
|
||||
"next_match": "Next (Enter)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,36 @@
|
||||
"port": "Port",
|
||||
"all": "Tümü",
|
||||
"export": "Dışa Aktar",
|
||||
"import": "İçe Aktar"
|
||||
"import": "İçe Aktar",
|
||||
"ok": "Tamam",
|
||||
"cancel": "İptal",
|
||||
"error": "Hata!",
|
||||
"success": "Başarılı!",
|
||||
"warning": "Uyarı",
|
||||
"info": "Bilgi",
|
||||
"delete": "Sil",
|
||||
"edit": "Düzenle",
|
||||
"refresh": "Yenile",
|
||||
"search": "Ara",
|
||||
"loading": "Yükleniyor...",
|
||||
"starting": "Başlatılıyor",
|
||||
"are_you_sure": "Emin misiniz?",
|
||||
"yes_delete": "Evet, Sil",
|
||||
"go_to_fix": "Sorunu Düzeltmeye Git",
|
||||
"select": "SEÇ",
|
||||
"next": "İLERİ",
|
||||
"back": "GERİ",
|
||||
"finish": "BİTİR",
|
||||
"download": "İNDİR",
|
||||
"available": "İndirilebilir",
|
||||
"reset": "Sıfırla",
|
||||
"copy": "Kopyala",
|
||||
"browse": "Gözat",
|
||||
"delete_confirm": "Bu projeyi silmek istediğinize emin misiniz?",
|
||||
"stop_status": "Durduruluyor",
|
||||
"reset_confirm_title": "Emin misiniz?",
|
||||
"reset_confirm_text": "{{service}} verilerini sıfırlamak istiyor musunuz? Bu işlem tüm verileri siler ve temiz kurulum yapar.",
|
||||
"reset_btn": "Evet, Sıfırla"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Trunçgil Multi-PHP Server",
|
||||
@@ -20,6 +49,180 @@
|
||||
"active_version": "Aktif PHP Sürümü",
|
||||
"quick_look": "Hızlı Bakış",
|
||||
"start_all": "Tümünü Başlat",
|
||||
"stop_all": "Tümünü Durdur"
|
||||
"stop_all": "Tümünü Durdur",
|
||||
"all_started": "Tüm servisler başlatıldı.",
|
||||
"all_stopped": "Tüm servisler durduruldu."
|
||||
},
|
||||
"projects": {
|
||||
"title": "Projelerim",
|
||||
"add_new": "Yeni Proje Ekle",
|
||||
"edit": "Proje Düzenle",
|
||||
"empty": "Henüz bir proje eklenmemiş.",
|
||||
"name": "Proje Adı",
|
||||
"path": "Dosya Yolu",
|
||||
"host": "Host / Domain",
|
||||
"hostname_placeholder": "Hostname (örn: local.test)",
|
||||
"php_version": "PHP Sürümü",
|
||||
"mariadb_version": "MariaDB Sürümü",
|
||||
"server_type": "Web Sunucusu",
|
||||
"apache_htaccess": "Apache (htaccess desteği)",
|
||||
"actions": "Aksiyonlar",
|
||||
"no_php_warning": "Önce PHP sürümü indirmelisiniz",
|
||||
"added": "Proje başarıyla eklendi.",
|
||||
"updated": "Proje başarıyla güncellendi.",
|
||||
"deleted": "Proje silindi.",
|
||||
"delete_confirm": "Bu projeyi silmek istediğinize emin misiniz? Dosyalarınız silinmez, sadece listeden kaldırılır."
|
||||
},
|
||||
"settings": {
|
||||
"general": "Genel Ayarlar",
|
||||
"server_settings": "Sunucu Ayarları",
|
||||
"saved": "Ayarlar kaydedildi.",
|
||||
"save_failed": "Ayarlar kaydedilemedi.",
|
||||
"language": "Dil",
|
||||
"nginx_port": "Nginx Portu",
|
||||
"apache_port": "Apache Portu",
|
||||
"php_port": "PHP-FPM Portu",
|
||||
"mariadb_port": "MariaDB Portu",
|
||||
"remote_access": "Dış Erişime İzin Ver",
|
||||
"server_type_select": "Varsayılan Sunucu Tipi",
|
||||
"php_versions": "PHP Sürümleri",
|
||||
"mariadb_versions": "MariaDB Sürümleri",
|
||||
"nginx_versions": "Nginx Sürümleri",
|
||||
"apache_versions": "Apache Sürümleri",
|
||||
"php_versions_desc": "Gereken PHP sürümlerini buradan indirebilir ve yönetebilirsiniz.",
|
||||
"mariadb_versions_desc": "MariaDB sürümlerini buradan yönetebilirsiniz.",
|
||||
"nginx_versions_desc": "Nginx sürümlerini buradan yönetebilirsiniz.",
|
||||
"apache_versions_desc": "Apache sürümlerini buradan yönetebilirsiniz.",
|
||||
"nginx_port_desc": "Nginx'in çalışacağı port (Varsayılan: 80)"
|
||||
},
|
||||
"server": {
|
||||
"nginx": {
|
||||
"title": "Nginx",
|
||||
"config": "Nginx Ayarları",
|
||||
"config_title": "Nginx Yapılandırması (nginx.conf)",
|
||||
"config_warning": "Dikkat: Hatalı yapılandırma Nginx'in çalışmasını durdurabilir. Değişiklik yapmadan önce test edin.",
|
||||
"test_config": "Yapılandırmayı Test Et",
|
||||
"save_reload": "Kaydet ve Yeniden Yükle",
|
||||
"config_saved": "Nginx yapılandırması başarıyla kaydedildi.",
|
||||
"test_failed": "Yapılandırma Hatası"
|
||||
},
|
||||
"apache": {
|
||||
"title": "Apache",
|
||||
"config": "Apache Ayarları",
|
||||
"config_title": "Apache (httpd.conf) Yapılandırması",
|
||||
"config_desc": "Düzenlediğiniz bu dosya Apache sunucusunun ana (global) yapılandırma dosyasıdır.",
|
||||
"test_config": "Yapılandırmayı Test Et",
|
||||
"save_reload": "Kaydet ve Yeniden Yükle",
|
||||
"config_saved": "Apache yapılandırması kaydedildi."
|
||||
},
|
||||
"project_nginx": {
|
||||
"title": "{{host}} Nginx Yapılandırması",
|
||||
"tip": "İpucu: Bu yapılandırma sadece {{host}} projesi için geçerlidir.",
|
||||
"error_line": "Hata Satırı: {{line}}"
|
||||
}
|
||||
},
|
||||
"pma": {
|
||||
"ready_desc": "Veritabanı yönetimi için phpMyAdmin hazır.",
|
||||
"install_desc": "Veritabanlarını web üzerinden yönetmek için phpMyAdmin kurun.",
|
||||
"installing": "KURULUYOR...",
|
||||
"install_button": "KURULUMU BAŞLAT",
|
||||
"open": "AÇ",
|
||||
"progress": "İndiriliyor... %{{progress}}"
|
||||
},
|
||||
"mariadb": {
|
||||
"import": {
|
||||
"title": "MariaDB Veri İçe Aktar",
|
||||
"desc": "Seçtiğiniz bir .sql veya arşiv dosyasını hızlıca veritabanına yükleyin.",
|
||||
"button": "İÇE AKTAR",
|
||||
"wizard_title": "MariaDB Hızlı Dump/Import Sihirbazı",
|
||||
"step1": "Veri Seçimi",
|
||||
"step2": "Sunucu Seçimi",
|
||||
"step3": "Veritabanı Yapılandırması",
|
||||
"step4": "Özet ve İşlem",
|
||||
"step1_desc": "Lütfen yüklenecek olan .sql dosyasını veya arşivini (.zip, .tar.gz) seçin.",
|
||||
"step2_desc": "Dosyanın hangi MariaDB sunucusuna yükleneceğini seçin.",
|
||||
"step3_desc": "Veritabanı ve kullanıcı bilgilerini yapılandırın.",
|
||||
"no_file": "Dosya seçilmedi...",
|
||||
"root_pass": "Root Şifresi (Eğer varsa)",
|
||||
"root_pass_helper": "MariaDB 'root' kullanıcısının mevcut şifresini girin. Boşsa boş bırakın.",
|
||||
"db_name": "Veritabanı Adı",
|
||||
"db_user": "Veritabanı Kullanıcısı",
|
||||
"db_pass": "Kullanıcı Şifresi",
|
||||
"summary": "Özet Bilgiler",
|
||||
"file": "Dosya",
|
||||
"server": "Sunucu",
|
||||
"db": "Veritabanı",
|
||||
"user": "Kullanıcı",
|
||||
"success_title": "İşlem Başarılı!",
|
||||
"error_title": "Hata Oluştu!",
|
||||
"access_info": "Erişim Bilgileri",
|
||||
"host": "Host",
|
||||
"starting": "[Sistem] İşlem başlatılıyor...",
|
||||
"overwrite_title": "Veritabanı Mevcut!",
|
||||
"overwrite_desc": "'{{dbName}}' veritabanı zaten var. Üzerine yazmak istiyor musunuz? Mevcut tüm veriler silinecektir!",
|
||||
"btn_summary": "ÖZETİ GÖR",
|
||||
"btn_start": "IMPORTU BAŞLAT"
|
||||
},
|
||||
"export": {
|
||||
"title": "MariaDB Veri Dışa Aktar",
|
||||
"desc": "Veritabanlarını .sql veya .sql.gz olarak güvenle yedekleyin.",
|
||||
"button": "DIŞA AKTAR",
|
||||
"wizard_title": "MariaDB Veritabanı Dışa Aktarma Sihirbazı",
|
||||
"step1": "Sunucu Seçimi",
|
||||
"step2": "Veritabanı Seçimi",
|
||||
"step3": "Dışa Aktarma Ayarları",
|
||||
"step4": "Özet ve İşlem",
|
||||
"step1_desc": "Veritabanın hangi MariaDB sunucusunda olduğunu seçin.",
|
||||
"step2_desc": "Dışa aktarmak istediğiniz veritabanını seçin.",
|
||||
"step3_desc": "Dosyanın kaydedileceği yeri ve formatını belirleyin.",
|
||||
"placeholder": "Kaydedilecek dosya...",
|
||||
"compress": "Gzip ile Sıkıştır (.sql.gz)",
|
||||
"target": "Hedef",
|
||||
"compression": "Sıkıştırma",
|
||||
"on": "Açık (.gz)",
|
||||
"off": "Kapalı (.sql)",
|
||||
"btn_show_file": "DOSYAYI GÖSTER",
|
||||
"btn_start": "EXPORTU BAŞLAT",
|
||||
"starting": "[Sistem] Dışa aktarma işlemi başlatılıyor...",
|
||||
"no_db_found": "Seçili sunucuda erişilebilir veritabanı bulunamadı.",
|
||||
"list_error": "Veritabanları listelenemedi: "
|
||||
},
|
||||
"wizard": {
|
||||
"import_title": "MariaDB Veri İçe Aktarma Sihirbazı",
|
||||
"export_title": "MariaDB Veri Dışa Aktarma Sihirbazı",
|
||||
"select_version": "MariaDB Sürümü Seçin",
|
||||
"select_db": "Veritabanı Seçin",
|
||||
"select_file": "Dosya Seçin",
|
||||
"import_success": "Veri başarıyla içe aktarıldı.",
|
||||
"export_success": "Veri başarıyla dışa aktarıldı."
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"logs": "Hata Logları",
|
||||
"noLogs": "Henüz log kaydı bulunmuyor."
|
||||
},
|
||||
"php": {
|
||||
"extensions": {
|
||||
"title": "PHP {{version}} Eklentileri",
|
||||
"desc": "php.ini üzerinden eklentileri yönetin",
|
||||
"search_placeholder": "Eklenti ara... (mysql, gd, mbstring...)",
|
||||
"search_file_placeholder": "Dosya içerisinde ara...",
|
||||
"raw_editor": "RAW EDİTÖR",
|
||||
"none": "Hiç eklenti yok.",
|
||||
"not_found": "Eklenti bulunamadı.",
|
||||
"active": "Aktif",
|
||||
"ini_edit": "php.ini Düzenle ({{version}})",
|
||||
"file_open_tip": "Dosyayı sistemde aç",
|
||||
"saving": "Yapılandırma Kaydediliyor",
|
||||
"restarting": "PHP servisi yeniden başlatılıyor...",
|
||||
"adjusting": "Eklenti Ayarlanıyor",
|
||||
"adjusting_desc": "{{extName}} {{mode}} ve PHP yeniden başlatılıyor...",
|
||||
"save_restart_btn": "KAYDET VE YENİDEN BAŞLAT",
|
||||
"saving_btn": "KAYDEDİLİYOR...",
|
||||
"save_error": "Eklentiler kaydedilirken hata oluştu.",
|
||||
"success_msg": "Yapılandırma kaydedildi ve servis yeniden başlatıldı.",
|
||||
"prev_match": "Önceki (Shift+Enter)",
|
||||
"next_match": "Sonraki (Enter)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class ErrorBoundary extends React.Component<{ children: React.ReactNode }, { has
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div style={{ padding: 20, color: 'white' }}>
|
||||
<h1>Görüntüleme Hatası Oluştu</h1>
|
||||
<h1>{i18n.t('common.error')}</h1>
|
||||
<pre style={{ whiteSpace: 'pre-wrap' }}>{this.state.error?.toString()}</pre>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user