feat: implement dashboard UI components, IPC handlers, and service configuration templates
This commit is contained in:
@@ -8,7 +8,7 @@ Alias /{{HOST}} "{{PATH}}"
|
||||
|
||||
# --- KRİTİK EKLEME BURASI ---
|
||||
# PHP'ye php.ini dosyasını {{PHP_DIR}} klasöründe aramasını söyler
|
||||
SetEnv PHPRC "{{PHP_DIR}}"
|
||||
SetEnv PHPRC "{{PHP_INI_DIR}}"
|
||||
# ----------------------------
|
||||
|
||||
# Passing Authorization header to PHP
|
||||
|
||||
@@ -6,6 +6,9 @@ Alias /{{HOST}} "{{PATH}}"
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
|
||||
# PHP'ye php.ini dosyasını generated_configs klasöründe aramasını söyler
|
||||
SetEnv PHPRC "{{PHP_INI_DIR}}"
|
||||
|
||||
# Passing Authorization header to PHP
|
||||
CGIPassAuth On
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
[PHP]
|
||||
engine = On
|
||||
short_open_tag = Off
|
||||
precision = 14
|
||||
output_buffering = 4096
|
||||
zlib.output_compression = Off
|
||||
implicit_flush = Off
|
||||
unserialize_callback_func =
|
||||
serialize_precision = -1
|
||||
disable_functions =
|
||||
disable_classes =
|
||||
zend.enable_gc = On
|
||||
expose_php = On
|
||||
max_execution_time = 300
|
||||
max_input_time = 120
|
||||
memory_limit = 512M
|
||||
error_reporting = {{ERROR_REPORTING}}asdasd
|
||||
display_errors = {{DISPLAY_ERRORS}}
|
||||
display_startup_errors = On
|
||||
log_errors = On
|
||||
log_errors_max_len = 1024
|
||||
ignore_repeated_errors = Off
|
||||
ignore_repeated_source = Off
|
||||
report_memleaks = On
|
||||
html_errors = On
|
||||
variables_order = "GPCS"
|
||||
request_order = "GP"
|
||||
register_argc_argv = Off
|
||||
auto_globals_jit = On
|
||||
post_max_size = 100M
|
||||
auto_prepend_file =
|
||||
auto_append_file =
|
||||
default_mimetype = "text/html"
|
||||
default_charset = "UTF-8"
|
||||
doc_root =
|
||||
user_dir =
|
||||
enable_dl = Off
|
||||
file_uploads = On
|
||||
upload_max_filesize = 100M
|
||||
max_file_uploads = 20
|
||||
allow_url_fopen = On
|
||||
allow_url_include = Off
|
||||
default_socket_timeout = 60
|
||||
session.save_path = "{{SESSION_DIR}}"
|
||||
upload_tmp_dir = "{{TEMP_DIR}}"
|
||||
sys_temp_dir = "{{TEMP_DIR}}"
|
||||
extension_dir = "{{EXT_DIR}}"
|
||||
fastcgi.impersonate = 1
|
||||
cgi.force_redirect = 0
|
||||
cgi.fix_pathinfo = 0
|
||||
|
||||
[ExtensionList]
|
||||
{{EXTENSIONS}}
|
||||
|
||||
[Date]
|
||||
date.timezone = UTC
|
||||
@@ -1,4 +1,317 @@
|
||||
[
|
||||
{
|
||||
"service": "php:5.6.40",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "200rgoskm",
|
||||
"timestamp": 1775189179480
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "lb7cc11oe",
|
||||
"timestamp": 1775189179463
|
||||
},
|
||||
{
|
||||
"service": "php:8.2.30",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "etjx8kz61",
|
||||
"timestamp": 1775189179447
|
||||
},
|
||||
{
|
||||
"service": "php:8.5.4",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "jw31owy76",
|
||||
"timestamp": 1775189179430
|
||||
},
|
||||
{
|
||||
"service": "mariadb:10.11.8",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "905twpheo",
|
||||
"timestamp": 1775189179167
|
||||
},
|
||||
{
|
||||
"service": "mariadb:11.4.2",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "3cpe3886a",
|
||||
"timestamp": 1775189179146
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "1puz4ewk4",
|
||||
"timestamp": 1775189136125
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "cp1skav2y",
|
||||
"timestamp": 1775189136113
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "5ssshkepi",
|
||||
"timestamp": 1775189128458
|
||||
},
|
||||
{
|
||||
"service": "nginx",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "2w0dgrom5",
|
||||
"timestamp": 1775189121191
|
||||
},
|
||||
{
|
||||
"service": "apache",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "ce020djd5",
|
||||
"timestamp": 1775189116024
|
||||
},
|
||||
{
|
||||
"service": "mariadb:11.4.2",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "f22mfjz6j",
|
||||
"timestamp": 1775189109611
|
||||
},
|
||||
{
|
||||
"service": "mariadb:10.11.8",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "bj1yhdd0b",
|
||||
"timestamp": 1775189109603
|
||||
},
|
||||
{
|
||||
"service": "php:5.6.40",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "dwo60nc99",
|
||||
"timestamp": 1775189109591
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "vc72hwpnw",
|
||||
"timestamp": 1775189109584
|
||||
},
|
||||
{
|
||||
"service": "php:8.2.30",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "dmk8j6iad",
|
||||
"timestamp": 1775189109577
|
||||
},
|
||||
{
|
||||
"service": "php:8.5.4",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "ck9ctfdg9",
|
||||
"timestamp": 1775189109571
|
||||
},
|
||||
{
|
||||
"service": "apache",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "f4qs2eaz5",
|
||||
"timestamp": 1775189109550
|
||||
},
|
||||
{
|
||||
"service": "nginx",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "m1fkgarlg",
|
||||
"timestamp": 1775189109547
|
||||
},
|
||||
{
|
||||
"service": "mariadb:11.4.2",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "1cjzxt5i8",
|
||||
"timestamp": 1775189109537
|
||||
},
|
||||
{
|
||||
"service": "mariadb:10.11.8",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "ss8vlatqg",
|
||||
"timestamp": 1775189109529
|
||||
},
|
||||
{
|
||||
"service": "php:5.6.40",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "38on99hkk",
|
||||
"timestamp": 1775189109520
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "qinl5mvi9",
|
||||
"timestamp": 1775189109513
|
||||
},
|
||||
{
|
||||
"service": "php:8.2.30",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "tc2wax0xc",
|
||||
"timestamp": 1775189109502
|
||||
},
|
||||
{
|
||||
"service": "php:8.5.4",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "vlawi3k8e",
|
||||
"timestamp": 1775189109494
|
||||
},
|
||||
{
|
||||
"service": "apache",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "6ujdvt7j1",
|
||||
"timestamp": 1775189109479
|
||||
},
|
||||
{
|
||||
"service": "nginx",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "k7rezgoaj",
|
||||
"timestamp": 1775189109477
|
||||
},
|
||||
{
|
||||
"service": "apache",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "70tu2y5as",
|
||||
"timestamp": 1775189102787
|
||||
},
|
||||
{
|
||||
"service": "apache",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: 1",
|
||||
"id": "9lfnqbgwe",
|
||||
"timestamp": 1775189101318
|
||||
},
|
||||
{
|
||||
"service": "php:5.6.40",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "wgqvhqwe2",
|
||||
"timestamp": 1775189054380
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "cz9laoefl",
|
||||
"timestamp": 1775189054362
|
||||
},
|
||||
{
|
||||
"service": "php:8.2.30",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "81z3uz9zw",
|
||||
"timestamp": 1775189054344
|
||||
},
|
||||
{
|
||||
"service": "php:8.5.4",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "0hegp84kv",
|
||||
"timestamp": 1775189054324
|
||||
},
|
||||
{
|
||||
"service": "mariadb:11.4.2",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "r2fm405gd",
|
||||
"timestamp": 1775189054117
|
||||
},
|
||||
{
|
||||
"service": "mariadb:10.11.8",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "knua7kh8u",
|
||||
"timestamp": 1775189054097
|
||||
},
|
||||
{
|
||||
"service": "apache",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "l4paq57hz",
|
||||
"timestamp": 1775189053345
|
||||
},
|
||||
{
|
||||
"service": "nginx",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "khg59iy1d",
|
||||
"timestamp": 1775189053276
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "hg9972rds",
|
||||
"timestamp": 1775188622685
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "1knv5xq4h",
|
||||
"timestamp": 1775188618390
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "7132k0rd3",
|
||||
"timestamp": 1775188618378
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "start",
|
||||
"status": "success",
|
||||
"id": "j8dmzg0qj",
|
||||
"timestamp": 1775188599983
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "exit",
|
||||
"status": "failure",
|
||||
"details": "Exit code: null",
|
||||
"id": "o26b3cigi",
|
||||
"timestamp": 1775188594701
|
||||
},
|
||||
{
|
||||
"service": "php:7.4.33",
|
||||
"action": "stop",
|
||||
"status": "info",
|
||||
"id": "ox74ttj4y",
|
||||
"timestamp": 1775188594690
|
||||
},
|
||||
{
|
||||
"service": "php:5.6.40",
|
||||
"action": "start",
|
||||
|
||||
@@ -258,6 +258,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
|
||||
if (!normalizedPath.endsWith('/')) normalizedPath += '/'
|
||||
|
||||
const phpDir = path.join(configService.getBasePath(), 'bin', `php-${p.phpVersion}`)
|
||||
const phpIniDir = path.join(configService.getBasePath(), 'generated_configs', 'php', p.phpVersion)
|
||||
const phpCgiBinary = findExecutable(phpDir, process.platform === 'win32' ? 'php-cgi.exe' : 'php-cgi') || ''
|
||||
|
||||
// Auto-suffix hostname if it's a simple slug
|
||||
@@ -268,6 +269,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
|
||||
PATH: normalizedPath,
|
||||
PHP_PORT: phpPort.toString(),
|
||||
PHP_DIR: phpDir.replace(/\\/g, '/'),
|
||||
PHP_INI_DIR: phpIniDir.replace(/\\/g, '/'),
|
||||
PHP_CGI_PATH: phpCgiBinary.replace(/\\/g, '/'),
|
||||
PHP_BIN_URL: `/php-bin-${p.host}`,
|
||||
PORT: settings.apachePort || '8080'
|
||||
@@ -279,6 +281,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
|
||||
PATH: normalizedPath,
|
||||
PHP_PORT: phpPort.toString(),
|
||||
PHP_DIR: phpDir.replace(/\\/g, '/'),
|
||||
PHP_INI_DIR: phpIniDir.replace(/\\/g, '/'),
|
||||
PHP_CGI_PATH: phpCgiBinary.replace(/\\/g, '/'),
|
||||
PHP_BIN_URL: `/php-bin-alias-${p.host}`,
|
||||
PORT: settings.apachePort || '8080'
|
||||
|
||||
@@ -202,6 +202,9 @@ export default function DashboardDetails({
|
||||
return 'n/a';
|
||||
};
|
||||
const isRunning = currentStatus.status === 'running';
|
||||
const isStarting = currentStatus.status === 'starting';
|
||||
const isStopping = currentStatus.status === 'stopping';
|
||||
const isTransitioning = isStarting || isStopping;
|
||||
|
||||
const serviceProjects = projects.filter(p => {
|
||||
if (serviceId === 'nginx') return !p.serverType || p.serverType === 'nginx';
|
||||
@@ -244,11 +247,14 @@ export default function DashboardDetails({
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography variant="h5" sx={{ fontWeight: 800 }}>{serviceId.toUpperCase()}</Typography>
|
||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.4)' }}>
|
||||
{isRunning ? t('common.running', 'Çalışıyor') : t('common.stopped', 'Durduruldu')}
|
||||
{isStarting && <Box component="span" sx={{ color: 'warning.light' }}>{t('common.starting', 'Başlatılıyor...')}</Box>}
|
||||
{isStopping && <Box component="span" sx={{ color: 'warning.light' }}>{t('common.stopping', 'Durduruluyor...')}</Box>}
|
||||
{isRunning && <Box component="span" sx={{ color: 'success.light' }}>{t('common.running', 'Çalışıyor')}</Box>}
|
||||
{!isRunning && !isStarting && !isStopping && <Box component="span" sx={{ opacity: 0.5 }}>{t('common.stopped', 'Durduruldu')}</Box>}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack direction="row" spacing={1}>
|
||||
{isRunning && (
|
||||
{isRunning && !isTransitioning && (
|
||||
<IconButton onClick={() => onReloadService(serviceId)} sx={{ bgcolor: 'rgba(57, 167, 255, 0.1)', color: 'primary.main' }}>
|
||||
<RefreshIcon />
|
||||
</IconButton>
|
||||
@@ -256,11 +262,16 @@ export default function DashboardDetails({
|
||||
<Button
|
||||
variant="contained"
|
||||
color={isRunning ? 'error' : 'success'}
|
||||
startIcon={isRunning ? <StopIcon /> : <StartIcon />}
|
||||
disabled={isTransitioning}
|
||||
startIcon={
|
||||
isTransitioning
|
||||
? <CircularProgress size={20} color="inherit" />
|
||||
: isRunning ? <StopIcon /> : <StartIcon />
|
||||
}
|
||||
onClick={() => onToggleService(serviceId)}
|
||||
sx={{ borderRadius: 2 }}
|
||||
sx={{ borderRadius: 2, minWidth: 100 }}
|
||||
>
|
||||
{isRunning ? t('common.stop', 'Durdur') : t('common.start', 'Başlat')}
|
||||
{isStarting ? t('common.starting', '...') : (isStopping ? t('common.stopping', '...') : (isRunning ? t('common.stop', 'Durdur') : t('common.start', 'Başlat')))}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
@@ -26,13 +26,21 @@ export default function DashboardManager({
|
||||
onSelectProject
|
||||
}: DashboardManagerProps) {
|
||||
const [selectedServiceId, setSelectedServiceId] = useState<string | null>('nginx');
|
||||
const [isToggling, setIsToggling] = useState<string | null>(null);
|
||||
const [toggledStates, setToggledStates] = useState<Record<string, string>>({});
|
||||
|
||||
const handleToggleService = async (service: string) => {
|
||||
if (!window.api) return;
|
||||
if (isToggling) return;
|
||||
|
||||
const currentStatus = status[service]?.status || 'stopped';
|
||||
const isRunning = currentStatus === 'running';
|
||||
|
||||
setIsToggling(service);
|
||||
// Optimistically set transition state if not already there
|
||||
setToggledStates(prev => ({ ...prev, [service]: isRunning ? 'stopping' : 'starting' }));
|
||||
|
||||
try {
|
||||
const result = isRunning
|
||||
? await window.api.stopService(service)
|
||||
: await window.api.startService(service);
|
||||
@@ -46,9 +54,23 @@ export default function DashboardManager({
|
||||
color: '#fff'
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
setIsToggling(null);
|
||||
setToggledStates(prev => {
|
||||
const updated = { ...prev };
|
||||
delete updated[service];
|
||||
return updated;
|
||||
});
|
||||
onFetchStatus();
|
||||
}
|
||||
};
|
||||
|
||||
// Merge actual status with our local transition states
|
||||
const mergedStatus = { ...status };
|
||||
Object.keys(toggledStates).forEach(service => {
|
||||
mergedStatus[service] = { ...mergedStatus[service], status: toggledStates[service] };
|
||||
});
|
||||
|
||||
const handleReloadService = async (service: string) => {
|
||||
if (!window.api) return;
|
||||
const result = await window.api.invoke('services:reload', service);
|
||||
@@ -67,7 +89,7 @@ export default function DashboardManager({
|
||||
return (
|
||||
<Box sx={{ display: 'flex', height: 'calc(100vh - 120px)', bgcolor: 'background.default', overflow: 'hidden', borderRadius: 4, border: '1px solid rgba(255, 255, 255, 0.05)', boxShadow: '0 8px 32px rgba(0,0,0,0.2)' }}>
|
||||
<DashboardSidebar
|
||||
status={status}
|
||||
status={mergedStatus}
|
||||
phpVersions={phpVersions}
|
||||
mariaDbVersions={mariaDbVersions}
|
||||
selectedServiceId={selectedServiceId}
|
||||
@@ -76,7 +98,7 @@ export default function DashboardManager({
|
||||
/>
|
||||
<DashboardDetails
|
||||
serviceId={selectedServiceId}
|
||||
status={status}
|
||||
status={mergedStatus}
|
||||
settings={settings}
|
||||
projects={projects}
|
||||
t={t}
|
||||
|
||||
@@ -72,10 +72,17 @@ export default function DashboardSidebar({
|
||||
height: 10,
|
||||
borderRadius: '50%',
|
||||
bgcolor: isStarting ? 'warning.main' : (isRunning ? 'success.main' : 'error.main'),
|
||||
boxShadow: isRunning ? '0 0 8px rgba(76, 175, 80, 0.5)' : 'none',
|
||||
boxShadow: isRunning ? '0 0 8px rgba(76, 175, 80, 0.5)' : (isStarting ? '0 0 8px rgba(255, 177, 66, 0.5)' : 'none'),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
justifyContent: 'center',
|
||||
position: 'relative',
|
||||
'@keyframes pulse': {
|
||||
'0%': { transform: 'scale(1)', opacity: 1 },
|
||||
'50%': { transform: 'scale(1.2)', opacity: 0.7 },
|
||||
'100%': { transform: 'scale(1)', opacity: 1 }
|
||||
},
|
||||
animation: isStarting ? 'pulse 1.5s infinite ease-in-out' : 'none'
|
||||
}}>
|
||||
{isStarting && <CircularProgress size={8} thickness={6} color="inherit" />}
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user