diff --git a/internal/api/ui/iot-console.html b/internal/api/ui/iot-console.html index db230fa..01ffe16 100644 --- a/internal/api/ui/iot-console.html +++ b/internal/api/ui/iot-console.html @@ -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() {
- +
Тест: введите любую строку без пробелов — например alice или my-device-test.
Каждая строка → отдельный изолированный namespace.
@@ -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() { IoT Console
+ ${S.displayName ? `${h(S.displayName)}` : ''} `; } @@ -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'); }