This commit is contained in:
fyears 2022-04-06 00:24:27 +08:00
parent b39544b43b
commit b3c107ce58
19 changed files with 359 additions and 45 deletions

View File

@ -84,6 +84,7 @@ export interface RemotelySavePluginSettings {
syncConfigDir?: boolean; syncConfigDir?: boolean;
syncUnderscoreItems?: boolean; syncUnderscoreItems?: boolean;
lang?: LangTypeAndAuto; lang?: LangTypeAndAuto;
logToDB?: boolean;
/** /**
* @deprecated * @deprecated
@ -156,3 +157,8 @@ export const API_VER_STAT_FOLDER = "0.13.27";
export const API_VER_REQURL = "0.13.26"; export const API_VER_REQURL = "0.13.26";
export const VALID_REQURL = export const VALID_REQURL =
requireApiVersion(API_VER_REQURL) && !Platform.isAndroidApp; requireApiVersion(API_VER_REQURL) && !Platform.isAndroidApp;
export const DEFAULT_DEBUG_FOLDER = "_debug_remotely_save/";
export const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX =
"sync_plans_hist_exported_on_";
export const DEFAULT_LOG_HISTORY_FILE_PREFIX = "log_hist_exported_on_";

View File

@ -3,8 +3,7 @@ import { reverseString } from "./misc";
import type { RemotelySavePluginSettings } from "./baseTypes"; import type { RemotelySavePluginSettings } from "./baseTypes";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
const DEFAULT_README: string = const DEFAULT_README: string =
"The file contains sensitive info, so DO NOT take screenshot of, copy, or share it to anyone! It's also generated automatically, so do not edit it manually."; "The file contains sensitive info, so DO NOT take screenshot of, copy, or share it to anyone! It's also generated automatically, so do not edit it manually.";

View File

@ -1,15 +1,19 @@
import { TAbstractFile, TFolder, TFile, Vault } from "obsidian"; import { TAbstractFile, TFolder, TFile, Vault } from "obsidian";
import type { SyncPlanType } from "./sync"; import type { SyncPlanType } from "./sync";
import { readAllSyncPlanRecordTextsByVault } from "./localdb"; import {
readAllSyncPlanRecordTextsByVault,
readAllLogRecordTextsByVault,
} from "./localdb";
import type { InternalDBs } from "./localdb"; import type { InternalDBs } from "./localdb";
import { mkdirpInVault } from "./misc"; import { mkdirpInVault } from "./misc";
import {
DEFAULT_DEBUG_FOLDER,
DEFAULT_LOG_HISTORY_FILE_PREFIX,
DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX,
} from "./baseTypes";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
const DEFAULT_DEBUG_FOLDER = "_debug_remotely_save/";
const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX = "sync_plans_hist_exported_on_";
export const exportVaultSyncPlansToFiles = async ( export const exportVaultSyncPlansToFiles = async (
db: InternalDBs, db: InternalDBs,
@ -34,3 +38,27 @@ export const exportVaultSyncPlansToFiles = async (
}); });
log.info("finish exporting"); log.info("finish exporting");
}; };
export const exportVaultLoggerOutputToFiles = async (
db: InternalDBs,
vault: Vault,
vaultRandomID: string
) => {
await mkdirpInVault(DEFAULT_DEBUG_FOLDER, vault);
const records = await readAllLogRecordTextsByVault(db, vaultRandomID);
let md = "";
if (records.length === 0) {
md = "No logger history found.";
} else {
md =
"Logger history found:\n\n" +
"```text\n" +
records.join("\n") +
"\n```\n";
}
const ts = Date.now();
const filePath = `${DEFAULT_DEBUG_FOLDER}${DEFAULT_LOG_HISTORY_FILE_PREFIX}${ts}.md`;
await vault.create(filePath, md, {
mtime: ts,
});
};

View File

@ -1,8 +1,7 @@
import { base32, base64url } from "rfc4648"; import { base32, base64url } from "rfc4648";
import { bufferToArrayBuffer, hexStringToTypedArray } from "./misc"; import { bufferToArrayBuffer, hexStringToTypedArray } from "./misc";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
const DEFAULT_ITER = 20000; const DEFAULT_ITER = 20000;

View File

@ -7,8 +7,7 @@ import {
RemotelySavePluginSettings, RemotelySavePluginSettings,
} from "./baseTypes"; } from "./baseTypes";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
export const exportQrCodeUri = async ( export const exportQrCodeUri = async (
settings: RemotelySavePluginSettings, settings: RemotelySavePluginSettings,

@ -1 +1 @@
Subproject commit 75a3b2a830c5e3286fa26a0c13178505f7ff5cac Subproject commit 2afc10b080356dc8d25e77105838fcfc91f072c6

View File

@ -1,14 +1,13 @@
import localforage from "localforage"; import localforage from "localforage";
export type LocalForage = typeof localforage;
import { nanoid } from "nanoid";
import { requireApiVersion, TAbstractFile, TFile, TFolder } from "obsidian"; import { requireApiVersion, TAbstractFile, TFile, TFolder } from "obsidian";
import { API_VER_STAT_FOLDER, SUPPORTED_SERVICES_TYPE } from "./baseTypes"; import { API_VER_STAT_FOLDER, SUPPORTED_SERVICES_TYPE } from "./baseTypes";
import type { SyncPlanType } from "./sync"; import type { SyncPlanType } from "./sync";
import { toText, unixTimeToStr } from "./misc";
export type LocalForage = typeof localforage; import { log } from "./moreOnLog";
import * as origLog from "loglevel";
import { nanoid } from "nanoid";
const log = origLog.getLogger("rs-default");
const DB_VERSION_NUMBER_IN_HISTORY = [20211114, 20220108, 20220326]; const DB_VERSION_NUMBER_IN_HISTORY = [20211114, 20220108, 20220326];
export const DEFAULT_DB_VERSION_NUMBER: number = 20220326; export const DEFAULT_DB_VERSION_NUMBER: number = 20220326;
@ -18,6 +17,7 @@ export const DEFAULT_TBL_FILE_HISTORY = "filefolderoperationhistory";
export const DEFAULT_TBL_SYNC_MAPPING = "syncmetadatahistory"; export const DEFAULT_TBL_SYNC_MAPPING = "syncmetadatahistory";
export const DEFAULT_SYNC_PLANS_HISTORY = "syncplanshistory"; export const DEFAULT_SYNC_PLANS_HISTORY = "syncplanshistory";
export const DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING = "vaultrandomidmapping"; export const DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING = "vaultrandomidmapping";
export const DEFAULT_TBL_LOGGER_OUTPUT = "loggeroutput";
export interface FileFolderHistoryRecord { export interface FileFolderHistoryRecord {
key: string; key: string;
@ -57,6 +57,7 @@ export interface InternalDBs {
syncMappingTbl: LocalForage; syncMappingTbl: LocalForage;
syncPlansTbl: LocalForage; syncPlansTbl: LocalForage;
vaultRandomIDMappingTbl: LocalForage; vaultRandomIDMappingTbl: LocalForage;
loggerOutputTbl: LocalForage;
} }
/** /**
@ -211,6 +212,10 @@ export const prepareDBs = async (
name: DEFAULT_DB_NAME, name: DEFAULT_DB_NAME,
storeName: DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING, storeName: DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING,
}), }),
loggerOutputTbl: localforage.createInstance({
name: DEFAULT_DB_NAME,
storeName: DEFAULT_TBL_LOGGER_OUTPUT,
}),
} as InternalDBs; } as InternalDBs;
// try to get vaultRandomID firstly // try to get vaultRandomID firstly
@ -546,3 +551,91 @@ export const readAllSyncPlanRecordTextsByVault = async (
return records.map((x) => x.syncPlan); return records.map((x) => x.syncPlan);
} }
}; };
export const readAllLogRecordTextsByVault = async (
db: InternalDBs,
vaultRandomID: string
) => {
const records = [] as { ts: number; r: string }[];
await db.loggerOutputTbl.iterate((value, key, iterationNumber) => {
if (key.startsWith(`${vaultRandomID}\t`)) {
const item = {
ts: parseInt(key.split("\t")[1]),
r: value as string,
};
records.push(item);
}
});
// while reading the logs, we want it to be ascending
records.sort((a, b) => a.ts - b.ts);
if (records === undefined) {
return [] as string[];
} else {
return records.map((x) => x.r);
}
};
export const insertLoggerOutputByVault = async (
db: InternalDBs,
vaultRandomID: string,
...msg: any[]
) => {
const ts = Date.now();
const tsFmt = unixTimeToStr(ts);
const key = `${vaultRandomID}\t${ts}`;
try {
const val = [`[${tsFmt}]`, ...msg.map((x) => toText(x))].join(" ");
db.loggerOutputTbl.setItem(key, val);
} catch (err) {
// give up, and let it pass
}
};
export const clearAllLoggerOutputRecords = async (db: InternalDBs) => {
await db.loggerOutputTbl.clear();
};
/**
* We remove records that are older than 7 days or 10000 records.
* It's a heavy operation, so we shall not place it in the start up.
* @param db
*/
export const clearExpiredLoggerOutputRecords = async (db: InternalDBs) => {
const MILLISECONDS_OLD = 1000 * 60 * 60 * 24 * 7; // 7 days
const COUNT_TO_MANY = 10000;
const currTs = Date.now();
const expiredTs = currTs - MILLISECONDS_OLD;
let records = (await db.loggerOutputTbl.keys()).map((key) => {
const ts = parseInt(key.split("\t")[1]);
const expired = ts <= expiredTs;
return {
ts: ts,
key: key,
expired: expired,
};
});
const keysToRemove = new Set(
records.filter((x) => x.expired).map((x) => x.key)
);
if (records.length - keysToRemove.size > COUNT_TO_MANY) {
// we need to find out records beyond 10000 records
records = records.filter((x) => !x.expired); // shrink the array
records.sort((a, b) => -(a.ts - b.ts)); // descending
records.slice(COUNT_TO_MANY).forEach((element) => {
keysToRemove.add(element.key);
});
}
const ps = [] as Promise<void>[];
keysToRemove.forEach((element) => {
ps.push(db.loggerOutputTbl.removeItem(element));
});
await Promise.all(ps);
};

View File

@ -24,6 +24,8 @@ import {
loadFileHistoryTableByVault, loadFileHistoryTableByVault,
prepareDBs, prepareDBs,
InternalDBs, InternalDBs,
insertLoggerOutputByVault,
clearExpiredLoggerOutputRecords,
} from "./localdb"; } from "./localdb";
import { RemoteClient } from "./remote"; import { RemoteClient } from "./remote";
import { import {
@ -48,11 +50,11 @@ import { ObsConfigDirFileType, listFilesInObsFolder } from "./obsFolderLister";
import { I18n } from "./i18n"; import { I18n } from "./i18n";
import type { LangType, LangTypeAndAuto, TransItemType } from "./i18n"; import type { LangType, LangTypeAndAuto, TransItemType } from "./i18n";
import * as origLog from "loglevel";
import { DeletionOnRemote, MetadataOnRemote } from "./metadataOnRemote"; import { DeletionOnRemote, MetadataOnRemote } from "./metadataOnRemote";
import { SyncAlgoV2Modal } from "./syncAlgoV2Notice"; import { SyncAlgoV2Modal } from "./syncAlgoV2Notice";
import { applyPresetRulesInplace } from "./presetRules"; import { applyPresetRulesInplace } from "./presetRules";
const log = origLog.getLogger("rs-default");
import { applyLogWriterInplace, log } from "./moreOnLog";
const DEFAULT_SETTINGS: RemotelySavePluginSettings = { const DEFAULT_SETTINGS: RemotelySavePluginSettings = {
s3: DEFAULT_S3_CONFIG, s3: DEFAULT_S3_CONFIG,
@ -70,6 +72,7 @@ const DEFAULT_SETTINGS: RemotelySavePluginSettings = {
syncConfigDir: false, syncConfigDir: false,
syncUnderscoreItems: false, syncUnderscoreItems: false,
lang: "auto", lang: "auto",
logToDB: false,
}; };
interface OAuth2Info { interface OAuth2Info {
@ -343,8 +346,8 @@ export default class RemotelySavePlugin extends Plugin {
triggerSource: triggerSource, triggerSource: triggerSource,
syncStatus: this.syncStatus, syncStatus: this.syncStatus,
}); });
log.info(msg); log.error(msg);
log.info(error); log.error(error);
getNotice(msg, 10 * 1000); getNotice(msg, 10 * 1000);
getNotice(error.message, 10 * 1000); getNotice(error.message, 10 * 1000);
this.syncStatus = "idle"; this.syncStatus = "idle";
@ -412,6 +415,10 @@ export default class RemotelySavePlugin extends Plugin {
throw err; throw err;
} }
// must AFTER preparing DB
this.addOutputToDBIfSet();
this.enableAutoClearOutputToDBHistIfSet();
this.syncStatus = "idle"; this.syncStatus = "idle";
this.registerEvent( this.registerEvent(
@ -911,4 +918,34 @@ export default class RemotelySavePlugin extends Plugin {
// just skip // just skip
} }
} }
addOutputToDBIfSet() {
if (this.settings.logToDB) {
applyLogWriterInplace((...msg: any[]) => {
insertLoggerOutputByVault(this.db, this.vaultRandomID, ...msg);
});
}
}
enableAutoClearOutputToDBHistIfSet() {
const initClearOutputToDBHistAfterMilliseconds = 1000 * 45;
const autoClearOutputToDBHistAfterMilliseconds = 1000 * 60 * 5;
this.app.workspace.onLayoutReady(() => {
// init run
window.setTimeout(() => {
if (this.settings.logToDB) {
clearExpiredLoggerOutputRecords(this.db);
}
}, initClearOutputToDBHistAfterMilliseconds);
// scheduled run
const intervalID = window.setInterval(() => {
if (this.settings.logToDB) {
clearExpiredLoggerOutputRecords(this.db);
}
}, autoClearOutputToDBHistAfterMilliseconds);
this.registerInterval(intervalID);
});
}
} }

View File

@ -4,8 +4,7 @@ import * as path from "path";
import { base32, base64url } from "rfc4648"; import { base32, base64url } from "rfc4648";
import XRegExp from "xregexp"; import XRegExp from "xregexp";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
declare global { declare global {
interface Window { interface Window {
@ -319,3 +318,64 @@ export const unixTimeToStr = (x: number | undefined | null) => {
} }
return window.moment(x).format() as string; return window.moment(x).format() as string;
}; };
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples
* @returns
*/
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key: any, value: any) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
/**
* Convert "any" value to string.
* @param x
* @returns
*/
export const toText = (x: any) => {
if (x === undefined || x === null) {
return `${x}`;
}
if (typeof x === "string") {
return x;
}
if (
x instanceof String ||
x instanceof Date ||
typeof x === "number" ||
typeof x === "bigint" ||
typeof x === "boolean"
) {
return `${x}`;
}
if (
x instanceof Error ||
(x &&
x.stack &&
x.message &&
typeof x.stack === "string" &&
typeof x.message === "string")
) {
return (x.stack || x.message) as string;
}
try {
const y = JSON.stringify(x, getCircularReplacer(), 2);
if (y !== undefined) {
return y;
}
throw new Error("not jsonable");
} catch {
return `${x}`;
}
};

34
src/moreOnLog.ts Normal file
View File

@ -0,0 +1,34 @@
// It's very dangerous for this file to depend on other files in the same project.
// We should avoid this situation as much as possible.
import { TAbstractFile, TFolder, TFile, Vault } from "obsidian";
import * as origLog from "loglevel";
import type { LogLevelNumbers, Logger, LogLevel, LogLevelDesc } from "loglevel";
const log2 = origLog.getLogger("rs-default");
const originalFactory = log2.methodFactory;
export const applyLogWriterInplace = function (writer: (...msg: any[]) => any) {
log2.methodFactory = function (
methodName: string,
logLevel: LogLevelNumbers,
loggerName: string | symbol
) {
const rawMethod = originalFactory(methodName, logLevel, loggerName);
return function (...msg: any[]) {
rawMethod.apply(undefined, msg);
writer(...msg);
};
};
log2.setLevel(log2.getLevel());
};
export const restoreLogWritterInplace = () => {
log2.methodFactory = originalFactory;
log2.setLevel(log2.getLevel());
};
export const log = log2;

View File

@ -3,9 +3,6 @@ import { Queue } from "@fyears/tsqueue";
import chunk from "lodash/chunk"; import chunk from "lodash/chunk";
import flatten from "lodash/flatten"; import flatten from "lodash/flatten";
import * as origLog from "loglevel";
const log = origLog.getLogger("rs-default");
export interface ObsConfigDirFileType { export interface ObsConfigDirFileType {
key: string; key: string;
ctime: number; ctime: number;

View File

@ -11,8 +11,7 @@ import * as onedrive from "./remoteForOnedrive";
import * as s3 from "./remoteForS3"; import * as s3 from "./remoteForS3";
import * as webdav from "./remoteForWebdav"; import * as webdav from "./remoteForWebdav";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
export class RemoteClient { export class RemoteClient {
readonly serviceType: SUPPORTED_SERVICES_TYPE; readonly serviceType: SUPPORTED_SERVICES_TYPE;

View File

@ -12,8 +12,7 @@ import { bufferToArrayBuffer, getFolderLevels, mkdirpInVault } from "./misc";
export { Dropbox } from "dropbox"; export { Dropbox } from "dropbox";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
export const DEFAULT_DROPBOX_CONFIG: DropboxConfig = { export const DEFAULT_DROPBOX_CONFIG: DropboxConfig = {
accessToken: "", accessToken: "",

View File

@ -6,7 +6,6 @@ import type {
User, User,
} from "@microsoft/microsoft-graph-types"; } from "@microsoft/microsoft-graph-types";
import cloneDeep from "lodash/cloneDeep"; import cloneDeep from "lodash/cloneDeep";
import * as origLog from "loglevel";
import { request, requestUrl, requireApiVersion, Vault } from "obsidian"; import { request, requestUrl, requireApiVersion, Vault } from "obsidian";
import { import {
API_VER_REQURL, API_VER_REQURL,
@ -24,7 +23,7 @@ import {
mkdirpInVault, mkdirpInVault,
} from "./misc"; } from "./misc";
const log = origLog.getLogger("rs-default"); import { log } from "./moreOnLog";
const SCOPES = ["User.Read", "Files.ReadWrite.AppFolder", "offline_access"]; const SCOPES = ["User.Read", "Files.ReadWrite.AppFolder", "offline_access"];
const REDIRECT_URI = `obsidian://${COMMAND_CALLBACK_ONEDRIVE}`; const REDIRECT_URI = `obsidian://${COMMAND_CALLBACK_ONEDRIVE}`;

View File

@ -39,8 +39,7 @@ import {
export { S3Client } from "@aws-sdk/client-s3"; export { S3Client } from "@aws-sdk/client-s3";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// special handler using Obsidian requestUrl // special handler using Obsidian requestUrl

View File

@ -9,8 +9,7 @@ import { RemoteItem, VALID_REQURL, WebdavConfig } from "./baseTypes";
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt"; import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
import { bufferToArrayBuffer, getPathFolder, mkdirpInVault } from "./misc"; import { bufferToArrayBuffer, getPathFolder, mkdirpInVault } from "./misc";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
import type { import type {
FileStat, FileStat,

View File

@ -9,18 +9,25 @@ import {
} from "obsidian"; } from "obsidian";
import { import {
API_VER_REQURL, API_VER_REQURL,
DEFAULT_DEBUG_FOLDER,
SUPPORTED_SERVICES_TYPE, SUPPORTED_SERVICES_TYPE,
SUPPORTED_SERVICES_TYPE_WITH_REMOTE_BASE_DIR, SUPPORTED_SERVICES_TYPE_WITH_REMOTE_BASE_DIR,
VALID_REQURL, VALID_REQURL,
WebdavAuthType, WebdavAuthType,
WebdavDepthType, WebdavDepthType,
} from "./baseTypes"; } from "./baseTypes";
import { exportVaultSyncPlansToFiles } from "./debugMode"; import {
exportVaultSyncPlansToFiles,
exportVaultLoggerOutputToFiles,
} from "./debugMode";
import { exportQrCodeUri } from "./importExport"; import { exportQrCodeUri } from "./importExport";
import { import {
clearAllSyncMetaMapping, clearAllSyncMetaMapping,
clearAllSyncPlanRecords, clearAllSyncPlanRecords,
destroyDBs, destroyDBs,
clearAllLoggerOutputRecords,
insertLoggerOutputByVault,
clearExpiredLoggerOutputRecords,
} from "./localdb"; } from "./localdb";
import type RemotelySavePlugin from "./main"; // unavoidable import type RemotelySavePlugin from "./main"; // unavoidable
import { RemoteClient } from "./remote"; import { RemoteClient } from "./remote";
@ -36,11 +43,14 @@ import {
} from "./remoteForOnedrive"; } from "./remoteForOnedrive";
import { messyConfigToNormal } from "./configPersist"; import { messyConfigToNormal } from "./configPersist";
import type { TransItemType } from "./i18n"; import type { TransItemType } from "./i18n";
import * as origLog from "loglevel";
import { checkHasSpecialCharForDir } from "./misc"; import { checkHasSpecialCharForDir } from "./misc";
import { applyWebdavPresetRulesInplace } from "./presetRules"; import { applyWebdavPresetRulesInplace } from "./presetRules";
const log = origLog.getLogger("rs-default");
import {
applyLogWriterInplace,
log,
restoreLogWritterInplace,
} from "./moreOnLog";
class PasswordModal extends Modal { class PasswordModal extends Modal {
plugin: RemotelySavePlugin; plugin: RemotelySavePlugin;
@ -1702,6 +1712,64 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
}); });
}); });
const logToDBDiv = debugDiv.createEl("div");
new Setting(logToDBDiv)
.setName(t("settings_logtodb"))
.setDesc(t("settings_logtodb_desc"))
.addDropdown(async (dropdown) => {
dropdown.addOption("enable", t("enable"));
dropdown.addOption("disable", t("disable"));
dropdown
.setValue(this.plugin.settings.logToDB ? "enable" : "disable")
.onChange(async (val: string) => {
const logToDB = val === "enable";
if (logToDB) {
applyLogWriterInplace((...msg: any[]) => {
insertLoggerOutputByVault(
this.plugin.db,
this.plugin.vaultRandomID,
...msg
);
});
} else {
restoreLogWritterInplace();
}
clearExpiredLoggerOutputRecords(this.plugin.db);
this.plugin.settings.logToDB = logToDB;
await this.plugin.saveSettings();
});
});
new Setting(logToDBDiv)
.setName(t("settings_logtodbexport"))
.setDesc(
t("settings_logtodbexport_desc", {
debugFolder: DEFAULT_DEBUG_FOLDER,
})
)
.addButton(async (button) => {
button.setButtonText(t("settings_logtodbexport_button"));
button.onClick(async () => {
await exportVaultLoggerOutputToFiles(
this.plugin.db,
this.app.vault,
this.plugin.vaultRandomID
);
new Notice(t("settings_logtodbexport_notice"));
});
});
new Setting(logToDBDiv)
.setName(t("settings_logtodbclear"))
.setDesc(t("settings_logtodbclear_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_logtodbclear_button"));
button.onClick(async () => {
await clearAllLoggerOutputRecords(this.plugin.db);
new Notice(t("settings_logtodbclear_notice"));
});
});
const syncMappingDiv = debugDiv.createEl("div"); const syncMappingDiv = debugDiv.createEl("div");
new Setting(syncMappingDiv) new Setting(syncMappingDiv)
.setName(t("settings_delsyncmap")) .setName(t("settings_delsyncmap"))

View File

@ -47,8 +47,7 @@ import {
} from "./metadataOnRemote"; } from "./metadataOnRemote";
import { isInsideObsFolder, ObsConfigDirFileType } from "./obsFolderLister"; import { isInsideObsFolder, ObsConfigDirFileType } from "./obsFolderLister";
import * as origLog from "loglevel"; import { log } from "./moreOnLog";
const log = origLog.getLogger("rs-default");
export type SyncStatusType = export type SyncStatusType =
| "idle" | "idle"

View File

@ -1,8 +1,8 @@
import { App, Modal, Notice, PluginSettingTab, Setting } from "obsidian"; import { App, Modal, Notice, PluginSettingTab, Setting } from "obsidian";
import type RemotelySavePlugin from "./main"; // unavoidable import type RemotelySavePlugin from "./main"; // unavoidable
import type { TransItemType } from "./i18n"; import type { TransItemType } from "./i18n";
import * as origLog from "loglevel";
const log = origLog.getLogger("rs-default"); import { log } from "./moreOnLog";
export class SyncAlgoV2Modal extends Modal { export class SyncAlgoV2Modal extends Modal {
agree: boolean; agree: boolean;