mirror of
https://github.com/zadam/trilium.git
synced 2025-10-26 07:46:30 +01:00
feat(react/settings): port sync options
This commit is contained in:
@@ -374,33 +374,36 @@ async function openInAppHelp($button: JQuery<HTMLElement>) {
|
||||
|
||||
const inAppHelpPage = $button.attr("data-in-app-help");
|
||||
if (inAppHelpPage) {
|
||||
// Dynamic import to avoid import issues in tests.
|
||||
const appContext = (await import("../components/app_context.js")).default;
|
||||
const activeContext = appContext.tabManager.getActiveContext();
|
||||
if (!activeContext) {
|
||||
return;
|
||||
}
|
||||
const subContexts = activeContext.getSubContexts();
|
||||
const targetNote = `_help_${inAppHelpPage}`;
|
||||
const helpSubcontext = subContexts.find((s) => s.viewScope?.viewMode === "contextual-help");
|
||||
const viewScope: ViewScope = {
|
||||
viewMode: "contextual-help",
|
||||
};
|
||||
if (!helpSubcontext) {
|
||||
// The help is not already open, open a new split with it.
|
||||
const { ntxId } = subContexts[subContexts.length - 1];
|
||||
appContext.triggerCommand("openNewNoteSplit", {
|
||||
ntxId,
|
||||
notePath: targetNote,
|
||||
hoistedNoteId: "_help",
|
||||
viewScope
|
||||
})
|
||||
} else {
|
||||
// There is already a help window open, make sure it opens on the right note.
|
||||
helpSubcontext.setNote(targetNote, { viewScope });
|
||||
}
|
||||
openInAppHelpFromUrl(inAppHelpPage);
|
||||
}
|
||||
}
|
||||
|
||||
export async function openInAppHelpFromUrl(inAppHelpPage: string) {
|
||||
// Dynamic import to avoid import issues in tests.
|
||||
const appContext = (await import("../components/app_context.js")).default;
|
||||
const activeContext = appContext.tabManager.getActiveContext();
|
||||
if (!activeContext) {
|
||||
return;
|
||||
}
|
||||
const subContexts = activeContext.getSubContexts();
|
||||
const targetNote = `_help_${inAppHelpPage}`;
|
||||
const helpSubcontext = subContexts.find((s) => s.viewScope?.viewMode === "contextual-help");
|
||||
const viewScope: ViewScope = {
|
||||
viewMode: "contextual-help",
|
||||
};
|
||||
if (!helpSubcontext) {
|
||||
// The help is not already open, open a new split with it.
|
||||
const { ntxId } = subContexts[subContexts.length - 1];
|
||||
appContext.triggerCommand("openNewNoteSplit", {
|
||||
ntxId,
|
||||
notePath: targetNote,
|
||||
hoistedNoteId: "_help",
|
||||
viewScope
|
||||
})
|
||||
} else {
|
||||
// There is already a help window open, make sure it opens on the right note.
|
||||
helpSubcontext.setNote(targetNote, { viewScope });
|
||||
}
|
||||
}
|
||||
|
||||
function initHelpButtons($el: JQuery<HTMLElement> | JQuery<Window>) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { InputHTMLAttributes, RefObject } from "preact/compat";
|
||||
import FormText from "./FormText";
|
||||
|
||||
interface FormTextBoxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value"> {
|
||||
id?: string;
|
||||
@@ -11,9 +10,11 @@ interface FormTextBoxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "
|
||||
export default function FormTextBox({ inputRef, className, type, currentValue, onChange, ...rest}: FormTextBoxProps) {
|
||||
if (type === "number" && currentValue) {
|
||||
const { min, max } = rest;
|
||||
if (min && currentValue < min) {
|
||||
console.log(currentValue , min, max);
|
||||
const currentValueNum = parseInt(currentValue, 10);
|
||||
if (min && currentValueNum < parseInt(String(min), 10)) {
|
||||
currentValue = String(min);
|
||||
} else if (max && currentValue > max) {
|
||||
} else if (max && currentValueNum > parseInt(String(max), 10)) {
|
||||
currentValue = String(max);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { OptionNames } from "@triliumnext/commons";
|
||||
import options, { type OptionValue } from "../../services/options";
|
||||
import utils, { reloadFrontendApp } from "../../services/utils";
|
||||
import Component from "../../components/component";
|
||||
import server from "../../services/server";
|
||||
|
||||
type TriliumEventHandler<T extends EventNames> = (data: EventData<T>) => void;
|
||||
const registeredHandlers: Map<Component, Map<EventNames, TriliumEventHandler<any>[]>> = new Map();
|
||||
@@ -150,6 +151,19 @@ export function useTriliumOptionJson<T>(name: OptionNames): [ T, (newValue: T) =
|
||||
];
|
||||
}
|
||||
|
||||
export function useTriliumOptions<T extends OptionNames>(...names: T[]) {
|
||||
const values: Record<string, string> = {};
|
||||
for (const name of names) {
|
||||
values[name] = options.get(name);
|
||||
}
|
||||
|
||||
const setValue = (newValues: Record<T, string>) => server.put<void>("options", newValues);
|
||||
return [
|
||||
values as Record<T, string>,
|
||||
setValue
|
||||
] as const;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique name via a random alphanumeric string of a fixed length.
|
||||
*
|
||||
|
||||
@@ -13,7 +13,6 @@ import PasswordOptions from "./options/password/password.js";
|
||||
import ProtectedSessionTimeoutOptions from "./options/password/protected_session_timeout.js";
|
||||
import EtapiOptions from "./options/etapi.js";
|
||||
import BackupOptions from "./options/backup.js";
|
||||
import SyncOptions from "./options/sync.js";
|
||||
import SearchEngineOptions from "./options/other/search_engine.js";
|
||||
import TrayOptions from "./options/other/tray.js";
|
||||
import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js";
|
||||
@@ -40,6 +39,7 @@ import { renderReactWidget } from "../react/ReactBasicWidget.jsx";
|
||||
import ImageSettings from "./options/images.jsx";
|
||||
import AdvancedSettings from "./options/advanced.jsx";
|
||||
import InternationalizationOptions from "./options/i18n.jsx";
|
||||
import SyncOptions from "./options/sync.jsx";
|
||||
|
||||
const TPL = /*html*/`<div class="note-detail-content-widget note-detail-printable">
|
||||
<style>
|
||||
@@ -102,9 +102,7 @@ const CONTENT_WIDGETS: Record<OptionPages | "_backendLog", ((typeof NoteContextA
|
||||
_optionsBackup: [
|
||||
BackupOptions
|
||||
],
|
||||
_optionsSync: [
|
||||
SyncOptions
|
||||
],
|
||||
_optionsSync: <SyncOptions />,
|
||||
_optionsAi: [AiSettingsOptions],
|
||||
_optionsOther: [
|
||||
SearchEngineOptions,
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import server from "../../../services/server.js";
|
||||
import toastService from "../../../services/toast.js";
|
||||
import OptionsWidget from "./options_widget.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import type { OptionMap } from "@triliumnext/commons";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="options-section">
|
||||
<h4 style="margin-top: 0px;">${t("sync_2.config_title")}</h4>
|
||||
|
||||
<form class="sync-setup-form">
|
||||
<div class="form-group">
|
||||
<label for="sync-server-host" >${t("sync_2.server_address")}</label>
|
||||
<input id="sync-server-host" class="sync-server-host form-control" placeholder="https://<host>:<port>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="sync-proxy form-control" >${t("sync_2.proxy_label")}</label>
|
||||
<input id="sync-proxy form-control" class="sync-proxy form-control" placeholder="https://<host>:<port>">
|
||||
|
||||
<p class="form-text"><strong>${t("sync_2.note")}:</strong> ${t("sync_2.note_description")}</p>
|
||||
<p class="form-text">${t("sync_2.special_value_description")}</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="sync-server-timeout">${t("sync_2.timeout")}</label>
|
||||
<label class="input-group tn-number-unit-pair">
|
||||
<input id="sync-server-timeout" class="sync-server-timeout form-control" min="1" max="10000000" type="number" style="text-align: left;">
|
||||
<span class="input-group-text">${t("sync_2.timeout_unit")}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<button class="btn btn-primary">${t("sync_2.save")}</button>
|
||||
|
||||
<button class="btn btn-secondary" type="button" data-help-page="synchronization.html">${t("sync_2.help")}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="options-section">
|
||||
<h4>${t("sync_2.test_title")}</h4>
|
||||
|
||||
<p>${t("sync_2.test_description")}</p>
|
||||
|
||||
<button class="test-sync-button btn btn-secondary">${t("sync_2.test_button")}</button>
|
||||
</div>`;
|
||||
|
||||
// TODO: Deduplicate
|
||||
interface TestResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export default class SyncOptions extends OptionsWidget {
|
||||
|
||||
private $form!: JQuery<HTMLElement>;
|
||||
private $syncServerHost!: JQuery<HTMLElement>;
|
||||
private $syncServerTimeout!: JQuery<HTMLElement>;
|
||||
private $syncProxy!: JQuery<HTMLElement>;
|
||||
private $testSyncButton!: JQuery<HTMLElement>;
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
|
||||
this.$form = this.$widget.find(".sync-setup-form");
|
||||
this.$syncServerHost = this.$widget.find(".sync-server-host");
|
||||
this.$syncServerTimeout = this.$widget.find(".sync-server-timeout");
|
||||
this.$syncProxy = this.$widget.find(".sync-proxy");
|
||||
this.$testSyncButton = this.$widget.find(".test-sync-button");
|
||||
|
||||
this.$form.on("submit", () => this.save());
|
||||
|
||||
this.$testSyncButton.on("click", async () => {
|
||||
const result = await server.post<TestResponse>("sync/test");
|
||||
|
||||
if (result.success) {
|
||||
toastService.showMessage(result.message);
|
||||
} else {
|
||||
toastService.showError(t("sync_2.handshake_failed", { message: result.message }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
optionsLoaded(options: OptionMap) {
|
||||
this.$syncServerHost.val(options.syncServerHost);
|
||||
this.$syncServerTimeout.val(options.syncServerTimeout);
|
||||
this.$syncProxy.val(options.syncProxy);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.updateMultipleOptions({
|
||||
syncServerHost: String(this.$syncServerHost.val()),
|
||||
syncServerTimeout: String(this.$syncServerTimeout.val()),
|
||||
syncProxy: String(this.$syncProxy.val())
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
62
apps/client/src/widgets/type_widgets/options/sync.tsx
Normal file
62
apps/client/src/widgets/type_widgets/options/sync.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { useRef } from "preact/hooks";
|
||||
import { t } from "../../../services/i18n";
|
||||
import { openInAppHelpFromUrl } from "../../../services/utils";
|
||||
import Button from "../../react/Button";
|
||||
import FormGroup from "../../react/FormGroup";
|
||||
import FormTextBox, { FormTextBoxWithUnit } from "../../react/FormTextBox";
|
||||
import RawHtml from "../../react/RawHtml";
|
||||
import OptionsSection from "./components/OptionsSection";
|
||||
import { useTriliumOptions } from "../../react/hooks";
|
||||
|
||||
export default function SyncOptions() {
|
||||
const [ options, setOptions ] = useTriliumOptions("syncServerHost", "syncServerTimeout", "syncProxy");
|
||||
const syncServerHost = useRef(options.syncServerHost);
|
||||
const syncServerTimeout = useRef(options.syncServerTimeout);
|
||||
const syncProxy = useRef(options.syncProxy);
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("sync_2.config_title")}>
|
||||
<form onSubmit={(e) => {
|
||||
setOptions({
|
||||
syncServerHost: syncServerHost.current,
|
||||
syncServerTimeout: syncServerTimeout.current,
|
||||
syncProxy: syncProxy.current
|
||||
});
|
||||
e.preventDefault();
|
||||
}}>
|
||||
<FormGroup label={t("sync_2.server_address")}>
|
||||
<FormTextBox
|
||||
name="sync-server-host"
|
||||
placeholder="https://<host>:<port>"
|
||||
currentValue={syncServerHost.current} onChange={(newValue) => syncServerHost.current = newValue}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("sync_2.proxy_label")} description={<>
|
||||
<strong>{t("sync_2.note")}:</strong> {t("sync_2.note_description")}<br/>
|
||||
<RawHtml html={t("sync_2.special_value_description")} /></>}
|
||||
>
|
||||
<FormTextBox
|
||||
name="sync-proxy"
|
||||
placeholder="https://<host>:<port>"
|
||||
currentValue={syncProxy.current} onChange={(newValue) => syncProxy.current = newValue}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("sync_2.timeout")}>
|
||||
<FormTextBoxWithUnit
|
||||
name="sync-server-timeout"
|
||||
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")} primary />
|
||||
<Button text={t("sync_2.help")} onClick={() => openInAppHelpFromUrl("cbkrhQjrkKrh")} />
|
||||
</div>
|
||||
</form>
|
||||
</OptionsSection>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user