feat: RDP ACL exclusivity, mobile wall, nav buttons, resolution xrandr
- RDP сервис может быть назначен только одному пользователю в ACL - Мобильная заглушка на dashboard при ширине < 1024px - rdp-proxy: кнопки навигации, спиннер Ожидайте, реконнект - session_wait_page: тёмная тема, CSS спиннер - kiosk/universal-runtime manager.py: xrandr + cvt --newmode для resolution - Dockerfiles: x11-xserver-utils, x11-utils
This commit is contained in:
@@ -70,7 +70,7 @@
|
||||
<div class="list-title">ACL выбранного пользователя</div>
|
||||
<div class="acl-grid">
|
||||
{% for s in services %}
|
||||
<label><input type="checkbox" class="acl_service" value="{{s.id}}" /> {{s.name}} ({{s.slug}})</label>
|
||||
<label><input type="checkbox" class="acl_service" value="{{s.id}}" data-stype="{{s.type.value}}" /> {{s.name}} ({{s.slug}})<span class="acl-owner"></span></label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button onclick="saveAclForSelectedUser()">Save ACL</button>
|
||||
@@ -513,6 +513,8 @@
|
||||
const csrf = "{{ csrf_token }}";
|
||||
const aclMap = {{ acl | tojson }};
|
||||
const serviceCategoryMap = {{ service_category_map | tojson }};
|
||||
const rdpOccupiedBy = {{ rdp_occupied_by | tojson }};
|
||||
const rdpOccupiedUsername = {{ rdp_occupied_username | tojson }};
|
||||
const placeholderIcon = '/static/service-placeholder.svg';
|
||||
let activeTab = 'users';
|
||||
|
||||
@@ -683,7 +685,21 @@
|
||||
const userId = parseInt(document.getElementById('u_id').value || '0', 10);
|
||||
const allowed = new Set((aclMap[userId] || []));
|
||||
document.querySelectorAll('.acl_service').forEach((box) => {
|
||||
box.checked = allowed.has(parseInt(box.value, 10));
|
||||
const sid = parseInt(box.value, 10);
|
||||
box.checked = allowed.has(sid);
|
||||
const isRdp = box.dataset.stype === 'RDP';
|
||||
const occupiedBy = rdpOccupiedBy[sid];
|
||||
const currentUserHasIt = allowed.has(sid);
|
||||
const ownerSpan = box.closest('label').querySelector('.acl-owner');
|
||||
if (isRdp && occupiedBy && occupiedBy !== userId && !currentUserHasIt) {
|
||||
box.disabled = true;
|
||||
box.closest('label').style.opacity = '0.45';
|
||||
if (ownerSpan) ownerSpan.textContent = ` (${rdpOccupiedUsername[sid]})`;
|
||||
} else {
|
||||
box.disabled = false;
|
||||
box.closest('label').style.opacity = '';
|
||||
if (ownerSpan) ownerSpan.textContent = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,25 @@
|
||||
<link rel="alternate icon" type="image/png" href="/static/favicon.png" />
|
||||
</head>
|
||||
<body class="dashboard-page">
|
||||
{% raw %}<style>
|
||||
#mobile-wall{display:none;position:fixed;inset:0;z-index:9999;background:linear-gradient(135deg,#0d1b2a 0%,#1a2e45 60%,#0f2137 100%);flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center;font-family:sans-serif}
|
||||
@media(max-width:1023px){#mobile-wall{display:flex}}
|
||||
.mw-icon{font-size:4rem;margin-bottom:1.2rem;filter:drop-shadow(0 0 18px rgba(42,140,214,.5))}
|
||||
.mw-title{font-size:1.55rem;font-weight:800;color:#fff;margin-bottom:.7rem;letter-spacing:.01em}
|
||||
.mw-sub{font-size:1rem;color:#a0b8cc;max-width:340px;line-height:1.6;margin-bottom:2rem}
|
||||
.mw-badge{display:inline-flex;align-items:center;gap:.55rem;background:rgba(42,140,214,.15);border:1px solid rgba(42,140,214,.4);border-radius:999px;padding:.55rem 1.1rem;color:#6bbfff;font-size:.88rem;font-weight:600;letter-spacing:.02em}
|
||||
.mw-badge svg{width:18px;height:18px;flex-shrink:0}
|
||||
</style>{% endraw %}
|
||||
<div id="mobile-wall">
|
||||
<div class="mw-icon">🖥️</div>
|
||||
<div class="mw-title">Только для компьютера</div>
|
||||
<div class="mw-sub">Инфраструктурный полигон МОНТ оптимизирован для работы на ПК.<br>Пожалуйста, откройте портал с настольного компьютера или ноутбука.</div>
|
||||
<div class="mw-badge">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
|
||||
Минимальная ширина экрана: 1024 px
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header class="header">
|
||||
<div style="display:flex; align-items:center; gap:0.6rem;">
|
||||
<img src="/static/logo.png" alt="MONT" class="header-logo" />
|
||||
|
||||
Reference in New Issue
Block a user