refactor: remove sync interval preference
This commit is contained in:
1 parent
3a49b16d9c
commit
d4821eb486
12 files changed
+16
-196
No files matched your search
@@ -45,8 +45,6 @@ interface SettingsPaneProps {
|
||||
onOpenAiPrompts: () => void;
|
||||
imageCompressionEnabled: boolean;
|
||||
onImageCompressionChange: (enabled: boolean) => void;
|
||||
syncIntervalMs: number | null;
|
||||
onSyncIntervalChange: (intervalMs: number | null) => void;
|
||||
shortcutSettings: ShortcutSettings;
|
||||
onShortcutSettingsChange: (settings: ShortcutSettings) => void;
|
||||
editorContentAlignment: EditorContentAlignment;
|
||||
@@ -86,8 +84,6 @@ export const SettingsPane = ({
|
||||
onOpenAiPrompts,
|
||||
imageCompressionEnabled,
|
||||
onImageCompressionChange,
|
||||
syncIntervalMs,
|
||||
onSyncIntervalChange,
|
||||
shortcutSettings,
|
||||
onShortcutSettingsChange,
|
||||
editorContentAlignment,
|
||||
@@ -208,8 +204,6 @@ export const SettingsPane = ({
|
||||
<PreferenceCard
|
||||
imageCompressionEnabled={imageCompressionEnabled}
|
||||
onImageCompressionChange={onImageCompressionChange}
|
||||
syncIntervalMs={syncIntervalMs}
|
||||
onSyncIntervalChange={onSyncIntervalChange}
|
||||
shortcutSettings={shortcutSettings}
|
||||
onShortcutSettingsChange={onShortcutSettingsChange}
|
||||
editorContentAlignment={editorContentAlignment}
|
||||
|
||||
@@ -795,9 +795,7 @@ export const WorkspaceApp = ({
|
||||
setImageCompressionEnabled,
|
||||
setMemoListWidth,
|
||||
setShortcutSettings,
|
||||
setSyncIntervalMs,
|
||||
shortcutSettings,
|
||||
syncIntervalMs,
|
||||
} = useWorkspacePreferences();
|
||||
const [rightView, setRightView] = useState<"editor" | "settings" | "plugins" | "assets" | "tags" | "templates" | "ai-prompts" | "evernote-migration">(() =>
|
||||
isInitialSettingsRoute
|
||||
@@ -1311,12 +1309,11 @@ export const WorkspaceApp = ({
|
||||
}, [mobilePullToRefreshActive, refreshLatestMemos]);
|
||||
|
||||
useWorkspaceSyncLifecycle({
|
||||
pendingSyncCount: syncSummary.total,
|
||||
failedSyncCount: syncSummary.error,
|
||||
backgroundRefreshKey: localDataScope,
|
||||
refreshWorkspace: refreshWorkspaceFromServer,
|
||||
runQueuedSync,
|
||||
setOnline: setIsOnline,
|
||||
syncIntervalMs,
|
||||
});
|
||||
|
||||
const selectedNotebookDescendantIds = useMemo(
|
||||
@@ -3100,8 +3097,6 @@ export const WorkspaceApp = ({
|
||||
onOpenAiPrompts={handleOpenAiPrompts}
|
||||
imageCompressionEnabled={imageCompressionEnabled}
|
||||
onImageCompressionChange={setImageCompressionEnabled}
|
||||
syncIntervalMs={syncIntervalMs}
|
||||
onSyncIntervalChange={setSyncIntervalMs}
|
||||
shortcutSettings={shortcutSettings}
|
||||
onShortcutSettingsChange={setShortcutSettings}
|
||||
editorContentAlignment={editorContentAlignment}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AlignHorizontalJustifyCenter, ChartNoAxesCombined, FileCode2, Image, Keyboard, Languages, MousePointerClick, Palette, RefreshCw, Sparkles } from "lucide-react";
|
||||
import { AlignHorizontalJustifyCenter, ChartNoAxesCombined, FileCode2, Image, Keyboard, Languages, MousePointerClick, Palette, Sparkles } from "lucide-react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { writeSyncIntervalPreference, type EditorContentAlignment, type ShortcutSettings, type SyncIntervalPreference } from "@/lib/app-helpers";
|
||||
import type { EditorContentAlignment, ShortcutSettings } from "@/lib/app-helpers";
|
||||
import {
|
||||
EDITOR_LINK_OPEN_MODE_CHANGED_EVENT,
|
||||
getStoredEditorLinkOpenMode,
|
||||
@@ -45,8 +45,6 @@ import {
|
||||
interface PreferenceCardProps {
|
||||
imageCompressionEnabled: boolean;
|
||||
onImageCompressionChange: (enabled: boolean) => void;
|
||||
syncIntervalMs: number | null;
|
||||
onSyncIntervalChange: (intervalMs: number | null) => void;
|
||||
shortcutSettings: ShortcutSettings;
|
||||
onShortcutSettingsChange: (settings: ShortcutSettings) => void;
|
||||
editorContentAlignment: EditorContentAlignment;
|
||||
@@ -56,8 +54,6 @@ interface PreferenceCardProps {
|
||||
export const PreferenceCard = ({
|
||||
imageCompressionEnabled,
|
||||
onImageCompressionChange,
|
||||
syncIntervalMs,
|
||||
onSyncIntervalChange,
|
||||
shortcutSettings,
|
||||
onShortcutSettingsChange,
|
||||
editorContentAlignment,
|
||||
@@ -185,9 +181,6 @@ export const PreferenceCard = ({
|
||||
void changeAppLocalePreference(preference);
|
||||
};
|
||||
|
||||
const syncIntervalPreference: SyncIntervalPreference =
|
||||
syncIntervalMs === 300_000 ? "5m" : syncIntervalMs === 900_000 ? "15m" : syncIntervalMs === 1_800_000 ? "30m" : syncIntervalMs === 3_600_000 ? "1h" : syncIntervalMs === 7_200_000 ? "2h" : "30s";
|
||||
|
||||
return (
|
||||
<Card className="w-full min-w-0 overflow-hidden shadow-none">
|
||||
<CardHeader className="p-4">
|
||||
@@ -357,40 +350,6 @@ export const PreferenceCard = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-16 flex-col items-start gap-3 px-4 py-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
|
||||
<div className="flex min-w-0 items-start gap-3">
|
||||
<RefreshCw className="mt-0.5 h-4 w-4 shrink-0 text-emerald-700" />
|
||||
<div className="min-w-0">
|
||||
<div className="text-sm font-semibold text-slate-900">{t("settings.syncIntervalTitle")}</div>
|
||||
<div className="mt-0.5 text-xs leading-4 text-slate-500">{t("settings.syncIntervalDescription")}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full shrink-0 sm:w-44">
|
||||
<Select
|
||||
value={syncIntervalPreference}
|
||||
onValueChange={(value) => {
|
||||
const preference = value as SyncIntervalPreference;
|
||||
writeSyncIntervalPreference(preference);
|
||||
onSyncIntervalChange(
|
||||
preference === "5m" ? 300_000 : preference === "15m" ? 900_000 : preference === "30m" ? 1_800_000 : preference === "1h" ? 3_600_000 : preference === "2h" ? 7_200_000 : 30_000
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger aria-label={t("settings.syncIntervalTitle")} className="h-9 bg-white">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="30s">{t("settings.syncIntervals.30s")}</SelectItem>
|
||||
<SelectItem value="5m">{t("settings.syncIntervals.5m")}</SelectItem>
|
||||
<SelectItem value="15m">{t("settings.syncIntervals.15m")}</SelectItem>
|
||||
<SelectItem value="30m">{t("settings.syncIntervals.30m")}</SelectItem>
|
||||
<SelectItem value="1h">{t("settings.syncIntervals.1h")}</SelectItem>
|
||||
<SelectItem value="2h">{t("settings.syncIntervals.2h")}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-16 flex-col items-start gap-3 px-4 py-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
|
||||
<div className="flex min-w-0 items-start gap-3">
|
||||
<Image className="mt-0.5 h-4 w-4 shrink-0 text-emerald-700" />
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { syncIntervalMsToPreference } from "./useWorkspacePreferences.ts";
|
||||
|
||||
describe("workspace sync interval preference", () => {
|
||||
test("serializes every supported interval", () => {
|
||||
expect([null, 30_000, 300_000, 900_000, 1_800_000, 3_600_000, 7_200_000].map(syncIntervalMsToPreference))
|
||||
.toEqual(["off", "30s", "5m", "15m", "30m", "1h", "2h"]);
|
||||
});
|
||||
|
||||
test("falls back to the default interval for an unknown value", () => {
|
||||
expect(syncIntervalMsToPreference(1234)).toBe("30s");
|
||||
});
|
||||
});
|
||||
@@ -7,41 +7,23 @@ import {
|
||||
readImageCompressionPreference,
|
||||
readMemoListWidthPreference,
|
||||
readShortcutSettingsPreference,
|
||||
readSyncIntervalPreference,
|
||||
writeDesktopFocusModePreference,
|
||||
writeEditorContentAlignmentPreference,
|
||||
writeImageCompressionPreference,
|
||||
writeMemoListWidthPreference,
|
||||
writeShortcutSettingsPreference,
|
||||
writeSyncIntervalPreference,
|
||||
type ShortcutSettings,
|
||||
type EditorContentAlignment,
|
||||
} from "@/lib/app-helpers";
|
||||
|
||||
export type SyncIntervalPreference = "off" | "30s" | "5m" | "15m" | "30m" | "1h" | "2h";
|
||||
|
||||
export const syncIntervalMsToPreference = (intervalMs: number | null): SyncIntervalPreference => {
|
||||
switch (intervalMs) {
|
||||
case null: return "off";
|
||||
case 300_000: return "5m";
|
||||
case 900_000: return "15m";
|
||||
case 1_800_000: return "30m";
|
||||
case 3_600_000: return "1h";
|
||||
case 7_200_000: return "2h";
|
||||
default: return "30s";
|
||||
}
|
||||
};
|
||||
|
||||
export const useWorkspacePreferences = () => {
|
||||
const [imageCompressionEnabled, setImageCompressionEnabled] = useState(readImageCompressionPreference);
|
||||
const [syncIntervalMs, setSyncIntervalMs] = useState(readSyncIntervalPreference);
|
||||
const [desktopFocusMode, setDesktopFocusModeState] = useState(readDesktopFocusModePreference);
|
||||
const [editorContentAlignment, setEditorContentAlignmentState] = useState(readEditorContentAlignmentPreference);
|
||||
const [shortcutSettings, setShortcutSettings] = useState<ShortcutSettings>(readShortcutSettingsPreference);
|
||||
const [memoListWidth, setMemoListWidthState] = useState(readMemoListWidthPreference);
|
||||
|
||||
useEffect(() => writeImageCompressionPreference(imageCompressionEnabled), [imageCompressionEnabled]);
|
||||
useEffect(() => writeSyncIntervalPreference(syncIntervalMsToPreference(syncIntervalMs)), [syncIntervalMs]);
|
||||
useEffect(() => writeShortcutSettingsPreference(shortcutSettings), [shortcutSettings]);
|
||||
|
||||
const setDesktopFocusMode = useCallback((enabled: boolean) => {
|
||||
@@ -75,8 +57,6 @@ export const useWorkspacePreferences = () => {
|
||||
setImageCompressionEnabled,
|
||||
setMemoListWidth,
|
||||
setShortcutSettings,
|
||||
setSyncIntervalMs,
|
||||
shortcutSettings,
|
||||
syncIntervalMs,
|
||||
};
|
||||
};
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
BACKGROUND_WORKSPACE_REFRESH_INTERVAL_MS,
|
||||
claimBackgroundRefreshLease,
|
||||
createRefreshSingleFlight,
|
||||
DEFERRED_MEMO_SYNC_DELAY_MS,
|
||||
releaseBackgroundRefreshLease,
|
||||
type WorkspaceRefreshMode,
|
||||
} from "@/lib/workspace-refresh";
|
||||
@@ -13,22 +14,19 @@ import {
|
||||
type RefreshWorkspace = (mode: WorkspaceRefreshMode) => Promise<unknown>;
|
||||
|
||||
export const useWorkspaceSyncLifecycle = ({
|
||||
pendingSyncCount,
|
||||
failedSyncCount,
|
||||
backgroundRefreshKey,
|
||||
refreshWorkspace,
|
||||
runQueuedSync,
|
||||
setOnline,
|
||||
syncIntervalMs,
|
||||
}: {
|
||||
pendingSyncCount: number;
|
||||
failedSyncCount: number;
|
||||
backgroundRefreshKey: string;
|
||||
refreshWorkspace: RefreshWorkspace;
|
||||
runQueuedSync: () => Promise<void>;
|
||||
setOnline: (online: boolean) => void;
|
||||
syncIntervalMs: number | null;
|
||||
}) => {
|
||||
const deferredSyncTimerRef = useRef<number | null>(null);
|
||||
const deferredSyncPendingRef = useRef(false);
|
||||
const runQueuedSyncRef = useRef(runQueuedSync);
|
||||
const refreshWorkspaceRef = useRef(refreshWorkspace);
|
||||
const backgroundRefreshOwnerRef = useRef(createClientUuid());
|
||||
@@ -108,7 +106,6 @@ export const useWorkspaceSyncLifecycle = ({
|
||||
|
||||
useEffect(() => {
|
||||
const handleQueueChanged = () => {
|
||||
deferredSyncPendingRef.current = false;
|
||||
if (deferredSyncTimerRef.current !== null) {
|
||||
window.clearTimeout(deferredSyncTimerRef.current);
|
||||
deferredSyncTimerRef.current = null;
|
||||
@@ -121,21 +118,17 @@ export const useWorkspaceSyncLifecycle = ({
|
||||
|
||||
useEffect(() => {
|
||||
const scheduleDeferredSync = () => {
|
||||
deferredSyncPendingRef.current = true;
|
||||
if (deferredSyncTimerRef.current !== null) {
|
||||
window.clearTimeout(deferredSyncTimerRef.current);
|
||||
deferredSyncTimerRef.current = null;
|
||||
}
|
||||
if (syncIntervalMs === null) return;
|
||||
deferredSyncTimerRef.current = window.setTimeout(() => {
|
||||
deferredSyncTimerRef.current = null;
|
||||
deferredSyncPendingRef.current = false;
|
||||
void runQueuedSyncRef.current();
|
||||
}, syncIntervalMs);
|
||||
}, DEFERRED_MEMO_SYNC_DELAY_MS);
|
||||
};
|
||||
|
||||
window.addEventListener(SYNC_QUEUE_DEFERRED_EVENT, scheduleDeferredSync);
|
||||
if (deferredSyncPendingRef.current) scheduleDeferredSync();
|
||||
return () => {
|
||||
window.removeEventListener(SYNC_QUEUE_DEFERRED_EVENT, scheduleDeferredSync);
|
||||
if (deferredSyncTimerRef.current !== null) {
|
||||
@@ -143,7 +136,7 @@ export const useWorkspaceSyncLifecycle = ({
|
||||
deferredSyncTimerRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [syncIntervalMs]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const leaseKey = `edgeever.background-refresh:${backgroundRefreshKey}`;
|
||||
@@ -201,8 +194,8 @@ export const useWorkspaceSyncLifecycle = ({
|
||||
}, [backgroundRefreshKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (pendingSyncCount === 0) return;
|
||||
if (failedSyncCount === 0) return;
|
||||
const timer = window.setInterval(() => void runQueuedSync(), 15_000);
|
||||
return () => window.clearInterval(timer);
|
||||
}, [pendingSyncCount, runQueuedSync]);
|
||||
}, [failedSyncCount, runQueuedSync]);
|
||||
};
|
||||
@@ -1,25 +1,21 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
import {
|
||||
DEFAULT_SHORTCUT_SETTINGS,
|
||||
DEFAULT_SYNC_INTERVAL_MS,
|
||||
DESKTOP_FOCUS_MODE_STORAGE_KEY,
|
||||
DESKTOP_READING_PROTECTION_STORAGE_KEY,
|
||||
EDITOR_CONTENT_ALIGNMENT_STORAGE_KEY,
|
||||
NOTEBOOK_SORT_STORAGE_KEY,
|
||||
SHORTCUT_SETTINGS_STORAGE_KEY,
|
||||
SYNC_INTERVAL_STORAGE_KEY,
|
||||
getSearchShortcutScope,
|
||||
getShortcutActionForEvent,
|
||||
getNotebookSortComparator,
|
||||
readEditorContentAlignmentPreference,
|
||||
readNotebookSortPreference,
|
||||
readSyncIntervalPreference,
|
||||
readDesktopFocusModePreference,
|
||||
readDesktopReadingProtectionPreference,
|
||||
readShortcutSettingsPreference,
|
||||
writeEditorContentAlignmentPreference,
|
||||
writeNotebookSortPreference,
|
||||
writeSyncIntervalPreference,
|
||||
writeDesktopFocusModePreference,
|
||||
writeDesktopReadingProtectionPreference,
|
||||
} from "./app-helpers.ts";
|
||||
@@ -194,53 +190,6 @@ describe("custom notebook sorting", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("automatic sync interval preference", () => {
|
||||
test("defaults to 30 seconds", () => {
|
||||
installLocalStorage();
|
||||
expect(readSyncIntervalPreference()).toBe(DEFAULT_SYNC_INTERVAL_MS);
|
||||
expect(DEFAULT_SYNC_INTERVAL_MS).toBe(30_000);
|
||||
});
|
||||
|
||||
test("reads and writes sync intervals", () => {
|
||||
const values = installLocalStorage();
|
||||
|
||||
writeSyncIntervalPreference("30s");
|
||||
expect(values.get(SYNC_INTERVAL_STORAGE_KEY)).toBe("30s");
|
||||
expect(readSyncIntervalPreference()).toBe(30_000);
|
||||
|
||||
writeSyncIntervalPreference("5m");
|
||||
expect(values.get(SYNC_INTERVAL_STORAGE_KEY)).toBe("5m");
|
||||
expect(readSyncIntervalPreference()).toBe(300_000);
|
||||
});
|
||||
|
||||
test("preserves the legacy preference stored under the old key", () => {
|
||||
const values = installLocalStorage();
|
||||
values.set("edgeever.autoSaveInterval", "15m");
|
||||
expect(readSyncIntervalPreference()).toBe(900_000);
|
||||
});
|
||||
|
||||
test("migrates the former one-minute default to 30 seconds", () => {
|
||||
const values = installLocalStorage();
|
||||
values.set(SYNC_INTERVAL_STORAGE_KEY, "1m");
|
||||
expect(readSyncIntervalPreference()).toBe(30_000);
|
||||
});
|
||||
|
||||
test("falls back to the default for unknown or unavailable storage", () => {
|
||||
const values = installLocalStorage();
|
||||
values.set(SYNC_INTERVAL_STORAGE_KEY, "unexpected");
|
||||
expect(readSyncIntervalPreference()).toBe(30_000);
|
||||
|
||||
globalThis.window = {
|
||||
localStorage: {
|
||||
getItem: () => {
|
||||
throw new Error("blocked");
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(readSyncIntervalPreference()).toBe(30_000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("workspace shortcut preferences", () => {
|
||||
test("provides navigation, AI, save, reading protection, and editor mode defaults", () => {
|
||||
expect(DEFAULT_SHORTCUT_SETTINGS.focusGlobalSearch).toEqual({
|
||||
|
||||
@@ -129,8 +129,6 @@ export { buildNotebookTree, type NotebookNode };
|
||||
export { DEFAULT_MEMO_TITLE };
|
||||
|
||||
export const IMAGE_COMPRESSION_STORAGE_KEY = "edgeever.imageCompressionEnabled";
|
||||
export const SYNC_INTERVAL_STORAGE_KEY = "edgeever.syncInterval";
|
||||
const LEGACY_AUTO_SAVE_INTERVAL_STORAGE_KEY = "edgeever.autoSaveInterval";
|
||||
export const DESKTOP_FOCUS_MODE_STORAGE_KEY = "edgeever.desktopFocusMode";
|
||||
export const DESKTOP_READING_PROTECTION_STORAGE_KEY = "edgeever.desktopReadingProtection";
|
||||
export const EDITOR_CONTENT_ALIGNMENT_STORAGE_KEY = "edgeever.editorContentAlignment";
|
||||
@@ -143,18 +141,6 @@ export const MIN_MEMO_LIST_WIDTH_PX = 300;
|
||||
export const MAX_MEMO_LIST_WIDTH_PX = 540;
|
||||
export const EDITOR_LOCAL_SAVE_DELAY_MS = 1_200;
|
||||
|
||||
export type SyncIntervalPreference = "30s" | "5m" | "15m" | "30m" | "1h" | "2h" | "off";
|
||||
export const DEFAULT_SYNC_INTERVAL_MS = 30_000;
|
||||
const SYNC_INTERVAL_VALUES: Record<SyncIntervalPreference, number | null> = {
|
||||
"30s": 30_000,
|
||||
"5m": 300_000,
|
||||
"15m": 900_000,
|
||||
"30m": 1_800_000,
|
||||
"1h": 3_600_000,
|
||||
"2h": 7_200_000,
|
||||
off: null,
|
||||
};
|
||||
|
||||
export const MEMO_DRAG_MIME = "application/x-edgeever-memos";
|
||||
export const NOTEBOOK_DRAG_MIME = "application/x-edgeever-notebook";
|
||||
|
||||
@@ -337,29 +323,6 @@ export const writeImageCompressionPreference = (enabled: boolean) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const readSyncIntervalPreference = (): number | null => {
|
||||
try {
|
||||
const stored = (
|
||||
window.localStorage.getItem(SYNC_INTERVAL_STORAGE_KEY)
|
||||
?? window.localStorage.getItem(LEGACY_AUTO_SAVE_INTERVAL_STORAGE_KEY)
|
||||
);
|
||||
const preference = stored === "1m" ? "30s" : stored;
|
||||
return preference && preference in SYNC_INTERVAL_VALUES
|
||||
? SYNC_INTERVAL_VALUES[preference as SyncIntervalPreference]
|
||||
: DEFAULT_SYNC_INTERVAL_MS;
|
||||
} catch {
|
||||
return DEFAULT_SYNC_INTERVAL_MS;
|
||||
}
|
||||
};
|
||||
|
||||
export const writeSyncIntervalPreference = (preference: SyncIntervalPreference) => {
|
||||
try {
|
||||
window.localStorage.setItem(SYNC_INTERVAL_STORAGE_KEY, preference);
|
||||
} catch {
|
||||
// Local storage can be unavailable in private or restricted browser contexts.
|
||||
}
|
||||
};
|
||||
|
||||
export const readDesktopFocusModePreference = () => {
|
||||
try {
|
||||
return window.localStorage.getItem(DESKTOP_FOCUS_MODE_STORAGE_KEY) === "true";
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
BACKGROUND_WORKSPACE_REFRESH_INTERVAL_MS,
|
||||
claimBackgroundRefreshLease,
|
||||
createRefreshSingleFlight,
|
||||
DEFERRED_MEMO_SYNC_DELAY_MS,
|
||||
releaseBackgroundRefreshLease,
|
||||
refreshWorkspaceData,
|
||||
resolveCreatedMemoSelection,
|
||||
@@ -12,6 +13,10 @@ import {
|
||||
} from "./workspace-refresh.ts";
|
||||
|
||||
describe("refreshWorkspaceData", () => {
|
||||
it("uses a fixed 30-second delay for uploading memo edits", () => {
|
||||
assert.equal(DEFERRED_MEMO_SYNC_DELAY_MS, 30_000);
|
||||
});
|
||||
|
||||
it("uses a shared five-minute background refresh interval", () => {
|
||||
assert.equal(BACKGROUND_WORKSPACE_REFRESH_INTERVAL_MS, 5 * 60_000);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export type WorkspaceRefreshMode = "background" | "manual";
|
||||
export type WorkspaceMemoView = "notebook" | "trash";
|
||||
|
||||
export const DEFERRED_MEMO_SYNC_DELAY_MS = 30_000;
|
||||
export const BACKGROUND_WORKSPACE_REFRESH_INTERVAL_MS = 5 * 60_000;
|
||||
export const BACKGROUND_WORKSPACE_REFRESH_LEASE_MS = BACKGROUND_WORKSPACE_REFRESH_INTERVAL_MS * 2;
|
||||
export const BACKGROUND_WORKSPACE_REFRESH_COALESCE_MS = 1_000;
|
||||
|
||||
@@ -244,9 +244,6 @@ export const enUS = {
|
||||
linkOpenModifierTitle: "Open web links with Ctrl/⌘ + click while editing",
|
||||
linkOpenModifierDescription: "On by default: hold Ctrl/⌘ and click to open web links, preventing accidental opens while editing. Note references always open with one click. Desktop only.",
|
||||
linkOpenModifierAria: "Require Ctrl or ⌘ click to open web links while editing",
|
||||
syncIntervalTitle: "Automatic sync interval",
|
||||
syncIntervalDescription: "Sync edits to the server automatically while keeping local drafts available immediately.",
|
||||
syncIntervals: { "30s": "Every 30 seconds", "5m": "Every 5 minutes", "15m": "Every 15 minutes", "30m": "Every 30 minutes", "1h": "Every hour", "2h": "Every 2 hours" },
|
||||
mermaidThemeTitle: "Diagram theme",
|
||||
mermaidThemeDescription: "Follow the app appearance or choose a fixed visual theme for diagrams.",
|
||||
markdownThemeTitle: "Markdown source theme",
|
||||
|
||||
@@ -244,9 +244,6 @@ export const zhCN = {
|
||||
linkOpenModifierTitle: "编辑时用 Ctrl/⌘ + 点击打开网页链接",
|
||||
linkOpenModifierDescription: "默认开启:网页链接需按住 Ctrl/⌘ 再点击,避免编辑时误触;笔记引用始终单击打开(仅桌面)。",
|
||||
linkOpenModifierAria: "编辑时是否需要 Ctrl 或 ⌘ 再点击才能打开网页链接",
|
||||
syncIntervalTitle: "自动同步间隔",
|
||||
syncIntervalDescription: "定期将编辑内容同步到服务器,本地草稿仍会即时保留。",
|
||||
syncIntervals: { "30s": "每 30 秒", "5m": "每 5 分钟", "15m": "每 15 分钟", "30m": "每 30 分钟", "1h": "每 1 小时", "2h": "每 2 小时" },
|
||||
mermaidThemeTitle: "图表主题",
|
||||
mermaidThemeDescription: "跟随应用外观,或为笔记图表选择固定主题。",
|
||||
markdownThemeTitle: "Markdown 源码主题",
|
||||
|
||||
Reference in new issue
Block a user