From 69e80011843f7a6f7b5a802f48f1d55ae9d1bb83 Mon Sep 17 00:00:00 2001 From: Peter Heiss Date: Thu, 8 Aug 2024 21:26:41 +0200 Subject: [PATCH] fix issue with updateOnStartup this was, because i do not load cached settings correctly --- main.ts | 1 - src/processing/getTasks.ts | 5 --- src/processing/processor.ts | 37 ++++++++-------------- src/settings/VaultTaskCache.ts | 41 +++++++++++++++++-------- src/settings/mainSetting.ts | 56 +++++++++++++++++++++++----------- 5 files changed, 81 insertions(+), 59 deletions(-) diff --git a/main.ts b/main.ts index 4e88e9f..659ef27 100644 --- a/main.ts +++ b/main.ts @@ -83,7 +83,6 @@ export default class VikunjaPlugin extends Plugin { this.userObject = undefined; this.labelsApi = new Label(this.app, this); this.projectsApi = new Projects(this.app, this); - this.cache = new VaultTaskCache(this.app, this); } private setupCommands() { diff --git a/src/processing/getTasks.ts b/src/processing/getTasks.ts index 203406f..145d8ae 100644 --- a/src/processing/getTasks.ts +++ b/src/processing/getTasks.ts @@ -65,11 +65,6 @@ class GetTasks implements IAutomatonSteps { await this.handleDataviewIndex(); } - if (this.plugin.settings.updateOnCursorMovement) { - const tasks = this.plugin.cache.getCachedTasks(); - if (this.plugin.settings.debugging) console.log("GetTasks: Using cache", tasks); - return tasks; - } if (this.plugin.settings.debugging) console.log("Step GetTask: Pulling tasks from vault"); return await this.vaultSearcher.getTasks(this.taskParser); } diff --git a/src/processing/processor.ts b/src/processing/processor.ts index 16317c9..48c4ac9 100644 --- a/src/processing/processor.ts +++ b/src/processing/processor.ts @@ -2,8 +2,7 @@ import Plugin from "../../main"; import {App, MarkdownView, moment, Notice, TFile} from "obsidian"; import {PluginTask, VaultSearcher} from "../vaultSearcher/vaultSearcher"; import {TaskFormatter, TaskParser} from "../taskFormats/taskFormats"; -import {Automaton, AutomatonStatus, IAutomatonSteps} from "./automaton"; -import UpdateTasks from "./updateTasks"; +import {Automaton, AutomatonStatus} from "./automaton"; import {EmojiTaskFormatter, EmojiTaskParser} from "../taskFormats/emojiTaskFormat"; import {backendToFindTasks, chooseOutputFile, supportedTasksPluginsFormat} from "../enums"; import {DataviewSearcher} from "../vaultSearcher/dataviewSearcher"; @@ -119,23 +118,14 @@ class Processor { * This method should only be triggered on startup of obsidian and only once. After this, we cannot guerantee that the updated information of files are in sync. */ async updateTasksOnStartup() { - if (this.plugin.settings.debugging) console.log("Processor: Update tasks in vault and vikunja"); - if (this.alreadyUpdateTasksOnStartup) throw new Error("Update tasks on startup can only be called once"); - if (this.plugin.commands.isEverythingSetup()) { - if (this.plugin.settings.debugging) console.log("Processor: Found problems in plugin. Have to be fixed first. Syncing is stopped."); - return; - } if (!this.plugin.settings.updateOnStartup) { if (this.plugin.settings.debugging) console.log("Processor: Update on startup is disabled"); return; } + if (this.alreadyUpdateTasksOnStartup) throw new Error("Update tasks on startup can only be called once"); + if (this.plugin.settings.debugging) console.log("Processor: Update tasks in vault and vikunja"); - const localTasks = await this.vaultSearcher.getTasks(this.taskParser); - const vikunjaTasks = await this.plugin.tasksApi.getAllTasks(); - - const updateStep: IAutomatonSteps = new UpdateTasks(this.app, this.plugin, this); - await updateStep.step(localTasks, vikunjaTasks); - + await this.exec(); this.alreadyUpdateTasksOnStartup = true; } @@ -218,18 +208,17 @@ class Processor { await this.app.vault.process(file, (data: string) => { const lines = data.split("\n"); lines.splice(task.lineno, 1, newTask); - const content = lines.join("\n"); - try { - this.plugin.cache.update(task); - } catch (e) { - if (metadata) { - // raise error again, if metadata was wanted! otherwise it is expected, that update will fail. - throw e; - } - } - return content; + return lines.join("\n"); }); + try { + this.plugin.cache.update(task); + } catch (e) { + if (metadata) { + // raise error again, if metadata was wanted! otherwise it is expected, that update will fail, because id is missing. + throw e; + } + } } getVaultSearcher(): VaultSearcher { diff --git a/src/settings/VaultTaskCache.ts b/src/settings/VaultTaskCache.ts index bfb1149..32957ee 100644 --- a/src/settings/VaultTaskCache.ts +++ b/src/settings/VaultTaskCache.ts @@ -2,51 +2,63 @@ import VikunjaPlugin from "../../main"; import {App, moment} from "obsidian"; import {PluginTask} from "../vaultSearcher/vaultSearcher"; - -interface Cache { - [key: number]: T; -} - /* * This class is used to cache tasks which are updated in Vault, but not in Vikunja. * This should help to identify modifications in vault without Obsidian. * Also it makes it possible to update only modified tasks. See issue #9 for more details. */ export default class VaultTaskCache { + private static readonly SAVE_TO_DISK_DELAYED_INTERVAL = 250; plugin: VikunjaPlugin; app: App; changesMade: boolean; private cache: Map + private saveToDiskDelayedListener: number | undefined; constructor(app: App, plugin: VikunjaPlugin) { this.app = app; this.plugin = plugin; this.changesMade = false; this.cache = new Map(); + this.saveToDiskDelayedListener = undefined; } public static fromJson(json: any, app: App, plugin: VikunjaPlugin): VaultTaskCache { - const cache = new VaultTaskCache(app, plugin); + const taskCache = new VaultTaskCache(app, plugin); console.log("VaultTaskCache: Loading cache from disk", json); const tempCache = Object.entries(json).map((taskJson: any) => { - const id = parseInt(taskJson[0]); const task = PluginTask.fromJson(taskJson[1]); if (task === undefined) { return undefined } + const id = task.task.id; + if (id === undefined) { + throw new Error("VaultTaskCache: Task id is not defined"); + } return [id, task]; }).filter((task: any) => task !== undefined); // @ts-ignore - cache.cache = new Map(tempCache); - console.log("VaultTaskCache: Loaded cache from disk", cache.cache); - return cache; + taskCache.cache = new Map(tempCache); + console.log("VaultTaskCache: Loaded cache from disk", taskCache.cache); + return taskCache; + } + + /* + * This function is used to save the cache to disk, but it waits an interval until it is saved. + * It resets the interval everytime, anything calls this method. + */ + async saveCacheToDiskDelayed() { + window.clearInterval(this.saveToDiskDelayedListener); + this.saveToDiskDelayedListener = window.setInterval(async () => { + await this.saveCacheToDisk(); + }, VaultTaskCache.SAVE_TO_DISK_DELAYED_INTERVAL); + this.plugin.registerInterval(this.saveToDiskDelayedListener); } async saveCacheToDisk() { if (this.changesMade) { this.plugin.settings.cache = this.getCachedTasks().map(task => task.toJson()); if (this.plugin.settings.debugging) console.log("VaultTaskCache: Updated cache in settings", this.plugin.settings.cache); - if (this.plugin.settings.debugging) console.log("VaultTaskCache: Saving cache to disk"); await this.plugin.saveSettings(); } this.changesMade = false; @@ -77,8 +89,13 @@ export default class VaultTaskCache { } this.cache.set(local.task.id, local); - console.log("VaultTaskCache: Updated cache", this.cache); this.changesMade = true; + + if (this.plugin.settings.saveCacheToDiskImmediately) { + this.saveCacheToDiskDelayed().then(() => { + if (this.plugin.settings.debugging) console.log("VaultTaskCache: Saved cache to disk"); + }); + } } get(id: number): PluginTask | undefined { diff --git a/src/settings/mainSetting.ts b/src/settings/mainSetting.ts index f8a38eb..e7ff2e6 100644 --- a/src/settings/mainSetting.ts +++ b/src/settings/mainSetting.ts @@ -31,6 +31,7 @@ export interface VikunjaPluginSettings { selectedView: number, selectBucketForDoneTasks: number, cache: PluginTask[], // do not touch! Only via settings/VaultTaskCache.ts + saveCacheToDiskImmediately: boolean, saveCacheToDiskFrequency: number, updateCompletedStatusImmediately: boolean, } @@ -61,6 +62,7 @@ export const DEFAULT_SETTINGS: VikunjaPluginSettings = { selectedView: 0, selectBucketForDoneTasks: 0, cache: [], + saveCacheToDiskImmediately: true, saveCacheToDiskFrequency: 1, updateCompletedStatusImmediately: false, } @@ -75,7 +77,9 @@ export class MainSetting extends PluginSettingTab { super(app, plugin); this.plugin = plugin; - this.startCacheListener(); + if (!this.plugin.settings.saveCacheToDiskImmediately) { + this.startCacheListener(); + } this.startCronListener(); } @@ -202,25 +206,43 @@ export class MainSetting extends PluginSettingTab { } new Setting(containerEl) - .setName("Save cache to disk frequency") - .setDesc("This plugin uses a cache to calculate correct dates. Set the interval in minutes to save the cache to disk. Lower values will result in more frequent saves, but may cause performance issues. Set too high, task dates are not correctly calculated, because they are missing in cache in next startup. If you make bulk edits of tasks in your vault, you should set higher value. Cache will be only written, if changes were made since last check. If you are unsure, try lowest value and increase it, if you experience performance issues. Limits are 1 to 60 minutes.") - .addText(text => text - .setValue(this.plugin.settings.saveCacheToDiskFrequency.toString()) - .onChange(async (value: string) => { - const parsedNumber = parseInt(value); - if (Number.isNaN(parsedNumber)) { - return; - } - const lowerThanMax = Math.min(parsedNumber, 60); - if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - high limits", lowerThanMax); - const higherThanMin = Math.max(lowerThanMax, 1); - if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - low limits", higherThanMin); - this.plugin.settings.saveCacheToDiskFrequency = higherThanMin; - await this.plugin.saveSettings(); + .setName("Update cache to disk immediately") + .setDesc("If enabled, the cache will be written to disk immediately after a change. If disabled, the cache will be written to disk after a certain interval. If you experience performance issues, you should disable this and use a frequency.") + .addToggle(toggle => toggle + .setValue(this.plugin.settings.saveCacheToDiskImmediately) + .onChange(async (value: boolean) => { + this.plugin.settings.saveCacheToDiskImmediately = value; + await this.plugin.saveSettings(); + if (value) { + clearInterval(this.cacheListener); + } else { this.startCacheListener(); } + this.display(); + })); + + if (!this.plugin.settings.saveCacheToDiskImmediately) { + new Setting(containerEl) + .setName("Save cache to disk frequency") + .setDesc("This plugin uses a cache to calculate correct dates. Set the interval in minutes to save the cache to disk. Lower values will result in more frequent saves, but may cause performance issues. Set too high, task dates are not correctly calculated, because they are missing in cache in next startup. If you make bulk edits of tasks in your vault, you should set higher value. Cache will be only written, if changes were made since last check. If you are unsure, try lowest value and increase it, if you experience performance issues. Limits are 1 to 60 minutes.") + .addText(text => text + .setValue(this.plugin.settings.saveCacheToDiskFrequency.toString()) + .onChange(async (value: string) => { + const parsedNumber = parseInt(value); + if (Number.isNaN(parsedNumber)) { + return; + } + const lowerThanMax = Math.min(parsedNumber, 60); + if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - high limits", lowerThanMax); + const higherThanMin = Math.max(lowerThanMax, 1); + if (this.plugin.settings.debugging) console.log("Save cache to disk frequency - low limits", higherThanMin); + this.plugin.settings.saveCacheToDiskFrequency = higherThanMin; + await this.plugin.saveSettings(); + this.startCacheListener(); + } + ) ) - ) + } new Setting(containerEl).setHeading().setName('Vikunja Settings').setDesc('Settings to connect to Vikunja.');