v0.1.66: token input visible, display name in navbar

This commit is contained in:
Naeel
2026-04-05 17:31:02 +03:00
parent 69dc023bf7
commit 7e16dd0e0b
+36 -10
View File
@@ -275,14 +275,36 @@ const S = {
telemetryAutoRefresh: false, telemetryAutoRefresh: false,
telemetryRefreshTimer: null, telemetryRefreshTimer: null,
telemetryDeviceFilter: '', // '' = все устройства telemetryDeviceFilter: '', // '' = все устройства
// Отображаемое имя пользователя: email из JWT или plain token
displayName: localStorage.getItem('iot_display_name') || '',
}; };
// Сохраняем auth-параметры в localStorage // Сохраняем auth-параметры в localStorage
function saveSettings() { function saveSettings() {
localStorage.setItem('iot_token', S.token); localStorage.setItem('iot_token', S.token);
localStorage.setItem('iot_ns', S.ns); // сохраняем для восстановления сессии localStorage.setItem('iot_ns', S.ns);
localStorage.setItem('iot_api_base', S.apiBase); localStorage.setItem('iot_api_base', S.apiBase);
localStorage.setItem('iot_mqtt_base',S.mqttBase); localStorage.setItem('iot_mqtt_base', S.mqttBase);
localStorage.setItem('iot_display_name', S.displayName);
}
// displayNameFromToken — возвращает человекочитаемое имя для отображения в navbar.
// JWT: берём email (предпочтительно) или sub. Plain token: сама строка.
function displayNameFromToken(token) {
const parts = token.split('.');
if (parts.length === 3) {
try {
let payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
while (payload.length % 4) payload += '=';
const claims = JSON.parse(atob(payload));
return claims.email || claims.sub || token;
} catch(e) {
return token;
}
}
// Plain token — показываем как есть
return token;
} }
// namespaceFromToken — вычисляет k8s namespace из токена. // namespaceFromToken — вычисляет k8s namespace из токена.
@@ -573,7 +595,7 @@ function renderLogin() {
<div id="login-err"></div> <div id="login-err"></div>
<div class="form-group"> <div class="form-group">
<label>Bearer токен <span style="color:#e08020;font-size:10px;font-weight:600;">· тестовый режим</span></label> <label>Bearer токен <span style="color:#e08020;font-size:10px;font-weight:600;">· тестовый режим</span></label>
<input id="f-tok" type="password" value="${h(S.token)}" placeholder="любая-уникальная-строка или eyJ...JWT"> <input id="f-tok" type="text" value="${h(S.token)}" placeholder="любая-уникальная-строка или eyJ...JWT">
<div class="hint" style="margin-top:6px;"> <div class="hint" style="margin-top:6px;">
<b>Тест:</b> введите любую строку без пробелов — например <code>alice</code> или <code>my-device-test</code>.<br> <b>Тест:</b> введите любую строку без пробелов — например <code>alice</code> или <code>my-device-test</code>.<br>
Каждая строка → отдельный изолированный namespace.<br> Каждая строка → отдельный изолированный namespace.<br>
@@ -613,10 +635,11 @@ async function doLogin() {
return; return;
} }
S.apiBase = 'https://sless.kube5s.ru'; S.apiBase = 'https://sless.kube5s.ru';
S.mqttBase = 'wss://iot.kube5s.ru/mqtt'; S.mqttBase = 'wss://iot.kube5s.ru/mqtt';
S.ns = ns; S.ns = ns;
S.token = tok; S.token = tok;
S.displayName = displayNameFromToken(tok);
try { try {
// Создаём namespace если не существует — идемпотентный вызов. // Создаём namespace если не существует — идемпотентный вызов.
@@ -1253,6 +1276,7 @@ function navbar() {
<span class="navbar-logo-product">IoT Console</span> <span class="navbar-logo-product">IoT Console</span>
</div> </div>
<div class="navbar-spacer"></div> <div class="navbar-spacer"></div>
${S.displayName ? `<span style="font-size:13px;color:#7eb8e0;margin-right:12px;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${h(S.displayName)}">${h(S.displayName)}</span>` : ''}
<button class="btn btn-ghost btn-sm" onclick="doLogout()">Выйти</button> <button class="btn btn-ghost btn-sm" onclick="doLogout()">Выйти</button>
</nav>`; </nav>`;
} }
@@ -1260,8 +1284,10 @@ function navbar() {
function doLogout() { function doLogout() {
mqttStopAuto(); mqttStopAuto();
mqttCleanup(); mqttCleanup();
S.token = ''; S.token = '';
S.displayName = '';
localStorage.removeItem('iot_token'); localStorage.removeItem('iot_token');
localStorage.removeItem('iot_display_name');
nav('login'); nav('login');
} }