import LoadResults from "./load_results.js"; import froca from "./froca.js"; import utils from "./utils.js"; import options from "./options.js"; import noteAttributeCache from "./note_attribute_cache.js"; import Branch from "../entities/branch.js"; import Attribute from "../entities/attribute.js"; async function processEntityChanges(entityChanges) { const loadResults = new LoadResults(entityChanges); for (const ec of entityChanges) { try { if (ec.entityName === 'notes') { processNoteChange(loadResults, ec); } else if (ec.entityName === 'branches') { processBranchChange(loadResults, ec); } else if (ec.entityName === 'attributes') { processAttributeChange(loadResults, ec); } else if (ec.entityName === 'note_reordering') { processNoteReordering(loadResults, ec); } else if (ec.entityName === 'note_contents') { delete froca.noteComplementPromises[ec.entityId]; loadResults.addNoteContent(ec.entityId, ec.componentId); } else if (ec.entityName === 'note_revisions') { loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.componentId); } else if (ec.entityName === 'note_revision_contents') { // this should change only when toggling isProtected, ignore } else if (ec.entityName === 'options') { if (ec.entity.name === 'openTabs') { continue; // only noise } options.set(ec.entity.name, ec.entity.value); loadResults.addOption(ec.entity.name); } else if (ec.entityName === 'etapi_tokens') { // NOOP } else { throw new Error(`Unknown entityName ${ec.entityName}`); } } catch (e) { throw new Error(`Can't process entity ${JSON.stringify(ec)} with error ${e.message} ${e.stack}`); } } const missingNoteIds = []; for (const {entityName, entity} of entityChanges) { if (!entity) { // if erased continue; } if (entityName === 'branches' && !(entity.parentNoteId in froca.notes)) { missingNoteIds.push(entity.parentNoteId); } else if (entityName === 'attributes' && entity.type === 'relation' && entity.name === 'template' && !(entity.value in froca.notes)) { missingNoteIds.push(entity.value); } } if (missingNoteIds.length > 0) { await froca.reloadNotes(missingNoteIds); } if (!loadResults.isEmpty()) { if (loadResults.hasAttributeRelatedChanges()) { noteAttributeCache.invalidate(); } const appContext = (await import("./app_context.js")).default; await appContext.triggerEvent('entitiesReloaded', {loadResults}); } } function processNoteChange(loadResults, ec) { const note = froca.notes[ec.entityId]; if (!note) { // if this note has not been requested before then it's not part of froca's cached subset and // we're not interested in it return; } loadResults.addNote(ec.entityId, ec.componentId); if (ec.isErased && ec.entityId in froca.notes) { utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`); return; } if (ec.isErased || ec.entity?.isDeleted) { delete froca.notes[ec.entityId]; } else { note.update(ec.entity); } } function processBranchChange(loadResults, ec) { if (ec.isErased && ec.entityId in froca.branches) { utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`); return; } let branch = froca.branches[ec.entityId]; if (ec.isErased || ec.entity?.isDeleted) { if (branch) { const childNote = froca.notes[branch.noteId]; const parentNote = froca.notes[branch.parentNoteId]; if (childNote) { childNote.parents = childNote.parents.filter(parentNoteId => parentNoteId !== branch.parentNoteId); delete childNote.parentToBranch[branch.parentNoteId]; } if (parentNote) { parentNote.children = parentNote.children.filter(childNoteId => childNoteId !== branch.noteId); delete parentNote.childToBranch[branch.noteId]; } loadResults.addBranch(ec.entityId, ec.componentId); delete froca.branches[ec.entityId]; } return; } loadResults.addBranch(ec.entityId, ec.componentId); const childNote = froca.notes[ec.entity.noteId]; const parentNote = froca.notes[ec.entity.parentNoteId]; if (branch) { branch.update(ec.entity); } else if (childNote || parentNote) { froca.branches[ec.entityId] = branch = new Branch(froca, ec.entity); } if (childNote) { childNote.addParent(branch.parentNoteId, branch.branchId); } if (parentNote) { parentNote.addChild(branch.noteId, branch.branchId); } } function processNoteReordering(loadResults, ec) { const parentNoteIdsToSort = new Set(); for (const branchId in ec.positions) { const branch = froca.branches[branchId]; if (branch) { branch.notePosition = ec.positions[branchId]; parentNoteIdsToSort.add(branch.parentNoteId); } } for (const parentNoteId of parentNoteIdsToSort) { const parentNote = froca.notes[parentNoteId]; if (parentNote) { parentNote.sortChildren(); } } loadResults.addNoteReordering(ec.entityId, ec.componentId); } function processAttributeChange(loadResults, ec) { let attribute = froca.attributes[ec.entityId]; if (ec.isErased && ec.entityId in froca.attributes) { utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`); return; } if (ec.isErased || ec.entity?.isDeleted) { if (attribute) { const sourceNote = froca.notes[attribute.noteId]; const targetNote = attribute.type === 'relation' && froca.notes[attribute.value]; if (sourceNote) { sourceNote.attributes = sourceNote.attributes.filter(attributeId => attributeId !== attribute.attributeId); } if (targetNote) { targetNote.targetRelations = targetNote.targetRelations.filter(attributeId => attributeId !== attribute.attributeId); } loadResults.addAttribute(ec.entityId, ec.componentId); delete froca.attributes[ec.entityId]; } return; } loadResults.addAttribute(ec.entityId, ec.componentId); const sourceNote = froca.notes[ec.entity.noteId]; const targetNote = ec.entity.type === 'relation' && froca.notes[ec.entity.value]; if (attribute) { attribute.update(ec.entity); } else if (sourceNote || targetNote) { attribute = new Attribute(froca, ec.entity); froca.attributes[attribute.attributeId] = attribute; if (sourceNote && !sourceNote.attributes.includes(attribute.attributeId)) { sourceNote.attributes.push(attribute.attributeId); } if (targetNote && !targetNote.targetRelations.includes(attribute.attributeId)) { targetNote.targetRelations.push(attribute.attributeId); } } } export default { processEntityChanges }