diff --git a/README.md b/README.md index 86cce9b..7a8d713 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,24 @@ Each job also has three toggable options # Functionality +## API / UserScripts + +An API is exposed to add user functions via Javascript. The name is treated as a UUID for the job ensure that this is consistent across reloads of Obsidian to ensure that locks / last run data is usable. + +An instance of the Obsidian app is passed to all user function as the first and only paramater. + +To clear locks for jobs added via the API you can add a job with the corrosponding name and then pass the name to the `clearJobLock(name: string)` + +Example of a user function + +```javascript + +const cron = app.plugins.plugins.cron; + +cron.addCronJob('addCronJob', "* * * * 3", {"enableMobile": true}, function(app){console.log('Job has ran!')}); + +``` + ## Sync Obsidian cron has the ability to hook into the native Obsidian Sync plugin. When enabled all locks, cron runs & commands will wait for Obsidian Sync to be fully completed before running any cron jobs. diff --git a/package-lock.json b/package-lock.json index 6e95ec1..a5bf4b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,11 +11,13 @@ "dependencies": { "@popperjs/core": "^2.11.6", "cron-parser": "^4.8.1", - "eslint": "^8.36.0" + "eslint": "^8.36.0", + "uuid": "^9.0.0" }, "devDependencies": { "@semantic-release/git": "^10.0.1", "@types/node": "^16.11.6", + "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "5.29.0", "@typescript-eslint/parser": "5.29.0", "builtin-modules": "3.3.0", @@ -1110,6 +1112,12 @@ "@types/estree": "*" } }, + "node_modules/@types/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz", @@ -7624,6 +7632,14 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -8500,6 +8516,12 @@ "@types/estree": "*" } }, + "@types/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "5.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz", @@ -13067,6 +13089,11 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index 6b8fdc6..a524e95 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "devDependencies": { "@semantic-release/git": "^10.0.1", "@types/node": "^16.11.6", + "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "5.29.0", "@typescript-eslint/parser": "5.29.0", "builtin-modules": "3.3.0", @@ -32,7 +33,8 @@ "dependencies": { "@popperjs/core": "^2.11.6", "cron-parser": "^4.8.1", - "eslint": "^8.36.0" + "eslint": "^8.36.0", + "uuid": "^9.0.0" }, "release": { "tagFormat": "${version}", diff --git a/src/job.ts b/src/job.ts index 1ce872f..6b77d77 100644 --- a/src/job.ts +++ b/src/job.ts @@ -22,15 +22,17 @@ export default class Job { settings: CronJobSettings job: CronJobFunc | string name: string + id: string noRunReason: string - public constructor(name: string, job: CronJobFunc | string, frequency: string, settings: CronJobSettings, app: App, plugin: Cron, syncChecker: SyncChecker) { + public constructor(id: string, name: string, job: CronJobFunc | string, frequency: string, settings: CronJobSettings, app: App, plugin: Cron, syncChecker: SyncChecker) { this.syncChecker = syncChecker; this.plugin = plugin; this.app = app; - this.lockManager = new CronLockManager(name, settings, plugin, syncChecker) + this.lockManager = new CronLockManager(id, settings, plugin, syncChecker) this.name = name; + this.id = id; this.job = job; this.frequency = frequency; this.settings = settings; @@ -74,9 +76,9 @@ export default class Job { private jobIntervalPassed(): boolean { // job never ran - if(!this.plugin.settings.locks[this.name].lastRun) return true + const lastRun = this.lockManager.lastRun() + if(!lastRun) return true - const lastRun = window.moment(this.plugin.settings.locks[this.name].lastRun) const prevRun = window.moment(parseExpression(this.frequency).prev().toDate()) return prevRun.isAfter(lastRun) } diff --git a/src/lockManager.ts b/src/lockManager.ts index e529aaa..a232b7c 100644 --- a/src/lockManager.ts +++ b/src/lockManager.ts @@ -51,6 +51,10 @@ export default class CronLockManager { this.plugin.settings.locks[this.job].locked = false } + lastRun(): string | undefined { + return this.plugin.settings.locks[this.job].lastRun; + } + resetLastRun(): void { this.plugin.settings.locks[this.job].lastRun = undefined } diff --git a/src/main.ts b/src/main.ts index af6f357..38270f1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,6 +13,7 @@ export interface CronSettings { } export interface CRONJob { + id: string name: string job: string frequency: string @@ -66,10 +67,10 @@ export default class Cron extends Plugin { } } - public addCronJob(name: string, job: CronJobFunc, frequency: string, settings: CronJobSettings) { + public addCronJob(name: string, frequency: string, settings: CronJobSettings, job: CronJobFunc) { if(this.jobs[name]) throw new Error("CRON Job already exists") - this.jobs[name] = new Job(name, job, frequency, settings, this.app, this, this.syncChecker) + this.jobs[name] = new Job(name, name, job, frequency, settings, this.app, this, this.syncChecker) } public async runJob(name: string) { @@ -91,11 +92,11 @@ export default class Cron extends Plugin { public loadCrons() { this.settings.crons.forEach(cronjob => { - if(cronjob.frequency === "" || cronjob.job === "" || cronjob.name === "") { + if(cronjob.frequency === "" || cronjob.job === "") { return; } - this.jobs[cronjob.name] = new Job(cronjob.name, cronjob.job, cronjob.frequency, cronjob.settings, this.app, this, this.syncChecker) + this.jobs[cronjob.id] = new Job(cronjob.id, cronjob.name, cronjob.job, cronjob.frequency, cronjob.settings, this.app, this, this.syncChecker) }); } diff --git a/src/settings.ts b/src/settings.ts index 57e17d1..bf755dc 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,4 +1,5 @@ import { App, PluginSettingTab, Setting } from 'obsidian'; +import { v4 as uuidv4 } from 'uuid'; import { CommandSuggest } from './commandSuggest'; import type Cron from './main'; @@ -112,7 +113,7 @@ export default class CronSettingTab extends PluginSettingTab { button.setIcon(jobLocked ? "lucide-lock" : "lucide-unlock") .setTooltip("Toggle job lock (clear lock if accidentally left locked)") .onClick(() => { - this.plugin.settings.locks[cronjob.name].locked = !jobLocked; + this.plugin.settings.locks[cronjob.id].locked = !jobLocked; this.plugin.saveSettings(); // refresh this.display() @@ -134,7 +135,7 @@ export default class CronSettingTab extends PluginSettingTab { .setTooltip("Delete Job") .onClick(() => { this.plugin.settings.crons.splice(index, 1) - delete this.plugin.settings.locks[cronjob.name] + delete this.plugin.settings.locks[cronjob.id] this.plugin.saveSettings(); // Force refresh this.display(); @@ -149,6 +150,7 @@ export default class CronSettingTab extends PluginSettingTab { .setCta() .onClick(() => { this.plugin.settings.crons.push({ + id: uuidv4(), name: "", job: "", frequency: "",