mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-24 05:16:09 +00:00
fix(web): stop spurious page refresh on account menu open; plugin log auto-refresh as switch
Two unrelated frontend fixes: - LanguageSelector mounts each time the sidebar account dropdown opens and unconditionally called i18n.changeLanguage() on mount, emitting a languageChanged event even when the language was unchanged. That handed every useTranslation() consumer a fresh `t` reference, re-running effects keyed on `t` (e.g. the plugins page system-status fetch) and surfacing as a page "refresh". Guard the call so it only fires on an actual change. - Plugin logs auto-refresh control changed from a toggle Button to a Switch + Label; the on/off button i18n keys are replaced by a single static logsAutoRefresh label across all 8 locales.
This commit is contained in:
@@ -3,6 +3,8 @@ import { httpClient } from '@/app/infra/http/HttpClient';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PluginLogEntry } from '@/app/infra/entities/plugin';
|
import { PluginLogEntry } from '@/app/infra/entities/plugin';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
@@ -116,17 +118,19 @@ export default function PluginLogs({
|
|||||||
/>
|
/>
|
||||||
{t('plugins.logsRefresh')}
|
{t('plugins.logsRefresh')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<div className="flex items-center gap-2">
|
||||||
type="button"
|
<Switch
|
||||||
variant={autoRefresh ? 'default' : 'outline'}
|
id="plugin-logs-auto-refresh"
|
||||||
size="sm"
|
checked={autoRefresh}
|
||||||
className="h-8"
|
onCheckedChange={setAutoRefresh}
|
||||||
onClick={() => setAutoRefresh((v) => !v)}
|
/>
|
||||||
>
|
<Label
|
||||||
{autoRefresh
|
htmlFor="plugin-logs-auto-refresh"
|
||||||
? t('plugins.logsAutoRefreshOn')
|
className="cursor-pointer text-sm font-normal text-muted-foreground"
|
||||||
: t('plugins.logsAutoRefreshOff')}
|
>
|
||||||
</Button>
|
{t('plugins.logsAutoRefresh')}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -56,7 +56,16 @@ export function LanguageSelector({
|
|||||||
|
|
||||||
const savedLanguage = localStorage.getItem('langbot_language');
|
const savedLanguage = localStorage.getItem('langbot_language');
|
||||||
if (savedLanguage) {
|
if (savedLanguage) {
|
||||||
i18n.changeLanguage(savedLanguage);
|
// Only switch when the active language actually differs. Calling
|
||||||
|
// i18n.changeLanguage() unconditionally on every mount emits a
|
||||||
|
// `languageChanged` event even when nothing changed, which hands every
|
||||||
|
// useTranslation() consumer a fresh `t` reference and re-runs effects
|
||||||
|
// that depend on `t` (e.g. data refetches). Since this selector mounts
|
||||||
|
// each time the account dropdown opens, that surfaced as a spurious
|
||||||
|
// page "refresh". Guard the call to keep mounts side-effect-free.
|
||||||
|
if (i18n.language !== savedLanguage) {
|
||||||
|
i18n.changeLanguage(savedLanguage);
|
||||||
|
}
|
||||||
setCurrentLanguage(savedLanguage);
|
setCurrentLanguage(savedLanguage);
|
||||||
} else {
|
} else {
|
||||||
const browserLanguage = navigator.language;
|
const browserLanguage = navigator.language;
|
||||||
|
|||||||
@@ -593,8 +593,7 @@ const enUS = {
|
|||||||
tabLogs: 'Logs',
|
tabLogs: 'Logs',
|
||||||
logsLevelAll: 'All levels',
|
logsLevelAll: 'All levels',
|
||||||
logsRefresh: 'Refresh',
|
logsRefresh: 'Refresh',
|
||||||
logsAutoRefreshOn: 'Auto-refresh: On',
|
logsAutoRefresh: 'Auto-refresh',
|
||||||
logsAutoRefreshOff: 'Auto-refresh: Off',
|
|
||||||
logsEmpty:
|
logsEmpty:
|
||||||
'No logs yet. Logs printed by the plugin via logger will appear here.',
|
'No logs yet. Logs printed by the plugin via logger will appear here.',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
|
|||||||
@@ -605,8 +605,7 @@ const esES = {
|
|||||||
tabLogs: 'Registros',
|
tabLogs: 'Registros',
|
||||||
logsLevelAll: 'Todos los niveles',
|
logsLevelAll: 'Todos los niveles',
|
||||||
logsRefresh: 'Actualizar',
|
logsRefresh: 'Actualizar',
|
||||||
logsAutoRefreshOn: 'Auto-actualizar: Activado',
|
logsAutoRefresh: 'Auto-actualizar',
|
||||||
logsAutoRefreshOff: 'Auto-actualizar: Desactivado',
|
|
||||||
logsEmpty:
|
logsEmpty:
|
||||||
'Aún no hay registros. Los registros que el plugin imprima mediante logger aparecerán aquí.',
|
'Aún no hay registros. Los registros que el plugin imprima mediante logger aparecerán aquí.',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
|
|||||||
@@ -598,8 +598,7 @@ const jaJP = {
|
|||||||
tabLogs: 'ログ',
|
tabLogs: 'ログ',
|
||||||
logsLevelAll: 'すべてのレベル',
|
logsLevelAll: 'すべてのレベル',
|
||||||
logsRefresh: '更新',
|
logsRefresh: '更新',
|
||||||
logsAutoRefreshOn: '自動更新:オン',
|
logsAutoRefresh: '自動更新',
|
||||||
logsAutoRefreshOff: '自動更新:オフ',
|
|
||||||
logsEmpty:
|
logsEmpty:
|
||||||
'ログはまだありません。プラグインが logger で出力したログがここに表示されます。',
|
'ログはまだありません。プラグインが logger で出力したログがここに表示されます。',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
|
|||||||
@@ -604,8 +604,7 @@ const ruRU = {
|
|||||||
tabLogs: 'Журналы',
|
tabLogs: 'Журналы',
|
||||||
logsLevelAll: 'Все уровни',
|
logsLevelAll: 'Все уровни',
|
||||||
logsRefresh: 'Обновить',
|
logsRefresh: 'Обновить',
|
||||||
logsAutoRefreshOn: 'Автообновление: вкл.',
|
logsAutoRefresh: 'Автообновление',
|
||||||
logsAutoRefreshOff: 'Автообновление: выкл.',
|
|
||||||
logsEmpty:
|
logsEmpty:
|
||||||
'Журналов пока нет. Здесь появятся логи, выводимые плагином через logger.',
|
'Журналов пока нет. Здесь появятся логи, выводимые плагином через logger.',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
|
|||||||
@@ -585,8 +585,7 @@ const thTH = {
|
|||||||
tabLogs: 'บันทึก',
|
tabLogs: 'บันทึก',
|
||||||
logsLevelAll: 'ทุกระดับ',
|
logsLevelAll: 'ทุกระดับ',
|
||||||
logsRefresh: 'รีเฟรช',
|
logsRefresh: 'รีเฟรช',
|
||||||
logsAutoRefreshOn: 'รีเฟรชอัตโนมัติ: เปิด',
|
logsAutoRefresh: 'รีเฟรชอัตโนมัติ',
|
||||||
logsAutoRefreshOff: 'รีเฟรชอัตโนมัติ: ปิด',
|
|
||||||
logsEmpty: 'ยังไม่มีบันทึก บันทึกที่ปลั๊กอินพิมพ์ผ่าน logger จะแสดงที่นี่',
|
logsEmpty: 'ยังไม่มีบันทึก บันทึกที่ปลั๊กอินพิมพ์ผ่าน logger จะแสดงที่นี่',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
tooLarge: 'ขนาดไฟล์เกินขีดจำกัด 10MB',
|
tooLarge: 'ขนาดไฟล์เกินขีดจำกัด 10MB',
|
||||||
|
|||||||
@@ -599,8 +599,7 @@ const viVN = {
|
|||||||
tabLogs: 'Nhật ký',
|
tabLogs: 'Nhật ký',
|
||||||
logsLevelAll: 'Tất cả cấp độ',
|
logsLevelAll: 'Tất cả cấp độ',
|
||||||
logsRefresh: 'Làm mới',
|
logsRefresh: 'Làm mới',
|
||||||
logsAutoRefreshOn: 'Tự động làm mới: Bật',
|
logsAutoRefresh: 'Tự động làm mới',
|
||||||
logsAutoRefreshOff: 'Tự động làm mới: Tắt',
|
|
||||||
logsEmpty:
|
logsEmpty:
|
||||||
'Chưa có nhật ký. Nhật ký do plugin in qua logger sẽ hiển thị ở đây.',
|
'Chưa có nhật ký. Nhật ký do plugin in qua logger sẽ hiển thị ở đây.',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
|
|||||||
@@ -566,8 +566,7 @@ const zhHans = {
|
|||||||
tabLogs: '日志',
|
tabLogs: '日志',
|
||||||
logsLevelAll: '全部级别',
|
logsLevelAll: '全部级别',
|
||||||
logsRefresh: '刷新',
|
logsRefresh: '刷新',
|
||||||
logsAutoRefreshOn: '自动刷新:开',
|
logsAutoRefresh: '自动刷新',
|
||||||
logsAutoRefreshOff: '自动刷新:关',
|
|
||||||
logsEmpty: '暂无日志。插件通过 logger 打印的日志会显示在这里。',
|
logsEmpty: '暂无日志。插件通过 logger 打印的日志会显示在这里。',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
tooLarge: '文件大小超过 10MB 限制',
|
tooLarge: '文件大小超过 10MB 限制',
|
||||||
|
|||||||
@@ -566,8 +566,7 @@ const zhHant = {
|
|||||||
tabLogs: '日誌',
|
tabLogs: '日誌',
|
||||||
logsLevelAll: '全部級別',
|
logsLevelAll: '全部級別',
|
||||||
logsRefresh: '重新整理',
|
logsRefresh: '重新整理',
|
||||||
logsAutoRefreshOn: '自動重新整理:開',
|
logsAutoRefresh: '自動重新整理',
|
||||||
logsAutoRefreshOff: '自動重新整理:關',
|
|
||||||
logsEmpty: '暫無日誌。外掛透過 logger 列印的日誌會顯示在這裡。',
|
logsEmpty: '暫無日誌。外掛透過 logger 列印的日誌會顯示在這裡。',
|
||||||
fileUpload: {
|
fileUpload: {
|
||||||
tooLarge: '檔案大小超過 10MB 限制',
|
tooLarge: '檔案大小超過 10MB 限制',
|
||||||
|
|||||||
Reference in New Issue
Block a user