Add credentials panel on view page; remove copy buttons from dashboard cards
This commit is contained in:
+64
-1
@@ -2511,6 +2511,42 @@ def session_view_page(session_id: str, request: Request, user: User = Depends(re
|
|||||||
except Exception:
|
except Exception:
|
||||||
iframe_src = None
|
iframe_src = None
|
||||||
if iframe_src:
|
if iframe_src:
|
||||||
|
creds_html = ""
|
||||||
|
if service.type != ServiceType.RDP and (service.svc_login or service.svc_password):
|
||||||
|
rows = ""
|
||||||
|
if service.svc_login:
|
||||||
|
login_esc = service.svc_login.replace('"', '"').replace('<', '<')
|
||||||
|
rows += f'''<div class="cr-row"><span class="cr-label">Логин</span><span class="cr-val">{login_esc}</span><button class="cr-copy" data-copy="{login_esc}" title="Копировать">⎘</button></div>'''
|
||||||
|
if service.svc_password:
|
||||||
|
pass_esc = service.svc_password.replace('"', '"').replace('<', '<')
|
||||||
|
rows += f'''<div class="cr-row"><span class="cr-label">Пароль</span><span class="cr-val cr-masked">{pass_esc}</span><button class="cr-copy" data-copy="{pass_esc}" title="Копировать">⎘</button></div>'''
|
||||||
|
if service.svc_cred_hint:
|
||||||
|
hint_esc = service.svc_cred_hint.replace('<', '<')
|
||||||
|
rows += f'''<p class="cr-hint">{hint_esc}</p>'''
|
||||||
|
creds_html = f'''
|
||||||
|
<div class="creds-panel" id="creds-panel">
|
||||||
|
<button class="creds-close" id="creds-close" title="Закрыть">✕</button>
|
||||||
|
{rows}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.getElementById("creds-close").onclick = function() {{
|
||||||
|
document.getElementById("creds-panel").style.display = "none";
|
||||||
|
}};
|
||||||
|
document.querySelectorAll(".cr-copy").forEach(function(btn) {{
|
||||||
|
btn.addEventListener("click", async function() {{
|
||||||
|
var text = btn.dataset.copy;
|
||||||
|
try {{ await navigator.clipboard.writeText(text); }} catch(e) {{
|
||||||
|
var ta = document.createElement("textarea");
|
||||||
|
ta.value = text; ta.style.position = "fixed"; ta.style.opacity = "0";
|
||||||
|
document.body.appendChild(ta); ta.select();
|
||||||
|
document.execCommand("copy"); document.body.removeChild(ta);
|
||||||
|
}}
|
||||||
|
btn.classList.add("copied");
|
||||||
|
setTimeout(function() {{ btn.classList.remove("copied"); }}, 1500);
|
||||||
|
}});
|
||||||
|
}});
|
||||||
|
</script>'''
|
||||||
|
|
||||||
return HTMLResponse(
|
return HTMLResponse(
|
||||||
content=f"""
|
content=f"""
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
@@ -2520,10 +2556,37 @@ def session_view_page(session_id: str, request: Request, user: User = Depends(re
|
|||||||
<title>{service.name}</title>
|
<title>{service.name}</title>
|
||||||
<style>
|
<style>
|
||||||
html,body,iframe {{ margin:0; width:100%; height:100%; border:0; background:#0f1720; }}
|
html,body,iframe {{ margin:0; width:100%; height:100%; border:0; background:#0f1720; }}
|
||||||
|
.creds-panel{{
|
||||||
|
position:fixed;right:16px;top:16px;z-index:999;
|
||||||
|
background:linear-gradient(180deg,rgba(15,24,36,.88),rgba(9,14,22,.94));
|
||||||
|
border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px);
|
||||||
|
box-shadow:0 10px 28px rgba(0,0,0,.4);padding:10px 12px 11px;border-radius:14px;
|
||||||
|
min-width:220px;max-width:320px;
|
||||||
|
}}
|
||||||
|
.creds-close{{
|
||||||
|
position:absolute;top:6px;right:8px;background:none;border:none;
|
||||||
|
color:rgba(255,255,255,.55);font-size:14px;cursor:pointer;line-height:1;padding:2px 4px;
|
||||||
|
}}
|
||||||
|
.creds-close:hover{{color:#fff}}
|
||||||
|
.cr-row{{display:flex;align-items:center;gap:6px;margin-bottom:5px;}}
|
||||||
|
.cr-label{{font:600 11px/1 sans-serif;text-transform:uppercase;letter-spacing:.04em;
|
||||||
|
color:rgba(180,210,240,.7);min-width:46px;flex-shrink:0;}}
|
||||||
|
.cr-val{{font:600 13px/1 monospace;color:#dce8f5;flex:1;overflow:hidden;
|
||||||
|
text-overflow:ellipsis;white-space:nowrap;}}
|
||||||
|
.cr-masked{{letter-spacing:.1em;font-size:14px;}}
|
||||||
|
.cr-copy{{
|
||||||
|
flex-shrink:0;width:26px;height:26px;border:1px solid rgba(255,255,255,.26);
|
||||||
|
border-radius:6px;background:linear-gradient(180deg,#2a8cd6,#1668a6);
|
||||||
|
color:#fff;cursor:pointer;font-size:13px;display:grid;place-items:center;padding:0;
|
||||||
|
box-shadow:inset 0 1px 0 rgba(255,255,255,.22);transition:filter .15s;
|
||||||
|
}}
|
||||||
|
.cr-copy:hover{{filter:brightness(1.15)}}
|
||||||
|
.cr-copy.copied{{background:linear-gradient(180deg,#2ab86a,#1a8a4a);}}
|
||||||
|
.cr-hint{{margin:4px 0 0;font:400 11px/1.35 sans-serif;color:rgba(180,210,240,.65);}}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="{iframe_src}" allow="clipboard-read; clipboard-write"></iframe>
|
<iframe src="{iframe_src}" allow="clipboard-read; clipboard-write"></iframe>{creds_html}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""".strip()
|
""".strip()
|
||||||
|
|||||||
@@ -392,26 +392,6 @@ button {
|
|||||||
letter-spacing: .12em;
|
letter-spacing: .12em;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.svc-cred-copy {
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 26px;
|
|
||||||
height: 26px;
|
|
||||||
border: 1px solid #b0c8de;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: #fff;
|
|
||||||
color: #3a6d96;
|
|
||||||
cursor: pointer;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 0.78rem;
|
|
||||||
transition: background .15s, color .15s, border-color .15s;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
.svc-cred-copy::before { content: "\2398"; font-size: 0.9rem; }
|
|
||||||
.svc-cred-copy.copied { background: #1a8a4a; border-color: #1a8a4a; color: #fff; }
|
|
||||||
.svc-cred-copy.copied::before { content: "\2713"; }
|
|
||||||
.svc-cred-copy:hover:not(.copied) { background: #e6f0f9; border-color: #7aabcf; }
|
|
||||||
|
|
||||||
.tile-link {
|
.tile-link {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -91,14 +91,12 @@
|
|||||||
<div class="svc-cred-row">
|
<div class="svc-cred-row">
|
||||||
<span class="svc-cred-label">Логин</span>
|
<span class="svc-cred-label">Логин</span>
|
||||||
<span class="svc-cred-value">{{ service.svc_login }}</span>
|
<span class="svc-cred-value">{{ service.svc_login }}</span>
|
||||||
<button class="svc-cred-copy" type="button" data-copy="{{ service.svc_login }}" title="Копировать логин"></button>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if service.svc_password %}
|
{% if service.svc_password %}
|
||||||
<div class="svc-cred-row">
|
<div class="svc-cred-row">
|
||||||
<span class="svc-cred-label">Пароль</span>
|
<span class="svc-cred-label">Пароль</span>
|
||||||
<span class="svc-cred-value svc-cred-masked">{{ service.svc_password }}</span>
|
<span class="svc-cred-value svc-cred-masked">{{ service.svc_password }}</span>
|
||||||
<button class="svc-cred-copy" type="button" data-copy="{{ service.svc_password }}" title="Копировать пароль"></button>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if service.svc_cred_hint %}
|
{% if service.svc_cred_hint %}
|
||||||
@@ -219,21 +217,5 @@
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script>
|
|
||||||
document.querySelectorAll('.svc-cred-copy').forEach(btn => {
|
|
||||||
btn.addEventListener('click', async (e) => {
|
|
||||||
e.preventDefault(); e.stopPropagation();
|
|
||||||
const text = btn.dataset.copy;
|
|
||||||
try { await navigator.clipboard.writeText(text); } catch(_) {
|
|
||||||
const ta = document.createElement('textarea');
|
|
||||||
ta.value = text; ta.style.position='fixed'; ta.style.opacity='0';
|
|
||||||
document.body.appendChild(ta); ta.select();
|
|
||||||
document.execCommand('copy'); document.body.removeChild(ta);
|
|
||||||
}
|
|
||||||
btn.classList.add('copied');
|
|
||||||
setTimeout(() => btn.classList.remove('copied'), 1500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user