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.