mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-10 16:53:35 +08:00
feat(about): 关于页自动检查更新开关 + 自定义检查间隔
This commit is contained in:
@@ -231,6 +231,14 @@ describe('settings center layout', () => {
|
||||
expect(appSource).toContain("gridTemplateColumns: 'minmax(0, 1fr) minmax(220px, 260px)'");
|
||||
expect(appSource).toContain('className="gonavi-about-update-channel"');
|
||||
expect(appSource).toContain('<Segmented');
|
||||
expect(appSource).toContain("t('app.about.field.auto_check_updates')");
|
||||
expect(appSource).toContain("t('app.about.field.auto_check_interval')");
|
||||
expect(appSource).toContain("t('app.about.version_update.auto_check_hint')");
|
||||
expect(appSource).toContain("t('app.about.version_update.auto_check_disabled_hint')");
|
||||
expect(appSource).toContain('className="gonavi-about-auto-check-interval"');
|
||||
expect(appSource).toContain('checked={autoCheckForUpdates}');
|
||||
expect(appSource).toContain('setAutoCheckForUpdates(checked)');
|
||||
expect(appSource).toContain('setAutoCheckForUpdatesIntervalMinutes(Number(value))');
|
||||
expect(appSource).toContain('maxWidth: 360');
|
||||
expect(appSource).toContain("alignItems: 'start'");
|
||||
expect(appSource).toContain("overflowWrap: 'anywhere'");
|
||||
|
||||
@@ -40,6 +40,7 @@ import CustomThemeStyleHost, {
|
||||
type CustomThemeAntTokenSnapshot,
|
||||
} from './components/theme/CustomThemeStyleHost';
|
||||
import {
|
||||
AUTO_CHECK_FOR_UPDATES_INTERVAL_OPTIONS,
|
||||
DEFAULT_APPEARANCE,
|
||||
MAX_V2_SIDEBAR_RAIL_SCALE,
|
||||
MIN_V2_SIDEBAR_RAIL_SCALE,
|
||||
@@ -713,6 +714,10 @@ function App() {
|
||||
const setFontSize = useStore(state => state.setFontSize);
|
||||
const startupFullscreen = useStore(state => state.startupFullscreen);
|
||||
const setStartupFullscreen = useStore(state => state.setStartupFullscreen);
|
||||
const autoCheckForUpdates = useStore(state => state.autoCheckForUpdates);
|
||||
const setAutoCheckForUpdates = useStore(state => state.setAutoCheckForUpdates);
|
||||
const autoCheckForUpdatesIntervalMinutes = useStore(state => state.autoCheckForUpdatesIntervalMinutes);
|
||||
const setAutoCheckForUpdatesIntervalMinutes = useStore(state => state.setAutoCheckForUpdatesIntervalMinutes);
|
||||
const globalProxy = useStore(state => state.globalProxy);
|
||||
const replaceConnections = useStore(state => state.replaceConnections);
|
||||
const replaceGlobalProxy = useStore(state => state.replaceGlobalProxy);
|
||||
@@ -5026,8 +5031,8 @@ function App() {
|
||||
</div>
|
||||
<div style={{ borderTop: `1px solid ${dividerColor}`, padding: '18px 24px' }}>
|
||||
<div style={{ display: 'grid', gap: 8 }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(220px, 260px)', alignItems: 'center', gap: 16 }}>
|
||||
<div style={{ fontSize: 15, fontWeight: 600, color: overlayTheme.titleText }}>{t('app.about.field.update_channel')}</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '100px 1fr', alignItems: 'center', gap: 16 }}>
|
||||
<div style={{ fontSize: 15, fontWeight: 600, color: overlayTheme.titleText, whiteSpace: 'nowrap' }}>{t('app.about.field.update_channel')}</div>
|
||||
<Segmented
|
||||
className="gonavi-about-update-channel"
|
||||
value={updateChannel}
|
||||
@@ -5044,11 +5049,41 @@ function App() {
|
||||
|| updateDownloadProgress.status === 'start'
|
||||
|| updateDownloadProgress.status === 'downloading'
|
||||
}
|
||||
block
|
||||
style={{ width: '100%' }}
|
||||
style={{ flexShrink: 0 }}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ ...utilityMutedTextStyle, lineHeight: 1.55, maxWidth: 360 }}>{t('app.about.version_update.channel_hint')}</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '100px 1fr', alignItems: 'center', gap: 16, marginTop: 10 }}>
|
||||
<div style={{ fontSize: 15, fontWeight: 600, color: overlayTheme.titleText, whiteSpace: 'nowrap' }}>{t('app.about.field.auto_check_updates')}</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<Switch
|
||||
checked={autoCheckForUpdates}
|
||||
onChange={(checked) => setAutoCheckForUpdates(checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{autoCheckForUpdates ? (
|
||||
<>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '100px 1fr', alignItems: 'center', gap: 16, marginTop: 10 }}>
|
||||
<div style={{ fontSize: 15, fontWeight: 600, color: overlayTheme.titleText, whiteSpace: 'nowrap' }}>{t('app.about.field.auto_check_interval')}</div>
|
||||
<Select
|
||||
className="gonavi-about-auto-check-interval"
|
||||
value={autoCheckForUpdatesIntervalMinutes}
|
||||
options={AUTO_CHECK_FOR_UPDATES_INTERVAL_OPTIONS.map((minutes) => ({
|
||||
value: minutes,
|
||||
label: minutes >= 60 && minutes % 60 === 0
|
||||
? t('app.about.auto_check_interval.hours', { hours: minutes / 60 })
|
||||
: t('app.about.auto_check_interval.minutes', { minutes }),
|
||||
}))}
|
||||
onChange={(value) => setAutoCheckForUpdatesIntervalMinutes(Number(value))}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ ...utilityMutedTextStyle, lineHeight: 1.55, maxWidth: 360 }}>{t('app.about.version_update.auto_check_hint')}</div>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ ...utilityMutedTextStyle, lineHeight: 1.55, maxWidth: 360 }}>{t('app.about.version_update.auto_check_disabled_hint')}</div>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ height: 1, background: dividerColor, margin: '18px 0' }} />
|
||||
<div style={{ display: 'grid', gap: 13 }}>
|
||||
|
||||
@@ -14,12 +14,28 @@ const messageApi = vi.hoisted(() => ({
|
||||
error: vi.fn(),
|
||||
}));
|
||||
|
||||
const storeApi = vi.hoisted(() => ({
|
||||
autoCheckForUpdates: true,
|
||||
autoCheckForUpdatesIntervalMinutes: 30,
|
||||
}));
|
||||
|
||||
vi.mock('../../wailsjs/runtime', () => runtimeApi);
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
message: messageApi,
|
||||
}));
|
||||
|
||||
vi.mock('../store', () => ({
|
||||
useStore: (selector: (state: {
|
||||
autoCheckForUpdates: boolean;
|
||||
autoCheckForUpdatesIntervalMinutes: number;
|
||||
}) => unknown) =>
|
||||
selector({
|
||||
autoCheckForUpdates: storeApi.autoCheckForUpdates,
|
||||
autoCheckForUpdatesIntervalMinutes: storeApi.autoCheckForUpdatesIntervalMinutes,
|
||||
}),
|
||||
}));
|
||||
|
||||
type BackendAppMock = {
|
||||
CheckForUpdates: ReturnType<typeof vi.fn>;
|
||||
CheckForUpdatesSilently: ReturnType<typeof vi.fn>;
|
||||
@@ -72,6 +88,8 @@ describe('useAppUpdateManager', () => {
|
||||
backendApp = createBackendAppMock();
|
||||
hook = null;
|
||||
renderer = null;
|
||||
storeApi.autoCheckForUpdates = true;
|
||||
storeApi.autoCheckForUpdatesIntervalMinutes = 30;
|
||||
runtimeApi.EventsOn.mockClear();
|
||||
messageApi.info.mockReset();
|
||||
messageApi.success.mockReset();
|
||||
@@ -104,6 +122,82 @@ describe('useAppUpdateManager', () => {
|
||||
expect(resolveUpdateInstallAction({ packageType: 'msi', autoRelaunch: false })).toBe('launch-installer');
|
||||
});
|
||||
|
||||
it('schedules silent update checks when auto-check is enabled', async () => {
|
||||
backendApp.CheckForUpdatesSilently.mockResolvedValue({
|
||||
success: true,
|
||||
data: {
|
||||
hasUpdate: false,
|
||||
currentVersion: '0.8.1',
|
||||
latestVersion: '0.8.1',
|
||||
},
|
||||
});
|
||||
|
||||
renderHook();
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(2000);
|
||||
});
|
||||
|
||||
expect(backendApp.CheckForUpdatesSilently).toHaveBeenCalledTimes(1);
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(30 * 60 * 1000);
|
||||
});
|
||||
|
||||
expect(backendApp.CheckForUpdatesSilently).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('uses the configured auto-check interval for subsequent silent checks', async () => {
|
||||
storeApi.autoCheckForUpdatesIntervalMinutes = 15;
|
||||
backendApp.CheckForUpdatesSilently.mockResolvedValue({
|
||||
success: true,
|
||||
data: {
|
||||
hasUpdate: false,
|
||||
currentVersion: '0.8.1',
|
||||
latestVersion: '0.8.1',
|
||||
},
|
||||
});
|
||||
|
||||
renderHook();
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(2000);
|
||||
});
|
||||
expect(backendApp.CheckForUpdatesSilently).toHaveBeenCalledTimes(1);
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(14 * 60 * 1000);
|
||||
});
|
||||
expect(backendApp.CheckForUpdatesSilently).toHaveBeenCalledTimes(1);
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(60 * 1000);
|
||||
});
|
||||
expect(backendApp.CheckForUpdatesSilently).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('does not schedule silent update checks when auto-check is disabled', async () => {
|
||||
storeApi.autoCheckForUpdates = false;
|
||||
backendApp.CheckForUpdatesSilently.mockResolvedValue({
|
||||
success: true,
|
||||
data: {
|
||||
hasUpdate: false,
|
||||
currentVersion: '0.8.1',
|
||||
latestVersion: '0.8.1',
|
||||
},
|
||||
});
|
||||
|
||||
renderHook();
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(2000);
|
||||
await vi.advanceTimersByTimeAsync(30 * 60 * 1000);
|
||||
});
|
||||
|
||||
expect(backendApp.CheckForUpdatesSilently).not.toHaveBeenCalled();
|
||||
expect(backendApp.CheckForUpdates).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('merges complete MSI download metadata returned by the backend', async () => {
|
||||
backendApp.CheckForUpdates.mockResolvedValue({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState, type MutableRefObject } from 'react';
|
||||
import { message } from 'antd';
|
||||
import { EventsOn } from '../../wailsjs/runtime';
|
||||
import { useStore } from '../store';
|
||||
import { resolveAboutDisplayVersion } from '../utils/appVersionDisplay';
|
||||
|
||||
type Translator = (key: string, params?: Record<string, any>) => string;
|
||||
@@ -181,6 +182,10 @@ export const useAppUpdateManager = ({
|
||||
t,
|
||||
updateCenterBridgeRef,
|
||||
}: UseAppUpdateManagerOptions) => {
|
||||
const autoCheckForUpdates = useStore((state) => state.autoCheckForUpdates);
|
||||
const autoCheckForUpdatesIntervalMinutes = useStore(
|
||||
(state) => state.autoCheckForUpdatesIntervalMinutes,
|
||||
);
|
||||
const updateCheckInFlightRef = useRef(false);
|
||||
const updateDownloadInFlightRef = useRef(false);
|
||||
const updateUserDismissedRef = useRef(false);
|
||||
@@ -686,17 +691,21 @@ export const useAppUpdateManager = ({
|
||||
}, [loadUpdateChannel]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!autoCheckForUpdates) {
|
||||
return;
|
||||
}
|
||||
const intervalMs = Math.max(1, autoCheckForUpdatesIntervalMinutes) * 60 * 1000;
|
||||
const startupTimer = window.setTimeout(() => {
|
||||
void checkForUpdates(true);
|
||||
}, 2000);
|
||||
const interval = window.setInterval(() => {
|
||||
void checkForUpdates(true);
|
||||
}, 30 * 60 * 1000);
|
||||
}, intervalMs);
|
||||
return () => {
|
||||
window.clearTimeout(startupTimer);
|
||||
window.clearInterval(interval);
|
||||
};
|
||||
}, [checkForUpdates]);
|
||||
}, [autoCheckForUpdates, autoCheckForUpdatesIntervalMinutes, checkForUpdates]);
|
||||
|
||||
useEffect(() => {
|
||||
let offDownloadProgress: any = null;
|
||||
|
||||
@@ -2950,6 +2950,57 @@ describe('store appearance persistence', () => {
|
||||
expect(reloaded.useStore.getState().startupFullscreen).toBe(true);
|
||||
});
|
||||
|
||||
it('defaults auto-check for updates to true and persists explicit disable', async () => {
|
||||
const { useStore } = await importStore();
|
||||
|
||||
expect(useStore.getState().autoCheckForUpdates).toBe(true);
|
||||
|
||||
useStore.getState().setAutoCheckForUpdates(false);
|
||||
|
||||
const persisted = JSON.parse(storage.getItem('lite-db-storage') || '{}');
|
||||
expect(persisted.state.autoCheckForUpdates).toBe(false);
|
||||
|
||||
vi.resetModules();
|
||||
const reloaded = await importStore();
|
||||
expect(reloaded.useStore.getState().autoCheckForUpdates).toBe(false);
|
||||
|
||||
storage.setItem('lite-db-storage', JSON.stringify({
|
||||
state: {},
|
||||
version: 17,
|
||||
}));
|
||||
vi.resetModules();
|
||||
const hydrated = await importStore();
|
||||
expect(hydrated.useStore.getState().autoCheckForUpdates).toBe(true);
|
||||
});
|
||||
|
||||
it('defaults auto-check interval to 30 minutes and sanitizes invalid values', async () => {
|
||||
const { useStore } = await importStore();
|
||||
|
||||
expect(useStore.getState().autoCheckForUpdatesIntervalMinutes).toBe(30);
|
||||
|
||||
useStore.getState().setAutoCheckForUpdatesIntervalMinutes(60);
|
||||
|
||||
const persisted = JSON.parse(storage.getItem('lite-db-storage') || '{}');
|
||||
expect(persisted.state.autoCheckForUpdatesIntervalMinutes).toBe(60);
|
||||
|
||||
vi.resetModules();
|
||||
const reloaded = await importStore();
|
||||
expect(reloaded.useStore.getState().autoCheckForUpdatesIntervalMinutes).toBe(60);
|
||||
|
||||
reloaded.useStore.getState().setAutoCheckForUpdatesIntervalMinutes(7);
|
||||
expect(reloaded.useStore.getState().autoCheckForUpdatesIntervalMinutes).toBe(30);
|
||||
|
||||
storage.setItem('lite-db-storage', JSON.stringify({
|
||||
state: {
|
||||
autoCheckForUpdatesIntervalMinutes: 99,
|
||||
},
|
||||
version: 17,
|
||||
}));
|
||||
vi.resetModules();
|
||||
const hydrated = await importStore();
|
||||
expect(hydrated.useStore.getState().autoCheckForUpdatesIntervalMinutes).toBe(30);
|
||||
});
|
||||
|
||||
it('persists window state and bounds immediately so Windows reopen keeps maximise or size memory', async () => {
|
||||
const { useStore } = await importStore();
|
||||
|
||||
|
||||
@@ -192,6 +192,15 @@ const DEFAULT_FONT_SIZE = 14;
|
||||
const MIN_FONT_SIZE = 12;
|
||||
const MAX_FONT_SIZE = 20;
|
||||
const DEFAULT_STARTUP_FULLSCREEN = false;
|
||||
const DEFAULT_AUTO_CHECK_FOR_UPDATES = true;
|
||||
/** 自动检查更新间隔(分钟);与关于页 Select 选项保持一致 */
|
||||
export const AUTO_CHECK_FOR_UPDATES_INTERVAL_OPTIONS = [
|
||||
15, 30, 60, 120, 360, 720, 1440,
|
||||
] as const;
|
||||
const DEFAULT_AUTO_CHECK_FOR_UPDATES_INTERVAL_MINUTES = 30;
|
||||
const AUTO_CHECK_FOR_UPDATES_INTERVAL_OPTIONS_SET = new Set<number>(
|
||||
AUTO_CHECK_FOR_UPDATES_INTERVAL_OPTIONS,
|
||||
);
|
||||
const LEGACY_DEFAULT_OPACITY = 0.95;
|
||||
const OPACITY_EPSILON = 1e-6;
|
||||
const MAX_SIDEBAR_PERSISTED_FILTER_LENGTH = 120;
|
||||
@@ -1742,6 +1751,10 @@ interface AppState {
|
||||
uiScale: number;
|
||||
fontSize: number;
|
||||
startupFullscreen: boolean;
|
||||
/** 启动后与定时静默检查更新;默认开启 */
|
||||
autoCheckForUpdates: boolean;
|
||||
/** 自动检查更新间隔(分钟),默认 30 */
|
||||
autoCheckForUpdatesIntervalMinutes: number;
|
||||
globalProxy: GlobalProxyConfig;
|
||||
sqlFormatOptions: { keywordCase: "upper" | "lower" };
|
||||
queryOptions: QueryOptions;
|
||||
@@ -1909,6 +1922,8 @@ interface AppState {
|
||||
setUiScale: (scale: number) => void;
|
||||
setFontSize: (size: number) => void;
|
||||
setStartupFullscreen: (enabled: boolean) => void;
|
||||
setAutoCheckForUpdates: (enabled: boolean) => void;
|
||||
setAutoCheckForUpdatesIntervalMinutes: (minutes: number) => void;
|
||||
setGlobalProxy: (proxy: Partial<GlobalProxyConfig>) => void;
|
||||
replaceGlobalProxy: (proxy: Partial<GlobalProxyConfig>) => void;
|
||||
setSqlFormatOptions: (options: { keywordCase: "upper" | "lower" }) => void;
|
||||
@@ -2935,6 +2950,23 @@ const sanitizeStartupFullscreen = (value: unknown): boolean => {
|
||||
return value === true;
|
||||
};
|
||||
|
||||
const sanitizeAutoCheckForUpdates = (value: unknown): boolean => {
|
||||
return typeof value === "boolean" ? value : DEFAULT_AUTO_CHECK_FOR_UPDATES;
|
||||
};
|
||||
|
||||
const sanitizeAutoCheckForUpdatesIntervalMinutes = (
|
||||
value: unknown,
|
||||
): number => {
|
||||
const minutes = Math.round(Number(value));
|
||||
if (
|
||||
Number.isFinite(minutes) &&
|
||||
AUTO_CHECK_FOR_UPDATES_INTERVAL_OPTIONS_SET.has(minutes)
|
||||
) {
|
||||
return minutes;
|
||||
}
|
||||
return DEFAULT_AUTO_CHECK_FOR_UPDATES_INTERVAL_MINUTES;
|
||||
};
|
||||
|
||||
const sanitizeUiScale = (value: unknown): number => {
|
||||
return normalizeFloatInRange(
|
||||
value,
|
||||
@@ -3273,6 +3305,8 @@ const PERSISTED_STATE_DEPENDENCY_KEYS = [
|
||||
"uiScale",
|
||||
"fontSize",
|
||||
"startupFullscreen",
|
||||
"autoCheckForUpdates",
|
||||
"autoCheckForUpdatesIntervalMinutes",
|
||||
"aiChatOpenMode",
|
||||
"aiChatDetachedBoundsMemory",
|
||||
"globalProxy",
|
||||
@@ -3325,6 +3359,9 @@ const buildPersistedStateProjection = (
|
||||
uiScale: state.uiScale,
|
||||
fontSize: state.fontSize,
|
||||
startupFullscreen: state.startupFullscreen,
|
||||
autoCheckForUpdates: state.autoCheckForUpdates,
|
||||
autoCheckForUpdatesIntervalMinutes:
|
||||
state.autoCheckForUpdatesIntervalMinutes,
|
||||
aiChatOpenMode: sanitizeAIChatOpenMode(state.aiChatOpenMode),
|
||||
aiChatDetachedBoundsMemory: sanitizeAIChatDetachedBoundsMemory(
|
||||
state.aiChatDetachedBoundsMemory,
|
||||
@@ -3423,6 +3460,9 @@ export const useStore = create<AppState>()(
|
||||
uiScale: DEFAULT_UI_SCALE,
|
||||
fontSize: DEFAULT_FONT_SIZE,
|
||||
startupFullscreen: DEFAULT_STARTUP_FULLSCREEN,
|
||||
autoCheckForUpdates: DEFAULT_AUTO_CHECK_FOR_UPDATES,
|
||||
autoCheckForUpdatesIntervalMinutes:
|
||||
DEFAULT_AUTO_CHECK_FOR_UPDATES_INTERVAL_MINUTES,
|
||||
globalProxy: { ...DEFAULT_GLOBAL_PROXY },
|
||||
sqlFormatOptions: { keywordCase: "upper" },
|
||||
queryOptions: {
|
||||
@@ -4917,6 +4957,15 @@ export const useStore = create<AppState>()(
|
||||
set({ startupFullscreen: nextValue });
|
||||
writePersistedStatePatch({ startupFullscreen: nextValue });
|
||||
},
|
||||
setAutoCheckForUpdates: (enabled) => {
|
||||
set({ autoCheckForUpdates: sanitizeAutoCheckForUpdates(enabled) });
|
||||
},
|
||||
setAutoCheckForUpdatesIntervalMinutes: (minutes) => {
|
||||
set({
|
||||
autoCheckForUpdatesIntervalMinutes:
|
||||
sanitizeAutoCheckForUpdatesIntervalMinutes(minutes),
|
||||
});
|
||||
},
|
||||
setGlobalProxy: (proxy) =>
|
||||
set((state) => ({
|
||||
globalProxy: sanitizeGlobalProxy({ ...state.globalProxy, ...proxy }),
|
||||
@@ -5657,6 +5706,13 @@ export const useStore = create<AppState>()(
|
||||
nextState.startupFullscreen = sanitizeStartupFullscreen(
|
||||
state.startupFullscreen,
|
||||
);
|
||||
nextState.autoCheckForUpdates = sanitizeAutoCheckForUpdates(
|
||||
state.autoCheckForUpdates,
|
||||
);
|
||||
nextState.autoCheckForUpdatesIntervalMinutes =
|
||||
sanitizeAutoCheckForUpdatesIntervalMinutes(
|
||||
state.autoCheckForUpdatesIntervalMinutes,
|
||||
);
|
||||
nextState.globalProxy = sanitizeGlobalProxy(state.globalProxy);
|
||||
nextState.sqlFormatOptions = sanitizeSqlFormatOptions(
|
||||
state.sqlFormatOptions,
|
||||
@@ -5779,6 +5835,13 @@ export const useStore = create<AppState>()(
|
||||
uiScale: sanitizeUiScale(state.uiScale),
|
||||
fontSize: sanitizeFontSize(state.fontSize),
|
||||
startupFullscreen: sanitizeStartupFullscreen(state.startupFullscreen),
|
||||
autoCheckForUpdates: sanitizeAutoCheckForUpdates(
|
||||
state.autoCheckForUpdates,
|
||||
),
|
||||
autoCheckForUpdatesIntervalMinutes:
|
||||
sanitizeAutoCheckForUpdatesIntervalMinutes(
|
||||
state.autoCheckForUpdatesIntervalMinutes,
|
||||
),
|
||||
globalProxy: sanitizeGlobalProxy(state.globalProxy),
|
||||
tableSortPreference: sanitizeTableSortPreference(
|
||||
state.tableSortPreference,
|
||||
|
||||
@@ -2448,6 +2448,10 @@
|
||||
"app.about.download_progress.title_with_version": "Update {{version}} herunterladen",
|
||||
"app.about.field.author": "Autor",
|
||||
"app.about.field.community": "Community",
|
||||
"app.about.auto_check_interval.hours": "{{hours}} Stunden",
|
||||
"app.about.auto_check_interval.minutes": "{{minutes}} Minuten",
|
||||
"app.about.field.auto_check_interval": "Prüfintervall",
|
||||
"app.about.field.auto_check_updates": "Automatisch nach Updates suchen",
|
||||
"app.about.field.update_channel": "Update-Kanal",
|
||||
"app.about.field.update_status": "Updatestatus",
|
||||
"app.about.field.version": "Version",
|
||||
@@ -2489,6 +2493,8 @@
|
||||
"app.about.version.release_notes": "Updateinhalt",
|
||||
"app.about.version.release_time": "Veröffentlichungszeit",
|
||||
"app.about.version_update.available": "Update verfügbar",
|
||||
"app.about.version_update.auto_check_disabled_hint": "Wenn deaktiviert, werden Updates nur über die manuelle Aktion „Nach Updates suchen“ geprüft",
|
||||
"app.about.version_update.auto_check_hint": "Beim Start und im gewählten Intervall im Hintergrund nach Updates suchen",
|
||||
"app.about.version_update.channel_hint": "Neueste Entwicklungsversion erhalten",
|
||||
"app.about.version_update.title": "Version und Updates",
|
||||
"app.about.version_update.up_to_date": "Auf dem neuesten Stand",
|
||||
|
||||
@@ -2448,6 +2448,10 @@
|
||||
"app.about.download_progress.title_with_version": "Download Update {{version}}",
|
||||
"app.about.field.author": "Author",
|
||||
"app.about.field.community": "Community",
|
||||
"app.about.auto_check_interval.hours": "{{hours}} hours",
|
||||
"app.about.auto_check_interval.minutes": "{{minutes}} minutes",
|
||||
"app.about.field.auto_check_interval": "Check interval",
|
||||
"app.about.field.auto_check_updates": "Automatically check for updates",
|
||||
"app.about.field.update_channel": "Update Channel",
|
||||
"app.about.field.update_status": "Update Status",
|
||||
"app.about.field.version": "Version",
|
||||
@@ -2489,6 +2493,8 @@
|
||||
"app.about.version.release_notes": "Update Notes",
|
||||
"app.about.version.release_time": "Release Time",
|
||||
"app.about.version_update.available": "Update available",
|
||||
"app.about.version_update.auto_check_disabled_hint": "When off, updates are only checked via the manual Check for Updates action",
|
||||
"app.about.version_update.auto_check_hint": "Check for updates in the background on startup and at the selected interval",
|
||||
"app.about.version_update.channel_hint": "Receive the latest development build",
|
||||
"app.about.version_update.title": "Version and Updates",
|
||||
"app.about.version_update.up_to_date": "Up to date",
|
||||
|
||||
@@ -2448,6 +2448,10 @@
|
||||
"app.about.download_progress.title_with_version": "更新をダウンロード {{version}}",
|
||||
"app.about.field.author": "作者",
|
||||
"app.about.field.community": "コミュニティ",
|
||||
"app.about.auto_check_interval.hours": "{{hours}} 時間",
|
||||
"app.about.auto_check_interval.minutes": "{{minutes}} 分",
|
||||
"app.about.field.auto_check_interval": "チェック間隔",
|
||||
"app.about.field.auto_check_updates": "更新を自動チェック",
|
||||
"app.about.field.update_channel": "更新チャネル",
|
||||
"app.about.field.update_status": "更新状況",
|
||||
"app.about.field.version": "バージョン",
|
||||
@@ -2489,6 +2493,8 @@
|
||||
"app.about.version.release_notes": "更新内容",
|
||||
"app.about.version.release_time": "公開日時",
|
||||
"app.about.version_update.available": "利用可能な更新があります",
|
||||
"app.about.version_update.auto_check_disabled_hint": "オフの場合、手動の「更新を確認」でのみ新バージョンを取得します",
|
||||
"app.about.version_update.auto_check_hint": "起動後にバックグラウンドで確認し、設定した間隔で繰り返し確認します",
|
||||
"app.about.version_update.channel_hint": "最新の開発版を受け取る",
|
||||
"app.about.version_update.title": "バージョンと更新",
|
||||
"app.about.version_update.up_to_date": "最新です",
|
||||
|
||||
@@ -2448,6 +2448,10 @@
|
||||
"app.about.download_progress.title_with_version": "Скачать обновление {{version}}",
|
||||
"app.about.field.author": "Автор",
|
||||
"app.about.field.community": "Сообщество",
|
||||
"app.about.auto_check_interval.hours": "{{hours}} ч.",
|
||||
"app.about.auto_check_interval.minutes": "{{minutes}} мин.",
|
||||
"app.about.field.auto_check_interval": "Интервал проверки",
|
||||
"app.about.field.auto_check_updates": "Автоматически проверять обновления",
|
||||
"app.about.field.update_channel": "Канал обновления",
|
||||
"app.about.field.update_status": "Статус обновления",
|
||||
"app.about.field.version": "Версия",
|
||||
@@ -2489,6 +2493,8 @@
|
||||
"app.about.version.release_notes": "Содержание обновления",
|
||||
"app.about.version.release_time": "Время выпуска",
|
||||
"app.about.version_update.available": "Доступно обновление",
|
||||
"app.about.version_update.auto_check_disabled_hint": "При отключении обновления проверяются только вручную через «Проверить обновления»",
|
||||
"app.about.version_update.auto_check_hint": "Проверять обновления в фоне при запуске и с выбранным интервалом",
|
||||
"app.about.version_update.channel_hint": "Получать последнюю dev-версию",
|
||||
"app.about.version_update.title": "Версия и обновления",
|
||||
"app.about.version_update.up_to_date": "Актуально",
|
||||
|
||||
@@ -2448,6 +2448,10 @@
|
||||
"app.about.download_progress.title_with_version": "下载更新 {{version}}",
|
||||
"app.about.field.author": "作者",
|
||||
"app.about.field.community": "技术圈",
|
||||
"app.about.auto_check_interval.hours": "{{hours}} 小时",
|
||||
"app.about.auto_check_interval.minutes": "{{minutes}} 分钟",
|
||||
"app.about.field.auto_check_interval": "检查间隔",
|
||||
"app.about.field.auto_check_updates": "自动检查更新",
|
||||
"app.about.field.update_channel": "更新通道",
|
||||
"app.about.field.update_status": "更新状态",
|
||||
"app.about.field.version": "版本",
|
||||
@@ -2489,6 +2493,8 @@
|
||||
"app.about.version.release_notes": "更新内容",
|
||||
"app.about.version.release_time": "发布时间",
|
||||
"app.about.version_update.available": "有可用更新",
|
||||
"app.about.version_update.auto_check_disabled_hint": "关闭后仅可通过手动「检查更新」获取新版本",
|
||||
"app.about.version_update.auto_check_hint": "启动后在后台检查,并按设定间隔重复检查",
|
||||
"app.about.version_update.channel_hint": "接收最新的开发版本",
|
||||
"app.about.version_update.title": "版本与更新",
|
||||
"app.about.version_update.up_to_date": "当前已是最新",
|
||||
|
||||
@@ -2448,6 +2448,10 @@
|
||||
"app.about.download_progress.title_with_version": "下載更新 {{version}}",
|
||||
"app.about.field.author": "作者",
|
||||
"app.about.field.community": "技術圈",
|
||||
"app.about.auto_check_interval.hours": "{{hours}} 小時",
|
||||
"app.about.auto_check_interval.minutes": "{{minutes}} 分鐘",
|
||||
"app.about.field.auto_check_interval": "檢查間隔",
|
||||
"app.about.field.auto_check_updates": "自動檢查更新",
|
||||
"app.about.field.update_channel": "更新通道",
|
||||
"app.about.field.update_status": "更新状态",
|
||||
"app.about.field.version": "版本",
|
||||
@@ -2489,6 +2493,8 @@
|
||||
"app.about.version.release_notes": "更新內容",
|
||||
"app.about.version.release_time": "發布時間",
|
||||
"app.about.version_update.available": "有可用更新",
|
||||
"app.about.version_update.auto_check_disabled_hint": "關閉後僅可透過手動「檢查更新」取得新版本",
|
||||
"app.about.version_update.auto_check_hint": "啟動後在背景檢查,並依設定間隔重複檢查",
|
||||
"app.about.version_update.channel_hint": "接收最新的開發版本",
|
||||
"app.about.version_update.title": "版本與更新",
|
||||
"app.about.version_update.up_to_date": "目前已是最新",
|
||||
|
||||
Reference in New Issue
Block a user