diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index 848e0e5..505b885 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -374,14 +374,23 @@ export function registerIpcHandlers(): void { }) ipcMain.handle('projects:add', async (_event, project) => { - return projectService.addProject(project) + const result = await projectService.addProject(project) + // Trigger Nginx reload + await ipcMain.emit('services:reload', null, 'nginx') + return result }) ipcMain.handle('projects:remove', async (_event, id) => { - return projectService.removeProject(id) + const result = projectService.removeProject(id) + // Trigger Nginx reload + await ipcMain.emit('services:reload', null, 'nginx') + return result }) ipcMain.handle('projects:update', async (_event, project) => { - return projectService.updateProject(project) + const result = projectService.updateProject(project) + // Trigger Nginx reload + await ipcMain.emit('services:reload', null, 'nginx') + return result }) // Config management @@ -390,7 +399,60 @@ export function registerIpcHandlers(): void { }) ipcMain.handle('config:save', async (_event, config: any) => { - return { success: true, settings: configService.updateSettings(config) } + const settings = configService.updateSettings(config) + return { success: true, settings } + }) + + // Nginx Config Management + ipcMain.handle('nginx:config:get', async () => { + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') + if (fs.existsSync(configPath)) { + return fs.readFileSync(configPath, 'utf8') + } + return '' + }) + + ipcMain.handle('nginx:config:save', async (_event, content) => { + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') + fs.writeFileSync(configPath, content) + // Reload Nginx after save + await ipcMain.emit('services:reload', null, 'nginx') + return { success: true } + }) + + ipcMain.handle('nginx:config:test', async () => { + try { + const binDir = path.join(configService.getBasePath(), 'bin', 'nginx') + const nginxVersions = fs.readdirSync(binDir).filter(f => fs.statSync(path.join(binDir, f)).isDirectory()) + const activeVersion = nginxVersions[0] + if (!activeVersion) throw new Error('Nginx not found') + + const nginxPrefix = path.join(binDir, activeVersion) + const binPath = path.join(nginxPrefix, 'nginx.exe') + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') + + const success = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', configPath], 'nginx') + return { success, message: success ? 'Configuration test successful' : 'Configuration test failed' } + } catch (error: any) { + return { success: false, message: error.message } + } + }) + + // Project Nginx Config + ipcMain.handle('project:nginx:get', async (_event, host) => { + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`) + if (fs.existsSync(configPath)) { + return fs.readFileSync(configPath, 'utf8') + } + return '' + }) + + ipcMain.handle('project:nginx:save', async (_event, host, content) => { + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`) + fs.writeFileSync(configPath, content) + // Reload Nginx after save + await ipcMain.emit('services:reload', null, 'nginx') + return { success: true } }) // phpMyAdmin diff --git a/src/preload/index.ts b/src/preload/index.ts index a8bb2e9..03e3857 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -35,7 +35,8 @@ const api = { const listener = (_event, msg) => callback(msg) electronAPI.ipcRenderer.on('mysql:import:log', listener) return () => electronAPI.ipcRenderer.removeListener('mysql:import:log', listener) - } + }, + invoke: (channel: string, ...args: any[]) => electronAPI.ipcRenderer.invoke(channel, ...args) } // Use `contextBridge` APIs to expose Electron APIs to diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index a24db7b..83d00d2 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -132,6 +132,11 @@ function App(): JSX.Element { const [pmaLoading, setPmaLoading] = useState(false) const [pmaProgress, setPmaProgress] = useState(0) const [isMySqlWizardOpen, setIsMySqlWizardOpen] = useState(false) + const [isNginxConfigOpen, setIsNginxConfigOpen] = useState(false) + const [nginxConfig, setNginxConfig] = useState('') + const [isProjectNginxConfigOpen, setIsProjectNginxConfigOpen] = useState(false) + const [projectNginxConfig, setProjectNginxConfig] = useState('') + const [selectedProjectHost, setSelectedProjectHost] = useState('') const fetchStatus = async () => { if (window.api && window.api.getServiceStatus) { @@ -442,9 +447,74 @@ function App(): JSX.Element { const handleRemoveProject = async (id: string) => { if (!window.api) return - await window.api.removeProject(id) - setNotification({ open: true, message: 'Proje silindi.', severity: 'success' }) - fetchProjects() + const result = await Swal.fire({ + title: 'Emin misiniz?', + text: "Bu projeyi silmek istediğinize emin misiniz? Nginx ayarları otomatik olarak güncellenecektir.", + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#ff4444', + cancelButtonColor: '#3085d6', + confirmButtonText: 'Evet, sil!', + cancelButtonText: 'İptal', + background: '#1e1e1e', + color: '#fff' + }) + + if (result.isConfirmed) { + await window.api.removeProject(id) + setNotification({ open: true, message: 'Proje silindi. Nginx yeniden yüklendi.', severity: 'success' }) + fetchProjects() + } + } + + const handleOpenNginxConfig = async () => { + if (window.api && window.api.invoke) { + const config = await window.api.invoke('nginx:config:get') + setNginxConfig(config) + setIsNginxConfigOpen(true) + } + } + + const handleSaveNginxConfig = async () => { + if (window.api && window.api.invoke) { + const result = await window.api.invoke('nginx:config:save', nginxConfig) + if (result.success) { + setNotification({ open: true, message: 'Nginx yapılandırması kaydedildi ve yeniden yüklendi.', severity: 'success' }) + setIsNginxConfigOpen(false) + } + } + } + + const handleTestNginxConfig = async () => { + if (window.api && window.api.invoke) { + const result = await window.api.invoke('nginx:config:test') + Swal.fire({ + title: result.success ? 'Başarılı' : 'Hata', + text: result.message, + icon: result.success ? 'success' : 'error', + background: '#1e1e1e', + color: '#fff' + }) + } + } + + const handleOpenProjectNginxConfig = async (host: string) => { + if (window.api && window.api.invoke) { + const config = await window.api.invoke('project:nginx:get', host) + setProjectNginxConfig(config) + setSelectedProjectHost(host) + setIsProjectNginxConfigOpen(true) + } + } + + const handleSaveProjectNginxConfig = async () => { + if (window.api && window.api.invoke) { + const result = await window.api.invoke('project:nginx:save', selectedProjectHost, projectNginxConfig) + if (result.success) { + setNotification({ open: true, message: `${selectedProjectHost} için Nginx yapılandırması kaydedildi.`, severity: 'success' }) + setIsProjectNginxConfigOpen(false) + } + } } const handleDownloadPhp = async (id: string) => { @@ -814,6 +884,14 @@ function App(): JSX.Element { handleOpenLogs('nginx')} title="Hata Logları" size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}> + + + { window.api.invoke('services:reload', 'nginx').then((res: any) => { @@ -1055,6 +1133,11 @@ function App(): JSX.Element { + + handleOpenProjectNginxConfig(project.host)} sx={{ color: 'rgba(255,255,255,0.4)', '&:hover': { color: '#39A7FF' } }}> + + + handleRemoveProject(project.id)} sx={{ color: 'rgba(255,255,255,0.4)', '&:hover': { color: '#ff4444' } }}> @@ -1309,7 +1392,127 @@ function App(): JSX.Element { onClose={() => setIsMySqlWizardOpen(false)} mySqlVersions={mySqlVersions} /> - + + setIsNginxConfigOpen(false)} + maxWidth="md" + fullWidth + PaperProps={{ + sx: { + bgcolor: '#1e1e1e', + color: '#fff', + borderRadius: 3, + border: '1px solid rgba(255,255,255,0.1)' + } + }} + > + + Nginx Yapılandırması (nginx.conf) + setIsNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}> + + + + + + Dikkat: Hatalı yapılandırma Nginx'in çalışmasını durdurabilir. Değişiklik yapmadan önce test edin. + + setNginxConfig(e.target.value)} + sx={{ + '& .MuiInputBase-root': { + fontFamily: 'monospace', + fontSize: '0.875rem', + color: '#fff' + }, + '& .MuiOutlinedInput-notchedOutline': { + borderColor: 'rgba(255,255,255,0.1)' + } + }} + /> + + + + + + + + + setIsProjectNginxConfigOpen(false)} + maxWidth="md" + fullWidth + PaperProps={{ + sx: { + bgcolor: '#1e1e1e', + color: '#fff', + borderRadius: 3, + border: '1px solid rgba(255,255,255,0.1)' + } + }} + > + + {selectedProjectHost} Nginx Yapılandırması + setIsProjectNginxConfigOpen(false)} sx={{ color: 'rgba(255,255,255,0.5)' }}> + + + + + + İpucu: Bu yapılandırma sadece {selectedProjectHost} projesi için geçerlidir. + + setProjectNginxConfig(e.target.value)} + sx={{ + '& .MuiInputBase-root': { + fontFamily: 'monospace', + fontSize: '0.875rem', + color: '#fff' + }, + '& .MuiOutlinedInput-notchedOutline': { + borderColor: 'rgba(255,255,255,0.1)' + } + }} + /> + + + + + + + ) }