feat: add Nginx configuration editor component and integrate it into the main application interface

This commit is contained in:
Ümit Tunç
2026-03-30 07:41:51 +03:00
parent 702fe9cad0
commit 98295e38ef
4 changed files with 95 additions and 42 deletions
+28
View File
@@ -15,12 +15,15 @@
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@mui/icons-material": "^6.0.0", "@mui/icons-material": "^6.0.0",
"@mui/material": "^6.0.0", "@mui/material": "^6.0.0",
"@types/prismjs": "^1.26.6",
"axios": "^1.14.0", "axios": "^1.14.0",
"decompress": "^4.2.1", "decompress": "^4.2.1",
"i18next": "^23.1.0", "i18next": "^23.1.0",
"prismjs": "^1.30.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-i18next": "^13.0.0", "react-i18next": "^13.0.0",
"react-simple-code-editor": "^0.14.1",
"sweetalert2": "^11.26.24" "sweetalert2": "^11.26.24"
}, },
"devDependencies": { "devDependencies": {
@@ -2478,6 +2481,12 @@
"xmlbuilder": ">=11.0.1" "xmlbuilder": ">=11.0.1"
} }
}, },
"node_modules/@types/prismjs": {
"version": "1.26.6",
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz",
"integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==",
"license": "MIT"
},
"node_modules/@types/prop-types": { "node_modules/@types/prop-types": {
"version": "15.7.15", "version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
@@ -7778,6 +7787,15 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/prismjs": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/process-nextick-args": { "node_modules/process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -7949,6 +7967,16 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-simple-code-editor": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.14.1.tgz",
"integrity": "sha512-BR5DtNRy+AswWJECyA17qhUDvrrCZ6zXOCfkQY5zSmb96BVUbpVAv03WpcjcwtCwiLbIANx3gebHOcXYn1EHow==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/react-transition-group": { "node_modules/react-transition-group": {
"version": "4.4.5", "version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+3
View File
@@ -27,12 +27,15 @@
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@mui/icons-material": "^6.0.0", "@mui/icons-material": "^6.0.0",
"@mui/material": "^6.0.0", "@mui/material": "^6.0.0",
"@types/prismjs": "^1.26.6",
"axios": "^1.14.0", "axios": "^1.14.0",
"decompress": "^4.2.1", "decompress": "^4.2.1",
"i18next": "^23.1.0", "i18next": "^23.1.0",
"prismjs": "^1.30.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-i18next": "^13.0.0", "react-i18next": "^13.0.0",
"react-simple-code-editor": "^0.14.1",
"sweetalert2": "^11.26.24" "sweetalert2": "^11.26.24"
}, },
"devDependencies": { "devDependencies": {
+7 -42
View File
@@ -64,7 +64,6 @@ import {
OpenInNew as OpenIcon, OpenInNew as OpenIcon,
Edit as EditIcon, Edit as EditIcon,
Folder as FolderIcon, Folder as FolderIcon,
Storage as MySQLIcon,
Language as HostIcon, Language as HostIcon,
Launch as LaunchIcon, Launch as LaunchIcon,
Handyman as ToolsIcon, Handyman as ToolsIcon,
@@ -73,6 +72,7 @@ import {
import Swal from 'sweetalert2' import Swal from 'sweetalert2'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import MySqlImportWizard from './components/MySqlImportWizard' import MySqlImportWizard from './components/MySqlImportWizard'
import NginxCodeEditor from './components/NginxCodeEditor'
declare global { declare global {
interface Window { interface Window {
@@ -108,7 +108,6 @@ function App(): JSX.Element {
const [phpVersions, setPhpVersions] = useState<any[]>([]) const [phpVersions, setPhpVersions] = useState<any[]>([])
const [mySqlVersions, setMySqlVersions] = useState<any[]>([]) const [mySqlVersions, setMySqlVersions] = useState<any[]>([])
const [nginxVersions, setNginxVersions] = useState<any[]>([]) const [nginxVersions, setNginxVersions] = useState<any[]>([])
const [loadingVersions, setLoadingVersions] = useState(false)
const [isProjectDialogOpen, setIsProjectDialogOpen] = useState(false) const [isProjectDialogOpen, setIsProjectDialogOpen] = useState(false)
const slugify = (text: string) => text.toLowerCase().trim().replace(/[^\w\s-]/g, '').replace(/[\s_-]+/g, '-').replace(/^-+|-+$/g, ''); const slugify = (text: string) => text.toLowerCase().trim().replace(/[^\w\s-]/g, '').replace(/[\s_-]+/g, '-').replace(/^-+|-+$/g, '');
const [newProject, setNewProject] = useState<any>({ name: '', path: '', phpVersion: '', mySqlVersion: '', host: 'localhost' }) const [newProject, setNewProject] = useState<any>({ name: '', path: '', phpVersion: '', mySqlVersion: '', host: 'localhost' })
@@ -187,14 +186,6 @@ function App(): JSX.Element {
} }
} }
const handleRefreshVersions = async () => {
setLoadingVersions(true)
try {
await Promise.all([fetchPhpVersions(), fetchMySqlVersions(), fetchNginxVersions()])
} finally {
setLoadingVersions(false)
}
}
useEffect(() => { useEffect(() => {
if (isProjectDialogOpen && !newProject.id) { if (isProjectDialogOpen && !newProject.id) {
@@ -671,7 +662,7 @@ function App(): JSX.Element {
<Typography variant="body2" color="text.secondary">Gereken PHP sürümlerini buradan indirebilir ve yönetebilirsiniz.</Typography> <Typography variant="body2" color="text.secondary">Gereken PHP sürümlerini buradan indirebilir ve yönetebilirsiniz.</Typography>
</Box> </Box>
<List sx={{ maxHeight: 500, overflow: 'auto' }}> <List sx={{ maxHeight: 500, overflow: 'auto' }}>
{phpVersions.length === 0 && !loadingVersions && ( {phpVersions.length === 0 && (
<ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem> <ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem>
)} )}
{phpVersions.map((v) => ( {phpVersions.map((v) => (
@@ -712,7 +703,7 @@ function App(): JSX.Element {
<Typography variant="body2" color="text.secondary">Farklı MySQL sürümlerini indirebilir ve sunucunuzda kullanabilirsiniz.</Typography> <Typography variant="body2" color="text.secondary">Farklı MySQL sürümlerini indirebilir ve sunucunuzda kullanabilirsiniz.</Typography>
</Box> </Box>
<List sx={{ maxHeight: 500, overflow: 'auto' }}> <List sx={{ maxHeight: 500, overflow: 'auto' }}>
{mySqlVersions.length === 0 && !loadingVersions && ( {mySqlVersions.length === 0 && (
<ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem> <ListItem><ListItemText primary="Yükleniyor veya liste boş..." /></ListItem>
)} )}
{mySqlVersions.map((v) => ( {mySqlVersions.map((v) => (
@@ -1417,22 +1408,9 @@ function App(): JSX.Element {
<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. Dikkat: Hatalı yapılandırma Nginx'in çalışmasını durdurabilir. Değişiklik yapmadan önce test edin.
</Typography> </Typography>
<TextField <NginxCodeEditor
fullWidth
multiline
rows={20}
value={nginxConfig} value={nginxConfig}
onChange={(e) => setNginxConfig(e.target.value)} onChange={(val) => setNginxConfig(val)}
sx={{
'& .MuiInputBase-root': {
fontFamily: 'monospace',
fontSize: '0.875rem',
color: '#fff'
},
'& .MuiOutlinedInput-notchedOutline': {
borderColor: 'rgba(255,255,255,0.1)'
}
}}
/> />
</DialogContent> </DialogContent>
<DialogActions sx={{ p: 2, gap: 1 }}> <DialogActions sx={{ p: 2, gap: 1 }}>
@@ -1481,22 +1459,9 @@ function App(): JSX.Element {
<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. İpucu: Bu yapılandırma sadece {selectedProjectHost} projesi için geçerlidir.
</Typography> </Typography>
<TextField <NginxCodeEditor
fullWidth
multiline
rows={20}
value={projectNginxConfig} value={projectNginxConfig}
onChange={(e) => setProjectNginxConfig(e.target.value)} onChange={(val) => setProjectNginxConfig(val)}
sx={{
'& .MuiInputBase-root': {
fontFamily: 'monospace',
fontSize: '0.875rem',
color: '#fff'
},
'& .MuiOutlinedInput-notchedOutline': {
borderColor: 'rgba(255,255,255,0.1)'
}
}}
/> />
</DialogContent> </DialogContent>
<DialogActions sx={{ p: 2, gap: 1 }}> <DialogActions sx={{ p: 2, gap: 1 }}>
@@ -0,0 +1,57 @@
import React from 'react'
import Editor from 'react-simple-code-editor'
import Prism from 'prismjs'
import 'prismjs/components/prism-nginx'
import 'prismjs/themes/prism-tomorrow.css'
interface NginxCodeEditorProps {
value: string
onChange: (value: string) => void
}
const NginxCodeEditor: React.FC<NginxCodeEditorProps> = ({ value, onChange }) => {
return (
<div style={{
borderRadius: '4px',
overflow: 'hidden',
border: '1px solid rgba(255,255,255,0.1)',
backgroundColor: '#1e1e1e',
fontFamily: '"Fira code", "Fira Mono", monospace',
fontSize: '14px',
minHeight: '300px'
}}>
<Editor
value={value}
onValueChange={code => onChange(code)}
highlight={code => Prism.highlight(code, Prism.languages.nginx, 'nginx')}
padding={15}
style={{
fontFamily: '"Fira code", "Fira Mono", monospace',
fontSize: 14,
minHeight: '400px',
outline: 'none'
}}
textareaClassName="nginx-editor-textarea"
preClassName="nginx-editor-pre"
/>
<style>{`
.nginx-editor-textarea {
outline: none !important;
}
.nginx-editor-pre {
pointer-events: none;
}
.token.comment { color: #6a9955; }
.token.directive { color: #569cd6; font-weight: bold; }
.token.variable { color: #9cdcfe; }
.token.string { color: #ce9178; }
.token.number { color: #b5cea8; }
.token.boolean { color: #569cd6; }
.token.operator { color: #d4d4d4; }
.token.punctuation { color: #d4d4d4; }
`}</style>
</div>
)
}
export default NginxCodeEditor