diff --git a/web/index.html b/web/index.html
index ff8be2a..c2ab048 100644
--- a/web/index.html
+++ b/web/index.html
@@ -4,7 +4,7 @@
-
NetX · UME
+ NetX
diff --git a/web/src/components/HeaderMenu.tsx b/web/src/components/HeaderMenu.tsx
index 321423d..f6baf01 100644
--- a/web/src/components/HeaderMenu.tsx
+++ b/web/src/components/HeaderMenu.tsx
@@ -31,7 +31,7 @@ export function HeaderMenu() {
-
- {t("layout.netxApi")}: {connections.netxApi}
- {netxSuffix}
-
-
- {t("layout.oclawBridge")}: {connections.oclawBridge}
- {oclawSuffix}
-
- {user ? (
-
- {user.username}
+
+
+ {t("layout.netxApi")}: {connections.netxApi}
+ {netxSuffix}
- ) : null}
- {user ? (
-
- ) : null}
-
+ {t("layout.oclawBridge")}: {connections.oclawBridge}
+ {oclawSuffix}
+
+
+ {user ? (
+ <>
+
+
+
+ {user.username}
+
+
+
+
+ >
+ ) : (
+
+ )}
diff --git a/web/src/pages/ApiTokensPage.tsx b/web/src/pages/ApiTokensPage.tsx
index 9bb3de8..f12cf3c 100644
--- a/web/src/pages/ApiTokensPage.tsx
+++ b/web/src/pages/ApiTokensPage.tsx
@@ -4,6 +4,7 @@ import { useAuth } from "../auth/AuthContext";
import { useI18n } from "../i18n";
import { useToast } from "../hooks/useToast";
import { apiDelete, apiGet, apiPost } from "../services/api";
+import { formatSystemTime } from "../utils/time";
type TokenRow = {
id: string;
@@ -33,6 +34,12 @@ const EXPIRY_OPTIONS = [
{ value: 0, labelKey: "auth.expireNever" },
] as const;
+function tokenStatusClass(row: TokenRow): string {
+ if (row.revoked) return "pt-list-status--failed";
+ if (row.expired) return "pt-list-status--warning";
+ return "pt-list-status--ok";
+}
+
export function ApiTokensPage() {
const { t } = useI18n();
const { ready, user, isAdmin } = useAuth();
@@ -98,102 +105,130 @@ export function ApiTokensPage() {
};
return (
-
-
{t("auth.apiKeysTitle")}
-
{t("auth.apiKeysHint")}
+
+
+
+
{t("auth.apiKeysTitle")}
+
+ {t("auth.apiKeysHint")}
-