mirror of
https://github.com/zadam/trilium.git
synced 2026-06-18 16:29:46 +02:00
174 lines
5.6 KiB
TypeScript
174 lines
5.6 KiB
TypeScript
import "./setup.css";
|
|
|
|
import { ComponentChildren, render } from "preact";
|
|
import { useEffect, useState } from "preact/hooks";
|
|
|
|
import { initLocale, t } from "./services/i18n";
|
|
import server from "./services/server";
|
|
import Button from "./widgets/react/Button";
|
|
import { CardFrame } from "./widgets/react/Card";
|
|
import FormTextBox from "./widgets/react/FormTextBox";
|
|
import Icon from "./widgets/react/Icon";
|
|
|
|
async function main() {
|
|
await initLocale();
|
|
|
|
const bodyWrapper = document.createElement("div");
|
|
document.body.classList.add("setup");
|
|
render(<App />, bodyWrapper);
|
|
document.body.replaceChildren(bodyWrapper);
|
|
}
|
|
|
|
type State = "firstOptions" | "syncFromDesktop" | "syncFromServer" | "syncInProgress" | "syncFailed";
|
|
|
|
function App() {
|
|
const [ state, setState ] = useState<State>("syncFromServer");
|
|
|
|
return (
|
|
<div class="setup-container">
|
|
{state === "firstOptions" && <SetupOptions setState={setState} />}
|
|
{state === "syncFromServer" && <SyncFromServer setState={setState} />}
|
|
{state === "syncInProgress" && <SyncInProgress />}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function SetupOptions({ setState }: { setState: (state: State) => void }) {
|
|
return (
|
|
<div class="page setup-options-container">
|
|
<h1>{t("setup.heading")}</h1>
|
|
|
|
<main class="setup-options">
|
|
<SetupOptionCard
|
|
icon="bx bx-file-blank"
|
|
title={t("setup.new-document")}
|
|
description={t("setup.new-document-description")}
|
|
onClick={async () => {
|
|
await server.post("setup/new-document");
|
|
|
|
// After creating a new document, we can just reload the page to load it.
|
|
location.reload();
|
|
}}
|
|
/>
|
|
|
|
<SetupOptionCard
|
|
icon="bx bx-server"
|
|
title={t("setup.sync-from-server")}
|
|
description={t("setup.sync-from-server-description")}
|
|
onClick={() => setState("syncFromServer")}
|
|
/>
|
|
|
|
<SetupOptionCard
|
|
icon="bx bx-desktop"
|
|
title={t("setup.sync-from-desktop")}
|
|
description={t("setup.sync-from-desktop-description")}
|
|
onClick={() => setState("syncFromDesktop")}
|
|
/>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
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;">
|
|
<div />
|
|
<div />
|
|
<div />
|
|
<div />
|
|
</div>);
|
|
}
|
|
|
|
function SyncFromServer({ setState }: { setState: (state: State) => void }) {
|
|
const [serverUrl, setServerUrl] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
|
|
async function handleFinishSetup() {
|
|
await server.post("setup/sync-from-server", {
|
|
syncServerHost: serverUrl,
|
|
password
|
|
});
|
|
setState("syncInProgress");
|
|
}
|
|
|
|
return (
|
|
<div class="page sync-from-server">
|
|
<h1>{t("setup.sync-from-server-page-title")}</h1>
|
|
<p>{t("setup.sync-from-server-page-description")}</p>
|
|
|
|
<main>
|
|
<form>
|
|
<FormItemWithIcon icon="bx bx-server">
|
|
<FormTextBox placeholder="https://example.com" currentValue={serverUrl} onChange={setServerUrl} />
|
|
</FormItemWithIcon>
|
|
|
|
<FormItemWithIcon icon="bx bx-lock">
|
|
<FormTextBox placeholder={t("setup.password-placeholder")} type="password" currentValue={password} onChange={setPassword} />
|
|
</FormItemWithIcon>
|
|
</form>
|
|
</main>
|
|
|
|
<footer>
|
|
<Button text={t("setup.button-back")} onClick={() => setState("firstOptions")} kind="lowProfile" />
|
|
<Button text={t("setup.button-finish-setup")} kind="primary" onClick={handleFinishSetup} />
|
|
</footer>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function FormItemWithIcon({ icon, children }: { icon: string; children: ComponentChildren }) {
|
|
return (
|
|
<div class="form-item-with-icon">
|
|
<Icon icon={icon} />
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function SetupOptionCard({ title, description, icon, onClick }: { title: string; description: string, icon: string, onClick?: () => void }) {
|
|
return (
|
|
<CardFrame className="setup-option-card" onClick={onClick}>
|
|
<Icon icon={icon} />
|
|
|
|
<div>
|
|
<h3>{title}</h3>
|
|
<p>{description}</p>
|
|
</div>
|
|
</CardFrame>
|
|
);
|
|
}
|
|
|
|
main();
|