mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
added runOnAttributeChange event
This commit is contained in:
parent
5b15424498
commit
ac25770c0e
@ -28,6 +28,18 @@ class Attribute extends Entity {
|
|||||||
return await repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]);
|
return await repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.noteId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTargetNote() {
|
||||||
|
if (this.type !== 'relation') {
|
||||||
|
throw new Error(`Attribute ${this.attributeId} is not relation`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await repository.getEntity("SELECT * FROM notes WHERE noteId = ?", [this.value]);
|
||||||
|
}
|
||||||
|
|
||||||
isDefinition() {
|
isDefinition() {
|
||||||
return this.type === 'label-definition' || this.type === 'relation-definition';
|
return this.type === 'label-definition' || this.type === 'relation-definition';
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,22 @@ const ApiToken = require('../entities/api_token');
|
|||||||
const Option = require('../entities/option');
|
const Option = require('../entities/option');
|
||||||
const repository = require('../services/repository');
|
const repository = require('../services/repository');
|
||||||
|
|
||||||
|
const TABLE_NAME_TO_ENTITY = {
|
||||||
|
"attributes": Attribute.constructor,
|
||||||
|
"images": Image.constructor,
|
||||||
|
"note_images": NoteImage.constructor,
|
||||||
|
"branches": Branch.constructor,
|
||||||
|
"notes": Note.constructor,
|
||||||
|
"note_revisions": NoteRevision.constructor,
|
||||||
|
"recent_notes": RecentNote.constructor,
|
||||||
|
"options": Option.constructor,
|
||||||
|
"api_tokens": ApiToken.constructor,
|
||||||
|
};
|
||||||
|
|
||||||
|
function getEntityFromTableName(tableName) {
|
||||||
|
return TABLE_NAME_TO_ENTITY[tableName];
|
||||||
|
}
|
||||||
|
|
||||||
function createEntityFromRow(row) {
|
function createEntityFromRow(row) {
|
||||||
let entity;
|
let entity;
|
||||||
|
|
||||||
@ -46,8 +62,9 @@ function createEntityFromRow(row) {
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
repository.setEntityConstructor(createEntityFromRow);
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createEntityFromRow
|
createEntityFromRow,
|
||||||
};
|
getEntityFromTableName
|
||||||
|
};
|
||||||
|
|
||||||
|
repository.setEntityConstructor(module.exports);
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import ScriptContext from "./script_context.js";
|
import ScriptContext from "./script_context.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
|
|
||||||
async function getAndExecuteBundle(noteId, workNote = null) {
|
async function getAndExecuteBundle(noteId, workEntity = null) {
|
||||||
const bundle = await server.get('script/bundle/' + noteId);
|
const bundle = await server.get('script/bundle/' + noteId);
|
||||||
|
|
||||||
await executeBundle(bundle, workNote);
|
await executeBundle(bundle, workEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeBundle(bundle, workNote) {
|
async function executeBundle(bundle, workEntity) {
|
||||||
const apiContext = ScriptContext(bundle.note, bundle.allNotes, workNote);
|
const apiContext = ScriptContext(bundle.note, bundle.allNotes, workEntity);
|
||||||
|
|
||||||
return await (function () {
|
return await (function () {
|
||||||
return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`);
|
return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`);
|
||||||
|
@ -4,7 +4,7 @@ import utils from './utils.js';
|
|||||||
import infoService from './info.js';
|
import infoService from './info.js';
|
||||||
import linkService from './link.js';
|
import linkService from './link.js';
|
||||||
|
|
||||||
function ScriptApi(startNote, currentNote, workNote = null) {
|
function ScriptApi(startNote, currentNote, workEntity = null) {
|
||||||
const $pluginButtons = $("#plugin-buttons");
|
const $pluginButtons = $("#plugin-buttons");
|
||||||
|
|
||||||
async function activateNote(notePath) {
|
async function activateNote(notePath) {
|
||||||
@ -44,7 +44,8 @@ function ScriptApi(startNote, currentNote, workNote = null) {
|
|||||||
params: prepareParams(params),
|
params: prepareParams(params),
|
||||||
startNoteId: startNote.noteId,
|
startNoteId: startNote.noteId,
|
||||||
currentNoteId: currentNote.noteId,
|
currentNoteId: currentNote.noteId,
|
||||||
workNoteId: workNote ? workNote.noteId : null
|
workEntityName: workEntity ? workEntity.constructor.tableName() : null
|
||||||
|
workEntityId: workEntity ? workEntity.noteId : null
|
||||||
});
|
});
|
||||||
|
|
||||||
return ret.executionResult;
|
return ret.executionResult;
|
||||||
@ -53,7 +54,7 @@ function ScriptApi(startNote, currentNote, workNote = null) {
|
|||||||
return {
|
return {
|
||||||
startNote: startNote,
|
startNote: startNote,
|
||||||
currentNote: currentNote,
|
currentNote: currentNote,
|
||||||
workNote: workNote,
|
workEntity: workEntity,
|
||||||
addButtonToToolbar,
|
addButtonToToolbar,
|
||||||
activateNote,
|
activateNote,
|
||||||
getInstanceName: () => window.glob.instanceName,
|
getInstanceName: () => window.glob.instanceName,
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import ScriptApi from './script_api.js';
|
import ScriptApi from './script_api.js';
|
||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
|
|
||||||
function ScriptContext(startNote, allNotes, workNote = null) {
|
function ScriptContext(startNote, allNotes, workEntity = null) {
|
||||||
const modules = {};
|
const modules = {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
modules: modules,
|
modules: modules,
|
||||||
notes: utils.toObject(allNotes, note => [note.noteId, note]),
|
notes: utils.toObject(allNotes, note => [note.noteId, note]),
|
||||||
apis: utils.toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note, workNote)]),
|
apis: utils.toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note, workEntity)]),
|
||||||
require: moduleNoteIds => {
|
require: moduleNoteIds => {
|
||||||
return moduleName => {
|
return moduleName => {
|
||||||
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));
|
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));
|
||||||
|
@ -6,7 +6,7 @@ const repository = require('../../services/repository');
|
|||||||
|
|
||||||
async function exec(req) {
|
async function exec(req) {
|
||||||
const result = await scriptService.executeScript(req.body.script, req.body.params, req.body.startNoteId,
|
const result = await scriptService.executeScript(req.body.script, req.body.params, req.body.startNoteId,
|
||||||
req.body.currentNoteId, req.body.workNoteId);
|
req.body.currentNoteId, req.body.workEntityName, req.body.workEntityId);
|
||||||
|
|
||||||
return { executionResult: result };
|
return { executionResult: result };
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -2,16 +2,21 @@ const eventService = require('./events');
|
|||||||
const scriptService = require('./script');
|
const scriptService = require('./script');
|
||||||
const treeService = require('./tree');
|
const treeService = require('./tree');
|
||||||
const messagingService = require('./messaging');
|
const messagingService = require('./messaging');
|
||||||
|
const repository = require('./repository');
|
||||||
|
|
||||||
eventService.subscribe(eventService.NOTE_TITLE_CHANGED, async note => {
|
async function runAttachedRelations(note, relationName, workEntity) {
|
||||||
const attributes = await note.getAttributes();
|
const attributes = await note.getAttributes();
|
||||||
const runRelations = attributes.filter(relation => relation.type === 'relation' && relation.name === 'runOnNoteTitleChange');
|
const runRelations = attributes.filter(relation => relation.type === 'relation' && relation.name === relationName);
|
||||||
|
|
||||||
for (const relation of runRelations) {
|
for (const relation of runRelations) {
|
||||||
const scriptNote = await relation.getTargetNote();
|
const scriptNote = await relation.getTargetNote();
|
||||||
|
|
||||||
await scriptService.executeNote(scriptNote, scriptNote, note);
|
await scriptService.executeNote(scriptNote, scriptNote, workEntity);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventService.subscribe(eventService.NOTE_TITLE_CHANGED, async note => {
|
||||||
|
await runAttachedRelations(note, 'runOnNoteTitleChange', note);
|
||||||
|
|
||||||
if (!note.isRoot()) {
|
if (!note.isRoot()) {
|
||||||
const parents = await note.getParentNotes();
|
const parents = await note.getParentNotes();
|
||||||
@ -24,4 +29,12 @@ eventService.subscribe(eventService.NOTE_TITLE_CHANGED, async note => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityId, entityName }) => {
|
||||||
|
if (entityName === 'attributes') {
|
||||||
|
const attribute = await repository.getEntityFromName(entityName, entityId);
|
||||||
|
|
||||||
|
await runAttachedRelations(await attribute.getNote(), 'runOnAttributeChange', attribute);
|
||||||
|
}
|
||||||
});
|
});
|
@ -9,10 +9,16 @@ async function setEntityConstructor(constructor) {
|
|||||||
entityConstructor = constructor;
|
entityConstructor = constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getEntityFromName(entityName, entityId) {
|
||||||
|
const entityConstructor = entityConstructor.getEntityFromTableName(entityName);
|
||||||
|
|
||||||
|
return await getEntity(`SELECT * FROM ${entityConstructor.tableName()} WHERE ${entityConstructor.primaryKeyName()} = ?`, [entityId]);
|
||||||
|
}
|
||||||
|
|
||||||
async function getEntities(query, params = []) {
|
async function getEntities(query, params = []) {
|
||||||
const rows = await sql.getRows(query, params);
|
const rows = await sql.getRows(query, params);
|
||||||
|
|
||||||
return rows.map(entityConstructor);
|
return rows.map(entityConstructor.createEntityFromRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getEntity(query, params = []) {
|
async function getEntity(query, params = []) {
|
||||||
@ -22,7 +28,7 @@ async function getEntity(query, params = []) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entityConstructor(row);
|
return entityConstructor.createEntityFromRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getNote(noteId) {
|
async function getNote(noteId) {
|
||||||
@ -73,6 +79,7 @@ async function updateEntity(entity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
getEntityFromName,
|
||||||
getEntities,
|
getEntities,
|
||||||
getEntity,
|
getEntity,
|
||||||
getNote,
|
getNote,
|
||||||
|
@ -4,17 +4,17 @@ const repository = require('./repository');
|
|||||||
const cls = require('./cls');
|
const cls = require('./cls');
|
||||||
const sourceIdService = require('./source_id');
|
const sourceIdService = require('./source_id');
|
||||||
|
|
||||||
async function executeNote(note, targetNote) {
|
async function executeNote(note, workEntity) {
|
||||||
if (!note.isJavaScript()) {
|
if (!note.isJavaScript()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bundle = await getScriptBundle(note);
|
const bundle = await getScriptBundle(note);
|
||||||
|
|
||||||
await executeBundle(bundle, note, targetNote);
|
await executeBundle(bundle, note, workEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeBundle(bundle, startNote, workNote = null) {
|
async function executeBundle(bundle, startNote, workEntity = null) {
|
||||||
if (!startNote) {
|
if (!startNote) {
|
||||||
// this is the default case, the only exception is when we want to preserve frontend startNote
|
// this is the default case, the only exception is when we want to preserve frontend startNote
|
||||||
startNote = bundle.note;
|
startNote = bundle.note;
|
||||||
@ -23,7 +23,7 @@ async function executeBundle(bundle, startNote, workNote = null) {
|
|||||||
// last \r\n is necessary if script contains line comment on its last line
|
// last \r\n is necessary if script contains line comment on its last line
|
||||||
const script = "async function() {\r\n" + bundle.script + "\r\n}";
|
const script = "async function() {\r\n" + bundle.script + "\r\n}";
|
||||||
|
|
||||||
const ctx = new ScriptContext(startNote, bundle.allNotes, workNote);
|
const ctx = new ScriptContext(startNote, bundle.allNotes, workEntity);
|
||||||
|
|
||||||
if (await bundle.note.hasLabel('manualTransactionHandling')) {
|
if (await bundle.note.hasLabel('manualTransactionHandling')) {
|
||||||
return await execute(ctx, script, '');
|
return await execute(ctx, script, '');
|
||||||
@ -37,10 +37,10 @@ async function executeBundle(bundle, startNote, workNote = null) {
|
|||||||
* This method preserves frontend startNode - that's why we start execution from currentNote and override
|
* This method preserves frontend startNode - that's why we start execution from currentNote and override
|
||||||
* bundle's startNote.
|
* bundle's startNote.
|
||||||
*/
|
*/
|
||||||
async function executeScript(script, params, startNoteId, currentNoteId, targetNoteId) {
|
async function executeScript(script, params, startNoteId, currentNoteId, workEntityName, workEntityId) {
|
||||||
const startNote = await repository.getNote(startNoteId);
|
const startNote = await repository.getNote(startNoteId);
|
||||||
const currentNote = await repository.getNote(currentNoteId);
|
const currentNote = await repository.getNote(currentNoteId);
|
||||||
const targetNote = await repository.getNote(targetNoteId);
|
const workEntity = await repository.getEntityFromName(workEntityName, workEntityId);
|
||||||
|
|
||||||
currentNote.content = `return await (${script}\r\n)(${getParams(params)})`;
|
currentNote.content = `return await (${script}\r\n)(${getParams(params)})`;
|
||||||
currentNote.type = 'code';
|
currentNote.type = 'code';
|
||||||
@ -48,7 +48,7 @@ async function executeScript(script, params, startNoteId, currentNoteId, targetN
|
|||||||
|
|
||||||
const bundle = await getScriptBundle(currentNote);
|
const bundle = await getScriptBundle(currentNote);
|
||||||
|
|
||||||
return await executeBundle(bundle, startNote, targetNote);
|
return await executeBundle(bundle, startNote, workEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function execute(ctx, script, paramsStr) {
|
async function execute(ctx, script, paramsStr) {
|
||||||
|
@ -10,10 +10,10 @@ const config = require('./config');
|
|||||||
const repository = require('./repository');
|
const repository = require('./repository');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
|
||||||
function ScriptContext(startNote, allNotes, workNote = null) {
|
function ScriptContext(startNote, allNotes, workEntity = null) {
|
||||||
this.modules = {};
|
this.modules = {};
|
||||||
this.notes = utils.toObject(allNotes, note => [note.noteId, note]);
|
this.notes = utils.toObject(allNotes, note => [note.noteId, note]);
|
||||||
this.apis = utils.toObject(allNotes, note => [note.noteId, new ScriptApi(startNote, note, workNote)]);
|
this.apis = utils.toObject(allNotes, note => [note.noteId, new ScriptApi(startNote, note, workEntity)]);
|
||||||
this.require = moduleNoteIds => {
|
this.require = moduleNoteIds => {
|
||||||
return moduleName => {
|
return moduleName => {
|
||||||
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));
|
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));
|
||||||
@ -28,10 +28,10 @@ function ScriptContext(startNote, allNotes, workNote = null) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function ScriptApi(startNote, currentNote, workNote) {
|
function ScriptApi(startNote, currentNote, workEntity) {
|
||||||
this.startNote = startNote;
|
this.startNote = startNote;
|
||||||
this.currentNote = currentNote;
|
this.currentNote = currentNote;
|
||||||
this.workNote = workNote;
|
this.workEntity = workEntity;
|
||||||
|
|
||||||
this.axios = axios;
|
this.axios = axios;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user