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,
telemetryRefreshTimer: null,
telemetryDeviceFilter: '', // '' = все устройства
// Отображаемое имя пользователя: email из JWT или plain token
displayName: localStorage.getItem('iot_display_name') || '',
};
// Сохраняем auth-параметры в localStorage
function saveSettings() {
localStorage.setItem('iot_token', S.token);
localStorage.setItem('iot_ns', S.ns); // сохраняем для восстановления сессии
localStorage.setItem('iot_api_base', S.apiBase);
localStorage.setItem('iot_mqtt_base',S.mqttBase);
localStorage.setItem('iot_token', S.token);
localStorage.setItem('iot_ns', S.ns);
localStorage.setItem('iot_api_base', S.apiBase);
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 из токена.
@@ -573,7 +595,7 @@ function renderLogin() {
<div id="login-err"></div>
<div class="form-group">
<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;">
<b>Тест:</b> введите любую строку без пробелов — например <code>alice</code> или <code>my-device-test</code>.<br>
Каждая строка → отдельный изолированный namespace.<br>
@@ -613,10 +635,11 @@ async function doLogin() {
return;
}
S.apiBase = 'https://sless.kube5s.ru';
S.mqttBase = 'wss://iot.kube5s.ru/mqtt';
S.ns = ns;
S.token = tok;
S.apiBase = 'https://sless.kube5s.ru';
S.mqttBase = 'wss://iot.kube5s.ru/mqtt';
S.ns = ns;
S.token = tok;
S.displayName = displayNameFromToken(tok);
try {
// Создаём namespace если не существует — идемпотентный вызов.
@@ -1253,6 +1276,7 @@ function navbar() {
<span class="navbar-logo-product">IoT Console</span>
</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>
</nav>`;
}
@@ -1260,8 +1284,10 @@ function navbar() {
function doLogout() {
mqttStopAuto();
mqttCleanup();
S.token = '';
S.token = '';
S.displayName = '';
localStorage.removeItem('iot_token');
localStorage.removeItem('iot_display_name');
nav('login');
}