- Setting dialogue very slightly refined.
  - The hodgepodge inside the `Hatch` pane has been sorted into more explicit categorised panes.
  - Applying the settings will now be more informative.

New features:
- Word-segmented chunk building on users language.

Fixed:
- Sending chunks on `Send chunk in bulk` are now buffered to avoid the out-of-memory error.
- `Send chunk in bulk` is back to default disabled.
- Merging conflicts of JSON files are now works fine even if it contains `null`.
Development:
- Implemented the logic for automatically generating the stub of document for the setting dialogue.
This commit is contained in:
vorotamoroz
2024-09-24 14:00:44 +01:00
parent 48e4d57278
commit b73ca73776
15 changed files with 3274 additions and 2315 deletions

View File

@@ -134,7 +134,13 @@ export function generatePatchObj(from: Record<string | number | symbol, any>, to
//if type is not match, replace completely.
ret[key] = { [MARK_SWAPPED]: value };
} else {
if (typeof (v) == "object" && typeof (value) == "object" && !Array.isArray(v) && !Array.isArray(value)) {
if (v === null && value === null) {
// NO OP.
} else if (v === null && value !== null) {
ret[key] = { [MARK_SWAPPED]: value };
} else if (v !== null && value === null) {
ret[key] = { [MARK_SWAPPED]: value };
} else if (typeof (v) == "object" && typeof (value) == "object" && !Array.isArray(v) && !Array.isArray(value)) {
const wk = generatePatchObj(v, value);
if (Object.keys(wk).length > 0) ret[key] = wk;
} else if (typeof (v) == "object" && typeof (value) == "object" && Array.isArray(v) && Array.isArray(value)) {
@@ -169,6 +175,10 @@ export function applyPatch(from: Record<string | number | symbol, any>, patch: R
delete ret[key];
continue;
}
if (value === null) {
ret[key] = null;
continue;
}
if (typeof (value) == "object") {
if (MARK_SWAPPED in value) {
ret[key] = value[MARK_SWAPPED];
@@ -251,6 +261,7 @@ export function mergeObject(
export function flattenObject(obj: Record<string | number | symbol, any>, path: string[] = []): [string, any][] {
if (typeof (obj) != "object") return [[path.join("."), obj]];
if (obj === null) return [[path.join("."), null]];
if (Array.isArray(obj)) return [[path.join("."), JSON.stringify(obj)]];
const e = Object.entries(obj);
const ret = []
@@ -489,6 +500,35 @@ export function useMemo<T>({ key, forceUpdate, validator }: MemoOption, updateFu
return value;
}
// const _static = new Map<string, any>();
const _staticObj = new Map<string, {
value: any
}>();
export function useStatic<T>(key: string): { value: (T | undefined) };
export function useStatic<T>(key: string, initial: T): { value: T };
export function useStatic<T>(key: string, initial?: T) {
// if (!_static.has(key) && initial) {
// _static.set(key, initial);
// }
const obj = _staticObj.get(key);
if (obj !== undefined) {
return obj;
} else {
// let buf = initial;
const obj = {
_buf: initial,
get value() {
return this._buf as T;
},
set value(value: T) {
this._buf = value
}
}
_staticObj.set(key, obj);
return obj;
}
}
export function disposeMemo(key: string) {
_cached.delete(key);
}

View File

@@ -129,7 +129,7 @@ export class LogAddOn extends LiveSyncCommands {
this.statusBarLabels = statusBarLabels;
const applyToDisplay = throttle((label: typeof statusBarLabels.value) => {
const v = label;
// const v = label;
this.applyStatusBarText();
}, 20);
@@ -161,10 +161,10 @@ export class LogAddOn extends LiveSyncCommands {
}
onload(): void | Promise<void> {
eventHub.on(EVENT_FILE_RENAMED, (evt: CustomEvent<{ oldPath: string, newPath: string }>) => {
eventHub.onEvent(EVENT_FILE_RENAMED, (evt: CustomEvent<{ oldPath: string, newPath: string }>) => {
this.setFileStatus();
});
eventHub.on(EVENT_LEAF_ACTIVE_CHANGED, () => this.onActiveLeafChange());
eventHub.onEvent(EVENT_LEAF_ACTIVE_CHANGED, () => this.onActiveLeafChange());
const w = document.querySelectorAll(`.livesync-status`);
w.forEach(e => e.remove());
@@ -175,7 +175,7 @@ export class LogAddOn extends LiveSyncCommands {
this.messageArea = this.statusDiv.createDiv({ cls: "livesync-status-messagearea" });
this.logMessage = this.statusDiv.createDiv({ cls: "livesync-status-logmessage" });
this.logHistory = this.statusDiv.createDiv({ cls: "livesync-status-loghistory" });
eventHub.on(EVENT_LAYOUT_READY, () => this.adjustStatusDivPosition());
eventHub.onEvent(EVENT_LAYOUT_READY, () => this.adjustStatusDivPosition());
if (this.settings.showStatusOnStatusbar) {
this.statusBar = this.plugin.addStatusBarItem();
this.statusBar.addClass("syncstatusbar");

Submodule src/lib updated: 633af447d2...3108e3e3db

View File

@@ -46,7 +46,7 @@ import { LogAddOn } from "./features/CmdStatusInsideEditor.ts";
import { eventHub } from "./lib/src/hub/hub.ts";
import { EVENT_FILE_RENAMED, EVENT_LAYOUT_READY, EVENT_LEAF_ACTIVE_CHANGED, EVENT_PLUGIN_LOADED, EVENT_PLUGIN_UNLOADED, EVENT_SETTING_SAVED } from "./common/events.ts";
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
import { yieldMicrotask } from "octagonal-wheels/promises";
setNoticeClass(Notice);
@@ -354,10 +354,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin
return new PouchDB(name, optionPass);
}
beforeOnUnload(db: LiveSyncLocalDB): void {
this.kvDB.close();
if (this.kvDB) this.kvDB.close();
}
onClose(db: LiveSyncLocalDB): void {
this.kvDB.close();
if (this.kvDB) this.kvDB.close();
}
getNewReplicator(settingOverride: Partial<ObsidianLiveSyncSettings> = {}): LiveSyncAbstractReplicator {
const settings = { ...this.settings, ...settingOverride };
@@ -367,8 +367,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin
return new LiveSyncCouchDBReplicator(this);
}
async onInitializeDatabase(db: LiveSyncLocalDB): Promise<void> {
await delay(10);
this.kvDB = await OpenKeyValueDatabase(db.dbname + "-livesync-kv");
// this.trench = new Trench(this.simpleStore);
this.replicator = this.getNewReplicator();
}
async onResetDatabase(db: LiveSyncLocalDB): Promise<void> {
@@ -376,8 +376,9 @@ export default class ObsidianLiveSyncPlugin extends Plugin
this.kvDB.del(kvDBKey);
// localStorage.removeItem(lsKey);
await this.kvDB.destroy();
await yieldMicrotask();
this.kvDB = await OpenKeyValueDatabase(db.dbname + "-livesync-kv");
// this.trench = new Trench(this.simpleStore);
await yieldMicrotask();
this.replicator = this.getNewReplicator()
}
getReplicator() {
@@ -710,7 +711,7 @@ ___However, to enable either of these changes, both remote and local databases n
}
async onLayoutReady() {
eventHub.emit(EVENT_LAYOUT_READY);
eventHub.emitEvent(EVENT_LAYOUT_READY);
this.registerFileWatchEvents();
if (!this.localDatabase.isReady) {
Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL_NOTICE);
@@ -1160,34 +1161,34 @@ Note: We can always able to read V1 format. It will be progressively converted.
}
wireUpEvents() {
eventHub.on(EVENT_SETTING_SAVED, (evt: CustomEvent<ObsidianLiveSyncSettings>) => {
eventHub.onEvent(EVENT_SETTING_SAVED, (evt: CustomEvent<ObsidianLiveSyncSettings>) => {
const settings = evt.detail;
this.localDatabase.settings = settings;
setLang(settings.displayLanguage);
this.settingTab.requestReload();
this.ignoreFiles = settings.ignoreFiles.split(",").map(e => e.trim());
});
eventHub.on(EVENT_SETTING_SAVED, (evt: CustomEvent<ObsidianLiveSyncSettings>) => {
eventHub.onEvent(EVENT_SETTING_SAVED, (evt: CustomEvent<ObsidianLiveSyncSettings>) => {
const settings = evt.detail;
if (settings.settingSyncFile != "") {
fireAndForget(() => this.saveSettingToMarkdown(settings.settingSyncFile));
}
})
eventHub.on(EVENT_SETTING_SAVED, (evt: CustomEvent<ObsidianLiveSyncSettings>) => {
eventHub.onEvent(EVENT_SETTING_SAVED, (evt: CustomEvent<ObsidianLiveSyncSettings>) => {
fireAndForget(() => this.realizeSettingSyncMode());
})
}
connectObsidianEvents() {
// this.registerEvent(this.app.workspace.on("editor-change", ));
this.registerEvent(this.app.vault.on("rename", (file, oldPath) => {
eventHub.emit(EVENT_FILE_RENAMED, { newPath: file.path, old: oldPath });
eventHub.emitEvent(EVENT_FILE_RENAMED, { newPath: file.path, old: oldPath });
}));
this.registerEvent(this.app.workspace.on("active-leaf-change", () => eventHub.emit(EVENT_LEAF_ACTIVE_CHANGED)));
this.registerEvent(this.app.workspace.on("active-leaf-change", () => eventHub.emitEvent(EVENT_LEAF_ACTIVE_CHANGED)));
}
async onload() {
this.wireUpEvents();
this.connectObsidianEvents();
eventHub.emit(EVENT_PLUGIN_LOADED, this);
eventHub.emitEvent(EVENT_PLUGIN_LOADED, this);
logStore.pipeTo(new QueueProcessor(logs => logs.forEach(e => this.addLog(e.message, e.level, e.key)), { suspended: false, batchSize: 20, concurrentLimit: 1, delay: 0 })).startPipeline();
Logger("loading plugin");
__onMissingTranslation(() => { });
@@ -1214,6 +1215,36 @@ Note: We can always able to read V1 format. It will be progressively converted.
}
});
})
type STUB = {
toc: Set<string>,
stub: { [key: string]: { [key: string]: Map<string, Record<string, string>> } }
};
eventHub.onEvent("document-stub-created", async (e: CustomEvent<STUB>) => {
const stub = e.detail.stub;
const toc = e.detail.toc;
const stubDocX =
Object.entries(stub).map(([key, value]) => {
return [`## ${key}`, Object.entries(value).
map(([key2, value2]) => {
return [`### ${key2}`,
([...(value2.entries())].map(([key3, value3]) => {
// return `#### ${key3}` + "\n" + JSON.stringify(value3);
const isObsolete = value3["is_obsolete"] ? " (obsolete)" : "";
const desc = value3["desc"] ?? "";
const key = value3["key"] ? "Setting key: " + value3["key"] + "\n" : "";
return `#### ${key3}${isObsolete}\n${key}${desc}\n`
}))].flat()
}).flat()].flat()
}).flat();
const stubDocMD = `
| Icon | Description |
| :---: | ----------------------------------------------------------------- |
` +
[...toc.values()].map(e => `${e}`).join("\n") + "\n\n" +
stubDocX.join("\n");
await this.vaultAccess.adapterWrite(this.app.vault.configDir + "/ls-debug/stub-doc.md", stubDocMD);
})
}
this.settingTab = new ObsidianLiveSyncSettingTab(this.app, this);
this.addSettingTab(this.settingTab);
@@ -1292,7 +1323,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
}
onunload() {
eventHub.emit(EVENT_PLUGIN_UNLOADED);
eventHub.emitEvent(EVENT_PLUGIN_UNLOADED);
cancelAllPeriodicTask();
cancelAllTasks();
stopAllRunningProcessors();
@@ -1305,7 +1336,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
}
this.periodicSyncProcessor?.disable();
if (this.localDatabase != null) {
this.replicator.closeReplication();
this.replicator?.closeReplication();
this.localDatabase.close();
}
Logger($f`unloading plugin`);
@@ -1496,7 +1527,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
}
await this.saveData(settings);
eventHub.emit(EVENT_SETTING_SAVED, settings);
eventHub.emitEvent(EVENT_SETTING_SAVED, settings);
}
extractSettingFromWholeText(data: string): { preamble: string, body: string, postscript: string } {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,339 @@
import { Setting, TextComponent, type ToggleComponent, type DropdownComponent, ButtonComponent, type TextAreaComponent, type ValueComponent } from "obsidian";
import { unique } from "octagonal-wheels/collection";
import { LEVEL_ADVANCED, LEVEL_POWER_USER, statusDisplay, type ConfigurationItem } from "../../lib/src/common/types";
import { type ObsidianLiveSyncSettingTab, type AutoWireOption, wrapMemo, type OnUpdateResult, createStub, findAttrFromParent } from "../ObsidianLiveSyncSettingTab";
import { type AllSettingItemKey, getConfig, type AllSettings, type AllStringItemKey, type AllNumericItemKey, type AllBooleanItemKey } from "../settingConstants";
export class LiveSyncSetting extends Setting {
autoWiredComponent?: TextComponent | ToggleComponent | DropdownComponent | ButtonComponent | TextAreaComponent;
applyButtonComponent?: ButtonComponent;
selfKey?: AllSettingItemKey;
watchDirtyKeys = [] as AllSettingItemKey[];
holdValue: boolean = false;
static env: ObsidianLiveSyncSettingTab;
descBuf: string | DocumentFragment = "";
nameBuf: string | DocumentFragment = "";
placeHolderBuf: string = "";
hasPassword: boolean = false;
invalidateValue?: () => void;
setValue?: (value: any) => void;
constructor(containerEl: HTMLElement) {
super(containerEl);
LiveSyncSetting.env.settingComponents.push(this);
}
_createDocStub(key: string, value: string | DocumentFragment) {
DEV: {
const paneName = findAttrFromParent(this.settingEl, "data-pane");
const panelName = findAttrFromParent(this.settingEl, "data-panel");
const itemName = typeof this.nameBuf == "string" ? this.nameBuf : this.nameBuf.textContent?.toString() ?? "";
const strValue = typeof value == "string" ? value : value.textContent?.toString() ?? "";
createStub(itemName, key, strValue, panelName, paneName);
}
}
setDesc(desc: string | DocumentFragment): this {
this.descBuf = desc;
DEV: {
this._createDocStub("desc", desc);
}
super.setDesc(desc);
return this;
}
setName(name: string | DocumentFragment): this {
this.nameBuf = name;
DEV: {
this._createDocStub("name", name);
}
super.setName(name);
return this;
}
setAuto(key: AllSettingItemKey, opt?: AutoWireOption) {
this.autoWireSetting(key, opt);
return this;
}
autoWireSetting(key: AllSettingItemKey, opt?: AutoWireOption) {
const conf = getConfig(key);
if (!conf) {
// throw new Error(`No such setting item :${key}`)
return;
}
const name = `${conf.name}${statusDisplay(conf.status)}`;
this.setName(name);
if (conf.desc) {
this.setDesc(conf.desc);
}
DEV: {
this._createDocStub("key", key);
if (conf.obsolete) this._createDocStub("is_obsolete", "true");
if (conf.level) this._createDocStub("level", conf.level);
}
this.holdValue = opt?.holdValue || this.holdValue;
this.selfKey = key;
if (conf.obsolete || opt?.obsolete) {
this.settingEl.toggleClass("sls-setting-obsolete", true);
}
if (opt?.onUpdate) this.addOnUpdate(opt.onUpdate);
const stat = this._getComputedStatus();
if (stat.visibility === false) {
this.settingEl.toggleClass("sls-setting-hidden", !stat.visibility);
}
return conf;
}
autoWireComponent(component: ValueComponent<any>, conf?: ConfigurationItem, opt?: AutoWireOption) {
this.placeHolderBuf = conf?.placeHolder || opt?.placeHolder || "";
if (conf?.level == LEVEL_ADVANCED) {
this.settingEl.toggleClass("sls-setting-advanced", true);
} else if (conf?.level == LEVEL_POWER_USER) {
this.settingEl.toggleClass("sls-setting-poweruser", true);
}
if (this.placeHolderBuf && component instanceof TextComponent) {
component.setPlaceholder(this.placeHolderBuf);
}
if (opt?.onUpdate) this.addOnUpdate(opt.onUpdate);
}
async commitValue<T extends AllSettingItemKey>(value: AllSettings[T]) {
const key = this.selfKey as T;
if (key !== undefined) {
if (value != LiveSyncSetting.env.editingSettings[key]) {
LiveSyncSetting.env.editingSettings[key] = value;
if (!this.holdValue) {
await LiveSyncSetting.env.saveSettings([key]);
}
}
}
LiveSyncSetting.env.requestUpdate();
}
autoWireText(key: AllStringItemKey, opt?: AutoWireOption) {
const conf = this.autoWireSetting(key, opt);
this.addText(text => {
this.autoWiredComponent = text;
const setValue = wrapMemo((value: string) => text.setValue(value));
this.invalidateValue = () => setValue(`${LiveSyncSetting.env.editingSettings[key]}`);
this.invalidateValue();
text.onChange(async (value) => {
await this.commitValue(value);
});
if (opt?.isPassword) {
text.inputEl.setAttribute("type", "password");
this.hasPassword = true;
}
this.autoWireComponent(this.autoWiredComponent, conf, opt);
});
return this;
}
autoWireTextArea(key: AllStringItemKey, opt?: AutoWireOption) {
const conf = this.autoWireSetting(key, opt);
this.addTextArea(text => {
this.autoWiredComponent = text;
const setValue = wrapMemo((value: string) => text.setValue(value));
this.invalidateValue = () => setValue(`${LiveSyncSetting.env.editingSettings[key]}`);
this.invalidateValue();
text.onChange(async (value) => {
await this.commitValue(value);
});
if (opt?.isPassword) {
text.inputEl.setAttribute("type", "password");
this.hasPassword = true;
}
this.autoWireComponent(this.autoWiredComponent, conf, opt);
});
return this;
}
autoWireNumeric(key: AllNumericItemKey, opt: AutoWireOption & { clampMin?: number; clampMax?: number; acceptZero?: boolean; }) {
const conf = this.autoWireSetting(key, opt);
this.addText(text => {
this.autoWiredComponent = text;
if (opt.clampMin) {
text.inputEl.setAttribute("min", `${opt.clampMin}`);
}
if (opt.clampMax) {
text.inputEl.setAttribute("max", `${opt.clampMax}`);
}
let lastError = false;
const setValue = wrapMemo((value: string) => text.setValue(value));
this.invalidateValue = () => {
if (!lastError) setValue(`${LiveSyncSetting.env.editingSettings[key]}`);
};
this.invalidateValue();
text.onChange(async (TextValue) => {
const parsedValue = Number(TextValue);
const value = parsedValue;
let hasError = false;
if (isNaN(value)) hasError = true;
if (opt.clampMax && opt.clampMax < value) hasError = true;
if (opt.clampMin && opt.clampMin > value) {
if (opt.acceptZero && value == 0) {
// This is ok.
} else {
hasError = true;
}
}
if (!hasError) {
lastError = false;
this.setTooltip(``);
text.inputEl.toggleClass("sls-item-invalid-value", false);
await this.commitValue(value);
} else {
this.setTooltip(`The value should ${opt.clampMin || "~"} < value < ${opt.clampMax || "~"}`);
text.inputEl.toggleClass("sls-item-invalid-value", true);
lastError = true;
return false;
}
});
text.inputEl.setAttr("type", "number");
this.autoWireComponent(this.autoWiredComponent, conf, opt);
});
return this;
}
autoWireToggle(key: AllBooleanItemKey, opt?: AutoWireOption) {
const conf = this.autoWireSetting(key, opt);
this.addToggle(toggle => {
this.autoWiredComponent = toggle;
const setValue = wrapMemo((value: boolean) => toggle.setValue(opt?.invert ? !value : value));
this.invalidateValue = () => setValue(LiveSyncSetting.env.editingSettings[key] ?? false);
this.invalidateValue();
toggle.onChange(async (value) => {
await this.commitValue(opt?.invert ? !value : value);
});
this.autoWireComponent(this.autoWiredComponent, conf, opt);
});
return this;
}
autoWireDropDown<T extends string>(key: AllStringItemKey, opt: AutoWireOption & { options: Record<T, string>; }) {
const conf = this.autoWireSetting(key, opt);
this.addDropdown(dropdown => {
this.autoWiredComponent = dropdown;
const setValue = wrapMemo((value: string) => {
dropdown.setValue(value);
});
dropdown
.addOptions(opt.options);
this.invalidateValue = () => setValue(LiveSyncSetting.env.editingSettings[key] || "");
this.invalidateValue();
dropdown.onChange(async (value) => {
await this.commitValue(value);
});
this.autoWireComponent(this.autoWiredComponent, conf, opt);
});
return this;
}
addApplyButton(keys: AllSettingItemKey[], text?: string) {
this.addButton((button) => {
this.applyButtonComponent = button;
this.watchDirtyKeys = unique([...keys, ...this.watchDirtyKeys]);
button.setButtonText(text ?? "Apply");
button.onClick(async () => {
await LiveSyncSetting.env.saveSettings(keys);
LiveSyncSetting.env.reloadAllSettings();
});
LiveSyncSetting.env.requestUpdate();
});
return this;
}
addOnUpdate(func: () => OnUpdateResult) {
this.updateHandlers.add(func);
// this._applyOnUpdateHandlers();
return this;
}
updateHandlers = new Set<() => OnUpdateResult>();
prevStatus: OnUpdateResult = {};
_getComputedStatus() {
let newConf = {} as OnUpdateResult;
for (const handler of this.updateHandlers) {
newConf = {
...newConf,
...handler(),
};
}
return newConf;
}
_applyOnUpdateHandlers() {
if (this.updateHandlers.size > 0) {
const newConf = this._getComputedStatus();
const keys = Object.keys(newConf) as [keyof OnUpdateResult];
for (const k of keys) {
if (k in this.prevStatus && this.prevStatus[k] == newConf[k]) {
continue;
}
// const newValue = newConf[k];
switch (k) {
case "visibility":
this.settingEl.toggleClass("sls-setting-hidden", !(newConf[k] || false));
this.prevStatus[k] = newConf[k];
break;
case "classes":
break;
case "disabled":
this.setDisabled((newConf[k] || false));
this.settingEl.toggleClass("sls-setting-disabled", (newConf[k] || false));
this.prevStatus[k] = newConf[k];
break;
case "isCta":
{
const component = this.autoWiredComponent;
if (component instanceof ButtonComponent) {
if (newConf[k]) {
component.setCta();
} else {
component.removeCta();
}
}
this.prevStatus[k] = newConf[k];
}
break;
case "isWarning":
{
const component = this.autoWiredComponent;
if (component instanceof ButtonComponent) {
if (newConf[k]) {
component.setWarning();
} else {
//TODO:IMPLEMENT
// component.removeCta();
}
}
this.prevStatus[k] = newConf[k];
}
break;
}
}
}
}
_onUpdate() {
if (this.applyButtonComponent) {
const isDirty = LiveSyncSetting.env.isSomeDirty(this.watchDirtyKeys);
this.applyButtonComponent.setDisabled(!isDirty);
if (isDirty) {
this.applyButtonComponent.setCta();
} else {
this.applyButtonComponent.removeCta();
}
}
if (this.selfKey && !LiveSyncSetting.env.isDirty(this.selfKey) && this.invalidateValue) {
this.invalidateValue();
}
if (this.holdValue && this.selfKey) {
const isDirty = LiveSyncSetting.env.isDirty(this.selfKey);
const alt = isDirty ? `Original: ${LiveSyncSetting.env.initialSettings![this.selfKey]}` : "";
this.controlEl.toggleClass("sls-item-dirty", isDirty);
if (!this.hasPassword) {
this.nameEl.toggleClass("sls-item-dirty-help", isDirty);
this.setTooltip(alt, { delay: 10, placement: "right" });
}
}
this._applyOnUpdateHandlers();
}
}

View File

@@ -198,8 +198,9 @@ export const SettingInformation: Partial<Record<keyof AllSettings, Configuration
"name": "Do not keep metadata of deleted files."
},
"useIndexedDBAdapter": {
"name": "Use an old adapter for compatibility",
"desc": "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this."
"name": "(Obsolete) Use an old adapter for compatibility",
"desc": "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.",
"obsolete": true
},
"watchInternalFileChanges": {
"name": "Scan changes on customization sync",
@@ -341,6 +342,18 @@ export const SettingInformation: Partial<Record<keyof AllSettings, Configuration
name: "Maximum size of chunks to send in one request",
desc: "MB"
},
"useAdvancedMode": {
name: "Enable advanced features",
// desc: "Enable advanced mode"
},
usePowerUserMode: {
name: "Enable power user features",
// desc: "Enable power user mode",
// level: LEVEL_ADVANCED
},
useEdgeCaseMode: {
name: "Enable edge case treatment features",
},
}
function translateInfo(infoSrc: ConfigurationItem | undefined | false) {
if (!infoSrc) return false;