mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
more relation events, events are now not triggered on sync changes
This commit is contained in:
parent
df9acd0504
commit
0f106fb96f
@ -6,6 +6,9 @@ const protectedSessionService = require('../services/protected_session');
|
||||
const repository = require('../services/repository');
|
||||
const dateUtils = require('../services/date_utils');
|
||||
|
||||
const LABEL = 'label';
|
||||
const RELATION = 'relation';
|
||||
|
||||
class Note extends Entity {
|
||||
static get tableName() { return "notes"; }
|
||||
static get primaryKeyName() { return "noteId"; }
|
||||
@ -78,6 +81,14 @@ class Note extends Entity {
|
||||
return this.__attributeCache;
|
||||
}
|
||||
|
||||
async getLabels() {
|
||||
return (await this.getAttributes()).filter(attr => attr.type === LABEL);
|
||||
}
|
||||
|
||||
async getRelations() {
|
||||
return (await this.getAttributes()).filter(attr => attr.type === RELATION);
|
||||
}
|
||||
|
||||
invalidateAttributeCache() {
|
||||
this.__attributeCache = null;
|
||||
}
|
||||
@ -145,55 +156,55 @@ class Note extends Entity {
|
||||
this.__attributeCache = filteredAttributes;
|
||||
}
|
||||
|
||||
async hasLabel(name) {
|
||||
return !!await this.getLabel(name);
|
||||
async hasAttribute(type, name) {
|
||||
return !!await this.getAttribute(type, name);
|
||||
}
|
||||
|
||||
// WARNING: this doesn't take into account the possibility to have multi-valued labels!
|
||||
async getLabel(name) {
|
||||
async getAttribute(type, name) {
|
||||
const attributes = await this.getAttributes();
|
||||
|
||||
return attributes.find(attr => attr.type === 'label' && attr.name === name);
|
||||
return attributes.find(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
|
||||
async getLabelValue(name) {
|
||||
const label = await this.getLabel(name);
|
||||
async getAttributeValue(type, name) {
|
||||
const attr = await this.getAttribute(type, name);
|
||||
|
||||
return label ? label.value : null;
|
||||
return attr ? attr.value : null;
|
||||
}
|
||||
|
||||
async toggleLabel(enabled, name, value = "") {
|
||||
async toggleAttribute(type, enabled, name, value = "") {
|
||||
if (enabled) {
|
||||
await this.setLabel(name, value);
|
||||
await this.setAttribute(type, name, value);
|
||||
}
|
||||
else {
|
||||
await this.removeLabel(name, value);
|
||||
await this.removeAttribute(type, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
async setLabel(name, value = "") {
|
||||
async setAttribute(type, name, value = "") {
|
||||
const attributes = await this.getOwnedAttributes();
|
||||
let label = attributes.find(attr => attr.type === 'label' && attr.value === value);
|
||||
let attr = attributes.find(attr => attr.type === type && attr.value === value);
|
||||
|
||||
if (!label) {
|
||||
label = new Attribute({
|
||||
if (!attr) {
|
||||
attr = new Attribute({
|
||||
noteId: this.noteId,
|
||||
type: 'label',
|
||||
type: type,
|
||||
name: name,
|
||||
value: value
|
||||
});
|
||||
|
||||
await label.save();
|
||||
await attr.save();
|
||||
|
||||
this.invalidateAttributeCache();
|
||||
}
|
||||
}
|
||||
|
||||
async removeLabel(name, value = "") {
|
||||
async removeAttribute(type, name, value = "") {
|
||||
const attributes = await this.getOwnedAttributes();
|
||||
|
||||
for (const attribute of attributes) {
|
||||
if (attribute.type === 'label' && (!value || value === attribute.value)) {
|
||||
if (attribute.type === type && (!value || value === attribute.value)) {
|
||||
attribute.isDeleted = true;
|
||||
await attribute.save();
|
||||
|
||||
@ -202,6 +213,24 @@ class Note extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
|
||||
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
|
||||
|
||||
async getLabel(name) { return await this.getAttribute(LABEL, name); }
|
||||
async getRelation(name) { return await this.getAttribute(RELATION, name); }
|
||||
|
||||
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
|
||||
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
|
||||
|
||||
async toggleLabel(enabled, name, value = "") { return await this.toggleAttribute(LABEL, enabled, name, value); }
|
||||
async toggleRelation(enabled, name, value = "") { return await this.toggleAttribute(RELATION, enabled, name, value); }
|
||||
|
||||
async setLabel(name, value = "") { return await this.setAttribute(LABEL, name, value); }
|
||||
async setRelation(name, value = "") { return await this.setAttribute(RELATION, name, value); }
|
||||
|
||||
async removeLabel(name, value = "") { return await this.removeAttribute(LABEL, name, value); }
|
||||
async removeRelation(name, value = "") { return await this.removeAttribute(RELATION, name, value); }
|
||||
|
||||
async getRevisions() {
|
||||
return await repository.getEntities("SELECT * FROM note_revisions WHERE noteId = ?", [this.noteId]);
|
||||
}
|
||||
|
@ -19,7 +19,11 @@ const BUILTIN_ATTRIBUTES = [
|
||||
|
||||
// relation names
|
||||
{ type: 'relation', name: 'runOnNoteView' },
|
||||
{ type: 'relation', name: 'runOnNoteCreation' },
|
||||
{ type: 'relation', name: 'runOnNoteTitleChange' },
|
||||
{ type: 'relation', name: 'runOnNoteChange' },
|
||||
{ type: 'relation', name: 'runOnChildNoteCreation' },
|
||||
{ type: 'relation', name: 'runOnAttributeCreation' },
|
||||
{ type: 'relation', name: 'runOnAttributeChange' },
|
||||
{ type: 'relation', name: 'inheritAttributes' }
|
||||
];
|
||||
@ -59,20 +63,19 @@ async function createAttribute(attribute) {
|
||||
}
|
||||
|
||||
async function getAttributeNames(type, nameLike) {
|
||||
let names;
|
||||
nameLike = nameLike.toLowerCase();
|
||||
|
||||
if (!nameLike) {
|
||||
names = BUILTIN_ATTRIBUTES
|
||||
.filter(attribute => attribute.type === type)
|
||||
.map(attribute => attribute.name);
|
||||
}
|
||||
else {
|
||||
names = await sql.getColumn(
|
||||
`SELECT DISTINCT name
|
||||
const names = await sql.getColumn(
|
||||
`SELECT DISTINCT name
|
||||
FROM attributes
|
||||
WHERE isDeleted = 0
|
||||
AND type = ?
|
||||
AND name LIKE '%${utils.sanitizeSql(nameLike)}%'`, [type]);
|
||||
|
||||
for (const attr of BUILTIN_ATTRIBUTES) {
|
||||
if (attr.type === type && attr.name.toLowerCase().includes(nameLike) && !names.includes(attr.name)) {
|
||||
names.push(attr.name);
|
||||
}
|
||||
}
|
||||
|
||||
names.sort();
|
||||
|
@ -2,7 +2,9 @@ const log = require('./log');
|
||||
|
||||
const NOTE_TITLE_CHANGED = "NOTE_TITLE_CHANGED";
|
||||
const ENTER_PROTECTED_SESSION = "ENTER_PROTECTED_SESSION";
|
||||
const ENTITY_CREATED = "ENTITY_CREATED";
|
||||
const ENTITY_CHANGED = "ENTITY_CHANGED";
|
||||
const CHILD_NOTE_CREATED = "CHILD_NOTE_CREATED";
|
||||
|
||||
const eventListeners = {};
|
||||
|
||||
@ -33,5 +35,7 @@ module.exports = {
|
||||
// event types:
|
||||
NOTE_TITLE_CHANGED,
|
||||
ENTER_PROTECTED_SESSION,
|
||||
ENTITY_CHANGED
|
||||
ENTITY_CREATED,
|
||||
ENTITY_CHANGED,
|
||||
CHILD_NOTE_CREATED
|
||||
};
|
@ -2,12 +2,10 @@ const eventService = require('./events');
|
||||
const scriptService = require('./script');
|
||||
const treeService = require('./tree');
|
||||
const messagingService = require('./messaging');
|
||||
const repository = require('./repository');
|
||||
const log = require('./log');
|
||||
|
||||
async function runAttachedRelations(note, relationName, originEntity) {
|
||||
const attributes = await note.getAttributes();
|
||||
const runRelations = attributes.filter(relation => relation.type === 'relation' && relation.name === relationName);
|
||||
const runRelations = (await note.getRelations()).filter(relation => relation.name === relationName);
|
||||
|
||||
for (const relation of runRelations) {
|
||||
const scriptNote = await relation.getTargetNote();
|
||||
@ -37,10 +35,24 @@ eventService.subscribe(eventService.NOTE_TITLE_CHANGED, async note => {
|
||||
}
|
||||
});
|
||||
|
||||
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityId, entityName }) => {
|
||||
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityName, entity }) => {
|
||||
if (entityName === 'attributes') {
|
||||
const attribute = await repository.getEntityFromName(entityName, entityId);
|
||||
|
||||
await runAttachedRelations(await attribute.getNote(), 'runOnAttributeChange', attribute);
|
||||
await runAttachedRelations(await entity.getNote(), 'runOnAttributeChange', entity);
|
||||
}
|
||||
else if (entityName === 'notes') {
|
||||
await runAttachedRelations(entity, 'runOnNoteChange', entity);
|
||||
}
|
||||
});
|
||||
|
||||
eventService.subscribe(eventService.ENTITY_CREATED, async ({ entityName, entity }) => {
|
||||
if (entityName === 'attributes') {
|
||||
await runAttachedRelations(await entity.getNote(), 'runOnAttributeCreation', entity);
|
||||
}
|
||||
else if (entityName === 'notes') {
|
||||
await runAttachedRelations(entity, 'runOnNoteCreation', entity);
|
||||
}
|
||||
});
|
||||
|
||||
eventService.subscribe(eventService.CHILD_NOTE_CREATED, async ({ parentNote, childNote }) => {
|
||||
await runAttachedRelations(parentNote, 'runOnChildNoteCreation', childNote);
|
||||
});
|
@ -228,13 +228,13 @@ function getNotePath(noteId) {
|
||||
}
|
||||
}
|
||||
|
||||
eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entityId}) => {
|
||||
eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entity}) => {
|
||||
if (!loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entityName === 'notes') {
|
||||
const note = await repository.getNote(entityId);
|
||||
const note = entity;
|
||||
|
||||
if (note.isDeleted) {
|
||||
delete noteTitles[note.noteId];
|
||||
@ -245,7 +245,7 @@ eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entityId
|
||||
}
|
||||
}
|
||||
else if (entityName === 'branches') {
|
||||
const branch = await repository.getBranch(entityId);
|
||||
const branch = entity;
|
||||
|
||||
if (childToParent[branch.noteId]) {
|
||||
childToParent[branch.noteId] = childToParent[branch.noteId].filter(noteId => noteId !== branch.parentNoteId)
|
||||
@ -266,7 +266,7 @@ eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entityId
|
||||
}
|
||||
}
|
||||
else if (entityName === 'attributes') {
|
||||
const attribute = await repository.getAttribute(entityId);
|
||||
const attribute = entity;
|
||||
|
||||
if (attribute.type === 'label' && attribute.name === 'archived') {
|
||||
// we're not using label object directly, since there might be other non-deleted archived label
|
||||
|
@ -35,6 +35,10 @@ async function getNewNotePosition(parentNoteId, noteData) {
|
||||
return newNotePos;
|
||||
}
|
||||
|
||||
async function triggerChildNoteCreated(childNote, parentNote) {
|
||||
await eventService.emit(eventService.CHILD_NOTE_CREATED, { childNote, parentNote });
|
||||
}
|
||||
|
||||
async function triggerNoteTitleChanged(note) {
|
||||
await eventService.emit(eventService.NOTE_TITLE_CHANGED, note);
|
||||
}
|
||||
@ -42,12 +46,10 @@ async function triggerNoteTitleChanged(note) {
|
||||
async function createNewNote(parentNoteId, noteData) {
|
||||
const newNotePos = await getNewNotePosition(parentNoteId, noteData);
|
||||
|
||||
if (parentNoteId !== 'root') {
|
||||
const parent = await repository.getNote(parentNoteId);
|
||||
const parentNote = await repository.getNote(parentNoteId);
|
||||
|
||||
noteData.type = noteData.type || parent.type;
|
||||
noteData.mime = noteData.mime || parent.mime;
|
||||
}
|
||||
noteData.type = noteData.type || parentNote.type;
|
||||
noteData.mime = noteData.mime || parentNote.mime;
|
||||
|
||||
const note = await new Note({
|
||||
title: noteData.title,
|
||||
@ -66,6 +68,7 @@ async function createNewNote(parentNoteId, noteData) {
|
||||
}).save();
|
||||
|
||||
await triggerNoteTitleChanged(note);
|
||||
await triggerChildNoteCreated(note, parentNote);
|
||||
|
||||
return {
|
||||
note,
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
const sql = require('./sql');
|
||||
const syncTableService = require('../services/sync_table');
|
||||
const eventService = require('./events');
|
||||
|
||||
let entityConstructor;
|
||||
|
||||
@ -56,6 +57,11 @@ async function getOption(name) {
|
||||
}
|
||||
|
||||
async function updateEntity(entity) {
|
||||
const entityName = entity.constructor.tableName;
|
||||
const primaryKeyName = entity.constructor.primaryKeyName;
|
||||
|
||||
const isNewEntity = !entity[primaryKeyName];
|
||||
|
||||
if (entity.beforeSaving) {
|
||||
await entity.beforeSaving();
|
||||
}
|
||||
@ -75,12 +81,24 @@ async function updateEntity(entity) {
|
||||
}
|
||||
|
||||
await sql.transactional(async () => {
|
||||
await sql.replace(entity.constructor.tableName, clone);
|
||||
await sql.replace(entityName, clone);
|
||||
|
||||
const primaryKey = entity[entity.constructor.primaryKeyName];
|
||||
const primaryKey = entity[primaryKeyName];
|
||||
|
||||
if (entity.isChanged && (entity.constructor.tableName !== 'options' || entity.isSynced)) {
|
||||
await syncTableService.addEntitySync(entity.constructor.tableName, primaryKey);
|
||||
if (entity.isChanged && (entityName !== 'options' || entity.isSynced)) {
|
||||
await syncTableService.addEntitySync(entityName, primaryKey);
|
||||
|
||||
if (isNewEntity) {
|
||||
await eventService.emit(eventService.ENTITY_CREATED, {
|
||||
entityName,
|
||||
entity
|
||||
});
|
||||
}
|
||||
|
||||
await eventService.emit(eventService.ENTITY_CHANGED, {
|
||||
entityName,
|
||||
entity
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ const sourceIdService = require('./source_id');
|
||||
const dateUtils = require('./date_utils');
|
||||
const log = require('./log');
|
||||
const cls = require('./cls');
|
||||
const eventService = require('./events');
|
||||
|
||||
async function addNoteSync(noteId, sourceId) {
|
||||
await addEntitySync("notes", noteId, sourceId)
|
||||
@ -52,11 +51,6 @@ async function addEntitySync(entityName, entityId, sourceId) {
|
||||
syncDate: dateUtils.nowDate(),
|
||||
sourceId: sourceId || cls.getSourceId() || sourceIdService.getCurrentSourceId()
|
||||
});
|
||||
|
||||
await eventService.emit(eventService.ENTITY_CHANGED, {
|
||||
entityName,
|
||||
entityId
|
||||
});
|
||||
}
|
||||
|
||||
async function cleanupSyncRowsForMissingEntities(entityName, entityKey) {
|
||||
@ -116,6 +110,5 @@ module.exports = {
|
||||
addAttributeSync,
|
||||
addApiTokenSync,
|
||||
addEntitySync,
|
||||
cleanupSyncRowsForMissingEntities,
|
||||
fillAllSyncRows
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user