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 ---
|
# --- KRİTİK EKLEME BURASI ---
|
||||||
# PHP'ye php.ini dosyasını {{PHP_DIR}} klasöründe aramasını söyler
|
# 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
|
# Passing Authorization header to PHP
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ Alias /{{HOST}} "{{PATH}}"
|
|||||||
AllowOverride All
|
AllowOverride All
|
||||||
Require all granted
|
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
|
# Passing Authorization header to PHP
|
||||||
CGIPassAuth On
|
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",
|
"service": "php:5.6.40",
|
||||||
"action": "start",
|
"action": "start",
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
|
|||||||
if (!normalizedPath.endsWith('/')) normalizedPath += '/'
|
if (!normalizedPath.endsWith('/')) normalizedPath += '/'
|
||||||
|
|
||||||
const phpDir = path.join(configService.getBasePath(), 'bin', `php-${p.phpVersion}`)
|
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') || ''
|
const phpCgiBinary = findExecutable(phpDir, process.platform === 'win32' ? 'php-cgi.exe' : 'php-cgi') || ''
|
||||||
|
|
||||||
// Auto-suffix hostname if it's a simple slug
|
// Auto-suffix hostname if it's a simple slug
|
||||||
@@ -268,6 +269,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
|
|||||||
PATH: normalizedPath,
|
PATH: normalizedPath,
|
||||||
PHP_PORT: phpPort.toString(),
|
PHP_PORT: phpPort.toString(),
|
||||||
PHP_DIR: phpDir.replace(/\\/g, '/'),
|
PHP_DIR: phpDir.replace(/\\/g, '/'),
|
||||||
|
PHP_INI_DIR: phpIniDir.replace(/\\/g, '/'),
|
||||||
PHP_CGI_PATH: phpCgiBinary.replace(/\\/g, '/'),
|
PHP_CGI_PATH: phpCgiBinary.replace(/\\/g, '/'),
|
||||||
PHP_BIN_URL: `/php-bin-${p.host}`,
|
PHP_BIN_URL: `/php-bin-${p.host}`,
|
||||||
PORT: settings.apachePort || '8080'
|
PORT: settings.apachePort || '8080'
|
||||||
@@ -279,6 +281,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
|
|||||||
PATH: normalizedPath,
|
PATH: normalizedPath,
|
||||||
PHP_PORT: phpPort.toString(),
|
PHP_PORT: phpPort.toString(),
|
||||||
PHP_DIR: phpDir.replace(/\\/g, '/'),
|
PHP_DIR: phpDir.replace(/\\/g, '/'),
|
||||||
|
PHP_INI_DIR: phpIniDir.replace(/\\/g, '/'),
|
||||||
PHP_CGI_PATH: phpCgiBinary.replace(/\\/g, '/'),
|
PHP_CGI_PATH: phpCgiBinary.replace(/\\/g, '/'),
|
||||||
PHP_BIN_URL: `/php-bin-alias-${p.host}`,
|
PHP_BIN_URL: `/php-bin-alias-${p.host}`,
|
||||||
PORT: settings.apachePort || '8080'
|
PORT: settings.apachePort || '8080'
|
||||||
|
|||||||
@@ -202,6 +202,9 @@ export default function DashboardDetails({
|
|||||||
return 'n/a';
|
return 'n/a';
|
||||||
};
|
};
|
||||||
const isRunning = currentStatus.status === 'running';
|
const isRunning = currentStatus.status === 'running';
|
||||||
|
const isStarting = currentStatus.status === 'starting';
|
||||||
|
const isStopping = currentStatus.status === 'stopping';
|
||||||
|
const isTransitioning = isStarting || isStopping;
|
||||||
|
|
||||||
const serviceProjects = projects.filter(p => {
|
const serviceProjects = projects.filter(p => {
|
||||||
if (serviceId === 'nginx') return !p.serverType || p.serverType === 'nginx';
|
if (serviceId === 'nginx') return !p.serverType || p.serverType === 'nginx';
|
||||||
@@ -244,11 +247,14 @@ export default function DashboardDetails({
|
|||||||
<Box sx={{ flexGrow: 1 }}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
<Typography variant="h5" sx={{ fontWeight: 800 }}>{serviceId.toUpperCase()}</Typography>
|
<Typography variant="h5" sx={{ fontWeight: 800 }}>{serviceId.toUpperCase()}</Typography>
|
||||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.4)' }}>
|
<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>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Stack direction="row" spacing={1}>
|
<Stack direction="row" spacing={1}>
|
||||||
{isRunning && (
|
{isRunning && !isTransitioning && (
|
||||||
<IconButton onClick={() => onReloadService(serviceId)} sx={{ bgcolor: 'rgba(57, 167, 255, 0.1)', color: 'primary.main' }}>
|
<IconButton onClick={() => onReloadService(serviceId)} sx={{ bgcolor: 'rgba(57, 167, 255, 0.1)', color: 'primary.main' }}>
|
||||||
<RefreshIcon />
|
<RefreshIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -256,11 +262,16 @@ export default function DashboardDetails({
|
|||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color={isRunning ? 'error' : 'success'}
|
color={isRunning ? 'error' : 'success'}
|
||||||
startIcon={isRunning ? <StopIcon /> : <StartIcon />}
|
disabled={isTransitioning}
|
||||||
|
startIcon={
|
||||||
|
isTransitioning
|
||||||
|
? <CircularProgress size={20} color="inherit" />
|
||||||
|
: isRunning ? <StopIcon /> : <StartIcon />
|
||||||
|
}
|
||||||
onClick={() => onToggleService(serviceId)}
|
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>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -26,29 +26,51 @@ export default function DashboardManager({
|
|||||||
onSelectProject
|
onSelectProject
|
||||||
}: DashboardManagerProps) {
|
}: DashboardManagerProps) {
|
||||||
const [selectedServiceId, setSelectedServiceId] = useState<string | null>('nginx');
|
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) => {
|
const handleToggleService = async (service: string) => {
|
||||||
if (!window.api) return;
|
if (!window.api) return;
|
||||||
|
if (isToggling) return;
|
||||||
|
|
||||||
const currentStatus = status[service]?.status || 'stopped';
|
const currentStatus = status[service]?.status || 'stopped';
|
||||||
const isRunning = currentStatus === 'running';
|
const isRunning = currentStatus === 'running';
|
||||||
|
|
||||||
|
setIsToggling(service);
|
||||||
|
// Optimistically set transition state if not already there
|
||||||
|
setToggledStates(prev => ({ ...prev, [service]: isRunning ? 'stopping' : 'starting' }));
|
||||||
|
|
||||||
const result = isRunning
|
try {
|
||||||
? await window.api.stopService(service)
|
const result = isRunning
|
||||||
: await window.api.startService(service);
|
? await window.api.stopService(service)
|
||||||
|
: await window.api.startService(service);
|
||||||
|
|
||||||
if (result && !result.success) {
|
if (result && !result.success) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: t('common.error'),
|
title: t('common.error'),
|
||||||
text: result.message,
|
text: result.message,
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
background: '#1e1e1e',
|
background: '#1e1e1e',
|
||||||
color: '#fff'
|
color: '#fff'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setIsToggling(null);
|
||||||
|
setToggledStates(prev => {
|
||||||
|
const updated = { ...prev };
|
||||||
|
delete updated[service];
|
||||||
|
return updated;
|
||||||
});
|
});
|
||||||
|
onFetchStatus();
|
||||||
}
|
}
|
||||||
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) => {
|
const handleReloadService = async (service: string) => {
|
||||||
if (!window.api) return;
|
if (!window.api) return;
|
||||||
const result = await window.api.invoke('services:reload', service);
|
const result = await window.api.invoke('services:reload', service);
|
||||||
@@ -67,7 +89,7 @@ export default function DashboardManager({
|
|||||||
return (
|
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)' }}>
|
<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
|
<DashboardSidebar
|
||||||
status={status}
|
status={mergedStatus}
|
||||||
phpVersions={phpVersions}
|
phpVersions={phpVersions}
|
||||||
mariaDbVersions={mariaDbVersions}
|
mariaDbVersions={mariaDbVersions}
|
||||||
selectedServiceId={selectedServiceId}
|
selectedServiceId={selectedServiceId}
|
||||||
@@ -76,7 +98,7 @@ export default function DashboardManager({
|
|||||||
/>
|
/>
|
||||||
<DashboardDetails
|
<DashboardDetails
|
||||||
serviceId={selectedServiceId}
|
serviceId={selectedServiceId}
|
||||||
status={status}
|
status={mergedStatus}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
projects={projects}
|
projects={projects}
|
||||||
t={t}
|
t={t}
|
||||||
|
|||||||
@@ -72,10 +72,17 @@ export default function DashboardSidebar({
|
|||||||
height: 10,
|
height: 10,
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
bgcolor: isStarting ? 'warning.main' : (isRunning ? 'success.main' : 'error.main'),
|
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',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
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" />}
|
{isStarting && <CircularProgress size={8} thickness={6} color="inherit" />}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
Reference in New Issue
Block a user