mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-26 14:32:58 +00:00
Complete Commonlib rc.6 integration and setup workflows
This commit is contained in:
@@ -11,7 +11,7 @@ import { type EntryDoc, type RemoteType } from "@vrtmrz/livesync-commonlib/compa
|
||||
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
||||
import { EVENT_FILE_SAVED, EVENT_SETTING_SAVED, eventHub } from "@/common/events";
|
||||
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import type { LiveSyncCore } from "@/main";
|
||||
import { ReplicateResultProcessor } from "./ReplicateResultProcessor";
|
||||
import { UnresolvedErrorManager } from "@vrtmrz/livesync-commonlib/compat/services/base/UnresolvedErrorManager";
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { escapeMarkdownValue } from "@vrtmrz/livesync-commonlib/compat/common/utils";
|
||||
import { AbstractModule } from "@/modules/AbstractModule.ts";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import type { InjectableServiceHub } from "@vrtmrz/livesync-commonlib/compat/services/implements/injectable/InjectableServiceHub";
|
||||
import type { LiveSyncCore } from "@/main.ts";
|
||||
import { REMOTE_P2P } from "@vrtmrz/livesync-commonlib/compat/common/models/setting.const";
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
eventHub,
|
||||
} from "@/common/events.ts";
|
||||
import { AbstractModule } from "@/modules/AbstractModule.ts";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { performDoctorConsultation, RebuildOptions } from "@vrtmrz/livesync-commonlib/compat/common/configForDoc";
|
||||
import { isValidPath } from "@/common/utils.ts";
|
||||
import { isMetaEntry } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type Editor, type MarkdownFileInfo, type MarkdownView } from "@/deps.ts";
|
||||
import { addIcon } from "@/deps.ts";
|
||||
import { type FilePathWithPrefix } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import type { LiveSyncCore } from "@/main.ts";
|
||||
import { AbstractModule } from "@/modules/AbstractModule.ts";
|
||||
// Obsidian specific menu commands.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { delay } from "octagonal-wheels/promises";
|
||||
import { __onMissingTranslation } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { __onMissingTranslation } from "@/common/translation";
|
||||
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
|
||||
import { LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||
// import { enableTestFunction } from "./devUtil/testUtils.ts";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { logMessages } from "@vrtmrz/livesync-commonlib/compat/mock_and_interop/stores";
|
||||
import { reactive, type ReactiveInstance } from "octagonal-wheels/dataobject/reactive";
|
||||
import { Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger";
|
||||
import { $msg as msg, currentLang as lang } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg as msg, currentLang as lang } from "@/common/translation";
|
||||
import { compatGlobal } from "@vrtmrz/livesync-commonlib/compat/common/coreEnvFunctions";
|
||||
|
||||
let unsubscribe: () => void;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { WorkspaceLeaf } from "@/deps.ts";
|
||||
import LogPaneComponent from "./LogPane.svelte";
|
||||
import type ObsidianLiveSyncPlugin from "@/main.ts";
|
||||
import { SvelteItemView } from "@/common/SvelteItemView.ts";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { mount } from "svelte";
|
||||
export const VIEW_TYPE_LOG = "log-log";
|
||||
//Log view
|
||||
|
||||
@@ -29,7 +29,7 @@ import { addIcon, debounce, normalizePath, Notice, stringifyYaml, type Workspace
|
||||
import { LOG_LEVEL_NOTICE, setGlobalLogFunction } from "octagonal-wheels/common/logger";
|
||||
import { LogPaneView, VIEW_TYPE_LOG } from "./Log/LogPaneView.ts";
|
||||
import { serialized } from "octagonal-wheels/concurrency/lock";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { P2PLogCollector } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/P2PLogCollector";
|
||||
import {
|
||||
REMOTE_REQUEST_ACTIVITY_MINIMUM_VISIBLE_MS,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
type AllNumericItemKey,
|
||||
type AllBooleanItemKey,
|
||||
} from "./settingConstants.ts";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { wrapMemo, type AutoWireOption, type OnUpdateResult } from "./SettingPane.ts";
|
||||
|
||||
export class LiveSyncSetting extends Setting {
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
type OnDialogSettings,
|
||||
getConfName,
|
||||
} from "./settingConstants.ts";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
|
||||
import { fireAndForget, yieldNextAnimationFrame } from "octagonal-wheels/promises";
|
||||
import { EVENT_REQUEST_RELOAD_SETTING_TAB, eventHub } from "@/common/events.ts";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { $msg, $t } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { SUPPORTED_I18N_LANGS, type I18N_LANGS } from "@vrtmrz/livesync-commonlib/compat/common/rosetta";
|
||||
import { $msg, $t } from "@/common/translation";
|
||||
import { SUPPORTED_I18N_LANGS, type I18N_LANGS } from "@/common/rosetta";
|
||||
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
|
||||
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
|
||||
import type { PageFunctions } from "./SettingPane.ts";
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { createBlob, getFileRegExp, isDocContentSame, readAsBlob } from "@vrtmrz/livesync-commonlib/compat/common/utils";
|
||||
import { Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger";
|
||||
import { addPrefix, shouldBeIgnored, stripAllPrefixes } from "@vrtmrz/livesync-commonlib/compat/string_and_binary/path";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
||||
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
|
||||
import {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
LOG_LEVEL_VERBOSE,
|
||||
} from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { Menu, type ButtonComponent } from "@/deps.ts";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
|
||||
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
|
||||
import type { PageFunctions } from "./SettingPane.ts";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MarkdownRenderer } from "@/deps.ts";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
|
||||
import { fireAndForget } from "octagonal-wheels/promises";
|
||||
import {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type ObsidianLiveSyncSettings, LOG_LEVEL_NOTICE, REMOTE_COUCHDB, LEVEL_ADVANCED } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
|
||||
import { EVENT_REQUEST_COPY_SETUP_URI, eventHub } from "@/common/events.ts";
|
||||
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { LEVEL_ADVANCED, LEVEL_EDGE_CASE, LEVEL_POWER_USER, type ConfigLevel } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import type { AllSettingItemKey, AllSettings } from "./settingConstants";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { requestToCouchDBWithCredentials } from "@/common/utils";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import {
|
||||
LOG_LEVEL_INFO,
|
||||
LOG_LEVEL_NOTICE,
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
applySettingsAndFetchOnActivation,
|
||||
applySettingsWithScheduledInitialisation,
|
||||
} from "@/serviceFeatures/setupObsidian/setupActivationLifecycle.ts";
|
||||
import { isP2PMainRemote } from "@/common/remoteConfiguration.ts";
|
||||
|
||||
function copySettingsForRemoteProfileUpdate(settings: ObsidianLiveSyncSettings): ObsidianLiveSyncSettings {
|
||||
return {
|
||||
@@ -368,10 +369,7 @@ export class SetupManager extends AbstractModule {
|
||||
userMode = UserMode.ExistingUser;
|
||||
} else if (userModeResult === "compatible-existing-user") {
|
||||
extra();
|
||||
const applied = await this.applySettingAndScheduleFetchOnActivation(
|
||||
newConf,
|
||||
UserMode.ExistingUser
|
||||
);
|
||||
const applied = await this.applySettingAndScheduleFetchOnActivation(newConf, UserMode.ExistingUser);
|
||||
if (applied) this._log("Settings from wizard applied.", LOG_LEVEL_NOTICE);
|
||||
return applied;
|
||||
} else if (userModeResult === "cancelled") {
|
||||
@@ -382,8 +380,9 @@ export class SetupManager extends AbstractModule {
|
||||
}
|
||||
const component = userMode === UserMode.NewUser ? OutroNewUser : OutroExistingUser;
|
||||
const confirm = await this.dialogManager.openWithExplicitCancel<
|
||||
OutroNewUserResultType | OutroExistingUserResultType
|
||||
>(component);
|
||||
OutroNewUserResultType | OutroExistingUserResultType,
|
||||
{ isP2P: boolean }
|
||||
>(component, { isP2P: isP2PMainRemote(newConf) });
|
||||
if (confirm === "cancelled") {
|
||||
this._log("User cancelled applying settings from wizard..", LOG_LEVEL_NOTICE);
|
||||
return false;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
DEFAULT_SETTINGS,
|
||||
REMOTE_COUCHDB,
|
||||
REMOTE_P2P,
|
||||
type ObsidianLiveSyncSettings,
|
||||
} from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { SettingService } from "@vrtmrz/livesync-commonlib/compat/services/base/SettingService";
|
||||
@@ -194,6 +195,37 @@ describe("SetupManager", () => {
|
||||
expect(setting.currentSettings().isConfigured).toBe(true);
|
||||
});
|
||||
|
||||
it("identifies P2P when opening the new-user initialisation confirmation", async () => {
|
||||
const { manager, setting, dialogManager } = createSetupManager();
|
||||
setting.settings = { ...setting.currentSettings(), isConfigured: false };
|
||||
dialogManager.openWithExplicitCancel.mockResolvedValueOnce(true);
|
||||
const p2pProfileId = "p2p-profile";
|
||||
|
||||
await manager.onConfirmApplySettingsFromWizard(
|
||||
{
|
||||
...setting.currentSettings(),
|
||||
isConfigured: true,
|
||||
// Imported profile settings can still carry the previous compatibility field
|
||||
// until the selected profile is projected by the setting lifecycle.
|
||||
remoteType: REMOTE_COUCHDB,
|
||||
activeConfigurationId: p2pProfileId,
|
||||
remoteConfigurations: {
|
||||
[p2pProfileId]: {
|
||||
id: p2pProfileId,
|
||||
name: "P2P room",
|
||||
uri: "sls+p2p://:secret@team-room?relays=wss%3A%2F%2Frelay.example",
|
||||
isEncrypted: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
UserMode.NewUser
|
||||
);
|
||||
|
||||
expect(dialogManager.openWithExplicitCancel).toHaveBeenCalledWith(expect.anything(), {
|
||||
isP2P: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("reserves Fetch when compatible imported settings activate an unconfigured device", async () => {
|
||||
const { manager, setting, dialogManager, core } = createSetupManager();
|
||||
setting.settings = { ...setting.currentSettings(), isConfigured: false };
|
||||
|
||||
@@ -5,33 +5,59 @@
|
||||
import Question from "@/modules/services/LiveSyncUI/components/Question.svelte";
|
||||
import Instruction from "@/modules/services/LiveSyncUI/components/Instruction.svelte";
|
||||
import UserDecisions from "@/modules/services/LiveSyncUI/components/UserDecisions.svelte";
|
||||
import { $msg as msg } from "@/common/translation";
|
||||
import { TYPE_APPLY, TYPE_CANCELLED, type OutroNewUserResultType } from "./setupDialogTypes";
|
||||
|
||||
type Props = {
|
||||
setResult: (result: OutroNewUserResultType) => void;
|
||||
getInitialData?: () => { isP2P?: boolean } | undefined;
|
||||
};
|
||||
const { setResult }: Props = $props();
|
||||
const { setResult, getInitialData }: Props = $props();
|
||||
const isP2P = $derived(getInitialData?.()?.isP2P === true);
|
||||
// let userType = $state<OutroNewUserResultType>(TYPE_CANCELLED);
|
||||
</script>
|
||||
|
||||
<DialogHeader title="Setup Complete: Preparing to Initialise Server" />
|
||||
<Guidance>
|
||||
<p>
|
||||
The connection to the server has been configured successfully. As the next step, <strong
|
||||
>the synchronisation data on the server will be built based on the current data on this device.</strong
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<strong>IMPORTANT</strong>
|
||||
<br />
|
||||
After restarting, the data on this device will be uploaded to the server as the 'master copy'. Please be aware that
|
||||
any unintended data currently on the server will be completely overwritten.
|
||||
</p>
|
||||
</Guidance>
|
||||
<Instruction>
|
||||
<Question>Please select the button below to restart and proceed to the final confirmation.</Question>
|
||||
</Instruction>
|
||||
<UserDecisions>
|
||||
<Decision title="Restart and Initialise Server" important={true} commit={() => setResult(TYPE_APPLY)} />
|
||||
<Decision title="No, please take me back" commit={() => setResult(TYPE_CANCELLED)} />
|
||||
</UserDecisions>
|
||||
{#if isP2P}
|
||||
<DialogHeader title={msg("Ui.SetupWizard.OutroNewP2PUser.Title")} />
|
||||
<Guidance>
|
||||
<p>{msg("Ui.SetupWizard.OutroNewP2PUser.GuidancePrimary")}</p>
|
||||
<p>
|
||||
<strong>{msg("Ui.SetupWizard.OutroNewP2PUser.Important")}</strong>
|
||||
<br />
|
||||
{msg("Ui.SetupWizard.OutroNewP2PUser.GuidanceNotice")}
|
||||
</p>
|
||||
</Guidance>
|
||||
<Instruction>
|
||||
<Question>{msg("Ui.SetupWizard.OutroNewP2PUser.Question")}</Question>
|
||||
</Instruction>
|
||||
<UserDecisions>
|
||||
<Decision
|
||||
title={msg("Ui.SetupWizard.OutroNewP2PUser.Proceed")}
|
||||
important={true}
|
||||
commit={() => setResult(TYPE_APPLY)}
|
||||
/>
|
||||
<Decision title="No, please take me back" commit={() => setResult(TYPE_CANCELLED)} />
|
||||
</UserDecisions>
|
||||
{:else}
|
||||
<DialogHeader title="Setup Complete: Preparing to Initialise Server" />
|
||||
<Guidance>
|
||||
<p>
|
||||
The connection to the server has been configured successfully. As the next step, <strong
|
||||
>the synchronisation data on the server will be built based on the current data on this device.</strong
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<strong>IMPORTANT</strong>
|
||||
<br />
|
||||
After restarting, the data on this device will be uploaded to the server as the 'master copy'. Please be aware
|
||||
that any unintended data currently on the server will be completely overwritten.
|
||||
</p>
|
||||
</Guidance>
|
||||
<Instruction>
|
||||
<Question>Please select the button below to restart and proceed to the final confirmation.</Question>
|
||||
</Instruction>
|
||||
<UserDecisions>
|
||||
<Decision title="Restart and Initialise Server" important={true} commit={() => setResult(TYPE_APPLY)} />
|
||||
<Decision title="No, please take me back" commit={() => setResult(TYPE_CANCELLED)} />
|
||||
</UserDecisions>
|
||||
{/if}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import InfoNote from "@/modules/services/LiveSyncUI/components/InfoNote.svelte";
|
||||
import ExtraItems from "@/modules/services/LiveSyncUI/components/ExtraItems.svelte";
|
||||
import Check from "@/modules/services/LiveSyncUI/components/Check.svelte";
|
||||
import { $msg as msg } from "@/common/translation";
|
||||
import {
|
||||
TYPE_CANCEL,
|
||||
TYPE_BACKUP_DONE,
|
||||
@@ -21,20 +22,19 @@
|
||||
|
||||
type Props = {
|
||||
setResult: (result: RebuildEverythingResult) => void;
|
||||
getInitialData?: () => { isP2P?: boolean } | undefined;
|
||||
};
|
||||
const { setResult }: Props = $props();
|
||||
const { setResult, getInitialData }: Props = $props();
|
||||
const isP2P = $derived(getInitialData?.()?.isP2P === true);
|
||||
|
||||
let backupType = $state<ResultTypeBackup>(TYPE_CANCEL);
|
||||
let confirmationCheck1 = $state(false);
|
||||
let confirmationCheck2 = $state(false);
|
||||
let confirmationCheck3 = $state(false);
|
||||
const canProceed = $derived.by(() => {
|
||||
return (
|
||||
(backupType === TYPE_BACKUP_DONE || backupType === TYPE_BACKUP_SKIPPED) &&
|
||||
confirmationCheck1 &&
|
||||
confirmationCheck2 &&
|
||||
confirmationCheck3
|
||||
);
|
||||
const backupConfirmed = backupType === TYPE_BACKUP_DONE || backupType === TYPE_BACKUP_SKIPPED;
|
||||
if (isP2P) return backupConfirmed && confirmationCheck1;
|
||||
return backupConfirmed && confirmationCheck1 && confirmationCheck2 && confirmationCheck3;
|
||||
});
|
||||
let preventFetchingConfig = $state(false);
|
||||
|
||||
@@ -48,33 +48,44 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<DialogHeader title="Final Confirmation: Overwrite Server Data with This Device's Files" />
|
||||
<Guidance
|
||||
>This procedure will first delete all existing synchronisation data from the server. Following this, the server data
|
||||
will be completely rebuilt, using the current state of your Vault on this device (including its local database) as
|
||||
<strong>the single, authoritative master copy</strong>.</Guidance
|
||||
>
|
||||
<InfoNote>
|
||||
You should perform this operation only in exceptional circumstances, such as when the server data is completely
|
||||
corrupted, when changes on all other devices are no longer needed, or when the database size has become unusually
|
||||
large in comparison to the Vault size.
|
||||
</InfoNote>
|
||||
<Guidance important title="⚠️ Please Confirm the Following">
|
||||
<Check
|
||||
title="I understand that all changes made on other smartphones or computers possibly could be lost."
|
||||
bind:value={confirmationCheck1}
|
||||
{#if isP2P}
|
||||
<DialogHeader title={msg("Ui.SetupWizard.RebuildEverythingP2P.Title")} />
|
||||
<Guidance>{msg("Ui.SetupWizard.RebuildEverythingP2P.Guidance")}</Guidance>
|
||||
<InfoNote>{msg("Ui.SetupWizard.RebuildEverythingP2P.Note")}</InfoNote>
|
||||
<Guidance important title={msg("Ui.SetupWizard.RebuildEverythingP2P.ConfirmTitle")}>
|
||||
<Check title={msg("Ui.SetupWizard.RebuildEverythingP2P.ConfirmLocalReset")} bind:value={confirmationCheck1}>
|
||||
<InfoNote>{msg("Ui.SetupWizard.RebuildEverythingP2P.ConfirmLocalResetNote")}</InfoNote>
|
||||
</Check>
|
||||
</Guidance>
|
||||
{:else}
|
||||
<DialogHeader title="Final Confirmation: Overwrite Server Data with This Device's Files" />
|
||||
<Guidance
|
||||
>This procedure will first delete all existing synchronisation data from the server. Following this, the server
|
||||
data will be completely rebuilt, using the current state of your Vault on this device (including its local
|
||||
database) as <strong>the single, authoritative master copy</strong>.</Guidance
|
||||
>
|
||||
<InfoNote>There is a way to resolve this on other devices.</InfoNote>
|
||||
<InfoNote>Of course, we can back up the data before proceeding.</InfoNote>
|
||||
</Check>
|
||||
<Check
|
||||
title="I understand that other devices will no longer be able to synchronise, and will need to be reset the synchronisation information."
|
||||
bind:value={confirmationCheck2}
|
||||
>
|
||||
<InfoNote>by resetting the remote, you will be informed on other devices.</InfoNote>
|
||||
</Check>
|
||||
<Check title="I understand that this action is irreversible once performed." bind:value={confirmationCheck3} />
|
||||
</Guidance>
|
||||
<InfoNote>
|
||||
You should perform this operation only in exceptional circumstances, such as when the server data is completely
|
||||
corrupted, when changes on all other devices are no longer needed, or when the database size has become unusually
|
||||
large in comparison to the Vault size.
|
||||
</InfoNote>
|
||||
<Guidance important title="⚠️ Please Confirm the Following">
|
||||
<Check
|
||||
title="I understand that all changes made on other smartphones or computers possibly could be lost."
|
||||
bind:value={confirmationCheck1}
|
||||
>
|
||||
<InfoNote>There is a way to resolve this on other devices.</InfoNote>
|
||||
<InfoNote>Of course, we can back up the data before proceeding.</InfoNote>
|
||||
</Check>
|
||||
<Check
|
||||
title="I understand that other devices will no longer be able to synchronise, and will need to be reset the synchronisation information."
|
||||
bind:value={confirmationCheck2}
|
||||
>
|
||||
<InfoNote>by resetting the remote, you will be informed on other devices.</InfoNote>
|
||||
</Check>
|
||||
<Check title="I understand that this action is irreversible once performed." bind:value={confirmationCheck3} />
|
||||
</Guidance>
|
||||
{/if}
|
||||
<hr />
|
||||
<Instruction>
|
||||
<Question>Have you created a backup before proceeding?</Question>
|
||||
@@ -103,12 +114,19 @@
|
||||
</Option>
|
||||
</Options>
|
||||
</Instruction>
|
||||
<Instruction>
|
||||
<ExtraItems title="Advanced">
|
||||
<Check title="Prevent fetching configuration from server" bind:value={preventFetchingConfig} />
|
||||
</ExtraItems>
|
||||
</Instruction>
|
||||
{#if !isP2P}
|
||||
<Instruction>
|
||||
<ExtraItems title="Advanced">
|
||||
<Check title="Prevent fetching configuration from server" bind:value={preventFetchingConfig} />
|
||||
</ExtraItems>
|
||||
</Instruction>
|
||||
{/if}
|
||||
<UserDecisions>
|
||||
<Decision title="I Understand, Overwrite Server" important disabled={!canProceed} commit={() => commit()} />
|
||||
<Decision
|
||||
title={isP2P ? msg("Ui.SetupWizard.RebuildEverythingP2P.Proceed") : "I Understand, Overwrite Server"}
|
||||
important
|
||||
disabled={!canProceed}
|
||||
commit={() => commit()}
|
||||
/>
|
||||
<Decision title="Cancel" commit={() => setResult(TYPE_CANCEL)} />
|
||||
</UserDecisions>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { requestToCouchDBWithCredentials } from "@/common/utils";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import { Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger";
|
||||
import type { ObsidianLiveSyncSettings } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { parseHeaderValues } from "@vrtmrz/livesync-commonlib/compat/common/utils";
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
EVENT_SETTING_SAVED,
|
||||
eventHub,
|
||||
} from "@/common/events.ts";
|
||||
import { $msg, setLang } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg, setLang } from "@/common/translation";
|
||||
import { AbstractModule } from "@/modules/AbstractModule.ts";
|
||||
import type { InjectableServiceHub } from "@vrtmrz/livesync-commonlib/compat/services/implements/injectable/InjectableServiceHub";
|
||||
import type { LiveSyncCore } from "@/main.ts";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
import { fireAndForget } from "octagonal-wheels/promises";
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount, tick } from "svelte";
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
import { getDialogContext } from "@/modules/services/LiveSyncUI/svelteDialog";
|
||||
import { _activeDocument } from "@vrtmrz/livesync-commonlib/compat/common/coreEnvFunctions";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
|
||||
type Props = {
|
||||
title?: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
|
||||
type Props = {
|
||||
children?: () => any;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
|
||||
type SignalWord = "danger" | "warning" | "caution" | "notice";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
|
||||
type Props = {
|
||||
label: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translateIfAvailable as translate } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { translateIfAvailable as translate } from "@/common/translation";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { type App, type Plugin, Notice } from "@/deps";
|
||||
import { scheduleTask, memoIfNotExist, memoObject, retrieveMemoObject, disposeMemoObject } from "@/common/utils";
|
||||
import { EVENT_PLUGIN_UNLOADED } from "@/common/events";
|
||||
import { $msg } from "@vrtmrz/livesync-commonlib/compat/common/i18n";
|
||||
import { $msg } from "@/common/translation";
|
||||
import type { Confirm, ConfirmActionLayout } from "@vrtmrz/livesync-commonlib/compat/interfaces/Confirm";
|
||||
import { confirmAction, pickOne, promptPassword, promptText } from "@vrtmrz/obsidian-plugin-kit";
|
||||
import type { ObsidianServiceContext } from "@/modules/services/ObsidianServiceContext";
|
||||
import {
|
||||
confirmWithMessageWithWideButton,
|
||||
confirmWithMessage as confirmWithLegacyMessage,
|
||||
} from "@/modules/coreObsidian/UILib/dialogs";
|
||||
import { confirmWithMessageWithWideButton } from "@/modules/coreObsidian/UILib/dialogs";
|
||||
|
||||
export class ObsidianConfirm<T extends ObsidianServiceContext = ObsidianServiceContext> implements Confirm {
|
||||
private _context: T;
|
||||
@@ -49,6 +46,7 @@ export class ObsidianConfirm<T extends ObsidianServiceContext = ObsidianServiceC
|
||||
yes: $msg("moduleInputUIObsidian.optionYes"),
|
||||
no: $msg("moduleInputUIObsidian.optionNo"),
|
||||
},
|
||||
actionLayout: "vertical",
|
||||
defaultAction: "no",
|
||||
sourcePath: "/",
|
||||
},
|
||||
@@ -92,6 +90,7 @@ export class ObsidianConfirm<T extends ObsidianServiceContext = ObsidianServiceC
|
||||
message,
|
||||
actions: ["Yes", "No"] as const,
|
||||
labels: { Yes: yesLabel, No: noLabel },
|
||||
actionLayout: "vertical",
|
||||
defaultAction: opt.defaultOption === "Yes" ? "Yes" : "No",
|
||||
sourcePath: "/",
|
||||
},
|
||||
@@ -136,6 +135,7 @@ export class ObsidianConfirm<T extends ObsidianServiceContext = ObsidianServiceC
|
||||
title: opt.title || defaultTitle,
|
||||
message,
|
||||
actions: buttons,
|
||||
actionLayout: "vertical",
|
||||
defaultAction: opt.defaultAction,
|
||||
sourcePath: "/",
|
||||
},
|
||||
@@ -210,7 +210,7 @@ export class ObsidianConfirm<T extends ObsidianServiceContext = ObsidianServiceC
|
||||
actionLayout?: ConfirmActionLayout
|
||||
): Promise<(typeof buttons)[number] | false> {
|
||||
if (this.hasCountdown(timeout)) {
|
||||
return confirmWithLegacyMessage(this._plugin, title, contentMd, buttons, defaultAction, timeout);
|
||||
return confirmWithMessageWithWideButton(this._plugin, title, contentMd, buttons, defaultAction, timeout);
|
||||
}
|
||||
const result = await confirmAction(
|
||||
this._app,
|
||||
@@ -220,7 +220,7 @@ export class ObsidianConfirm<T extends ObsidianServiceContext = ObsidianServiceC
|
||||
actions: buttons,
|
||||
defaultAction,
|
||||
sourcePath: "/",
|
||||
...(actionLayout === undefined ? {} : { actionLayout }),
|
||||
actionLayout: actionLayout ?? "vertical",
|
||||
},
|
||||
this.dialogueLifecycle
|
||||
);
|
||||
|
||||
@@ -93,6 +93,7 @@ describe("ObsidianConfirm Fancy Kit adapter", () => {
|
||||
expect.objectContaining({
|
||||
message: "Continue?",
|
||||
actions: ["yes", "no"],
|
||||
actionLayout: "vertical",
|
||||
defaultAction: "no",
|
||||
}),
|
||||
{ signal: expect.any(AbortSignal) }
|
||||
@@ -109,15 +110,14 @@ describe("ObsidianConfirm Fancy Kit adapter", () => {
|
||||
expect(mocks.legacyAskSelectString).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses Kit for untimed action dialogues and retains the legacy countdown path", async () => {
|
||||
it("keeps untimed and countdown action dialogues vertically stacked", async () => {
|
||||
const { confirm, app, plugin } = createConfirm();
|
||||
mocks.confirmAction.mockResolvedValueOnce("Apply").mockResolvedValueOnce("Yes");
|
||||
mocks.legacyConfirm.mockResolvedValueOnce("Cancel");
|
||||
mocks.legacyWideConfirm.mockResolvedValueOnce("No");
|
||||
mocks.legacyWideConfirm.mockResolvedValueOnce("Cancel").mockResolvedValueOnce("No");
|
||||
|
||||
await expect(
|
||||
confirm.confirmWithMessage("Review", "**Apply?**", ["Apply", "Cancel"], "Cancel", undefined, "vertical")
|
||||
).resolves.toBe("Apply");
|
||||
await expect(confirm.confirmWithMessage("Review", "**Apply?**", ["Apply", "Cancel"], "Cancel")).resolves.toBe(
|
||||
"Apply"
|
||||
);
|
||||
await expect(confirm.askYesNoDialog("Continue?", { title: "Question", defaultOption: "Yes" })).resolves.toBe(
|
||||
"yes"
|
||||
);
|
||||
@@ -139,8 +139,29 @@ describe("ObsidianConfirm Fancy Kit adapter", () => {
|
||||
},
|
||||
{ signal: expect.any(AbortSignal) }
|
||||
);
|
||||
expect(mocks.legacyConfirm).toHaveBeenCalledWith(plugin, "Timed", "Wait", ["Apply", "Cancel"], "Cancel", 30);
|
||||
expect(mocks.legacyWideConfirm).toHaveBeenCalledWith(
|
||||
expect(mocks.confirmAction).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
app,
|
||||
expect.objectContaining({
|
||||
title: "Question",
|
||||
message: "Continue?",
|
||||
actions: ["Yes", "No"],
|
||||
actionLayout: "vertical",
|
||||
defaultAction: "Yes",
|
||||
}),
|
||||
{ signal: expect.any(AbortSignal) }
|
||||
);
|
||||
expect(mocks.legacyWideConfirm).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
plugin,
|
||||
"Timed",
|
||||
"Wait",
|
||||
["Apply", "Cancel"],
|
||||
"Cancel",
|
||||
30
|
||||
);
|
||||
expect(mocks.legacyWideConfirm).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
plugin,
|
||||
expect.any(String),
|
||||
"Timed?",
|
||||
@@ -148,6 +169,7 @@ describe("ObsidianConfirm Fancy Kit adapter", () => {
|
||||
expect.any(String),
|
||||
10
|
||||
);
|
||||
expect(mocks.legacyConfirm).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses Kit for untimed multi-action selection and keeps timed wide actions on the countdown dialogue", async () => {
|
||||
@@ -176,6 +198,7 @@ describe("ObsidianConfirm Fancy Kit adapter", () => {
|
||||
title: "Next step",
|
||||
message: "Choose the next step",
|
||||
actions,
|
||||
actionLayout: "vertical",
|
||||
defaultAction: "Review later",
|
||||
sourcePath: "/",
|
||||
},
|
||||
|
||||
@@ -26,6 +26,7 @@ import { createScreenWakeLockManager } from "octagonal-wheels/browser/wakeLock";
|
||||
import { PouchDB } from "@vrtmrz/livesync-commonlib/compat/pouchdb/pouchdb-browser";
|
||||
import { OpenKeyValueDatabase } from "@/common/KeyValueDB";
|
||||
import { ObsidianNoticeGroupManager } from "./ObsidianNoticeGroups";
|
||||
import { setLang } from "@/common/translation";
|
||||
|
||||
// InjectableServiceHub
|
||||
|
||||
@@ -42,6 +43,7 @@ export class ObsidianServiceHub extends InjectableServiceHub<ObsidianServiceCont
|
||||
|
||||
const setting = new ObsidianSettingService(context, {
|
||||
APIService: API,
|
||||
onDisplayLanguageChanged: setLang,
|
||||
});
|
||||
const appLifecycle = new ObsidianAppLifecycleService(context, {
|
||||
settingService: setting,
|
||||
|
||||
Reference in New Issue
Block a user