feat: polish toolbar, live online count via SSE + emulator 3-state
CI / runtime-diagnostics (push) Skipped
CI / check (push) Successful in 30s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m5s

- Add emulator status 3-state (unknown/green/red) with tooltip
- Extract shared primary button style/constants for DRY toolbar code
- Add emulatorUnknown translations to all 25 locales
- Bump Next.js to 16.3.4
- Fix RCON delivery timeout caching (15s TTL / shared across clients)
- Who's-online tooltip throttled to max 1 request per 30s
This commit is contained in:
openhands committed 2026-09-02 21:34:30 +02:00
1 parent 67b67798b9
commit a30e4af32e
28 files changed
+115 -79

No files matched your search

+1 -1
View File
@@ -54,7 +54,7 @@
"motion": "13.1.1",
"music-metadata": "11.15.0",
"mysql2": "3.24.2",
"next": "16.3.3",
"next": "16.3.4",
"next-auth": "5.0.0-beta.32",
"next-intl": "4.14.1",
"otplib": "13.5.0",
+47 -47
View File
@@ -92,14 +92,14 @@ importers:
specifier: 3.24.2
version: 3.24.2(@types/[email protected])
next:
specifier: 16.3.3
version: 16.3.3(@types/[email protected])([email protected]([email protected]))([email protected])
specifier: 16.3.4
version: 16.3.4(@types/[email protected])([email protected]([email protected]))([email protected])
next-auth:
specifier: 5.0.0-beta.32
version: 5.0.0-beta.32([email protected].3(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
version: 5.0.0-beta.32([email protected].4(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
next-intl:
specifier: 4.14.1
version: 4.14.1(@swc/[email protected])([email protected].3(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
version: 4.14.1(@swc/[email protected])([email protected].4(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected])
otplib:
specifier: 13.5.0
version: 13.5.0
@@ -824,57 +824,57 @@ packages:
'@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4
'@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4
'@next/[email protected].3':
resolution: {integrity: sha512-U2eYQRwXj+dsqxV79zFqExDdatnNY/ZWc2nsJU1p/OgT7fd3dXwlF6OjYaFQCfMoeTA19PWq+wVmYgimVA+V+g==}
'@next/[email protected].4':
resolution: {integrity: sha512-cjWZnUUa6jZq2kFaNe/ZyJdZonOZ/QoN0Zka2nz/FLOrfx14pQuM9c5RaSVkWMqgdt4ksgPAMWPyHSs/CyV48Q==}
'@next/[email protected].3':
resolution: {integrity: sha512-8Hiv32QJPwdV6KYJ8meR9SBA061tQqnIKTJDocvOXlEQqib0xMFpzArosuffFUUc0sslbh7QQ8a3Yey1QV8EIw==}
'@next/[email protected].4':
resolution: {integrity: sha512-iBr3I5LZNk5/bgl5//iTgD2tcym14MX0Xo7fD//u9dYAEgGzza1y9oywluPtf74YnOswVdH1908aK9xVz7zQTw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@next/[email protected].3':
resolution: {integrity: sha512-A1lgKgwVchRYmSe467zdwhxT9040dd8lH+o65sL5Jet8fjB4kegw/rDyPIpYVRb6jAqwXFOJpjIXJLxQKLiE3A==}
'@next/[email protected].4':
resolution: {integrity: sha512-2dpiSyl2Jw/NrBPaU2MAKGSa+2MR82pJIn4Sm5Rjr+gxAeuh0z158Su3Z2O8zn7UNNq+ej4bToed6RcRN/Lydg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@next/[email protected].3':
resolution: {integrity: sha512-bf0FIssMFueU2dm7vQEWWxk0c8UjKTdW0yzuh0sQsD8pf1+KCLDdaqhYZNMYGmXwEOiHAUzgBKudovIlcvvBjg==}
'@next/[email protected].4':
resolution: {integrity: sha512-+t+U8HZT+fApePCS5h89CSH3datz29MkzyfCn+6fpsZBG/oiEOhINcb9rtkv6sdpToLGFn2e6146NzaKCXkqrA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@next/[email protected].3':
resolution: {integrity: sha512-W7viwCk9JY/cAkdz/A273rd5bb3RgT/IHwR7Upv90tunjBWNtAAhGhoecHh+teRNRSinuAFmE+l7fwZ4YKkrXg==}
'@next/[email protected].4':
resolution: {integrity: sha512-mx03GNs1ocQA5JQ4FxDMmIsNkdrZh8cuezKCrId28e5/gIPU/l7Kcy2+vmCCzdjnnmXJy+iOAu+7K0QppO6Urg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@next/[email protected].3':
resolution: {integrity: sha512-0W46zw1N3ODpI6n0GeivHvvob1pooozgZVqy65k0mh4/7vr+FbY9+WpHzNVXjHipJf/A3FDheBG19H1s5A25rA==}
'@next/[email protected].4':
resolution: {integrity: sha512-YIhGY6fSMfha52bnVxnzc9zaVBzJg+cqQTOD8tXIBSx4fuv0pVMxQTE0PaS59YhnMOiYiG09IMwxJAf/CFm/Dw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@next/[email protected].3':
resolution: {integrity: sha512-H4mBso8ZTMBPtdT0PN0pBx2ayTvQuTuvS6qT13d77yVFJXAPCxkyIhLTmdMaGTJs0krQYI/qpzdHijCeihXhbg==}
'@next/[email protected].4':
resolution: {integrity: sha512-+eaaX6axpDb0yF1GCpiERe6njplvdC+nks/fKfcHu3XPGRrald8P3/X7yv7QLdjA51knnxwl9pxdIJsg+w1L+Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@next/[email protected].3':
resolution: {integrity: sha512-cTMUJpcEGmeywofCUfhR+rSsoE33+rVPnPEYNTNdLNlsOeEg/vktOsKUSTb28vUGqD2jkm4Zaskcwn7OCI6FQg==}
'@next/[email protected].4':
resolution: {integrity: sha512-0jcXW7Xs/uzICrmgV3MhDYDeRy++1CqnpDIerlPIqYO4bhzB4WNbX/aRnQclustsAyTkFKB0z6rbcjmNg5tR8A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@next/[email protected].3':
resolution: {integrity: sha512-2VR4cTBzHXaBjnGsuH6GyJjENzQOmHeAh11uY1iUhjm3j5dEUrVJuUj+VL78jaGi/Dik8xS76zEj18BsFhlVZQ==}
'@next/[email protected].4':
resolution: {integrity: sha512-vvBzwu1pYQCp92maZCFCIw/XgOTMR5tur9GjakwIo2cmwRTMKajRZZDS9+e4KsUZWKu1E007WUeAFXRRjZeuzw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -2546,8 +2546,8 @@ packages:
next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
[email protected].3:
resolution: {integrity: sha512-tuRTx1nQ/yVw83cwJBo9F+njGUgMn3UHQycreWHB8XsStvvAh1AthbI8/4IpKnFaF58F+iSiHejYOlMQ/eq83g==}
[email protected].4:
resolution: {integrity: sha512-/Ztf6CeRH+ejEXUrYtqI4gkS66eFIHuSwqi60RgcpWKodxFZx2/dqVCMKBwILfAHXQ+F1b1vAudgj3mnxqtoIA==}
engines: {node: '>=20.9.0'}
hasBin: true
peerDependencies:
@@ -3460,30 +3460,30 @@ snapshots:
'@tybys/wasm-util': 0.10.3
optional: true
'@next/[email protected].3': {}
'@next/[email protected].4': {}
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@next/[email protected].3':
'@next/[email protected].4':
optional: true
'@noble/[email protected]': {}
@@ -4677,15 +4677,15 @@ snapshots:
dependencies:
content-type: 2.1.0
[email protected]([email protected].3(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
[email protected]([email protected].4(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
dependencies:
'@auth/core': 0.41.3
next: 16.3.3(@types/[email protected])([email protected]([email protected]))([email protected])
next: 16.3.4(@types/[email protected])([email protected]([email protected]))([email protected])
react: 19.2.8
[email protected]: {}
[email protected](@swc/[email protected])([email protected].3(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
[email protected](@swc/[email protected])([email protected].4(@types/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
dependencies:
'@eloqnt/config': 0.0.2
'@eloqnt/format-json': 0.0.3
@@ -4695,16 +4695,16 @@ snapshots:
'@swc/core': 1.16.1(@swc/[email protected])
icu-minify: 4.14.1
negotiator: 1.1.0
next: 16.3.3(@types/[email protected])([email protected]([email protected]))([email protected])
next: 16.3.4(@types/[email protected])([email protected]([email protected]))([email protected])
next-intl-swc-plugin-extractor: 4.14.1
react: 19.2.8
use-intl: 4.14.1([email protected])
transitivePeerDependencies:
- '@swc/helpers'
[email protected].3(@types/[email protected])([email protected]([email protected]))([email protected]):
[email protected].4(@types/[email protected])([email protected]([email protected]))([email protected]):
dependencies:
'@next/env': 16.3.3
'@next/env': 16.3.4
'@swc/helpers': 0.5.23
baseline-browser-mapping: 2.11.20
caniuse-lite: 1.0.30001810
@@ -4713,14 +4713,14 @@ snapshots:
react-dom: 19.2.8([email protected])
styled-jsx: 5.1.6([email protected])
optionalDependencies:
'@next/swc-darwin-arm64': 16.3.3
'@next/swc-darwin-x64': 16.3.3
'@next/swc-linux-arm64-gnu': 16.3.3
'@next/swc-linux-arm64-musl': 16.3.3
'@next/swc-linux-x64-gnu': 16.3.3
'@next/swc-linux-x64-musl': 16.3.3
'@next/swc-win32-arm64-msvc': 16.3.3
'@next/swc-win32-x64-msvc': 16.3.3
'@next/swc-darwin-arm64': 16.3.4
'@next/swc-darwin-x64': 16.3.4
'@next/swc-linux-arm64-gnu': 16.3.4
'@next/swc-linux-arm64-musl': 16.3.4
'@next/swc-linux-x64-gnu': 16.3.4
'@next/swc-linux-x64-musl': 16.3.4
'@next/swc-win32-arm64-msvc': 16.3.4
'@next/swc-win32-x64-msvc': 16.3.4
sharp: 0.35.4(@types/[email protected])
transitivePeerDependencies:
- '@babel/core'
+17 -6
View File
@@ -400,17 +400,28 @@ export function ClientView({
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.20)",
}}
role="status"
aria-label={
emulatorOk === null
? tToolbar("emulatorUnknown")
: emulatorOk
? tToolbar("emulatorOnline")
: tToolbar("emulatorOffline")
}
title={
emulatorOk === false
? tToolbar("emulatorOffline")
: tToolbar("emulatorOnline")
emulatorOk === null
? tToolbar("emulatorUnknown")
: emulatorOk
? tToolbar("emulatorOnline")
: tToolbar("emulatorOffline")
}
>
<span className="relative flex h-2.5 w-2.5">
{emulatorOk === false ? (
<span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-destructive ring-2 ring-destructive/30 shadow-[0_0_8px_rgba(239,68,68,0.8)]" />
) : (
{emulatorOk === null ? (
<span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-muted-foreground ring-2 ring-muted-foreground/30" />
) : emulatorOk ? (
<span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-success ring-2 ring-success/30 shadow-[0_0_8px_rgba(52,211,153,0.8)]" />
) : (
<span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-destructive ring-2 ring-destructive/30 shadow-[0_0_8px_rgba(239,68,68,0.8)]" />
)}
</span>
</div>
+2 -1
View File
@@ -21,6 +21,7 @@
"dragToMove": "اسحب للتحريك",
"hide": "إخفاء الشريط",
"fullscreenExit": "الخروج من ملء الشاشة",
"show": "إظهار الشريط"
"show": "إظهار الشريط",
"emulatorUnknown": "حالة المحاكي غير معروفة"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Влачете за преместване",
"hide": "Скрий лентата",
"fullscreenExit": "Изход от цял екран",
"show": "Покажи лентата"
"show": "Покажи лентата",
"emulatorUnknown": "Състоянието на емулатора е неизвестно"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Přetažením přesunete",
"hide": "Skrýt lištu",
"fullscreenExit": "Ukončit celou obrazovku",
"show": "Zobrazit lištu"
"show": "Zobrazit lištu",
"emulatorUnknown": "Stav emulátoru neznámý"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Træk for at flytte",
"hide": "Skjul værktøjslinje",
"fullscreenExit": "Afslut fuldskærm",
"show": "Vis værktøjslinje"
"show": "Vis værktøjslinje",
"emulatorUnknown": "Emulatorstatus ukendt"
}
}
+2 -1
View File
@@ -3275,6 +3275,7 @@
"dragToMove": "Ziehen zum Verschieben",
"hide": "Leiste ausblenden",
"fullscreenExit": "Vollbild beenden",
"show": "Leiste anzeigen"
"show": "Leiste anzeigen",
"emulatorUnknown": "Emulatorstatus unbekannt"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Σύρετε για μετακίνηση",
"hide": "Απόκρυψη γραμμής",
"fullscreenExit": "Έξοδος από πλήρη οθόνη",
"show": "Εμφάνιση γραμμής"
"show": "Εμφάνιση γραμμής",
"emulatorUnknown": "Άγνωστη κατάσταση εξομοιωτή"
}
}
+2 -1
View File
@@ -3333,6 +3333,7 @@
"dragToMove": "Drag to move",
"hide": "Hide toolbar",
"fullscreenExit": "Exit fullscreen",
"show": "Show toolbar"
"show": "Show toolbar",
"emulatorUnknown": "Emulator status unknown"
}
}
+2 -1
View File
@@ -3275,6 +3275,7 @@
"dragToMove": "Arrastra para mover",
"hide": "Ocultar barra",
"fullscreenExit": "Salir de pantalla completa",
"show": "Mostrar barra"
"show": "Mostrar barra",
"emulatorUnknown": "Estado del emulador desconocido"
}
}
+2 -1
View File
@@ -21,6 +21,7 @@
"dragToMove": "Vedä liikuttaaksesi",
"hide": "Piilota työkalupalkki",
"fullscreenExit": "Lopeta koko näyttö",
"show": "Näytä työkalupalkki"
"show": "Näytä työkalupalkki",
"emulatorUnknown": "Emulaattorin tila tuntematon"
}
}
+2 -1
View File
@@ -3275,6 +3275,7 @@
"dragToMove": "Glissez pour déplacer",
"hide": "Masquer la barre",
"fullscreenExit": "Quitter le plein écran",
"show": "Afficher la barre"
"show": "Afficher la barre",
"emulatorUnknown": "État de l'émulateur inconnu"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Povucite za pomicanje",
"hide": "Sakrij traku",
"fullscreenExit": "Izađi iz cijelog zaslona",
"show": "Prikaži traku"
"show": "Prikaži traku",
"emulatorUnknown": "Status emulatora nepoznat"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Húzás a mozgatáshoz",
"hide": "Sáv elrejtése",
"fullscreenExit": "Kilépés a teljes képernyőből",
"show": "Sáv megjelenítése"
"show": "Sáv megjelenítése",
"emulatorUnknown": "Az emulátor állapota ismeretlen"
}
}
+2 -1
View File
@@ -3332,6 +3332,7 @@
"dragToMove": "Trascina per spostare",
"hide": "Nascondi barra",
"fullscreenExit": "Esci dalla schermo intero",
"show": "Mostra barra"
"show": "Mostra barra",
"emulatorUnknown": "Stato dell'emulatore sconosciuto"
}
}
+2 -1
View File
@@ -21,6 +21,7 @@
"dragToMove": "ドラッグして移動",
"hide": "ツールバーを隠す",
"fullscreenExit": "全画面を終了",
"show": "ツールバーを表示"
"show": "ツールバーを表示",
"emulatorUnknown": "エミュレータの状態が不明です"
}
}
+2 -1
View File
@@ -3277,6 +3277,7 @@
"dragToMove": "Sleep om te verplaatsen",
"hide": "Werkbalk verbergen",
"fullscreenExit": "Volledig scherm afsluiten",
"show": "Werkbalk tonen"
"show": "Werkbalk tonen",
"emulatorUnknown": "Emulatorstatus onbekend"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Dra for å flytte",
"hide": "Skjul verktøylinje",
"fullscreenExit": "Avslutt fullskjerm",
"show": "Vis verktøylinje"
"show": "Vis verktøylinje",
"emulatorUnknown": "Emulatorstatus ukjent"
}
}
+2 -1
View File
@@ -3275,6 +3275,7 @@
"dragToMove": "Przeciągnij, aby przenieść",
"hide": "Ukryj pasek",
"fullscreenExit": "Zamknij pełny ekran",
"show": "Pokaż pasek"
"show": "Pokaż pasek",
"emulatorUnknown": "Status emulatora nieznany"
}
}
+2 -1
View File
@@ -3275,6 +3275,7 @@
"dragToMove": "Arraste para mover",
"hide": "Ocultar barra",
"fullscreenExit": "Sair da tela cheia",
"show": "Mostrar barra"
"show": "Mostrar barra",
"emulatorUnknown": "Estado do emulador desconhecido"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Trageți pentru a muta",
"hide": "Ascunde bara",
"fullscreenExit": "Ieșiți din ecran complet",
"show": "Afișați bara"
"show": "Afișați bara",
"emulatorUnknown": "Starea emulatorului necunoscută"
}
}
+2 -1
View File
@@ -3273,6 +3273,7 @@
"dragToMove": "Перетащите, чтобы переместить",
"hide": "Скрыть панель",
"fullscreenExit": "Выйти из полноэкранного режима",
"show": "Показать панель"
"show": "Показать панель",
"emulatorUnknown": "Состояние эмулятора неизвестно"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Potiahnite na presun",
"hide": "Skryť panel",
"fullscreenExit": "Ukončiť celú obrazovku",
"show": "Zobraziť panel"
"show": "Zobraziť panel",
"emulatorUnknown": "Stav emulátora neznámy"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Превуците да померите",
"hide": "Сакриј траку",
"fullscreenExit": "Изађи из целог екрана",
"show": "Прикажи траку"
"show": "Прикажи траку",
"emulatorUnknown": "Статус емулатора непознат"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Dra för att flytta",
"hide": "Dölj verktygsfält",
"fullscreenExit": "Avsluta helskärm",
"show": "Visa verktygsfält"
"show": "Visa verktygsfält",
"emulatorUnknown": "Emulatorstatus okänd"
}
}
+2 -1
View File
@@ -3275,6 +3275,7 @@
"dragToMove": "Taşımak için sürükleyin",
"hide": "Araç çubuğunu gizle",
"fullscreenExit": "Tam ekrandan çık",
"show": "Araç çubuğunu göster"
"show": "Araç çubuğunu göster",
"emulatorUnknown": "Emülatör durumu bilinmiyor"
}
}
+2 -1
View File
@@ -3274,6 +3274,7 @@
"dragToMove": "Перетягніть, щоб перемістити",
"hide": "Сховати панель",
"fullscreenExit": "Вийти з повноекранного режиму",
"show": "Показати панель"
"show": "Показати панель",
"emulatorUnknown": "Стан емулятора невідомий"
}
}