Merge pull request 'fix: sync CSS with refactored layout, restore sidebar, add asset versioning, fix routes/auth' (#90) from fix/policy-container-width into master
Reviewed-on: #90 Reviewed-by: rafaga21 <rafaelminaya20@hotmail.com>
This commit was merged in pull request #90.
This commit is contained in:
@@ -9,6 +9,7 @@ return [
|
|||||||
'debug' => filter_var($_ENV['APP_DEBUG'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
'debug' => filter_var($_ENV['APP_DEBUG'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
||||||
'url' => $_ENV['APP_URL'] ?? 'http://localhost',
|
'url' => $_ENV['APP_URL'] ?? 'http://localhost',
|
||||||
'timezone' => $_ENV['APP_TIMEZONE'] ?? 'America/Santo_Domingo',
|
'timezone' => $_ENV['APP_TIMEZONE'] ?? 'America/Santo_Domingo',
|
||||||
|
'asset_version' => $_ENV['ASSET_VERSION'] ?? '0.0.0',
|
||||||
],
|
],
|
||||||
|
|
||||||
'database' => [
|
'database' => [
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ code, pre {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* App Container */
|
/* App Container */
|
||||||
.app-container {
|
.app-layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ code, pre {
|
|||||||
min-height: var(--topbar-height);
|
min-height: var(--topbar-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-logo {
|
.sidebar-brand {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
@@ -169,32 +169,13 @@ code, pre {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-logo i {
|
.sidebar-brand i {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-toggle {
|
.nav-item i,
|
||||||
background: none;
|
.nav-sub-item i {
|
||||||
border: none;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
transition: color var(--transition);
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-toggle:hover {
|
|
||||||
color: var(--text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-toggle i,
|
|
||||||
.mobile-toggle i,
|
|
||||||
.nav-link i,
|
|
||||||
.nav-sub-item i,
|
|
||||||
.user-menu a i {
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,61 +185,6 @@ code, pre {
|
|||||||
padding: 0.75rem 0;
|
padding: 0.75rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-list {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item {
|
|
||||||
margin: 2px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75rem;
|
|
||||||
padding: 0.65rem 1.25rem;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
border-radius: 0;
|
|
||||||
transition: all var(--transition);
|
|
||||||
font-size: 0.92rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
border-left: 3px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link i {
|
|
||||||
width: 20px;
|
|
||||||
text-align: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link:hover {
|
|
||||||
color: var(--text-primary);
|
|
||||||
background: var(--bg-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link.active {
|
|
||||||
color: var(--accent);
|
|
||||||
background: var(--accent-light);
|
|
||||||
border-left-color: var(--accent);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-divider {
|
|
||||||
height: 1px;
|
|
||||||
background: var(--border-color);
|
|
||||||
margin: 0.5rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-section {
|
|
||||||
padding: 0.5rem 1.25rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.08em;
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-weight: 600;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-footer {
|
.sidebar-footer {
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid var(--border-color);
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
@@ -321,21 +247,72 @@ code, pre {
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 0.65rem 1.25rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-radius: 0;
|
||||||
|
transition: all var(--transition);
|
||||||
|
font-size: 0.92rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item i {
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
background: var(--bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
color: var(--accent);
|
||||||
|
background: var(--accent-light);
|
||||||
|
border-left-color: var(--accent);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: var(--border-color);
|
||||||
|
margin: 0.5rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-section {
|
||||||
|
padding: 0.5rem 1.25rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Collapsed state */
|
/* Collapsed state */
|
||||||
.sidebar.collapsed .logo-text,
|
.sidebar.collapsed .nav-item span,
|
||||||
.sidebar.collapsed .nav-link span,
|
.sidebar.collapsed .nav-chevron,
|
||||||
|
.sidebar.collapsed .notification-badge,
|
||||||
|
.sidebar.collapsed .nav-divider,
|
||||||
.sidebar.collapsed .nav-section,
|
.sidebar.collapsed .nav-section,
|
||||||
.sidebar.collapsed .user-details,
|
.sidebar.collapsed .user-details,
|
||||||
.sidebar.collapsed .user-menu,
|
.sidebar.collapsed .user-menu,
|
||||||
.sidebar.collapsed .nav-divider {
|
.sidebar.collapsed .sidebar-footer {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.collapsed .sidebar-logo {
|
.sidebar.collapsed .sidebar-brand {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.collapsed .nav-link {
|
.sidebar.collapsed .nav-item {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0.65rem;
|
padding: 0.65rem;
|
||||||
}
|
}
|
||||||
@@ -348,7 +325,7 @@ code, pre {
|
|||||||
Main Content
|
Main Content
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
.main-content {
|
.main-area {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-left: var(--sidebar-width);
|
margin-left: var(--sidebar-width);
|
||||||
transition: margin-left var(--transition);
|
transition: margin-left var(--transition);
|
||||||
@@ -357,7 +334,7 @@ code, pre {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.collapsed ~ .main-content {
|
.sidebar.collapsed ~ .main-area {
|
||||||
margin-left: var(--sidebar-collapsed);
|
margin-left: var(--sidebar-collapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +342,7 @@ code, pre {
|
|||||||
Top Bar
|
Top Bar
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
.top-bar {
|
.topbar {
|
||||||
height: var(--topbar-height);
|
height: var(--topbar-height);
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
@@ -378,48 +355,25 @@ code, pre {
|
|||||||
z-index: 50;
|
z-index: 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-bar-left {
|
.topbar-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-toggle {
|
.topbar-right {
|
||||||
display: none;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 1.3rem;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
transition: color var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-toggle:hover {
|
|
||||||
color: var(--text-primary);
|
|
||||||
background: var(--bg-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-overlay {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumb {
|
|
||||||
font-size: 0.92rem;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-bar-right {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-bar-actions {
|
.topbar-user {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.25rem;
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-icon {
|
.btn-icon {
|
||||||
@@ -442,11 +396,15 @@ code, pre {
|
|||||||
Content Area
|
Content Area
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
.content-area {
|
.page-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Page Header
|
Page Header
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
@@ -2340,20 +2298,22 @@ textarea.form-input {
|
|||||||
width: 280px;
|
width: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.mobile-open.collapsed .logo-text,
|
.sidebar.mobile-open.collapsed .nav-item span,
|
||||||
.sidebar.mobile-open.collapsed .nav-link span,
|
.sidebar.mobile-open.collapsed .nav-chevron,
|
||||||
|
.sidebar.mobile-open.collapsed .notification-badge,
|
||||||
|
.sidebar.mobile-open.collapsed .nav-divider,
|
||||||
.sidebar.mobile-open.collapsed .nav-section,
|
.sidebar.mobile-open.collapsed .nav-section,
|
||||||
.sidebar.mobile-open.collapsed .user-details,
|
.sidebar.mobile-open.collapsed .user-details,
|
||||||
.sidebar.mobile-open.collapsed .user-menu,
|
.sidebar.mobile-open.collapsed .user-menu,
|
||||||
.sidebar.mobile-open.collapsed .nav-divider {
|
.sidebar.mobile-open.collapsed .sidebar-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.mobile-open.collapsed .sidebar-logo {
|
.sidebar.mobile-open.collapsed .sidebar-brand {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.mobile-open.collapsed .nav-link {
|
.sidebar.mobile-open.collapsed .nav-item {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
padding: 0.65rem 1.25rem;
|
padding: 0.65rem 1.25rem;
|
||||||
}
|
}
|
||||||
@@ -2362,31 +2322,15 @@ textarea.form-input {
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-area {
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-toggle {
|
.page-content {
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-overlay {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
background: rgba(0,0,0,0.5);
|
|
||||||
z-index: 99;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-overlay.active {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-area {
|
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-bar {
|
.topbar {
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2414,7 +2358,7 @@ textarea.form-input {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-submenu {
|
.nav-sublist {
|
||||||
background: rgba(0,0,0,0.1);
|
background: rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2481,11 +2425,11 @@ textarea.form-input {
|
|||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
.sidebar, .top-bar {
|
.sidebar, .topbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-area {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2780,7 +2724,7 @@ textarea.form-input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Sidebar accordion */
|
/* Sidebar accordion */
|
||||||
.nav-item-accordion .nav-link {
|
.nav-item-accordion .nav-item-toggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
@@ -2797,20 +2741,13 @@ textarea.form-input {
|
|||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-submenu {
|
.nav-sublist {
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: max-height 0.25s ease;
|
transition: max-height 0.25s ease;
|
||||||
background: rgba(0,0,0,0.15);
|
background: rgba(0,0,0,0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-submenu-loading {
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
font-size: 0.78rem;
|
|
||||||
color: var(--text-muted);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-sub-item {
|
.nav-sub-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -3330,7 +3267,7 @@ input[type="range"]::-moz-range-track {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notif-dropdown-header {
|
.notif-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -3338,11 +3275,9 @@ input[type="range"]::-moz-range-track {
|
|||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.notif-dropdown-body {
|
.notif-list {
|
||||||
max-height: 360px;
|
max-height: 360px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notif-dropdown-footer {
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,14 +12,6 @@
|
|||||||
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
const sidebar = document.getElementById('sidebar');
|
||||||
const sidebarToggle = document.getElementById('sidebarToggle');
|
const sidebarToggle = document.getElementById('sidebarToggle');
|
||||||
const mobileToggle = document.getElementById('mobileToggle');
|
|
||||||
const mobileOverlay = document.getElementById('mobileOverlay');
|
|
||||||
|
|
||||||
function closeMobileSidebar() {
|
|
||||||
if (!sidebar) return;
|
|
||||||
sidebar.classList.remove('mobile-open');
|
|
||||||
if (mobileOverlay) mobileOverlay.classList.remove('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebarToggle && sidebar) {
|
if (sidebarToggle && sidebar) {
|
||||||
sidebarToggle.addEventListener('click', function () {
|
sidebarToggle.addEventListener('click', function () {
|
||||||
@@ -34,35 +26,6 @@
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mobileToggle && sidebar) {
|
|
||||||
mobileToggle.addEventListener('click', function () {
|
|
||||||
const opening = !sidebar.classList.contains('mobile-open');
|
|
||||||
if (opening) {
|
|
||||||
sidebar.classList.remove('collapsed');
|
|
||||||
sidebar.classList.add('mobile-open');
|
|
||||||
if (mobileOverlay) mobileOverlay.classList.add('active');
|
|
||||||
} else {
|
|
||||||
closeMobileSidebar();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar) {
|
|
||||||
document.addEventListener('click', function (e) {
|
|
||||||
if (window.innerWidth <= 768 &&
|
|
||||||
sidebar.classList.contains('mobile-open') &&
|
|
||||||
!sidebar.contains(e.target) &&
|
|
||||||
e.target !== mobileToggle &&
|
|
||||||
e.target !== mobileOverlay) {
|
|
||||||
closeMobileSidebar();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mobileOverlay) {
|
|
||||||
mobileOverlay.addEventListener('click', closeMobileSidebar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Theme Toggle
|
Theme Toggle
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ $router->get('/login', [AuthController::class, 'loginForm']);
|
|||||||
$router->post('/login', [AuthController::class, 'login'], [CSRFMiddleware::class, RateLimitMiddleware::class]);
|
$router->post('/login', [AuthController::class, 'login'], [CSRFMiddleware::class, RateLimitMiddleware::class]);
|
||||||
$router->get('/register', [AuthController::class, 'registerForm']);
|
$router->get('/register', [AuthController::class, 'registerForm']);
|
||||||
$router->post('/register', [AuthController::class, 'register'], [CSRFMiddleware::class]);
|
$router->post('/register', [AuthController::class, 'register'], [CSRFMiddleware::class]);
|
||||||
|
$router->get('/logout', [AuthController::class, 'logout']);
|
||||||
$router->post('/logout', [AuthController::class, 'logout'], [CSRFMiddleware::class]);
|
$router->post('/logout', [AuthController::class, 'logout'], [CSRFMiddleware::class]);
|
||||||
|
|
||||||
$router->get('/profile', [AuthController::class, 'profile'], [AuthMiddleware::class]);
|
$router->get('/profile', [AuthController::class, 'profile'], [AuthMiddleware::class]);
|
||||||
@@ -72,6 +73,11 @@ $router->get('/servers/:id/metrics', [ServerController::class, 'metrics'], [Auth
|
|||||||
$router->post('/servers/:id/thresholds', [ServerController::class, 'saveThresholds'], [AuthMiddleware::class, CSRFMiddleware::class]);
|
$router->post('/servers/:id/thresholds', [ServerController::class, 'saveThresholds'], [AuthMiddleware::class, CSRFMiddleware::class]);
|
||||||
$router->get('/sidebar/servers', [ServerController::class, 'sidebarServers'], [AuthMiddleware::class]);
|
$router->get('/sidebar/servers', [ServerController::class, 'sidebarServers'], [AuthMiddleware::class]);
|
||||||
|
|
||||||
|
$router->get('/account', function () {
|
||||||
|
$view = \ServerManager\Core\App::getInstance()->getView();
|
||||||
|
$view->redirect('/profile');
|
||||||
|
});
|
||||||
|
|
||||||
$router->get('/teams', [TeamController::class, 'index'], [AuthMiddleware::class, RoleMiddleware::class]);
|
$router->get('/teams', [TeamController::class, 'index'], [AuthMiddleware::class, RoleMiddleware::class]);
|
||||||
$router->get('/teams/search-users', [TeamController::class, 'searchUsers'], [AuthMiddleware::class, RoleMiddleware::class]);
|
$router->get('/teams/search-users', [TeamController::class, 'searchUsers'], [AuthMiddleware::class, RoleMiddleware::class]);
|
||||||
$router->get('/teams/create', [TeamController::class, 'create'], [AuthMiddleware::class, RoleMiddleware::class]);
|
$router->get('/teams/create', [TeamController::class, 'create'], [AuthMiddleware::class, RoleMiddleware::class]);
|
||||||
@@ -90,6 +96,16 @@ $router->post('/terminal/:id/execute', [TerminalController::class, 'execute'], [
|
|||||||
$router->get('/terminal/:id/history', [TerminalController::class, 'history'], [AuthMiddleware::class]);
|
$router->get('/terminal/:id/history', [TerminalController::class, 'history'], [AuthMiddleware::class]);
|
||||||
$router->post('/terminal/:id/clear-history', [TerminalController::class, 'clearHistory'], [AuthMiddleware::class, CSRFMiddleware::class]);
|
$router->post('/terminal/:id/clear-history', [TerminalController::class, 'clearHistory'], [AuthMiddleware::class, CSRFMiddleware::class]);
|
||||||
|
|
||||||
|
$router->get('/admin', function () {
|
||||||
|
$view = \ServerManager\Core\App::getInstance()->getView();
|
||||||
|
$view->redirect('/admin/audit');
|
||||||
|
}, [AuthMiddleware::class, RoleMiddleware::class]);
|
||||||
|
|
||||||
|
$router->get('/admin/activity', function () {
|
||||||
|
$view = \ServerManager\Core\App::getInstance()->getView();
|
||||||
|
$view->redirect('/admin/audit');
|
||||||
|
}, [AuthMiddleware::class, RoleMiddleware::class]);
|
||||||
|
|
||||||
$router->group(['prefix' => 'admin', 'middleware' => [AuthMiddleware::class, RoleMiddleware::class]], function (ServerManager\Core\Router $router) {
|
$router->group(['prefix' => 'admin', 'middleware' => [AuthMiddleware::class, RoleMiddleware::class]], function (ServerManager\Core\Router $router) {
|
||||||
$router->get('/users', [AdminController::class, 'users']);
|
$router->get('/users', [AdminController::class, 'users']);
|
||||||
$router->post('/users/create', [AdminController::class, 'createUser'], [CSRFMiddleware::class]);
|
$router->post('/users/create', [AdminController::class, 'createUser'], [CSRFMiddleware::class]);
|
||||||
|
|||||||
@@ -400,6 +400,7 @@ class ApiController
|
|||||||
'error' => 'Command execution failed.',
|
'error' => 'Command execution failed.',
|
||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function users(): void
|
public function users(): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class AuthController
|
|||||||
Session::set('username', $user['username']);
|
Session::set('username', $user['username']);
|
||||||
Session::set('user_role', $user['role']);
|
Session::set('user_role', $user['role']);
|
||||||
Session::set('user_email', $user['email']);
|
Session::set('user_email', $user['email']);
|
||||||
|
Session::set('api_token', $user['api_token']);
|
||||||
Session::set('login_time', time());
|
Session::set('login_time', time());
|
||||||
|
|
||||||
$lifetime = App::getConfig()['session']['lifetime'] ?? 1440;
|
$lifetime = App::getConfig()['session']['lifetime'] ?? 1440;
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ if (!function_exists('asset')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!function_exists('asset_version')) {
|
||||||
|
function asset_version(): string
|
||||||
|
{
|
||||||
|
$config = \ServerManager\Core\App::getConfig();
|
||||||
|
return $config['app']['asset_version'] ?? '0.0.0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!function_exists('url')) {
|
if (!function_exists('url')) {
|
||||||
function url(string $path = ''): string
|
function url(string $path = ''): string
|
||||||
{
|
{
|
||||||
@@ -90,11 +98,23 @@ if (!function_exists('auth')) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$apiToken = \ServerManager\Core\Session::get('api_token');
|
||||||
|
|
||||||
|
if (empty($apiToken)) {
|
||||||
|
$userModel = new \ServerManager\Models\User();
|
||||||
|
$user = $userModel->findById((int) \ServerManager\Core\Session::get('user_id'));
|
||||||
|
if ($user && !empty($user['api_token'])) {
|
||||||
|
$apiToken = $user['api_token'];
|
||||||
|
\ServerManager\Core\Session::set('api_token', $apiToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => \ServerManager\Core\Session::get('user_id'),
|
'id' => \ServerManager\Core\Session::get('user_id'),
|
||||||
'username' => \ServerManager\Core\Session::get('username'),
|
'username' => \ServerManager\Core\Session::get('username'),
|
||||||
'role' => \ServerManager\Core\Session::get('user_role'),
|
'role' => \ServerManager\Core\Session::get('user_role'),
|
||||||
'email' => \ServerManager\Core\Session::get('user_email'),
|
'email' => \ServerManager\Core\Session::get('user_email'),
|
||||||
|
'api_token' => $apiToken,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,4 +187,4 @@ function selected(string $value, string $compare): string {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/audit-log.js"></script>
|
<script src="/assets/js/audit-log.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -139,4 +139,4 @@ $data = $notifications['data'] ?? [];
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/admin-notifications.js"></script>
|
<script src="/assets/js/admin-notifications.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -102,4 +102,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/admin-security.js"></script>
|
<script src="/assets/js/admin-security.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -121,4 +121,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/admin-users.js"></script>
|
<script src="/assets/js/admin-users.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -165,5 +165,5 @@ $aggregatedMetrics = $aggregatedMetrics ?? [];
|
|||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
|
||||||
<script>const aggregatedData = <?= json_encode($aggregatedMetrics, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES) ?>;</script>
|
<script>const aggregatedData = <?= json_encode($aggregatedMetrics, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES) ?>;</script>
|
||||||
<script src="/assets/js/dashboard-chart.js"></script>
|
<script src="/assets/js/dashboard-chart.js?v=<?= asset_version() ?>"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title><?= htmlspecialchars($title ?? 'ServerManager') ?></title>
|
<title><?= htmlspecialchars($title ?? 'ServerManager') ?></title>
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/img/server.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/img/server.svg">
|
||||||
<link rel="stylesheet" href="/assets/css/style.css">
|
<link rel="stylesheet" href="/assets/css/style.css?v=<?= asset_version() ?>">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="auth-page">
|
<body class="auth-page">
|
||||||
@@ -13,6 +13,6 @@
|
|||||||
<?= $content ?? '' ?>
|
<?= $content ?? '' ?>
|
||||||
</div>
|
</div>
|
||||||
<div id="toastContainer" class="toast-container"></div>
|
<div id="toastContainer" class="toast-container"></div>
|
||||||
<script src="/assets/js/app.js"></script>
|
<script src="/assets/js/app.js?v=<?= asset_version() ?>"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
$user = $user ?? null;
|
|
||||||
$notifications = $notifications ?? [];
|
$notifications = $notifications ?? [];
|
||||||
$unreadCount = $unreadCount ?? 0;
|
$unreadCount = $unreadCount ?? 0;
|
||||||
$teamId = $teamId ?? null;
|
$teamId = $teamId ?? null;
|
||||||
@@ -7,6 +6,10 @@ $title = $title ?? 'ServerManager';
|
|||||||
$content = $content ?? '';
|
$content = $content ?? '';
|
||||||
|
|
||||||
$currentRoute = $_SERVER['REQUEST_URI'] ?? '/';
|
$currentRoute = $_SERVER['REQUEST_URI'] ?? '/';
|
||||||
|
|
||||||
|
if (!isset($user) || $user === null) {
|
||||||
|
$user = auth();
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -16,7 +19,7 @@ $currentRoute = $_SERVER['REQUEST_URI'] ?? '/';
|
|||||||
<title><?= htmlspecialchars($title) ?> — ServerManager</title>
|
<title><?= htmlspecialchars($title) ?> — ServerManager</title>
|
||||||
<meta name="api-token" content="<?= htmlspecialchars($user['api_token'] ?? '') ?>">
|
<meta name="api-token" content="<?= htmlspecialchars($user['api_token'] ?? '') ?>">
|
||||||
<meta name="csrf-token" content="<?= $this->csrfToken() ?>">
|
<meta name="csrf-token" content="<?= $this->csrfToken() ?>">
|
||||||
<link rel="stylesheet" href="/assets/css/style.css">
|
<link rel="stylesheet" href="/assets/css/style.css?v=<?= asset_version() ?>">
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/img/server.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/img/server.svg">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
@@ -41,6 +44,12 @@ $currentRoute = $_SERVER['REQUEST_URI'] ?? '/';
|
|||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<!-- Notifications -->
|
||||||
|
<a href="/notifications" class="nav-item <?= str_starts_with($currentRoute, '/notifications') ? 'active' : '' ?>">
|
||||||
|
<i class="fas fa-bell"></i>
|
||||||
|
<span>Notifications</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
<!-- Servers -->
|
<!-- Servers -->
|
||||||
<div class="nav-item-accordion <?= str_starts_with($currentRoute, '/servers') || str_starts_with($currentRoute, '/terminal') ? 'expanded' : '' ?>">
|
<div class="nav-item-accordion <?= str_starts_with($currentRoute, '/servers') || str_starts_with($currentRoute, '/terminal') ? 'expanded' : '' ?>">
|
||||||
<a href="#" class="nav-item nav-item-toggle <?= str_starts_with($currentRoute, '/servers') ? 'active' : '' ?>" onclick="toggleServerList(event)">
|
<a href="#" class="nav-item nav-item-toggle <?= str_starts_with($currentRoute, '/servers') ? 'active' : '' ?>" onclick="toggleServerList(event)">
|
||||||
@@ -53,41 +62,80 @@ $currentRoute = $_SERVER['REQUEST_URI'] ?? '/';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Teams -->
|
<!-- Administration -->
|
||||||
|
<?php if (is_super_admin()): ?>
|
||||||
|
<hr class="nav-divider">
|
||||||
|
<div class="nav-section">Administration</div>
|
||||||
|
|
||||||
<a href="/teams" class="nav-item <?= str_starts_with($currentRoute, '/teams') ? 'active' : '' ?>">
|
<a href="/teams" class="nav-item <?= str_starts_with($currentRoute, '/teams') ? 'active' : '' ?>">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-users-cog"></i>
|
||||||
<span>Teams</span>
|
<span>Teams</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Activity Log (admin+) -->
|
<a href="/admin/users" class="nav-item <?= str_starts_with($currentRoute, '/admin/users') ? 'active' : '' ?>">
|
||||||
<?php if (is_admin() || is_super_admin()): ?>
|
<i class="fas fa-users"></i>
|
||||||
<a href="/admin/activity" class="nav-item <?= str_starts_with($currentRoute, '/admin/activity') ? 'active' : '' ?>">
|
<span>Users</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="/admin/audit" class="nav-item <?= str_starts_with($currentRoute, '/admin/audit') ? 'active' : '' ?>">
|
||||||
<i class="fas fa-history"></i>
|
<i class="fas fa-history"></i>
|
||||||
<span>Activity Log</span>
|
<span>Audit Logs</span>
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<!-- Admin panel (admin+) -->
|
<a href="/admin/security" class="nav-item <?= str_starts_with($currentRoute, '/admin/security') ? 'active' : '' ?>">
|
||||||
<?php if (is_admin() || is_super_admin()): ?>
|
<i class="fas fa-shield-alt"></i>
|
||||||
<a href="/admin" class="nav-item <?= str_starts_with($currentRoute, '/admin') ? 'active' : '' ?>">
|
<span>Security</span>
|
||||||
<i class="fas fa-cog"></i>
|
|
||||||
<span>Administration</span>
|
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
|
<a href="/admin/app-version" class="nav-item <?= str_starts_with($currentRoute, '/admin/app-version') ? 'active' : '' ?>">
|
||||||
|
<i class="fas fa-mobile-alt"></i>
|
||||||
|
<span>App Version</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="/admin/notifications" class="nav-item <?= str_starts_with($currentRoute, '/admin/notifications') ? 'active' : '' ?>">
|
||||||
|
<i class="fas fa-bell"></i>
|
||||||
|
<span>Notifications</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="/admin/policies" class="nav-item <?= str_starts_with($currentRoute, '/admin/policies') ? 'active' : '' ?>">
|
||||||
|
<i class="fas fa-file-contract"></i>
|
||||||
|
<span>Policies</span>
|
||||||
|
</a>
|
||||||
|
<?php elseif (is_admin()): ?>
|
||||||
<hr class="nav-divider">
|
<hr class="nav-divider">
|
||||||
|
<div class="nav-section">Administration</div>
|
||||||
|
|
||||||
<!-- Account -->
|
<a href="/teams" class="nav-item <?= str_starts_with($currentRoute, '/teams') ? 'active' : '' ?>">
|
||||||
<a href="/account" class="nav-item <?= str_starts_with($currentRoute, '/account') ? 'active' : '' ?>">
|
<i class="fas fa-users-cog"></i>
|
||||||
<i class="fas fa-user"></i>
|
<span>Teams</span>
|
||||||
<span>My Account</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<a href="/logout" class="nav-item nav-item-danger">
|
<!-- Mobile -->
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
<hr class="nav-divider">
|
||||||
<span>Log out</span>
|
<div class="nav-section">Mobile</div>
|
||||||
|
<a href="/sysadmin.apk" class="nav-item" download>
|
||||||
|
<i class="fas fa-download"></i>
|
||||||
|
<span>Download APK</span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="user-avatar"><?= strtoupper(substr($user['username'] ?? '?', 0, 2)) ?></div>
|
||||||
|
<div class="user-details">
|
||||||
|
<span class="user-name"><?= htmlspecialchars($user['username'] ?? 'Guest') ?></span>
|
||||||
|
<span class="user-role"><?= htmlspecialchars(ucfirst(str_replace('_', ' ', $user['role'] ?? 'guest'))) ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="user-menu">
|
||||||
|
<a href="/profile" title="Profile"><i class="fas fa-user-cog"></i></a>
|
||||||
|
<form method="POST" action="/logout" class="logout-form" style="display:inline">
|
||||||
|
<input type="hidden" name="_csrf_token" value="<?= $this->csrfToken() ?>">
|
||||||
|
<button type="submit" title="Logout" style="background:none;border:none;color:inherit;cursor:pointer;padding:0;font:inherit;line-height:1"><i class="fas fa-sign-out-alt"></i></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
@@ -153,12 +201,12 @@ $currentRoute = $_SERVER['REQUEST_URI'] ?? '/';
|
|||||||
|
|
||||||
<div id="toastContainer" class="toast-container"></div>
|
<div id="toastContainer" class="toast-container"></div>
|
||||||
|
|
||||||
<script src="/assets/js/app.js"></script>
|
<script src="/assets/js/app.js?v=<?= asset_version() ?>"></script>
|
||||||
<?php if (isset($scripts)): ?>
|
<?php if (isset($scripts)): ?>
|
||||||
<?php foreach ($scripts as $script): ?>
|
<?php foreach ($scripts as $script): ?>
|
||||||
<script src="<?= htmlspecialchars($script) ?>"></script>
|
<script src="<?= htmlspecialchars($script) ?>"></script>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<script src="/assets/js/main.js"></script>
|
<script src="/assets/js/main.js?v=<?= asset_version() ?>"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -67,4 +67,4 @@ $data = $notifications ?? [];
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<script src="/assets/js/notifications.js"></script>
|
<script src="/assets/js/notifications.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?php ?><link rel="stylesheet" href="/assets/css/landing.css">
|
<?php ?><link rel="stylesheet" href="/assets/css/landing.css?v=<?= asset_version() ?>">
|
||||||
|
|
||||||
<div class="landing-page">
|
<div class="landing-page">
|
||||||
<section class="landing-hero">
|
<section class="landing-hero">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?php ?><link rel="stylesheet" href="/assets/css/legal.css">
|
<?php ?><link rel="stylesheet" href="/assets/css/legal.css?v=<?= asset_version() ?>">
|
||||||
<div class="legal-page">
|
<div class="legal-page">
|
||||||
<div class="legal-container">
|
<div class="legal-container">
|
||||||
<div class="legal-card" style="width:85%;margin:3rem auto;padding:3rem 3.5rem;background:var(--card-bg);border-radius:12px;box-shadow:0 2px 16px rgba(0,0,0,0.18)">
|
<div class="legal-card" style="width:85%;margin:3rem auto;padding:3rem 3.5rem;background:var(--card-bg);border-radius:12px;box-shadow:0 2px 16px rgba(0,0,0,0.18)">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?php ?><link rel="stylesheet" href="/assets/css/legal.css">
|
<?php ?><link rel="stylesheet" href="/assets/css/legal.css?v=<?= asset_version() ?>">
|
||||||
<div class="legal-page">
|
<div class="legal-page">
|
||||||
<div class="legal-container">
|
<div class="legal-container">
|
||||||
<div class="legal-card" style="width:85%;margin:3rem auto;padding:3rem 3.5rem;background:var(--card-bg);border-radius:12px;box-shadow:0 2px 16px rgba(0,0,0,0.18)">
|
<div class="legal-card" style="width:85%;margin:3rem auto;padding:3rem 3.5rem;background:var(--card-bg);border-radius:12px;box-shadow:0 2px 16px rgba(0,0,0,0.18)">
|
||||||
|
|||||||
@@ -171,4 +171,4 @@ document.querySelectorAll('.auth-method-tabs .tab').forEach(tab => {
|
|||||||
|
|
||||||
let permIndex = <?= !empty($savedPerms) && is_array($savedPerms) ? count($savedPerms) : 0 ?>;
|
let permIndex = <?= !empty($savedPerms) && is_array($savedPerms) ? count($savedPerms) : 0 ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/server-permissions.js"></script>
|
<script src="/assets/js/server-permissions.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -95,5 +95,5 @@ $status = $db['status'] ?? 'inactive';
|
|||||||
const serverId = <?= json_encode($server['id']) ?>;
|
const serverId = <?= json_encode($server['id']) ?>;
|
||||||
const databases = <?= json_encode(array_column($databases, 'name')) ?>;
|
const databases = <?= json_encode(array_column($databases, 'name')) ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/database-manager.js"></script>
|
<script src="/assets/js/database-manager.js?v=<?= asset_version() ?>"></script>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -156,4 +156,4 @@ $hasKey = !empty($server['ssh_key']);
|
|||||||
<script>
|
<script>
|
||||||
let permIndex = <?= count($permissions) ?>;
|
let permIndex = <?= count($permissions) ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/server-permissions.js"></script>
|
<script src="/assets/js/server-permissions.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -141,4 +141,4 @@ $groups = $groups ?? [];
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/server-list.js"></script>
|
<script src="/assets/js/server-list.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -323,5 +323,5 @@ $configValid = $nginx['config_valid'] ?? false;
|
|||||||
<script>
|
<script>
|
||||||
const serverId = <?= json_encode($server['id']) ?>;
|
const serverId = <?= json_encode($server['id']) ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/nginx-manager.js"></script>
|
<script src="/assets/js/nginx-manager.js?v=<?= asset_version() ?>"></script>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -103,4 +103,4 @@ $processList = $processList ?? [];
|
|||||||
<script>
|
<script>
|
||||||
const serverId = <?= $server['id'] ?>;
|
const serverId = <?= $server['id'] ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/server-processes.js"></script>
|
<script src="/assets/js/server-processes.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -51,5 +51,5 @@ const allServices = <?= json_encode($services, JSON_HEX_TAG | JSON_UNESCAPED_SLA
|
|||||||
const perPage = <?= $perPage ?>;
|
const perPage = <?= $perPage ?>;
|
||||||
const serverId = <?= $server['id'] ?>;
|
const serverId = <?= $server['id'] ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/server-services.js"></script>
|
<script src="/assets/js/server-services.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -375,4 +375,4 @@ $canManage = $server_role === 'owner' || $server_role === 'manager';
|
|||||||
const serverId = <?= $server['id'] ?>;
|
const serverId = <?= $server['id'] ?>;
|
||||||
const serverName = '<?= addslashes($server['name'] ?? '') ?>';
|
const serverName = '<?= addslashes($server['name'] ?? '') ?>';
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/server-show.js"></script>
|
<script src="/assets/js/server-show.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -191,4 +191,4 @@ $certs = $ssl['certificates'] ?? [];
|
|||||||
<script>
|
<script>
|
||||||
const serverId = <?= $server['id'] ?>;
|
const serverId = <?= $server['id'] ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/server-ssl.js"></script>
|
<script src="/assets/js/server-ssl.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -123,4 +123,4 @@ $lastLogins = $sysusers['last_logins'] ?? '';
|
|||||||
<script>
|
<script>
|
||||||
const serverId = <?= $server['id'] ?>;
|
const serverId = <?= $server['id'] ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/system-users.js"></script>
|
<script src="/assets/js/system-users.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -71,4 +71,4 @@
|
|||||||
<input type="hidden" name="_csrf_token" value="<?= $this->csrfToken() ?>">
|
<input type="hidden" name="_csrf_token" value="<?= $this->csrfToken() ?>">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<script src="/assets/js/team-index.js"></script>
|
<script src="/assets/js/team-index.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -150,4 +150,4 @@ const teamId = <?= $team['id'] ?>;
|
|||||||
const teamName = '<?= htmlspecialchars(addslashes($team['name'] ?? '')) ?>';
|
const teamName = '<?= htmlspecialchars(addslashes($team['name'] ?? '')) ?>';
|
||||||
const teamDescription = '<?= htmlspecialchars(addslashes($team['description'] ?? '')) ?>';
|
const teamDescription = '<?= htmlspecialchars(addslashes($team['description'] ?? '')) ?>';
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/team-show.js"></script>
|
<script src="/assets/js/team-show.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
@@ -150,4 +150,4 @@ $commandHistory = $commandHistory ?? [];
|
|||||||
<script>
|
<script>
|
||||||
const serverId = <?= $server['id'] ?>;
|
const serverId = <?= $server['id'] ?>;
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/terminal.js"></script>
|
<script src="/assets/js/terminal.js?v=<?= asset_version() ?>"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user