v0.1.66: token input visible, display name in navbar
This commit is contained in:
@@ -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');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user