feat(standalone/setup): sync from server without refresh

This commit is contained in:
Elian Doran
2026-03-24 10:18:23 +02:00
parent 697ea995cb
commit 3f5cdc533e
3 changed files with 56 additions and 35 deletions

View File

@@ -1,7 +1,7 @@
import "./setup.css";
import { ComponentChildren, render } from "preact";
import { useState } from "preact/hooks";
import { useEffect, useState } from "preact/hooks";
import { initLocale, t } from "./services/i18n";
import server from "./services/server";
@@ -22,7 +22,7 @@ async function main() {
type State = "firstOptions" | "syncFromDesktop" | "syncFromServer" | "syncInProgress" | "syncFailed";
function App() {
const [ state, setState ] = useState<State>("syncInProgress");
const [ state, setState ] = useState<State>("syncFromServer");
return (
<div class="setup-container">
@@ -70,15 +70,37 @@ function SetupOptions({ setState }: { setState: (state: State) => void }) {
}
function SyncInProgress() {
const { outstandingPullCount, initialized } = useOutstandingSyncInfo();
return (
<div class="page sync-in-progress">
<h1>{t("setup.sync-in-progress-title")}</h1>
<p>{t("setup.sync-in-progress-description")}</p>
<Spinner />
<p>Outstanding sync objects: {outstandingPullCount}</p>
</div>
);
}
function useOutstandingSyncInfo() {
const [ outstandingPullCount, setOutstandingPullCount ] = useState(0);
const [ initialized, setInitialized ] = useState(false);
async function refresh() {
const { outstandingPullCount, initialized } = await server.get("sync/stats");
setOutstandingPullCount(outstandingPullCount);
setInitialized(initialized);
}
useEffect(() => {
const interval = setInterval(refresh, 1000);
refresh();
return () => clearInterval(interval);
}, []);
return { outstandingPullCount, initialized };
}
function Spinner() {
return (
<div class="lds-ring" style="margin-right: 20px;">
@@ -93,11 +115,12 @@ function SyncFromServer({ setState }: { setState: (state: State) => void }) {
const [serverUrl, setServerUrl] = useState("");
const [password, setPassword] = useState("");
function handleFinishSetup() {
server.post("setup/sync-from-server", {
async function handleFinishSetup() {
await server.post("setup/sync-from-server", {
syncServerHost: serverUrl,
password
});
setState("syncInProgress");
}
return (

View File

@@ -14,32 +14,7 @@ const setDbAsInitialized = coreSqlInit.setDbAsInitialized;
const createInitialDatabase = coreSqlInit.createInitialDatabase;
const initializeDb = coreSqlInit.initializeDb;
export const getDbSize = coreSqlInit.getDbSize;
async function createDatabaseForSync(options: OptionRow[], syncServerHost = "", syncProxy = "") {
log.info("Creating database for sync");
if (isDbInitialized()) {
throw new Error("DB is already initialized");
}
const schema = fs.readFileSync(`${resourceDir.DB_INIT_DIR}/schema.sql`, "utf8");
// We have to import async since options init requires keyboard actions which require translations.
const optionsInitService = (await import("./options_init.js")).default;
sql.transactional(() => {
sql.executeScript(schema);
optionsInitService.initNotSyncedOptions(false, { syncServerHost, syncProxy });
// document options required for sync to kick off
for (const opt of options) {
new BOption(opt).save();
}
});
log.info("Schema and not synced options generated.");
}
const createDatabaseForSync = coreSqlInit.createDatabaseForSync;
export default {
dbReady,

View File

@@ -1,4 +1,4 @@
import { deferred } from "@triliumnext/commons";
import { deferred, OptionRow } from "@triliumnext/commons";
import { getSql } from "./sql";
import { getLog } from "./log";
import { isElectron } from "./utils";
@@ -11,6 +11,7 @@ import BNote from "../becca/entities/bnote";
import BBranch from "../becca/entities/bbranch";
import hidden_subtree from "./hidden_subtree";
import TaskContext from "./task_context";
import BOption from "../becca/entities/boption";
export const dbReady = deferred<void>();
@@ -75,10 +76,6 @@ async function initDbConnection() {
dbReady.resolve();
}
async function createDatabaseForSync(a: any, b: string, c: any) {
console.error("createDatabaseForSync is not implemented yet");
}
function setDbAsInitialized() {
if (!isDbInitialized()) {
optionService.setOption("initialized", "true");
@@ -222,4 +219,30 @@ async function createInitialDatabase(skipDemoDb?: boolean) {
initDbConnection();
}
async function createDatabaseForSync(options: OptionRow[], syncServerHost = "", syncProxy = "") {
const log = getLog();
const sql = getSql();
log.info("Creating database for sync");
if (isDbInitialized()) {
throw new Error("DB is already initialized");
}
// We have to import async since options init requires keyboard actions which require translations.
const optionsInitService = (await import("./options_init.js")).default;
sql.transactional(() => {
sql.executeScript(schema);
optionsInitService.initNotSyncedOptions(false, { syncServerHost, syncProxy });
// document options required for sync to kick off
for (const opt of options) {
new BOption(opt).save();
}
});
log.info("Schema and not synced options generated.");
}
export default { isDbInitialized, createDatabaseForSync, setDbAsInitialized, schemaExists, getDbSize, initDbConnection, dbReady, initializeDb, createInitialDatabase };