diff --git a/package-lock.json b/package-lock.json index 186f3af5a..339668e0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ }, "devDependencies": { "cross-env": "7.0.3", - "electron": "13.0.0-beta.11", + "electron": "13.0.0-beta.12", "electron-builder": "22.10.5", "electron-packager": "15.2.0", "electron-rebuild": "2.3.5", @@ -3312,9 +3312,9 @@ } }, "node_modules/electron": { - "version": "13.0.0-beta.11", - "resolved": "https://registry.npmjs.org/electron/-/electron-13.0.0-beta.11.tgz", - "integrity": "sha512-hSKu4n3BIznAgnmDmURFJ7Xe7BO5B2DKw8g+J8LLE/PLverIH1qBwVzHL/oWlMLxjPCCKd8WARNX7L8X/bOJHA==", + "version": "13.0.0-beta.12", + "resolved": "https://registry.npmjs.org/electron/-/electron-13.0.0-beta.12.tgz", + "integrity": "sha512-Ly+60Sgb5PITxRWA15XrW46GXSajOO8w+BHft07TZKKuicyGN+vqZAhR8HvvOtm9nGmVrrWsi430R9t4zQL8kw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -12984,9 +12984,9 @@ } }, "electron": { - "version": "13.0.0-beta.11", - "resolved": "https://registry.npmjs.org/electron/-/electron-13.0.0-beta.11.tgz", - "integrity": "sha512-hSKu4n3BIznAgnmDmURFJ7Xe7BO5B2DKw8g+J8LLE/PLverIH1qBwVzHL/oWlMLxjPCCKd8WARNX7L8X/bOJHA==", + "version": "13.0.0-beta.12", + "resolved": "https://registry.npmjs.org/electron/-/electron-13.0.0-beta.12.tgz", + "integrity": "sha512-Ly+60Sgb5PITxRWA15XrW46GXSajOO8w+BHft07TZKKuicyGN+vqZAhR8HvvOtm9nGmVrrWsi430R9t4zQL8kw==", "dev": true, "requires": { "@electron/get": "^1.0.1", diff --git a/package.json b/package.json index d5307d4bf..d552847c5 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ }, "devDependencies": { "cross-env": "7.0.3", - "electron": "13.0.0-beta.11", + "electron": "13.0.0-beta.12", "electron-builder": "22.10.5", "electron-packager": "15.2.0", "electron-rebuild": "2.3.5", diff --git a/src/entities/note.js b/src/entities/note.js index 0fc26c3a0..ab1638a45 100644 --- a/src/entities/note.js +++ b/src/entities/note.js @@ -303,6 +303,14 @@ class Note extends Entity { return this.getAttributes(LABEL, name); } + /** + * @param {string} [name] - label name to filter + * @returns {string[]} all note's label values, including inherited ones + */ + getLabelValues(name) { + return this.getLabels(name).map(l => l.value); + } + /** * @param {string} [name] - label name to filter * @returns {Attribute[]} all note's labels (attributes with type label), excluding inherited ones @@ -311,6 +319,14 @@ class Note extends Entity { return this.getOwnedAttributes(LABEL, name); } + /** + * @param {string} [name] - label name to filter + * @returns {string[]} all note's label values, excluding inherited ones + */ + getOwnedLabelValues(name) { + return this.getOwnedAttributes(LABEL, name).map(l => l.value); + } + /** * @param {string} [name] - relation name to filter * @returns {Attribute[]} all note's relations (attributes with type relation), including inherited ones diff --git a/src/public/app/widgets/attribute_widgets/attribute_detail.js b/src/public/app/widgets/attribute_widgets/attribute_detail.js index 7ca7a05da..3702fcec9 100644 --- a/src/public/app/widgets/attribute_widgets/attribute_detail.js +++ b/src/public/app/widgets/attribute_widgets/attribute_detail.js @@ -182,9 +182,11 @@ const ATTR_HELP = { `, + "runOnInstance": "Define which trilium instance should run this on. Default to all instances.", + "runAtHour": "On which hour should this run. Should be used together with #run=hourly", "disableInclusion": "scripts with this label won't be included into parent script execution.", "sorted": "keeps child notes sorted by title alphabetically", "hidePromotedAttributes": "Hide promoted attributes on this note", diff --git a/src/services/attributes.js b/src/services/attributes.js index ae78130f8..784bc1c60 100644 --- a/src/services/attributes.js +++ b/src/services/attributes.js @@ -25,6 +25,8 @@ const BUILTIN_ATTRIBUTES = [ { type: 'label', name: 'iconClass' }, { type: 'label', name: 'keyboardShortcut' }, { type: 'label', name: 'run', isDangerous: true }, + { type: 'label', name: 'runOnInstance', isDangerous: false }, + { type: 'label', name: 'runAtHours', isDangerous: false }, { type: 'label', name: 'customRequestHandler', isDangerous: true }, { type: 'label', name: 'customResourceProvider', isDangerous: true }, { type: 'label', name: 'widget', isDangerous: true }, diff --git a/src/services/scheduler.js b/src/services/scheduler.js index fffdc6152..805b8cf06 100644 --- a/src/services/scheduler.js +++ b/src/services/scheduler.js @@ -2,22 +2,45 @@ const scriptService = require('./script'); const repository = require('./repository'); const cls = require('./cls'); const sqlInit = require('./sql_init'); +const config = require('./config'); +const log = require('./log'); + +function getRunAtHours(note) { + try { + return note.getLabelValues('runAtHour').map(hour => parseInt(hour)); + } + catch (e) { + log.error(`Could not parse runAtHour for note ${note.noteId}: ${e.message}`); + + return []; + } +} function runNotesWithLabel(runAttrValue) { const notes = repository.getEntities(` SELECT notes.* FROM notes - JOIN attributes ON attributes.noteId = notes.noteId - AND attributes.isDeleted = 0 - AND attributes.type = 'label' - AND attributes.name = 'run' - AND attributes.value = ? + JOIN attributes ON attributes.noteId = notes.noteId + AND attributes.isDeleted = 0 + AND attributes.type = 'label' + AND attributes.name = 'run' + AND attributes.value = ? WHERE notes.type = 'code' AND notes.isDeleted = 0`, [runAttrValue]); + const instanceName = config.General ? config.General.instanceName : null; + const currentHours = new Date().getHours(); + for (const note of notes) { - scriptService.executeNoteNoException(note, { originEntity: note }); + const runOnInstances = note.getLabelValues('runOnInstance'); + const runAtHours = getRunAtHours(note); + + if ((runOnInstances.length === 0 || runOnInstances.includes(instanceName)) + && (runAtHours.length === 0 || runAtHours.includes(currentHours)) + ) { + scriptService.executeNoteNoException(note, {originEntity: note}); + } } }