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 logo from './assets/logo.svg'
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@@ -72,6 +72,7 @@ import {
|
|||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import Swal from 'sweetalert2'
|
import Swal from 'sweetalert2'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { supportedLngs } from './i18n'
|
||||||
import MariaDbImportWizard from './components/MariaDbImportWizard'
|
import MariaDbImportWizard from './components/MariaDbImportWizard'
|
||||||
import MariaDbExportWizard from './components/MariaDbExportWizard'
|
import MariaDbExportWizard from './components/MariaDbExportWizard'
|
||||||
import NginxCodeEditor from './components/NginxCodeEditor'
|
import NginxCodeEditor from './components/NginxCodeEditor'
|
||||||
@@ -346,10 +347,10 @@ function App(): JSX.Element {
|
|||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Hata!',
|
title: t('common.error'),
|
||||||
text: result.message,
|
text: result.message,
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
confirmButtonText: 'Tamam',
|
confirmButtonText: t('common.ok'),
|
||||||
background: '#1e1e1e',
|
background: '#1e1e1e',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
confirmButtonColor: '#153E5E',
|
confirmButtonColor: '#153E5E',
|
||||||
@@ -374,12 +375,12 @@ function App(): JSX.Element {
|
|||||||
|
|
||||||
const handleResetData = async (service: string) => {
|
const handleResetData = async (service: string) => {
|
||||||
const confirmResult = await Swal.fire({
|
const confirmResult = await Swal.fire({
|
||||||
title: 'Emin misiniz?',
|
title: t('common.reset_confirm_title'),
|
||||||
text: `${service} verilerini sıfırlamak istiyor musunuz? Bu işlem tüm verileri siler ve temiz kurulum yapar.`,
|
text: t('common.reset_confirm_text', { service }),
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonText: 'Evet, Sıfırla',
|
confirmButtonText: t('common.reset_btn'),
|
||||||
cancelButtonText: 'Vazgeç',
|
cancelButtonText: t('common.cancel'),
|
||||||
background: '#1e1e1e',
|
background: '#1e1e1e',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
confirmButtonColor: '#d33',
|
confirmButtonColor: '#d33',
|
||||||
@@ -389,7 +390,7 @@ function App(): JSX.Element {
|
|||||||
if (confirmResult.isConfirmed) {
|
if (confirmResult.isConfirmed) {
|
||||||
const result = await window.api.invoke('services:reset-data', service)
|
const result = await window.api.invoke('services:reset-data', service)
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: result.success ? 'Başarılı!' : 'Hata!',
|
title: result.success ? t('common.success') : t('common.error'),
|
||||||
text: result.message,
|
text: result.message,
|
||||||
icon: result.success ? 'success' : 'error',
|
icon: result.success ? 'success' : 'error',
|
||||||
background: '#1e1e1e',
|
background: '#1e1e1e',
|
||||||
@@ -403,14 +404,15 @@ function App(): JSX.Element {
|
|||||||
if (window.api && window.api.saveSettings) {
|
if (window.api && window.api.saveSettings) {
|
||||||
const result = await window.api.saveSettings(settings)
|
const result = await window.api.saveSettings(settings)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setNotification({ open: true, message: 'Ayarlar kaydedildi.', severity: 'success' })
|
setNotification({ open: true, message: t('settings.saved'), severity: 'success' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleLanguage = () => {
|
const handleLanguageChange = (event: any) => {
|
||||||
const newLang = i18n.language === 'tr' ? 'en' : i18n.language === 'en' ? 'de' : 'tr'
|
const newLang = event.target.value
|
||||||
i18n.changeLanguage(newLang)
|
i18n.changeLanguage(newLang)
|
||||||
|
setSettings(prev => ({ ...prev, language: newLang }))
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleStartAll = async () => {
|
const handleStartAll = async () => {
|
||||||
@@ -437,7 +439,7 @@ function App(): JSX.Element {
|
|||||||
])
|
])
|
||||||
|
|
||||||
fetchStatus()
|
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 () => {
|
const handleStopAll = async () => {
|
||||||
@@ -454,12 +456,12 @@ function App(): JSX.Element {
|
|||||||
])
|
])
|
||||||
|
|
||||||
fetchStatus()
|
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) => {
|
const getStatusChip = (s: string) => {
|
||||||
if (s === 'starting') {
|
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'
|
const color = s === 'running' ? 'success' : s === 'stopped' ? 'error' : 'warning'
|
||||||
return <Chip label={s.toUpperCase()} color={color} size="small" sx={{ fontWeight: 'bold' }} />
|
return <Chip label={s.toUpperCase()} color={color} size="small" sx={{ fontWeight: 'bold' }} />
|
||||||
@@ -474,28 +476,28 @@ function App(): JSX.Element {
|
|||||||
}
|
}
|
||||||
setIsProjectDialogOpen(false)
|
setIsProjectDialogOpen(false)
|
||||||
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost' })
|
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()
|
fetchProjects()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRemoveProject = async (id: string) => {
|
const handleRemoveProject = async (id: string) => {
|
||||||
if (!window.api) return
|
if (!window.api) return
|
||||||
const result = await Swal.fire({
|
const result = await Swal.fire({
|
||||||
title: 'Emin misiniz?',
|
title: t('common.are_you_sure'),
|
||||||
text: "Bu projeyi silmek istediğinize emin misiniz? Nginx ayarları otomatik olarak güncellenecektir.",
|
text: t('projects.delete_confirm'),
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: '#ff4444',
|
confirmButtonColor: '#ff4444',
|
||||||
cancelButtonColor: '#3085d6',
|
cancelButtonColor: '#3085d6',
|
||||||
confirmButtonText: 'Evet, sil!',
|
confirmButtonText: t('common.yes_delete'),
|
||||||
cancelButtonText: 'İptal',
|
cancelButtonText: t('common.cancel'),
|
||||||
background: '#1e1e1e',
|
background: '#1e1e1e',
|
||||||
color: '#fff'
|
color: '#fff'
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
await window.api.removeProject(id)
|
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()
|
fetchProjects()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,7 +514,7 @@ function App(): JSX.Element {
|
|||||||
if (window.api && window.api.invoke) {
|
if (window.api && window.api.invoke) {
|
||||||
const result = await window.api.invoke('nginx:config:save', nginxConfig)
|
const result = await window.api.invoke('nginx:config:save', nginxConfig)
|
||||||
if (result.success) {
|
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)
|
setIsNginxConfigOpen(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -530,7 +532,7 @@ function App(): JSX.Element {
|
|||||||
if (window.api && window.api.invoke) {
|
if (window.api && window.api.invoke) {
|
||||||
const result = await window.api.invoke('apache:config:save', apacheConfig)
|
const result = await window.api.invoke('apache:config:save', apacheConfig)
|
||||||
if (result.success) {
|
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)
|
setIsApacheConfigOpen(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -577,15 +579,15 @@ function App(): JSX.Element {
|
|||||||
${errorInfo?.host ? `
|
${errorInfo?.host ? `
|
||||||
<div style="margin-top: 15px; text-align: center;">
|
<div style="margin-top: 15px; text-align: center;">
|
||||||
<p style="font-size: 0.9rem; color: #ffb142;">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
`,
|
`,
|
||||||
icon: result.success ? 'success' : 'error',
|
icon: result.success ? 'success' : 'error',
|
||||||
showCancelButton: !result.success && !!errorInfo?.host,
|
showCancelButton: !result.success && !!errorInfo?.host,
|
||||||
confirmButtonText: !result.success && errorInfo?.host ? 'Düzeltmeye Git' : 'Tamam',
|
confirmButtonText: !result.success && errorInfo?.host ? t('common.go_to_fix') : t('common.ok'),
|
||||||
cancelButtonText: 'Kapat',
|
cancelButtonText: t('common.close'),
|
||||||
background: '#1e1e1e',
|
background: '#1e1e1e',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
width: '600px'
|
width: '600px'
|
||||||
@@ -611,7 +613,7 @@ function App(): JSX.Element {
|
|||||||
if (window.api && window.api.invoke) {
|
if (window.api && window.api.invoke) {
|
||||||
const result = await window.api.invoke('project:nginx:save', selectedProjectHost, projectNginxConfig)
|
const result = await window.api.invoke('project:nginx:save', selectedProjectHost, projectNginxConfig)
|
||||||
if (result.success) {
|
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)
|
setIsProjectNginxConfigOpen(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -668,10 +670,9 @@ function App(): JSX.Element {
|
|||||||
try {
|
try {
|
||||||
const success = await window.api.pmaSetup()
|
const success = await window.api.pmaSetup()
|
||||||
if (success) {
|
if (success) {
|
||||||
setPmaInstalled(true)
|
setNotification({ open: true, message: t('server.phpmyadmin.installed_success'), severity: 'success' })
|
||||||
setNotification({ open: true, message: 'phpMyAdmin başarıyla kuruldu.', severity: 'success' })
|
|
||||||
} else {
|
} 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 {
|
} finally {
|
||||||
setPmaLoading(false)
|
setPmaLoading(false)
|
||||||
@@ -718,12 +719,28 @@ function App(): JSX.Element {
|
|||||||
backdropFilter: 'blur(10px)'
|
backdropFilter: 'blur(10px)'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Toolbar sx={{ justifyContent: 'flex-end' }}>
|
<Toolbar sx={{ gap: 2 }}>
|
||||||
<Tooltip title="Dil Değiştir">
|
<FormControl size="small" variant="outlined" sx={{ minWidth: 120 }}>
|
||||||
<IconButton onClick={toggleLanguage} color="inherit">
|
<Select
|
||||||
<LanguageIcon />
|
value={i18n.language}
|
||||||
</IconButton>
|
onChange={handleLanguageChange}
|
||||||
</Tooltip>
|
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')}>
|
<IconButton color="inherit" onClick={() => setActiveTab('settings')}>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -747,19 +764,19 @@ function App(): JSX.Element {
|
|||||||
<ListItem disablePadding>
|
<ListItem disablePadding>
|
||||||
<ListItemButton selected={activeTab === 'dashboard'} onClick={() => setActiveTab('dashboard')}>
|
<ListItemButton selected={activeTab === 'dashboard'} onClick={() => setActiveTab('dashboard')}>
|
||||||
<ListItemIcon><DashboardIcon color={activeTab === 'dashboard' ? 'primary' : 'inherit'} /></ListItemIcon>
|
<ListItemIcon><DashboardIcon color={activeTab === 'dashboard' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||||
<ListItemText primary="Dashboard" />
|
<ListItemText primary={t('dashboard.title')} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem disablePadding>
|
<ListItem disablePadding>
|
||||||
<ListItemButton selected={activeTab === 'projects'} onClick={() => setActiveTab('projects')}>
|
<ListItemButton selected={activeTab === 'projects'} onClick={() => setActiveTab('projects')}>
|
||||||
<ListItemIcon><ProjectIcon color={activeTab === 'projects' ? 'primary' : 'inherit'} /></ListItemIcon>
|
<ListItemIcon><ProjectIcon color={activeTab === 'projects' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||||
<ListItemText primary="Projeler" />
|
<ListItemText primary={t('projects.title')} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem disablePadding>
|
<ListItem disablePadding>
|
||||||
<ListItemButton selected={activeTab === 'tools'} onClick={() => setActiveTab('tools')}>
|
<ListItemButton selected={activeTab === 'tools'} onClick={() => setActiveTab('tools')}>
|
||||||
<ListItemIcon><ToolsIcon color={activeTab === 'tools' ? 'primary' : 'inherit'} /></ListItemIcon>
|
<ListItemIcon><ToolsIcon color={activeTab === 'tools' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||||
<ListItemText primary="Araçlar" />
|
<ListItemText primary={t('common.tools')} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
@@ -768,7 +785,7 @@ function App(): JSX.Element {
|
|||||||
<ListItem disablePadding>
|
<ListItem disablePadding>
|
||||||
<ListItemButton selected={activeTab === 'settings'} onClick={() => setActiveTab('settings')}>
|
<ListItemButton selected={activeTab === 'settings'} onClick={() => setActiveTab('settings')}>
|
||||||
<ListItemIcon><SettingsIcon color={activeTab === 'settings' ? 'primary' : 'inherit'} /></ListItemIcon>
|
<ListItemIcon><SettingsIcon color={activeTab === 'settings' ? 'primary' : 'inherit'} /></ListItemIcon>
|
||||||
<ListItemText primary="Genel Ayarlar" />
|
<ListItemText primary={t('settings.general')} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
@@ -788,19 +805,19 @@ function App(): JSX.Element {
|
|||||||
<Tab label="MariaDB" icon={<DbIcon />} iconPosition="start" />
|
<Tab label="MariaDB" icon={<DbIcon />} iconPosition="start" />
|
||||||
<Tab label="Nginx" icon={<WebIcon />} iconPosition="start" />
|
<Tab label="Nginx" icon={<WebIcon />} iconPosition="start" />
|
||||||
<Tab label="Apache" icon={<ServerIcon />} 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>
|
</Tabs>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{settingsTab === 0 && (
|
{settingsTab === 0 && (
|
||||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 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)' }}>
|
<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="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.php_versions')}</Typography>
|
||||||
<Typography variant="body2" color="text.secondary">Gereken PHP sürümlerini buradan indirebilir ve yönetebilirsiniz.</Typography>
|
<Typography variant="body2" color="text.secondary">{t('settings.php_versions_desc')}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||||
{phpVersions.length === 0 && (
|
{phpVersions.length === 0 && (
|
||||||
<ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem>
|
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||||
)}
|
)}
|
||||||
{phpVersions.map((v) => (
|
{phpVersions.map((v) => (
|
||||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||||
@@ -809,13 +826,13 @@ function App(): JSX.Element {
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={`PHP ${v.version}`}
|
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 }}
|
sx={{ flexGrow: 1 }}
|
||||||
/>
|
/>
|
||||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||||
{v.status === 'available' && (
|
{v.status === 'available' && (
|
||||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadPhp(v.id)}>
|
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadPhp(v.id)}>
|
||||||
İNDİR
|
{t('common.download')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{v.status === 'downloading' && (
|
{v.status === 'downloading' && (
|
||||||
@@ -826,9 +843,9 @@ function App(): JSX.Element {
|
|||||||
{v.status === 'installed' && (
|
{v.status === 'installed' && (
|
||||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||||
<Button variant="outlined" size="small" startIcon={<ToolsIcon />} onClick={() => handleOpenPhpExtensions(v.version)}>
|
<Button variant="outlined" size="small" startIcon={<ToolsIcon />} onClick={() => handleOpenPhpExtensions(v.version)}>
|
||||||
EKLENTİLER
|
{t('php.extensions.title', { version: '' }).replace(' ', ' ')}
|
||||||
</Button>
|
</Button>
|
||||||
<Chip label="HAZIR" color="success" variant="outlined" size="small" />
|
<Chip label={t('common.ok').toUpperCase()} color="success" variant="outlined" size="small" />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -841,12 +858,12 @@ function App(): JSX.Element {
|
|||||||
{settingsTab === 1 && (
|
{settingsTab === 1 && (
|
||||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 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)' }}>
|
<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="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.mariadb_versions')}</Typography>
|
||||||
<Typography variant="body2" color="text.secondary">Farklı MariaDB sürümlerini indirebilir ve sunucunuzda kullanabilirsiniz.</Typography>
|
<Typography variant="body2" color="text.secondary">{t('settings.mariadb_versions_desc')}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||||
{mariaDbVersions.length === 0 && (
|
{mariaDbVersions.length === 0 && (
|
||||||
<ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem>
|
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||||
)}
|
)}
|
||||||
{mariaDbVersions.map((v) => (
|
{mariaDbVersions.map((v) => (
|
||||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||||
@@ -854,15 +871,8 @@ function App(): JSX.Element {
|
|||||||
{v.status === 'installed' ? <InstalledIcon color="success" /> : <AvailableIcon color="action" />}
|
{v.status === 'installed' ? <InstalledIcon color="success" /> : <AvailableIcon color="action" />}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={`MariaDB ${v.version}`}
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
secondary={v.status === 'downloading' ? `${t('common.loading')} %${Math.round(v.progress)}` : v.status === 'installed' ? t('php.extensions.active') : t('common.available')}
|
||||||
{`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'}
|
|
||||||
sx={{ flexGrow: 1 }}
|
sx={{ flexGrow: 1 }}
|
||||||
/>
|
/>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||||
@@ -883,7 +893,7 @@ function App(): JSX.Element {
|
|||||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||||
{v.status === 'available' && (
|
{v.status === 'available' && (
|
||||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadMariaDb(v.id)}>
|
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadMariaDb(v.id)}>
|
||||||
İNDİR
|
{t('common.download')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{v.status === 'downloading' && (
|
{v.status === 'downloading' && (
|
||||||
@@ -892,7 +902,7 @@ function App(): JSX.Element {
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{v.status === 'installed' && (
|
{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>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -905,24 +915,27 @@ function App(): JSX.Element {
|
|||||||
{settingsTab === 2 && (
|
{settingsTab === 2 && (
|
||||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 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)' }}>
|
<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="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.nginx_versions')}</Typography>
|
||||||
<Typography variant="body2" color="text.secondary">Sunucu için gerekli Nginx binary dosyalarını buradan indirebilirsiniz.</Typography>
|
<Typography variant="body2" color="text.secondary">{t('settings.nginx_versions_desc')}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<List>
|
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||||
|
{nginxVersions.length === 0 && (
|
||||||
|
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||||
|
)}
|
||||||
{nginxVersions.map((v) => (
|
{nginxVersions.map((v) => (
|
||||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
{v.status === 'installed' ? <InstalledIcon color="success" /> : <AvailableIcon color="action" />}
|
{v.status === 'installed' ? <InstalledIcon color="success" /> : <AvailableIcon color="action" />}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={`Nginx ${v.version} (Stable)`}
|
primary={`Nginx ${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 }}
|
sx={{ flexGrow: 1 }}
|
||||||
/>
|
/>
|
||||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||||
{v.status === 'available' && (
|
{v.status === 'available' && (
|
||||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadNginx(v.id)}>
|
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadNginx(v.id)}>
|
||||||
İNDİR
|
{t('common.download')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{v.status === 'downloading' && (
|
{v.status === 'downloading' && (
|
||||||
@@ -931,7 +944,7 @@ function App(): JSX.Element {
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{v.status === 'installed' && (
|
{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>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@@ -943,10 +956,13 @@ function App(): JSX.Element {
|
|||||||
{settingsTab === 3 && (
|
{settingsTab === 3 && (
|
||||||
<Paper sx={{ bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 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)' }}>
|
<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="subtitle1" sx={{ fontWeight: 'bold' }}>{t('settings.apache_versions')}</Typography>
|
||||||
<Typography variant="body2" color="text.secondary">Apache HTTP Server binary dosyalarını buradan yönetebilirsiniz.</Typography>
|
<Typography variant="body2" color="text.secondary">{t('settings.apache_versions_desc')}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<List>
|
<List sx={{ maxHeight: 500, overflow: 'auto' }}>
|
||||||
|
{apacheVersions.length === 0 && (
|
||||||
|
<ListItem><ListItemText primary={t('common.loading')} /></ListItem>
|
||||||
|
)}
|
||||||
{apacheVersions.map((v) => (
|
{apacheVersions.map((v) => (
|
||||||
<ListItem key={v.id} sx={{ py: 2 }}>
|
<ListItem key={v.id} sx={{ py: 2 }}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
@@ -954,13 +970,13 @@ function App(): JSX.Element {
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={`Apache ${v.version}`}
|
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 }}
|
sx={{ flexGrow: 1 }}
|
||||||
/>
|
/>
|
||||||
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
<Box sx={{ minWidth: 120, textAlign: 'right' }}>
|
||||||
{v.status === 'available' && (
|
{v.status === 'available' && (
|
||||||
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadApache(v.id)}>
|
<Button variant="outlined" size="small" startIcon={<DownloadIcon />} onClick={() => handleDownloadApache(v.id)}>
|
||||||
İNDİR
|
{t('common.download')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{v.status === 'downloading' && (
|
{v.status === 'downloading' && (
|
||||||
@@ -971,9 +987,9 @@ function App(): JSX.Element {
|
|||||||
{v.status === 'installed' && (
|
{v.status === 'installed' && (
|
||||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||||
<Button variant="outlined" size="small" startIcon={<SettingsIcon />} onClick={handleOpenApacheConfig}>
|
<Button variant="outlined" size="small" startIcon={<SettingsIcon />} onClick={handleOpenApacheConfig}>
|
||||||
YAPILANDIRMA
|
{t('common.settings').toUpperCase()}
|
||||||
</Button>
|
</Button>
|
||||||
<Chip label="HAZIR" color="success" variant="outlined" size="small" />
|
<Chip label={t('common.ok').toUpperCase()} color="success" variant="outlined" size="small" />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -984,78 +1000,50 @@ function App(): JSX.Element {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{settingsTab === 4 && (
|
{settingsTab === 4 && (
|
||||||
<Box component={Stack} spacing={3}>
|
<Paper sx={{ p: 4, bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
||||||
<Paper sx={{ p: 3, bgcolor: 'rgba(255, 255, 255, 0.03)', borderRadius: 2 }}>
|
<Typography variant="h6" gutterBottom sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
<Typography variant="h6" gutterBottom>Port Ayarları</Typography>
|
<SettingsIcon color="primary" />
|
||||||
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 3, mt: 2 }}>
|
{t('settings.server')}
|
||||||
<FormControl variant="filled" size="small" fullWidth>
|
</Typography>
|
||||||
<InputLabel>Varsayılan Web Sunucusu</InputLabel>
|
<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
|
<Select
|
||||||
value={settings.serverType || 'nginx'}
|
value={settings.serverType}
|
||||||
|
label={t('settings.server_type_select')}
|
||||||
onChange={(e) => setSettings({ ...settings, serverType: e.target.value as any })}
|
onChange={(e) => setSettings({ ...settings, serverType: e.target.value as any })}
|
||||||
>
|
>
|
||||||
<MenuItem value="nginx">Nginx (Performans)</MenuItem>
|
<MenuItem value="nginx">Nginx</MenuItem>
|
||||||
<MenuItem value="apache">Apache (htaccess Desteği)</MenuItem>
|
<MenuItem value="apache">Apache</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<TextField
|
</Grid>
|
||||||
label="Nginx Portu"
|
<Grid item xs={12}>
|
||||||
value={settings.nginxPort}
|
<FormControlLabel
|
||||||
onChange={(e) => setSettings({ ...settings, nginxPort: e.target.value })}
|
control={<Switch checked={settings.allowRemoteAccess} onChange={(e) => setSettings({ ...settings, allowRemoteAccess: e.target.checked })} />}
|
||||||
variant="filled"
|
label={t('settings.remote_access')}
|
||||||
size="small"
|
|
||||||
helperText="Varsayılan: 80"
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
</Grid>
|
||||||
label="Apache Portu"
|
<Grid item xs={12} sx={{ mt: 2 }}>
|
||||||
value={settings.apachePort}
|
<Button variant="contained" color="primary" size="large" startIcon={<SaveIcon />} onClick={handleSaveSettings} fullWidth>
|
||||||
onChange={(e) => setSettings({ ...settings, apachePort: e.target.value })}
|
{t('common.save')}
|
||||||
variant="filled"
|
</Button>
|
||||||
size="small"
|
</Grid>
|
||||||
helperText="Varsayılan: 8080"
|
</Grid>
|
||||||
/>
|
</Paper>
|
||||||
<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>
|
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
@@ -1094,12 +1082,12 @@ function App(): JSX.Element {
|
|||||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>Port: {settings.nginxPort}</Typography>
|
<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', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
<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" />
|
<TerminalIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={handleOpenNginxConfig}
|
onClick={handleOpenNginxConfig}
|
||||||
title="Nginx Yapılandırması"
|
title={t('server.nginx.config')}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'primary.main' } }}
|
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' })
|
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"
|
size="small"
|
||||||
disabled={status.nginx !== 'running'}
|
disabled={status.nginx !== 'running'}
|
||||||
sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'primary.main' } }}
|
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>
|
<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', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
<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" />
|
<TerminalIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={handleOpenApacheConfig}
|
onClick={handleOpenApacheConfig}
|
||||||
title="Apache Yapılandırması"
|
title={t('server.apache.config')}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'primary.main' } }}
|
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>
|
<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', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
<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" />
|
<TerminalIcon fontSize="small" />
|
||||||
</IconButton>
|
</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" />
|
<ResetIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -1262,7 +1250,7 @@ function App(): JSX.Element {
|
|||||||
<Box sx={{ flexGrow: 1 }}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>phpMyAdmin</Typography>
|
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>phpMyAdmin</Typography>
|
||||||
<Typography variant="body2" color="text.secondary">
|
<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>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -1275,7 +1263,7 @@ function App(): JSX.Element {
|
|||||||
startIcon={pmaLoading ? <CircularProgress size={20} /> : <DownloadIcon />}
|
startIcon={pmaLoading ? <CircularProgress size={20} /> : <DownloadIcon />}
|
||||||
sx={{ borderRadius: 2 }}
|
sx={{ borderRadius: 2 }}
|
||||||
>
|
>
|
||||||
{pmaLoading ? 'KURULUYOR...' : 'KURULUMU BAŞLAT'}
|
{pmaLoading ? t('pma.installing') : t('pma.install_button')}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
@@ -1285,7 +1273,7 @@ function App(): JSX.Element {
|
|||||||
startIcon={<OpenIcon />}
|
startIcon={<OpenIcon />}
|
||||||
sx={{ borderRadius: 2 }}
|
sx={{ borderRadius: 2 }}
|
||||||
>
|
>
|
||||||
AÇ
|
{t('pma.open')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -1294,7 +1282,7 @@ function App(): JSX.Element {
|
|||||||
<Box sx={{ mt: 3 }}>
|
<Box sx={{ mt: 3 }}>
|
||||||
<LinearProgress variant="determinate" value={pmaProgress} sx={{ height: 8, borderRadius: 4 }} />
|
<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' }}>
|
<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>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
@@ -1306,9 +1294,9 @@ function App(): JSX.Element {
|
|||||||
<DbIcon color="primary" sx={{ fontSize: 32 }} />
|
<DbIcon color="primary" sx={{ fontSize: 32 }} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ flexGrow: 1 }}>
|
<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">
|
<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>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -1319,7 +1307,7 @@ function App(): JSX.Element {
|
|||||||
startIcon={<DbIcon />}
|
startIcon={<DbIcon />}
|
||||||
sx={{ borderRadius: 2 }}
|
sx={{ borderRadius: 2 }}
|
||||||
>
|
>
|
||||||
İÇE AKTAR
|
{t('mariadb.import.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -1331,9 +1319,9 @@ function App(): JSX.Element {
|
|||||||
<DbIcon color="secondary" sx={{ fontSize: 32 }} />
|
<DbIcon color="secondary" sx={{ fontSize: 32 }} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ flexGrow: 1 }}>
|
<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">
|
<Typography variant="body2" color="text.secondary">
|
||||||
Veritabanlarını .sql veya .sql.gz olarak güvenle yedekleyin.
|
{t('mariadb.export.desc')}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -1345,7 +1333,7 @@ function App(): JSX.Element {
|
|||||||
startIcon={<DbIcon />}
|
startIcon={<DbIcon />}
|
||||||
sx={{ borderRadius: 2 }}
|
sx={{ borderRadius: 2 }}
|
||||||
>
|
>
|
||||||
DIŞA AKTAR
|
{t('mariadb.export.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -1358,16 +1346,16 @@ function App(): JSX.Element {
|
|||||||
<Box>
|
<Box>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
||||||
<Typography variant="h5" sx={{ fontWeight: 'medium' }}>
|
<Typography variant="h5" sx={{ fontWeight: 'medium' }}>
|
||||||
Projelerim
|
{t('projects.title')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button variant="contained" startIcon={<ProjectIcon />} onClick={() => setIsProjectDialogOpen(true)}>
|
<Button variant="contained" startIcon={<ProjectIcon />} onClick={() => setIsProjectDialogOpen(true)}>
|
||||||
Yeni Proje Ekle
|
{t('projects.add_new')}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{projects.length === 0 ? (
|
{projects.length === 0 ? (
|
||||||
<Paper sx={{ p: 4, textAlign: 'center', bgcolor: 'rgba(255, 255, 255, 0.03)' }}>
|
<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>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
@@ -1405,7 +1393,7 @@ function App(): JSX.Element {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ display: 'flex', gap: 0.5, flexShrink: 0 }}>
|
<Box sx={{ display: 'flex', gap: 0.5, flexShrink: 0 }}>
|
||||||
<Tooltip title="Düzenle">
|
<Tooltip title={t('common.edit')}>
|
||||||
<IconButton size="small" onClick={() => {
|
<IconButton size="small" onClick={() => {
|
||||||
setNewProject(project)
|
setNewProject(project)
|
||||||
setIsProjectDialogOpen(true)
|
setIsProjectDialogOpen(true)
|
||||||
@@ -1414,7 +1402,7 @@ function App(): JSX.Element {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{project.serverType !== 'apache' && (
|
{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' } }}>
|
<IconButton size="small" onClick={() => handleOpenProjectNginxConfig(project.host)} sx={{ color: 'rgba(255,255,255,0.4)', '&:hover': { color: '#39A7FF' } }}>
|
||||||
<TerminalIcon fontSize="small" />
|
<TerminalIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -1474,7 +1462,7 @@ function App(): JSX.Element {
|
|||||||
'&:hover': { bgcolor: 'rgba(57, 167, 255, 0.1)' }
|
'&:hover': { bgcolor: 'rgba(57, 167, 255, 0.1)' }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Gözat
|
{t('projects.browse')}
|
||||||
</Button>
|
</Button>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -1614,17 +1602,17 @@ function App(): JSX.Element {
|
|||||||
setIsProjectDialogOpen(false)
|
setIsProjectDialogOpen(false)
|
||||||
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost', serverType: 'nginx' })
|
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost', serverType: 'nginx' })
|
||||||
}} fullWidth maxWidth="sm">
|
}} 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>
|
<DialogContent>
|
||||||
<Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>
|
<Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||||
<TextField
|
<TextField
|
||||||
label="Proje Adı"
|
label={t('projects.name')}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={newProject.name}
|
value={newProject.name}
|
||||||
onChange={(e) => setNewProject({ ...newProject, name: e.target.value })}
|
onChange={(e) => setNewProject({ ...newProject, name: e.target.value })}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Dosya Yolu"
|
label={t('projects.path')}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={newProject.path}
|
value={newProject.path}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
@@ -1639,17 +1627,17 @@ function App(): JSX.Element {
|
|||||||
onChange={(e) => setNewProject({ ...newProject, path: e.target.value })}
|
onChange={(e) => setNewProject({ ...newProject, path: e.target.value })}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Hostname (örn: local.test)"
|
label={t('projects.hostname_placeholder')}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={newProject.host}
|
value={newProject.host}
|
||||||
onChange={(e) => setNewProject({ ...newProject, host: e.target.value })}
|
onChange={(e) => setNewProject({ ...newProject, host: e.target.value })}
|
||||||
/>
|
/>
|
||||||
<FormControl fullWidth disabled={installedPhpVersions.length === 0}>
|
<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
|
<Select
|
||||||
labelId="php-version-label"
|
labelId="php-version-label"
|
||||||
value={newProject.phpVersion}
|
value={newProject.phpVersion}
|
||||||
label="PHP Sürümü"
|
label={t('projects.php_version')}
|
||||||
onChange={(e) => setNewProject({ ...newProject, phpVersion: e.target.value })}
|
onChange={(e) => setNewProject({ ...newProject, phpVersion: e.target.value })}
|
||||||
>
|
>
|
||||||
{installedPhpVersions.length > 0 ? (
|
{installedPhpVersions.length > 0 ? (
|
||||||
@@ -1657,20 +1645,20 @@ function App(): JSX.Element {
|
|||||||
<MenuItem key={v.id} value={v.version}>PHP {v.version}</MenuItem>
|
<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>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth>
|
||||||
<InputLabel id="server-type-label">Web Sunucusu</InputLabel>
|
<InputLabel id="server-type-label">{t('projects.server_type')}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
labelId="server-type-label"
|
labelId="server-type-label"
|
||||||
value={newProject.serverType || 'nginx'}
|
value={newProject.serverType || 'nginx'}
|
||||||
label="Web Sunucusu"
|
label={t('projects.server_type')}
|
||||||
onChange={(e) => setNewProject({ ...newProject, serverType: e.target.value as any })}
|
onChange={(e) => setNewProject({ ...newProject, serverType: e.target.value as any })}
|
||||||
>
|
>
|
||||||
<MenuItem value="nginx">Nginx</MenuItem>
|
<MenuItem value="nginx">Nginx</MenuItem>
|
||||||
<MenuItem value="apache">Apache (htaccess desteği)</MenuItem>
|
<MenuItem value="apache">{t('projects.apache_htaccess')}</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -1679,13 +1667,13 @@ function App(): JSX.Element {
|
|||||||
<Button onClick={() => {
|
<Button onClick={() => {
|
||||||
setIsProjectDialogOpen(false)
|
setIsProjectDialogOpen(false)
|
||||||
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost', serverType: 'nginx' })
|
setNewProject({ name: '', path: '', phpVersion: '', mariaDbVersion: '', host: 'localhost', serverType: 'nginx' })
|
||||||
}}>İptal</Button>
|
}}>{t('common.cancel')}</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleAddProject}
|
onClick={handleAddProject}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
disabled={!newProject.name || !newProject.path || installedPhpVersions.length === 0}
|
disabled={!newProject.name || !newProject.path || installedPhpVersions.length === 0}
|
||||||
>
|
>
|
||||||
{newProject.id ? 'Güncelle' : 'Ekle'}
|
{newProject.id ? t('common.save') : t('common.save')}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -1717,14 +1705,14 @@ function App(): JSX.Element {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<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)' }}>
|
<IconButton onClick={() => setIsNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers sx={{ borderColor: 'rgba(255,255,255,0.1)' }}>
|
<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' }}>
|
<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>
|
</Typography>
|
||||||
<NginxCodeEditor
|
<NginxCodeEditor
|
||||||
value={nginxConfig}
|
value={nginxConfig}
|
||||||
@@ -1738,17 +1726,17 @@ function App(): JSX.Element {
|
|||||||
startIcon={<RefreshIcon />}
|
startIcon={<RefreshIcon />}
|
||||||
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
||||||
>
|
>
|
||||||
Yapılandırmayı Test Et
|
{t('server.nginx.test_config')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setIsNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
<Button onClick={() => setIsNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
||||||
İptal
|
{t('common.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSaveNginxConfig}
|
onClick={handleSaveNginxConfig}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
startIcon={<SaveIcon />}
|
startIcon={<SaveIcon />}
|
||||||
>
|
>
|
||||||
Kaydet ve Yeniden Yükle
|
{t('server.nginx.save_reload')}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -1768,14 +1756,14 @@ function App(): JSX.Element {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<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)' }}>
|
<IconButton onClick={() => setIsProjectNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers sx={{ borderColor: 'rgba(255,255,255,0.1)' }}>
|
<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' }}>
|
<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>
|
</Typography>
|
||||||
<NginxCodeEditor
|
<NginxCodeEditor
|
||||||
value={projectNginxConfig}
|
value={projectNginxConfig}
|
||||||
@@ -1798,7 +1786,7 @@ function App(): JSX.Element {
|
|||||||
.replace(/successful/g, '<span style="color: #33d9b2;">successful</span>')
|
.replace(/successful/g, '<span style="color: #33d9b2;">successful</span>')
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: result.success ? 'Başarılı' : 'Yapılandırma Hatası',
|
title: result.success ? t('common.success') : t('server.nginx.test_failed'),
|
||||||
html: `
|
html: `
|
||||||
<div class="nginx-error-container">
|
<div class="nginx-error-container">
|
||||||
${formattedMessage}
|
${formattedMessage}
|
||||||
@@ -1806,7 +1794,7 @@ function App(): JSX.Element {
|
|||||||
${!result.success && errorInfo ? `
|
${!result.success && errorInfo ? `
|
||||||
<div style="margin-top: 15px; text-align: center;">
|
<div style="margin-top: 15px; text-align: center;">
|
||||||
<p style="font-size: 0.9rem; color: #ffb142;">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
@@ -1822,17 +1810,17 @@ function App(): JSX.Element {
|
|||||||
startIcon={<RefreshIcon />}
|
startIcon={<RefreshIcon />}
|
||||||
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
||||||
>
|
>
|
||||||
Yapılandırmayı Test Et
|
{t('server.nginx.test_config')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setIsProjectNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
<Button onClick={() => setIsProjectNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
||||||
İptal
|
{t('common.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSaveProjectNginxConfig}
|
onClick={handleSaveProjectNginxConfig}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
startIcon={<SaveIcon />}
|
startIcon={<SaveIcon />}
|
||||||
>
|
>
|
||||||
Kaydet ve Yeniden Yükle
|
{t('server.nginx.save_reload')}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -1851,14 +1839,14 @@ function App(): JSX.Element {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<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)' }}>
|
<IconButton onClick={() => setIsApacheConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers sx={{ borderColor: 'rgba(255,255,255,0.1)' }}>
|
<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' }}>
|
<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>
|
</Typography>
|
||||||
<ApacheCodeEditor
|
<ApacheCodeEditor
|
||||||
value={apacheConfig}
|
value={apacheConfig}
|
||||||
@@ -1872,13 +1860,13 @@ function App(): JSX.Element {
|
|||||||
startIcon={<RefreshIcon />}
|
startIcon={<RefreshIcon />}
|
||||||
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
sx={{ color: '#fff', borderColor: 'rgba(255,255,255,0.3)' }}
|
||||||
>
|
>
|
||||||
Yapılandırmayı Test Et
|
{t('server.apache.test_config')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setIsApacheConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
<Button onClick={() => setIsApacheConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.6)' }}>
|
||||||
İptal
|
{t('common.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleSaveApacheConfig} variant="contained" color="primary" startIcon={<SaveIcon />}>
|
<Button onClick={handleSaveApacheConfig} variant="contained" color="primary" startIcon={<SaveIcon />}>
|
||||||
Kaydet ve Yeniden Yükle
|
{t('server.apache.save_reload')}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
Save as SaveIcon
|
Save as SaveIcon
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import Swal from 'sweetalert2'
|
import Swal from 'sweetalert2'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface MariaDbExportWizardProps {
|
interface MariaDbExportWizardProps {
|
||||||
open: boolean
|
open: boolean
|
||||||
@@ -36,14 +37,15 @@ interface MariaDbExportWizardProps {
|
|||||||
mariaDbVersions: any[]
|
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 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 [activeStep, setActiveStep] = useState(0)
|
||||||
const [selectedVersion, setSelectedVersion] = useState('')
|
const [selectedVersion, setSelectedVersion] = useState('')
|
||||||
const [databases, setDatabases] = useState<string[]>([])
|
const [databases, setDatabases] = useState<string[]>([])
|
||||||
@@ -79,7 +81,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
|
|
||||||
const handleStep1Next = async () => {
|
const handleStep1Next = async () => {
|
||||||
if (!selectedVersion) {
|
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
|
return
|
||||||
}
|
}
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
@@ -88,7 +90,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
setDatabases(dbs)
|
setDatabases(dbs)
|
||||||
nextStep()
|
nextStep()
|
||||||
} catch (err: any) {
|
} 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 {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
@@ -103,7 +105,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
|
|
||||||
const startExport = async () => {
|
const startExport = async () => {
|
||||||
setLoading(true)
|
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) => {
|
const removeListener = window.api.onMariaDbExportLog((msg: string) => {
|
||||||
setLogs(prev => [...prev, msg])
|
setLogs(prev => [...prev, msg])
|
||||||
@@ -131,12 +133,12 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
case 0:
|
case 0:
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 2 }}>
|
<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 }}>
|
<FormControl fullWidth sx={{ mt: 2 }}>
|
||||||
<InputLabel>MariaDB Sunucusu</InputLabel>
|
<InputLabel>{t('mariadb.import.server')}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={selectedVersion}
|
value={selectedVersion}
|
||||||
label="MariaDB Sunucusu"
|
label={t('mariadb.import.server')}
|
||||||
onChange={(e) => setSelectedVersion(e.target.value)}
|
onChange={(e) => setSelectedVersion(e.target.value)}
|
||||||
>
|
>
|
||||||
{mariaDbVersions.filter(v => v.status === 'installed').map(v => (
|
{mariaDbVersions.filter(v => v.status === 'installed').map(v => (
|
||||||
@@ -147,25 +149,25 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<TextField
|
<TextField
|
||||||
label="Root Şifresi (Eğer varsa)"
|
label={t('mariadb.import.root_pass')}
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ mt: 3 }}
|
sx={{ mt: 3 }}
|
||||||
value={rootPass}
|
value={rootPass}
|
||||||
type="password"
|
type="password"
|
||||||
onChange={(e) => setRootPass(e.target.value)}
|
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>
|
</Box>
|
||||||
)
|
)
|
||||||
case 1:
|
case 1:
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 2 }}>
|
<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 }}>
|
<FormControl fullWidth sx={{ mt: 2 }}>
|
||||||
<InputLabel>Veritabanı</InputLabel>
|
<InputLabel>{t('mariadb.export.db')}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={selectedDb}
|
value={selectedDb}
|
||||||
label="Veritabanı"
|
label={t('mariadb.export.db')}
|
||||||
onChange={(e) => setSelectedDb(e.target.value)}
|
onChange={(e) => setSelectedDb(e.target.value)}
|
||||||
>
|
>
|
||||||
{databases.map(db => (
|
{databases.map(db => (
|
||||||
@@ -175,7 +177,7 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
{databases.length === 0 && (
|
{databases.length === 0 && (
|
||||||
<Typography variant="caption" color="error" sx={{ mt: 1, display: 'block' }}>
|
<Typography variant="caption" color="error" sx={{ mt: 1, display: 'block' }}>
|
||||||
Seçili sunucuda erişilebilir veritabanı bulunamadı.
|
{t('mariadb.export.no_db_found')}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -183,17 +185,17 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
case 2:
|
case 2:
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 3 }}>
|
<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
|
<FormControlLabel
|
||||||
control={<Checkbox checked={compress} onChange={(e) => setCompress(e.target.checked)} />}
|
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' }}>
|
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={savePath}
|
value={savePath}
|
||||||
placeholder="Kaydedilecek dosya..."
|
placeholder={t('mariadb.export.placeholder')}
|
||||||
disabled
|
disabled
|
||||||
InputProps={{
|
InputProps={{
|
||||||
startAdornment: (
|
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>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
@@ -213,13 +215,13 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
{!exportResult ? (
|
{!exportResult ? (
|
||||||
<>
|
<>
|
||||||
<Paper sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.05)', borderRadius: 2 }}>
|
<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 }} />
|
<Divider sx={{ my: 1 }} />
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<Typography variant="body2"><strong>Sunucu:</strong> {selectedVersion}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.server')}:</strong> {selectedVersion}</Typography>
|
||||||
<Typography variant="body2"><strong>Veritabanı:</strong> {selectedDb}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.db')}:</strong> {selectedDb}</Typography>
|
||||||
<Typography variant="body2"><strong>Hedef:</strong> {savePath}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.export.target')}:</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.export.compression')}:</strong> {compress ? t('mariadb.export.on') : t('mariadb.export.off')}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
{loading && (
|
{loading && (
|
||||||
@@ -238,20 +240,20 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
{exportResult.success ? (
|
{exportResult.success ? (
|
||||||
<>
|
<>
|
||||||
<SuccessIcon color="success" sx={{ fontSize: 60 }} />
|
<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>
|
<Typography variant="body2" color="text.secondary">{exportResult.message}</Typography>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{ mt: 3 }}
|
sx={{ mt: 3 }}
|
||||||
onClick={() => window.api.invoke('shell:open-path', savePath.substring(0, savePath.lastIndexOf('\\')))}
|
onClick={() => window.api.invoke('shell:open-path', savePath.substring(0, savePath.lastIndexOf('\\')))}
|
||||||
>
|
>
|
||||||
DOSYAYI GÖSTER
|
{t('mariadb.export.btn_show_file')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<ErrorIcon color="error" sx={{ fontSize: 60 }} />
|
<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>
|
<Typography variant="body2" color="error">{exportResult.message}</Typography>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -260,13 +262,13 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return 'Bilinmeyen adım'
|
return t('common.error')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onClose={loading ? undefined : onClose} maxWidth="sm" fullWidth>
|
<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>
|
<DialogContent>
|
||||||
<Stepper activeStep={activeStep} orientation="horizontal" sx={{ pt: 2, pb: 4 }}>
|
<Stepper activeStep={activeStep} orientation="horizontal" sx={{ pt: 2, pb: 4 }}>
|
||||||
{steps.map((label) => (
|
{steps.map((label) => (
|
||||||
@@ -280,25 +282,25 @@ const MariaDbExportWizard: React.FC<MariaDbExportWizardProps> = ({ open, onClose
|
|||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={onClose} disabled={loading}>KAPAT</Button>
|
<Button onClick={onClose} disabled={loading}>{t('common.close')}</Button>
|
||||||
<Box sx={{ flexGrow: 1 }} />
|
<Box sx={{ flexGrow: 1 }} />
|
||||||
{activeStep > 0 && activeStep < 3 && !exportResult && (
|
{activeStep > 0 && activeStep < 3 && !exportResult && (
|
||||||
<Button onClick={prevStep} disabled={loading}>GERİ</Button>
|
<Button onClick={prevStep} disabled={loading}>{t('common.back')}</Button>
|
||||||
)}
|
)}
|
||||||
{activeStep === 0 && (
|
{activeStep === 0 && (
|
||||||
<Button variant="contained" onClick={handleStep1Next} disabled={loading}>
|
<Button variant="contained" onClick={handleStep1Next} disabled={loading}>
|
||||||
{loading ? <CircularProgress size={24} /> : 'İLERİ'}
|
{loading ? <CircularProgress size={24} /> : t('common.next')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{activeStep === 1 && (
|
{activeStep === 1 && (
|
||||||
<Button variant="contained" onClick={nextStep} disabled={!selectedDb}>İLERİ</Button>
|
<Button variant="contained" onClick={nextStep} disabled={!selectedDb}>{t('common.next')}</Button>
|
||||||
)}
|
)}
|
||||||
{activeStep === 2 && (
|
{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 && (
|
{activeStep === 3 && !exportResult && (
|
||||||
<Button variant="contained" color="primary" onClick={startExport} disabled={loading}>
|
<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>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
Error as ErrorIcon
|
Error as ErrorIcon
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import Swal from 'sweetalert2'
|
import Swal from 'sweetalert2'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface MariaDbImportWizardProps {
|
interface MariaDbImportWizardProps {
|
||||||
open: boolean
|
open: boolean
|
||||||
@@ -36,14 +37,15 @@ interface MariaDbImportWizardProps {
|
|||||||
mariaDbVersions: any[]
|
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 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 [activeStep, setActiveStep] = useState(0)
|
||||||
const [filePath, setFilePath] = useState('')
|
const [filePath, setFilePath] = useState('')
|
||||||
const [selectedVersion, setSelectedVersion] = useState('')
|
const [selectedVersion, setSelectedVersion] = useState('')
|
||||||
@@ -103,7 +105,7 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
|
|
||||||
const handleStep2Next = () => {
|
const handleStep2Next = () => {
|
||||||
if (!selectedVersion) {
|
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
|
return
|
||||||
}
|
}
|
||||||
nextStep()
|
nextStep()
|
||||||
@@ -111,7 +113,7 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
|
|
||||||
const handleStep3Next = async () => {
|
const handleStep3Next = async () => {
|
||||||
if (!dbConfig.dbName || !dbConfig.user) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,19 +122,19 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
const { exists } = await window.api.checkMariaDbDb(selectedVersion, dbConfig.dbName, dbConfig.rootPass)
|
const { exists } = await window.api.checkMariaDbDb(selectedVersion, dbConfig.dbName, dbConfig.rootPass)
|
||||||
if (exists) {
|
if (exists) {
|
||||||
const result = await Swal.fire({
|
const result = await Swal.fire({
|
||||||
title: 'Veritabanı Mevcut!',
|
title: t('mariadb.import.overwrite_title'),
|
||||||
text: `'${dbConfig.dbName}' veritabanı zaten var. Üzerine yazmak istiyor musunuz? Mevcut tüm veriler silinecektir!`,
|
text: t('mariadb.import.overwrite_desc', { dbName: dbConfig.dbName }),
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonText: 'Evet, Üzerine Yaz',
|
confirmButtonText: t('common.yes_delete'),
|
||||||
cancelButtonText: 'Hayır, Vazgeç',
|
cancelButtonText: t('common.cancel'),
|
||||||
confirmButtonColor: '#d33'
|
confirmButtonColor: '#d33'
|
||||||
})
|
})
|
||||||
if (!result.isConfirmed) return
|
if (!result.isConfirmed) return
|
||||||
}
|
}
|
||||||
nextStep()
|
nextStep()
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
Swal.fire('Hata', err.message, 'error')
|
Swal.fire(t('common.error'), err.message, 'error')
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
@@ -140,7 +142,7 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
|
|
||||||
const startImport = async () => {
|
const startImport = async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
setLogs(['[Sistem] İşlem başlatılıyor...'])
|
setLogs([t('mariadb.import.starting')])
|
||||||
|
|
||||||
const removeListener = window.api.onMariaDbImportLog((msg: string) => {
|
const removeListener = window.api.onMariaDbImportLog((msg: string) => {
|
||||||
setLogs(prev => [...prev, msg])
|
setLogs(prev => [...prev, msg])
|
||||||
@@ -170,13 +172,13 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
case 0:
|
case 0:
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 2, textAlign: 'center' }}>
|
<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 }}>
|
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center', mt: 3 }}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={filePath}
|
value={filePath}
|
||||||
placeholder="Dosya seçilmedi..."
|
placeholder={t('mariadb.import.no_file')}
|
||||||
disabled
|
disabled
|
||||||
InputProps={{
|
InputProps={{
|
||||||
startAdornment: (
|
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>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
case 1:
|
case 1:
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 2 }}>
|
<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 }}>
|
<FormControl fullWidth sx={{ mt: 2 }}>
|
||||||
<InputLabel>MariaDB Sunucusu</InputLabel>
|
<InputLabel>{t('mariadb.import.server')}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={selectedVersion}
|
value={selectedVersion}
|
||||||
label="MariaDB Sunucusu"
|
label={t('mariadb.import.server')}
|
||||||
onChange={(e) => setSelectedVersion(e.target.value)}
|
onChange={(e) => setSelectedVersion(e.target.value)}
|
||||||
>
|
>
|
||||||
{mariaDbVersions.filter(v => v.status === 'installed').map(v => (
|
{mariaDbVersions.filter(v => v.status === 'installed').map(v => (
|
||||||
@@ -209,34 +211,34 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<TextField
|
<TextField
|
||||||
label="Root Şifresi (Eğer varsa)"
|
label={t('mariadb.import.root_pass')}
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ mt: 3 }}
|
sx={{ mt: 3 }}
|
||||||
value={dbConfig.rootPass}
|
value={dbConfig.rootPass}
|
||||||
type="password"
|
type="password"
|
||||||
onChange={(e) => setDbConfig({ ...dbConfig, rootPass: e.target.value })}
|
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>
|
</Box>
|
||||||
)
|
)
|
||||||
case 2:
|
case 2:
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 3 }}>
|
<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
|
<TextField
|
||||||
label="Veritabanı Adı"
|
label={t('mariadb.import.db_name')}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={dbConfig.dbName}
|
value={dbConfig.dbName}
|
||||||
onChange={(e) => setDbConfig({ ...dbConfig, dbName: e.target.value })}
|
onChange={(e) => setDbConfig({ ...dbConfig, dbName: e.target.value })}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Veritabanı Kullanıcısı"
|
label={t('mariadb.import.db_user')}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={dbConfig.user}
|
value={dbConfig.user}
|
||||||
onChange={(e) => setDbConfig({ ...dbConfig, user: e.target.value })}
|
onChange={(e) => setDbConfig({ ...dbConfig, user: e.target.value })}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Kullanıcı Şifresi"
|
label={t('mariadb.import.db_pass')}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={dbConfig.pass}
|
value={dbConfig.pass}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -259,13 +261,13 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
{!importResult ? (
|
{!importResult ? (
|
||||||
<>
|
<>
|
||||||
<Paper sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.05)', borderRadius: 2 }}>
|
<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 }} />
|
<Divider sx={{ my: 1 }} />
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<Typography variant="body2"><strong>Dosya:</strong> {filePath.split(/[/\\]/).pop()}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.file')}:</strong> {filePath.split(/[/\\]/).pop()}</Typography>
|
||||||
<Typography variant="body2"><strong>Sunucu:</strong> {selectedVersion}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.server')}:</strong> {selectedVersion}</Typography>
|
||||||
<Typography variant="body2"><strong>Veritabanı:</strong> {dbConfig.dbName}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.db')}:</strong> {dbConfig.dbName}</Typography>
|
||||||
<Typography variant="body2"><strong>Kullanıcı:</strong> {dbConfig.user}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.user')}:</strong> {dbConfig.user}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
{loading && (
|
{loading && (
|
||||||
@@ -284,20 +286,20 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
{importResult.success ? (
|
{importResult.success ? (
|
||||||
<>
|
<>
|
||||||
<SuccessIcon color="success" sx={{ fontSize: 60 }} />
|
<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>
|
<Typography variant="body2" color="text.secondary">{importResult.message}</Typography>
|
||||||
<Paper sx={{ p: 2, mt: 3, textAlign: 'left', bgcolor: 'rgba(0,180,0,0.1)' }}>
|
<Paper sx={{ p: 2, mt: 3, textAlign: 'left', bgcolor: 'rgba(0,180,0,0.1)' }}>
|
||||||
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>Erişim Bilgileri:</Typography>
|
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>{t('mariadb.import.access_info')}:</Typography>
|
||||||
<Typography variant="body2"><strong>Host:</strong> localhost</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.host')}:</strong> localhost</Typography>
|
||||||
<Typography variant="body2"><strong>DB:</strong> {dbConfig.dbName}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.db')}:</strong> {dbConfig.dbName}</Typography>
|
||||||
<Typography variant="body2"><strong>User:</strong> {dbConfig.user}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.user')}:</strong> {dbConfig.user}</Typography>
|
||||||
<Typography variant="body2"><strong>Pass:</strong> {dbConfig.pass}</Typography>
|
<Typography variant="body2"><strong>{t('mariadb.import.db_pass')}:</strong> {dbConfig.pass}</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<ErrorIcon color="error" sx={{ fontSize: 60 }} />
|
<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>
|
<Typography variant="body2" color="error">{importResult.message}</Typography>
|
||||||
<Box sx={{ mt: 2, textAlign: 'left', bgcolor: '#000', p: 1, maxHeight: 150, overflowY: 'auto' }}>
|
<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>)}
|
{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>
|
</Box>
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return 'Bilinmeyen adım'
|
return t('common.error')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onClose={loading ? undefined : onClose} maxWidth="sm" fullWidth>
|
<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>
|
<DialogContent>
|
||||||
<Stepper activeStep={activeStep} orientation="horizontal" sx={{ pt: 2, pb: 4 }}>
|
<Stepper activeStep={activeStep} orientation="horizontal" sx={{ pt: 2, pb: 4 }}>
|
||||||
{steps.map((label) => (
|
{steps.map((label) => (
|
||||||
@@ -329,25 +331,25 @@ const MariaDbImportWizard: React.FC<MariaDbImportWizardProps> = ({ open, onClose
|
|||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={onClose} disabled={loading}>KAPAT</Button>
|
<Button onClick={onClose} disabled={loading}>{t('common.close')}</Button>
|
||||||
<Box sx={{ flexGrow: 1 }} />
|
<Box sx={{ flexGrow: 1 }} />
|
||||||
{activeStep > 0 && activeStep < 3 && !importResult && (
|
{activeStep > 0 && activeStep < 3 && !importResult && (
|
||||||
<Button onClick={prevStep} disabled={loading}>GERİ</Button>
|
<Button onClick={prevStep} disabled={loading}>{t('common.back')}</Button>
|
||||||
)}
|
)}
|
||||||
{activeStep === 0 && (
|
{activeStep === 0 && (
|
||||||
<Button variant="contained" onClick={nextStep} disabled={!filePath}>İLERİ</Button>
|
<Button variant="contained" onClick={nextStep} disabled={!filePath}>{t('common.next')}</Button>
|
||||||
)}
|
)}
|
||||||
{activeStep === 1 && (
|
{activeStep === 1 && (
|
||||||
<Button variant="contained" onClick={handleStep2Next}>İLERİ</Button>
|
<Button variant="contained" onClick={handleStep2Next}>{t('common.next')}</Button>
|
||||||
)}
|
)}
|
||||||
{activeStep === 2 && (
|
{activeStep === 2 && (
|
||||||
<Button variant="contained" onClick={handleStep3Next} disabled={loading}>
|
<Button variant="contained" onClick={handleStep3Next} disabled={loading}>
|
||||||
{loading ? <CircularProgress size={24} /> : 'ÖZETİ GÖR'}
|
{loading ? <CircularProgress size={24} /> : t('mariadb.import.btn_summary')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{activeStep === 3 && !importResult && (
|
{activeStep === 3 && !importResult && (
|
||||||
<Button variant="contained" color="primary" onClick={startImport} disabled={loading}>
|
<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>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
} from '@mui/material'
|
} from '@mui/material'
|
||||||
import { Search as SearchIcon, Close as CloseIcon, Refresh as RefreshIcon, EditNote as RawIcon, Save as SaveIcon } from '@mui/icons-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 Swal from 'sweetalert2'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import PhpIniCodeEditor from './PhpIniCodeEditor'
|
import PhpIniCodeEditor from './PhpIniCodeEditor'
|
||||||
|
|
||||||
interface PhpExtension {
|
interface PhpExtension {
|
||||||
@@ -34,6 +35,7 @@ interface PhpExtensionManagerProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose, phpVersion }) => {
|
const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose, phpVersion }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const [extensions, setExtensions] = useState<PhpExtension[]>([])
|
const [extensions, setExtensions] = useState<PhpExtension[]>([])
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
@@ -72,8 +74,8 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
const handleSaveRaw = async () => {
|
const handleSaveRaw = async () => {
|
||||||
setIsSavingRaw(true)
|
setIsSavingRaw(true)
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Yapılandırma Kaydediliyor',
|
title: t('php.extensions.saving'),
|
||||||
text: 'PHP servisi yeniden başlatılıyor...',
|
text: t('php.extensions.restarting'),
|
||||||
allowOutsideClick: false,
|
allowOutsideClick: false,
|
||||||
didOpen: () => {
|
didOpen: () => {
|
||||||
Swal.showLoading()
|
Swal.showLoading()
|
||||||
@@ -89,8 +91,8 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
await window.api.invoke('services:start', `php:${phpVersion}`)
|
await window.api.invoke('services:start', `php:${phpVersion}`)
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Başarılı',
|
title: t('common.success'),
|
||||||
text: 'Yapılandırma kaydedildi ve servis yeniden başlatıldı.',
|
text: t('php.extensions.success_msg'),
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
timer: 2000,
|
timer: 2000,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
@@ -121,8 +123,11 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
|
|
||||||
if (wasRunning) {
|
if (wasRunning) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Eklenti Ayarlanıyor',
|
title: t('php.extensions.adjusting'),
|
||||||
text: `${extName} ${enabled ? 'aktif ediliyor' : 'devre dışı bırakılıyor'} ve PHP yeniden başlatılıyor...`,
|
text: t('php.extensions.adjusting_desc', {
|
||||||
|
extName,
|
||||||
|
mode: enabled ? t('common.starting').toLowerCase() : t('common.stop').toLowerCase()
|
||||||
|
}),
|
||||||
allowOutsideClick: false,
|
allowOutsideClick: false,
|
||||||
didOpen: () => {
|
didOpen: () => {
|
||||||
Swal.showLoading()
|
Swal.showLoading()
|
||||||
@@ -142,10 +147,10 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
Swal.close()
|
Swal.close()
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
} 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 {
|
} finally {
|
||||||
setSaving(null)
|
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' }}>
|
<DialogTitle sx={{ m: 0, p: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h6">PHP {phpVersion} Eklentileri</Typography>
|
<Typography variant="h6">{t('php.extensions.title', { version: phpVersion })}</Typography>
|
||||||
<Typography variant="caption" color="text.secondary">php.ini üzerinden eklentileri yönetin</Typography>
|
<Typography variant="caption" color="text.secondary">{t('php.extensions.desc')}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<IconButton onClick={onClose} sx={{ color: 'text.secondary' }}>
|
<IconButton onClick={onClose} sx={{ color: 'text.secondary' }}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
@@ -187,7 +192,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="Eklenti ara... (mysql, gd, mbstring...)"
|
placeholder={t('php.extensions.search_placeholder')}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
@@ -205,7 +210,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
onClick={fetchRawConfig}
|
onClick={fetchRawConfig}
|
||||||
sx={{ whiteSpace: 'nowrap', borderColor: 'rgba(255,255,255,0.2)', color: '#fff' }}
|
sx={{ whiteSpace: 'nowrap', borderColor: 'rgba(255,255,255,0.2)', color: '#fff' }}
|
||||||
>
|
>
|
||||||
RAW EDİTÖR
|
{t('php.extensions.raw_editor')}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -218,7 +223,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
{filteredExtensions.length === 0 ? (
|
{filteredExtensions.length === 0 ? (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<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' }}
|
sx={{ textAlign: 'center', color: 'text.secondary' }}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@@ -245,7 +250,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
primary={
|
primary={
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
{ext.name}
|
{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>
|
</Box>
|
||||||
}
|
}
|
||||||
secondary={ext.dll}
|
secondary={ext.dll}
|
||||||
@@ -259,10 +264,10 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.02)' }}>
|
<DialogActions sx={{ p: 2, bgcolor: 'rgba(255,255,255,0.02)' }}>
|
||||||
<Button onClick={fetchExtensions} startIcon={<RefreshIcon />} sx={{ mr: 'auto' }}>
|
<Button onClick={fetchExtensions} startIcon={<RefreshIcon />} sx={{ mr: 'auto' }}>
|
||||||
YENİLE
|
{t('common.refresh').toUpperCase()}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onClose} variant="contained" color="primary">
|
<Button onClick={onClose} variant="contained" color="primary">
|
||||||
KAPAT
|
{t('common.close').toUpperCase()}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -282,7 +287,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
>
|
>
|
||||||
<DialogTitle sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, p: 2 }}>
|
<DialogTitle sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, p: 2 }}>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<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)' }}>
|
<IconButton onClick={() => setIsRawEditorOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -296,7 +301,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
'&:hover': { textDecoration: 'underline', color: 'primary.light' }
|
'&:hover': { textDecoration: 'underline', color: 'primary.light' }
|
||||||
}}
|
}}
|
||||||
onClick={() => window.api.invoke('shell:open-path', configPath)}
|
onClick={() => window.api.invoke('shell:open-path', configPath)}
|
||||||
title="Dosyayı sistemde aç"
|
title={t('php.extensions.file_open_tip')}
|
||||||
>
|
>
|
||||||
{configPath}
|
{configPath}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -305,7 +310,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="Dosya içerisinde ara..."
|
placeholder={t('php.extensions.search_file_placeholder')}
|
||||||
value={rawSearchTerm}
|
value={rawSearchTerm}
|
||||||
onChange={(e) => setRawSearchTerm(e.target.value)}
|
onChange={(e) => setRawSearchTerm(e.target.value)}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
@@ -331,7 +336,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions sx={{ p: 2, bgcolor: 'rgba(0,0,0,0.2)' }}>
|
<DialogActions sx={{ p: 2, bgcolor: 'rgba(0,0,0,0.2)' }}>
|
||||||
<Button onClick={() => setIsRawEditorOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
<Button onClick={() => setIsRawEditorOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}>
|
||||||
İPTAL
|
{t('common.cancel').toUpperCase()}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSaveRaw}
|
onClick={handleSaveRaw}
|
||||||
@@ -340,7 +345,7 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
startIcon={isSavingRaw ? <CircularProgress size={18} color="inherit" /> : <SaveIcon />}
|
startIcon={isSavingRaw ? <CircularProgress size={18} color="inherit" /> : <SaveIcon />}
|
||||||
disabled={isSavingRaw}
|
disabled={isSavingRaw}
|
||||||
>
|
>
|
||||||
{isSavingRaw ? 'KAYDEDİLİYOR...' : 'KAYDET VE SUNUCUYU DURDUR'}
|
{isSavingRaw ? t('php.extensions.saving_btn') : t('php.extensions.save_restart_btn')}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'prismjs/components/prism-ini'
|
|||||||
import 'prismjs/themes/prism-tomorrow.css'
|
import 'prismjs/themes/prism-tomorrow.css'
|
||||||
import { IconButton, Box, Typography, Tooltip } from '@mui/material'
|
import { IconButton, Box, Typography, Tooltip } from '@mui/material'
|
||||||
import { KeyboardArrowDown as DownIcon, KeyboardArrowUp as UpIcon } from '@mui/icons-material'
|
import { KeyboardArrowDown as DownIcon, KeyboardArrowUp as UpIcon } from '@mui/icons-material'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface PhpIniCodeEditorProps {
|
interface PhpIniCodeEditorProps {
|
||||||
value: string
|
value: string
|
||||||
@@ -13,6 +14,7 @@ interface PhpIniCodeEditorProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PhpIniCodeEditor: React.FC<PhpIniCodeEditorProps> = ({ value, onChange, searchTerm }) => {
|
const PhpIniCodeEditor: React.FC<PhpIniCodeEditorProps> = ({ value, onChange, searchTerm }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const editorRef = useRef<HTMLDivElement>(null)
|
const editorRef = useRef<HTMLDivElement>(null)
|
||||||
const [matches, setMatches] = useState<number[]>([])
|
const [matches, setMatches] = useState<number[]>([])
|
||||||
const [currentIndex, setCurrentIndex] = useState(0)
|
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' }}>
|
<Typography variant="caption" sx={{ color: '#aaa', mr: 1, minWidth: '40px', textAlign: 'center', userSelect: 'none' }}>
|
||||||
{matches.length > 0 ? `${currentIndex + 1} / ${matches.length}` : '0 / 0'}
|
{matches.length > 0 ? `${currentIndex + 1} / ${matches.length}` : '0 / 0'}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Tooltip title="Önceki (Shift+Enter)">
|
<Tooltip title={t('php.extensions.prev_match')}>
|
||||||
<IconButton size="small" onClick={handlePrev} sx={{ color: '#fff' }}>
|
<IconButton size="small" onClick={handlePrev} sx={{ color: '#fff' }}>
|
||||||
<UpIcon fontSize="small" />
|
<UpIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Sonraki (Enter)">
|
<Tooltip title={t('php.extensions.next_match')}>
|
||||||
<IconButton size="small" onClick={handleNext} sx={{ color: '#fff' }}>
|
<IconButton size="small" onClick={handleNext} sx={{ color: '#fff' }}>
|
||||||
<DownIcon fontSize="small" />
|
<DownIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|||||||
@@ -1,22 +1,31 @@
|
|||||||
import i18n from 'i18next'
|
import i18n from 'i18next'
|
||||||
import { initReactI18next } from 'react-i18next'
|
import { initReactI18next } from 'react-i18next'
|
||||||
import tr from './locales/tr.json'
|
|
||||||
import en from './locales/en.json'
|
// Dynamically import all json files in the locales directory
|
||||||
import de from './locales/de.json'
|
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
|
i18n
|
||||||
.use(initReactI18next)
|
.use(initReactI18next)
|
||||||
.init({
|
.init({
|
||||||
resources: {
|
resources,
|
||||||
tr: { translation: tr },
|
|
||||||
en: { translation: en },
|
|
||||||
de: { translation: de }
|
|
||||||
},
|
|
||||||
lng: 'tr',
|
lng: 'tr',
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
|
supportedLngs,
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false
|
escapeValue: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export { supportedLngs }
|
||||||
export default i18n
|
export default i18n
|
||||||
|
|||||||
@@ -2,22 +2,228 @@
|
|||||||
"common": {
|
"common": {
|
||||||
"start": "Starten",
|
"start": "Starten",
|
||||||
"stop": "Stoppen",
|
"stop": "Stoppen",
|
||||||
"restart": "Neustart",
|
"restart": "Neustarten",
|
||||||
"settings": "Einstellungen",
|
"settings": "Einstellungen",
|
||||||
"tools": "Werkzeuge",
|
"tools": "Werkzeuge",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"quit": "Beenden",
|
"quit": "Beenden",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"port": "Port",
|
"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": {
|
"dashboard": {
|
||||||
"title": "Trunçgil Multi-PHP Server",
|
"title": "Trunçgil Multi-PHP Server",
|
||||||
"status": "Serverstatus",
|
"status": "Serverstatus",
|
||||||
"services": "Dienste",
|
"services": "Dienste",
|
||||||
"active_version": "Aktive PHP-Version",
|
"active_version": "Aktive PHP-Version",
|
||||||
"quick_look": "Schnellansicht",
|
"quick_look": "Kurzübersicht",
|
||||||
"start_all": "Alle starten",
|
"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",
|
"quit": "Quit",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"port": "Port",
|
"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": {
|
"dashboard": {
|
||||||
"title": "Trunçgil Multi-PHP Server",
|
"title": "Trunçgil Multi-PHP Server",
|
||||||
@@ -18,6 +50,186 @@
|
|||||||
"active_version": "Active PHP Version",
|
"active_version": "Active PHP Version",
|
||||||
"quick_look": "Quick Look",
|
"quick_look": "Quick Look",
|
||||||
"start_all": "Start All",
|
"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",
|
"port": "Port",
|
||||||
"all": "Tümü",
|
"all": "Tümü",
|
||||||
"export": "Dışa Aktar",
|
"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": {
|
"dashboard": {
|
||||||
"title": "Trunçgil Multi-PHP Server",
|
"title": "Trunçgil Multi-PHP Server",
|
||||||
@@ -20,6 +49,180 @@
|
|||||||
"active_version": "Aktif PHP Sürümü",
|
"active_version": "Aktif PHP Sürümü",
|
||||||
"quick_look": "Hızlı Bakış",
|
"quick_look": "Hızlı Bakış",
|
||||||
"start_all": "Tümünü Başlat",
|
"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) {
|
if (this.state.hasError) {
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: 20, color: 'white' }}>
|
<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>
|
<pre style={{ whiteSpace: 'pre-wrap' }}>{this.state.error?.toString()}</pre>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user