mirror of
https://github.com/zadam/trilium.git
synced 2026-05-07 11:56:10 +02:00
feat(options): add nicer sync timeout selector (closes #5513)
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
import { SyncTestResponse } from "@triliumnext/commons";
|
||||
import { useRef } from "preact/hooks";
|
||||
|
||||
import { t } from "../../../services/i18n";
|
||||
import server from "../../../services/server";
|
||||
import toast from "../../../services/toast";
|
||||
import { openInAppHelpFromUrl } from "../../../services/utils";
|
||||
import Button from "../../react/Button";
|
||||
import FormGroup from "../../react/FormGroup";
|
||||
import FormTextBox, { FormTextBoxWithUnit } from "../../react/FormTextBox";
|
||||
import FormText from "../../react/FormText";
|
||||
import FormTextBox from "../../react/FormTextBox";
|
||||
import { useTriliumOptions } from "../../react/hooks";
|
||||
import RawHtml from "../../react/RawHtml";
|
||||
import OptionsSection from "./components/OptionsSection";
|
||||
import { useTriliumOptions } from "../../react/hooks";
|
||||
import FormText from "../../react/FormText";
|
||||
import server from "../../../services/server";
|
||||
import toast from "../../../services/toast";
|
||||
import { SyncTestResponse } from "@triliumnext/commons";
|
||||
import TimeSelector from "./components/TimeSelector";
|
||||
|
||||
export default function SyncOptions() {
|
||||
return (
|
||||
@@ -18,13 +20,12 @@ export default function SyncOptions() {
|
||||
<SyncConfiguration />
|
||||
<SyncTest />
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function SyncConfiguration() {
|
||||
const [ options, setOptions ] = useTriliumOptions("syncServerHost", "syncServerTimeout", "syncProxy");
|
||||
const [ options, setOptions ] = useTriliumOptions("syncServerHost", "syncProxy");
|
||||
const syncServerHost = useRef(options.syncServerHost);
|
||||
const syncServerTimeout = useRef(options.syncServerTimeout);
|
||||
const syncProxy = useRef(options.syncProxy);
|
||||
|
||||
return (
|
||||
@@ -32,13 +33,12 @@ export function SyncConfiguration() {
|
||||
<form onSubmit={(e) => {
|
||||
setOptions({
|
||||
syncServerHost: syncServerHost.current,
|
||||
syncServerTimeout: syncServerTimeout.current,
|
||||
syncProxy: syncProxy.current
|
||||
});
|
||||
e.preventDefault();
|
||||
}}>
|
||||
<FormGroup name="sync-server-host" label={t("sync_2.server_address")}>
|
||||
<FormTextBox
|
||||
<FormTextBox
|
||||
placeholder="https://<host>:<port>"
|
||||
currentValue={syncServerHost.current} onChange={(newValue) => syncServerHost.current = newValue}
|
||||
/>
|
||||
@@ -50,27 +50,28 @@ export function SyncConfiguration() {
|
||||
<RawHtml html={t("sync_2.special_value_description")} />
|
||||
</>}
|
||||
>
|
||||
<FormTextBox
|
||||
<FormTextBox
|
||||
placeholder="https://<host>:<port>"
|
||||
currentValue={syncProxy.current} onChange={(newValue) => syncProxy.current = newValue}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup name="sync-server-timeout" label={t("sync_2.timeout")}>
|
||||
<FormTextBoxWithUnit
|
||||
min={1} max={10000000} type="number"
|
||||
unit={t("sync_2.timeout_unit")}
|
||||
currentValue={syncServerTimeout.current} onChange={(newValue) => syncServerTimeout.current = newValue}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<div style={{ display: "flex", justifyContent: "spaceBetween"}}>
|
||||
<Button text={t("sync_2.save")} kind="primary" />
|
||||
<Button text={t("sync_2.help")} onClick={() => openInAppHelpFromUrl("cbkrhQjrkKrh")} />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<FormGroup name="sync-server-timeout" label={t("sync_2.timeout")}>
|
||||
<TimeSelector
|
||||
name="sync-server-timeout"
|
||||
optionValueId="syncServerTimeout"
|
||||
optionTimeScaleId="syncServerTimeoutTimeScale"
|
||||
minimumSeconds={1}
|
||||
/>
|
||||
</FormGroup>
|
||||
</OptionsSection>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function SyncTest() {
|
||||
@@ -90,5 +91,5 @@ export function SyncTest() {
|
||||
}}
|
||||
/>
|
||||
</OptionsSection>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ const ALLOWED_OPTIONS = new Set<OptionNames>([
|
||||
"codeNoteTheme",
|
||||
"syncServerHost",
|
||||
"syncServerTimeout",
|
||||
"syncServerTimeoutTimeScale",
|
||||
"syncProxy",
|
||||
"hoistedNoteId",
|
||||
"mainFontSize",
|
||||
|
||||
30
apps/server/src/services/options_init.spec.ts
Normal file
30
apps/server/src/services/options_init.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { migrateSyncTimeoutFromMilliseconds } from "./options_init.js";
|
||||
|
||||
describe("migrateSyncTimeoutFromMilliseconds", () => {
|
||||
it("returns null when no migration is needed", () => {
|
||||
// Values < 1000 are already in seconds/minutes format
|
||||
expect(migrateSyncTimeoutFromMilliseconds(120)).toBeNull();
|
||||
expect(migrateSyncTimeoutFromMilliseconds(500)).toBeNull();
|
||||
expect(migrateSyncTimeoutFromMilliseconds(999)).toBeNull();
|
||||
expect(migrateSyncTimeoutFromMilliseconds(NaN)).toBeNull();
|
||||
});
|
||||
|
||||
it("migrates to minutes when divisible by 60", () => {
|
||||
expect(migrateSyncTimeoutFromMilliseconds(60000)).toEqual({ value: 1, scale: 60 }); // 1 minute
|
||||
expect(migrateSyncTimeoutFromMilliseconds(120000)).toEqual({ value: 2, scale: 60 }); // 2 minutes
|
||||
expect(migrateSyncTimeoutFromMilliseconds(300000)).toEqual({ value: 5, scale: 60 }); // 5 minutes
|
||||
expect(migrateSyncTimeoutFromMilliseconds(3600000)).toEqual({ value: 60, scale: 60 }); // 60 minutes
|
||||
});
|
||||
|
||||
it("migrates to seconds when not divisible by 60", () => {
|
||||
expect(migrateSyncTimeoutFromMilliseconds(1000)).toEqual({ value: 1, scale: 1 }); // 1 second
|
||||
expect(migrateSyncTimeoutFromMilliseconds(45000)).toEqual({ value: 45, scale: 1 }); // 45 seconds
|
||||
expect(migrateSyncTimeoutFromMilliseconds(90000)).toEqual({ value: 90, scale: 1 }); // 90 seconds
|
||||
expect(migrateSyncTimeoutFromMilliseconds(150000)).toEqual({ value: 150, scale: 1 }); // 150 seconds
|
||||
});
|
||||
|
||||
it("rounds milliseconds to nearest second", () => {
|
||||
expect(migrateSyncTimeoutFromMilliseconds(120500)).toEqual({ value: 121, scale: 1 });
|
||||
});
|
||||
});
|
||||
@@ -66,7 +66,7 @@ async function initNotSyncedOptions(initialized: boolean, opts: NotSyncedOpts =
|
||||
optionService.createOption("textNoteEditorType", "ckeditor-classic", true);
|
||||
|
||||
optionService.createOption("syncServerHost", opts.syncServerHost || "", false);
|
||||
optionService.createOption("syncServerTimeout", "120000", false);
|
||||
optionService.createOption("syncServerTimeout", "2", false); // 2 minutes (with default scale of 60)
|
||||
optionService.createOption("syncProxy", opts.syncProxy || "", false);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ async function initNotSyncedOptions(initialized: boolean, opts: NotSyncedOpts =
|
||||
* Contains all the default options that must be initialized on new and existing databases (at startup). The value can also be determined based on other options, provided they have already been initialized.
|
||||
*/
|
||||
const defaultOptions: DefaultOption[] = [
|
||||
{ name: "syncServerTimeoutTimeScale", value: "60", isSynced: false }, // default to Minutes
|
||||
{ name: "revisionSnapshotTimeInterval", value: "600", isSynced: true },
|
||||
{ name: "revisionSnapshotTimeIntervalTimeScale", value: "60", isSynced: true }, // default to Minutes
|
||||
{ name: "revisionSnapshotNumberLimit", value: "-1", isSynced: true },
|
||||
@@ -255,6 +256,36 @@ function initStartupOptions() {
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
// Migrate syncServerTimeout from milliseconds to seconds/minutes (for existing installations)
|
||||
const syncTimeout = parseInt(optionsMap.syncServerTimeout, 10);
|
||||
const migrated = migrateSyncTimeoutFromMilliseconds(syncTimeout);
|
||||
if (migrated) {
|
||||
optionService.setOption("syncServerTimeout", String(migrated.value));
|
||||
optionService.setOption("syncServerTimeoutTimeScale", String(migrated.scale));
|
||||
const unit = migrated.scale === 60 ? "minutes" : "seconds";
|
||||
log.info(`Migrated syncServerTimeout from ${syncTimeout}ms to ${migrated.value} ${unit}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates a sync timeout value from milliseconds to a value/scale pair.
|
||||
* Values >= 1000 are assumed to be in milliseconds (since 1000+ seconds = 16+ minutes is unlikely).
|
||||
*
|
||||
* @returns The migrated value and scale, or null if no migration is needed.
|
||||
*/
|
||||
export function migrateSyncTimeoutFromMilliseconds(milliseconds: number): { value: number; scale: number } | null {
|
||||
if (isNaN(milliseconds) || milliseconds < 1000) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const seconds = Math.round(milliseconds / 1000);
|
||||
|
||||
// If divisible by 60, store as minutes; otherwise store as seconds
|
||||
if (seconds >= 60 && seconds % 60 === 0) {
|
||||
return { value: seconds / 60, scale: 60 };
|
||||
}
|
||||
return { value: seconds, scale: 1 };
|
||||
}
|
||||
|
||||
function getKeyboardDefaultOptions() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import optionService from "./options.js";
|
||||
|
||||
import config from "./config.js";
|
||||
import optionService from "./options.js";
|
||||
import { normalizeUrl } from "./utils.js";
|
||||
|
||||
/*
|
||||
@@ -29,6 +29,11 @@ export default {
|
||||
// and we need to override it with config from config.ini
|
||||
return !!syncServerHost && syncServerHost !== "disabled";
|
||||
},
|
||||
getSyncTimeout: () => parseInt(get("syncServerTimeout")) || 120000,
|
||||
// Value is stored with a time scale, convert to milliseconds for use
|
||||
getSyncTimeout: () => {
|
||||
const value = parseInt(get("syncServerTimeout"), 10) || 2;
|
||||
const scale = parseInt(optionService.getOption("syncServerTimeoutTimeScale"), 10) || 60;
|
||||
return value * scale * 1000;
|
||||
},
|
||||
getSyncProxy: () => get("syncProxy")
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi
|
||||
theme: string;
|
||||
syncServerHost: string;
|
||||
syncServerTimeout: string;
|
||||
syncServerTimeoutTimeScale: number;
|
||||
syncProxy: string;
|
||||
mainFontFamily: FontFamily;
|
||||
treeFontFamily: FontFamily;
|
||||
|
||||
Reference in New Issue
Block a user