diff --git a/apps/client/src/setup.css b/apps/client/src/setup.css index a30591847d..a567f8f1b9 100644 --- a/apps/client/src/setup.css +++ b/apps/client/src/setup.css @@ -83,6 +83,7 @@ body.setup { display: flex; flex-direction: column; padding-top: 1em; + overflow: auto; } >footer { @@ -102,6 +103,10 @@ body.setup { gap: 1rem; width: 80%; margin: auto; + + .admonition { + margin: 0; + } } .form-item-with-icon { diff --git a/apps/client/src/setup.tsx b/apps/client/src/setup.tsx index 95e3fe665b..21803aad64 100644 --- a/apps/client/src/setup.tsx +++ b/apps/client/src/setup.tsx @@ -1,10 +1,12 @@ import "./setup.css"; +import { SetupSyncFromServerResponse } from "@triliumnext/commons"; import { ComponentChildren, render } from "preact"; import { useEffect, useRef, useState } from "preact/hooks"; import { initLocale, t } from "./services/i18n"; import server from "./services/server"; +import Admonition from "./widgets/react/Admonition"; import Button from "./widgets/react/Button"; import { Card, CardFrame, CardSection } from "./widgets/react/Card"; import Collapsible from "./widgets/react/Collapsible"; @@ -212,15 +214,25 @@ function SyncFromServer({ setState }: { setState: (state: State) => void }) { const [ syncServerHost, setSyncServerHost ] = useState(""); const [ password, setPassword ] = useState(""); const [ syncProxy, setSyncProxy ] = useState(""); + const [ error, setError ] = useState(null); const isValid = syncServerHost.trim() !== "" && password !== ""; async function handleFinishSetup() { - await server.post("setup/sync-from-server", { - syncServerHost: syncServerHost.trim(), - syncProxy: syncProxy.trim(), - password - }); - setState("syncInProgress"); + try { + const resp = await server.post("setup/sync-from-server", { + syncServerHost: syncServerHost.trim(), + syncProxy: syncProxy.trim(), + password + }); + + if (resp.result === "success") { + setState("syncInProgress"); + } else { + setError(t("setup.sync-failed", { message: resp.error })); + } + } catch (e) { + setError(e instanceof Error ? e.message : String(e)); + } } return ( @@ -230,7 +242,7 @@ function SyncFromServer({ setState }: { setState: (state: State) => void }) {

{t("setup.sync-from-server-page-description")}

-
+ @@ -244,6 +256,8 @@ function SyncFromServer({ setState }: { setState: (state: State) => void }) { + + {error && {error}}
diff --git a/apps/client/src/setup_old.ts b/apps/client/src/setup_old.ts index 02aa5bcca4..c04435475a 100644 --- a/apps/client/src/setup_old.ts +++ b/apps/client/src/setup_old.ts @@ -101,16 +101,6 @@ class SetupController { const syncProxy = this.syncProxyInput.value.trim(); const password = this.passwordInput.value; - if (!syncServerHost) { - showAlert("Trilium server address can't be empty"); - return; - } - - if (!password) { - showAlert("Password can't be empty"); - return; - } - if (resp.result === "success") { hideAlert(); this.setStep("sync-in-progress"); diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 12771a86df..cd96de81ec 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2264,6 +2264,7 @@ "sync-from-desktop-step5": "Click \"Test sync\" button to verify connection is successful.", "sync-from-desktop-final": "Once you've completed these steps, you can proceed to the next step.", "sync-from-desktop-waiting": "Waiting for connection...", - "advanced-options": "Advanced options" + "advanced-options": "Advanced options", + "sync-failed": "Failed to sync: {{message}}" } } diff --git a/packages/commons/src/lib/server_api.ts b/packages/commons/src/lib/server_api.ts index e55d22d1a2..bf5c173cfe 100644 --- a/packages/commons/src/lib/server_api.ts +++ b/packages/commons/src/lib/server_api.ts @@ -370,3 +370,10 @@ export interface SetupSyncSeedResponse { syncVersion: number; options: OptionRow[]; } + +export type SetupSyncFromServerResponse = { + result: "success"; +} | { + result: "failure"; + error: string; +} diff --git a/packages/trilium-core/src/routes/api/setup.ts b/packages/trilium-core/src/routes/api/setup.ts index 6a929d6d57..26739aa4e2 100644 --- a/packages/trilium-core/src/routes/api/setup.ts +++ b/packages/trilium-core/src/routes/api/setup.ts @@ -3,6 +3,7 @@ import setupService from "../../services/setup.js"; import { getLog } from "../../services/log.js"; import appInfo from "../../services/app_info.js"; import type { Request } from "express"; +import { SetupSyncFromServerResponse } from "@triliumnext/commons"; function getStatus() { return { @@ -16,7 +17,7 @@ async function setupNewDocument() { await sqlInit.createInitialDatabase(); } -function setupSyncFromServer(req: Request) { +function setupSyncFromServer(req: Request): Promise { const { syncServerHost, syncProxy, password } = req.body; return setupService.setupSyncFromSyncServer(syncServerHost, syncProxy, password); diff --git a/packages/trilium-core/src/services/setup.ts b/packages/trilium-core/src/services/setup.ts index 046738dbd6..023b7b0fcf 100644 --- a/packages/trilium-core/src/services/setup.ts +++ b/packages/trilium-core/src/services/setup.ts @@ -6,7 +6,7 @@ import syncOptions from "./sync_options.js"; import appInfo from "./app_info.js"; import { timeLimit } from "./utils/index.js"; import becca from "../becca/becca.js"; -import type { SetupStatusResponse, SetupSyncSeedResponse } from "@triliumnext/commons"; +import type { SetupStatusResponse, SetupSyncFromServerResponse, SetupSyncSeedResponse } from "@triliumnext/commons"; import request from "./request.js"; async function hasSyncServerSchemaAndSeed() { @@ -61,7 +61,7 @@ async function requestToSyncServer(method: string, path: string, body?: strin )) as T; } -async function setupSyncFromSyncServer(syncServerHost: string, syncProxy: string, password: string) { +async function setupSyncFromSyncServer(syncServerHost: string, syncProxy: string, password: string): Promise { if (sqlInit.isDbInitialized()) { return { result: "failure",