mirror of
https://github.com/zadam/trilium.git
synced 2025-01-22 23:20:23 +08:00
improvements in frontend sync (WIP)
This commit is contained in:
parent
66374bf95f
commit
d0747b125c
10 changed files with 77 additions and 70 deletions
|
@ -41,44 +41,6 @@ class Attribute {
|
|||
return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name}, value=${this.value})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} - returns true if this attribute has the potential to influence the note in the argument.
|
||||
* That can happen in multiple ways:
|
||||
* 1. attribute is owned by the note
|
||||
* 2. attribute is owned by the template of the note
|
||||
* 3. attribute is owned by some note's ancestor and is inheritable
|
||||
*/
|
||||
isAffecting(affectedNote) {
|
||||
if (!affectedNote) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const attrNote = this.getNote();
|
||||
|
||||
if (!attrNote) {
|
||||
// the note (owner of the attribute) is not even loaded into the cache so it should not affect anything else
|
||||
return false;
|
||||
}
|
||||
|
||||
const owningNotes = [affectedNote, ...affectedNote.getTemplateNotes()];
|
||||
|
||||
for (const owningNote of owningNotes) {
|
||||
if (owningNote.noteId === attrNote.noteId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isInheritable) {
|
||||
for (const owningNote of owningNotes) {
|
||||
if (owningNote.hasAncestor(attrNote)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isDefinition() {
|
||||
return this.type === 'label' && (this.name.startsWith('label:') || this.name.startsWith('relation:'));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import server from './server.js';
|
||||
import froca from './froca.js';
|
||||
|
||||
async function addLabel(noteId, name, value = "") {
|
||||
await server.put(`notes/${noteId}/attribute`, {
|
||||
|
@ -20,8 +21,47 @@ async function removeAttributeById(noteId, attributeId) {
|
|||
await server.remove(`notes/${noteId}/attributes/${attributeId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} - returns true if this attribute has the potential to influence the note in the argument.
|
||||
* That can happen in multiple ways:
|
||||
* 1. attribute is owned by the note
|
||||
* 2. attribute is owned by the template of the note
|
||||
* 3. attribute is owned by some note's ancestor and is inheritable
|
||||
*/
|
||||
function isAffecting(attrRow, affectedNote) {
|
||||
if (!affectedNote || !attrRow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const attrNote = froca.notes[attrRow.noteId];
|
||||
|
||||
if (!attrNote) {
|
||||
// the note (owner of the attribute) is not even loaded into the cache so it should not affect anything else
|
||||
return false;
|
||||
}
|
||||
|
||||
const owningNotes = [affectedNote, ...affectedNote.getTemplateNotes()];
|
||||
|
||||
for (const owningNote of owningNotes) {
|
||||
if (owningNote.noteId === attrNote.noteId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isInheritable) {
|
||||
for (const owningNote of owningNotes) {
|
||||
if (owningNote.hasAncestor(attrNote)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export default {
|
||||
addLabel,
|
||||
setLabel,
|
||||
removeAttributeById
|
||||
removeAttributeById,
|
||||
isAffecting
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import froca from "../../services/froca.js";
|
|||
import attributeRenderer from "../../services/attribute_renderer.js";
|
||||
import noteCreateService from "../../services/note_create.js";
|
||||
import treeService from "../../services/tree.js";
|
||||
import attributeService from "../../services/attributes.js";
|
||||
|
||||
const HELP_TEXT = `
|
||||
<p>To add label, just type e.g. <code>#rock</code> or if you want to add also value then e.g. <code>#year = 2020</code></p>
|
||||
|
@ -511,7 +512,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget {
|
|||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attributeService.isAffecting(attr, this.note))) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||
import utils from "../services/utils.js";
|
||||
import protectedSessionHolder from "../services/protected_session_holder.js";
|
||||
import SpacedUpdate from "../services/spaced_update.js";
|
||||
import server from "../services/server.js";
|
||||
|
@ -20,6 +19,7 @@ import DeletedTypeWidget from "./type_widgets/deleted.js";
|
|||
import ReadOnlyTextTypeWidget from "./type_widgets/read_only_text.js";
|
||||
import ReadOnlyCodeTypeWidget from "./type_widgets/read_only_code.js";
|
||||
import NoneTypeWidget from "./type_widgets/none.js";
|
||||
import attributeService from "../services/attributes.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="note-detail">
|
||||
|
@ -246,12 +246,12 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
|
|||
const label = attrs.find(attr =>
|
||||
attr.type === 'label'
|
||||
&& ['readOnly', 'autoReadOnlyDisabled', 'cssClass', 'displayRelations'].includes(attr.name)
|
||||
&& attr.isAffecting(this.note));
|
||||
&& attributeService.isAffecting(attr, this.note));
|
||||
|
||||
const relation = attrs.find(attr =>
|
||||
attr.type === 'relation'
|
||||
&& ['template', 'renderNote'].includes(attr.name)
|
||||
&& attr.isAffecting(this.note));
|
||||
&& attributeService.isAffecting(attr, this.note));
|
||||
|
||||
if (label || relation) {
|
||||
// probably incorrect event
|
||||
|
|
|
@ -126,7 +126,7 @@ export default class NoteIconWidget extends NoteContextAwareWidget {
|
|||
for (const attr of loadResults.getAttributes()) {
|
||||
if (attr.type === 'label'
|
||||
&& ['iconClass', 'workspaceIconClass'].includes(attr.name)
|
||||
&& attr.isAffecting(this.note)) {
|
||||
&& attributeService.isAffecting(attr, this.note)) {
|
||||
|
||||
this.refresh();
|
||||
break;
|
||||
|
|
|
@ -972,36 +972,36 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||
const noteIdsToUpdate = new Set();
|
||||
const noteIdsToReload = new Set();
|
||||
|
||||
for (const attr of loadResults.getAttributes()) {
|
||||
if (attr.type === 'label' && ['iconClass', 'cssClass', 'workspace', 'workspaceIconClass', 'archived'].includes(attr.name)) {
|
||||
if (attr.isInheritable) {
|
||||
noteIdsToReload.add(attr.noteId);
|
||||
for (const ecAttr of loadResults.getAttributes()) {
|
||||
if (ecAttr.type === 'label' && ['iconClass', 'cssClass', 'workspace', 'workspaceIconClass', 'archived'].includes(ecAttr.name)) {
|
||||
if (ecAttr.isInheritable) {
|
||||
noteIdsToReload.add(ecAttr.noteId);
|
||||
}
|
||||
else {
|
||||
noteIdsToUpdate.add(attr.noteId);
|
||||
noteIdsToUpdate.add(ecAttr.noteId);
|
||||
}
|
||||
}
|
||||
else if (attr.type === 'relation' && attr.name === 'template') {
|
||||
else if (ecAttr.type === 'relation' && ecAttr.name === 'template') {
|
||||
// missing handling of things inherited from template
|
||||
noteIdsToReload.add(attr.noteId);
|
||||
noteIdsToReload.add(ecAttr.noteId);
|
||||
}
|
||||
else if (attr.type === 'relation' && attr.name === 'imageLink') {
|
||||
const note = froca.getNoteFromCache(attr.noteId);
|
||||
else if (ecAttr.type === 'relation' && ecAttr.name === 'imageLink') {
|
||||
const note = froca.getNoteFromCache(ecAttr.noteId);
|
||||
|
||||
if (note && note.getChildNoteIds().includes(attr.value)) {
|
||||
if (note && note.getChildNoteIds().includes(ecAttr.value)) {
|
||||
// there's new/deleted imageLink betwen note and its image child - which can show/hide
|
||||
// the image (if there is a imageLink relation between parent and child then it is assumed to be "contained" in the note and thus does not have to be displayed in the tree)
|
||||
noteIdsToReload.add(attr.noteId);
|
||||
noteIdsToReload.add(ecAttr.noteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const branch of loadResults.getBranches()) {
|
||||
for (const ecBranch of loadResults.getBranches()) {
|
||||
// adding noteId itself to update all potential clones
|
||||
noteIdsToUpdate.add(branch.noteId);
|
||||
noteIdsToUpdate.add(ecBranch.noteId);
|
||||
|
||||
for (const node of this.getNodesByBranch(branch)) {
|
||||
if (branch.isDeleted) {
|
||||
for (const node of this.getNodesByBranch(ecBranch)) {
|
||||
if (ecBranch.isDeleted) {
|
||||
if (node.isActive()) {
|
||||
const newActiveNode = node.getNextSibling()
|
||||
|| node.getPrevSibling()
|
||||
|
@ -1016,22 +1016,22 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||
node.remove();
|
||||
}
|
||||
|
||||
noteIdsToUpdate.add(branch.parentNoteId);
|
||||
noteIdsToUpdate.add(ecBranch.parentNoteId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!branch.isDeleted) {
|
||||
for (const parentNode of this.getNodesByNoteId(branch.parentNoteId)) {
|
||||
if (!ecBranch.isDeleted) {
|
||||
for (const parentNode of this.getNodesByNoteId(ecBranch.parentNoteId)) {
|
||||
if (parentNode.isFolder() && !parentNode.isLoaded()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const found = (parentNode.getChildren() || []).find(child => child.data.noteId === branch.noteId);
|
||||
const found = (parentNode.getChildren() || []).find(child => child.data.noteId === ecBranch.noteId);
|
||||
|
||||
if (!found) {
|
||||
// make sure it's loaded
|
||||
await froca.getNote(branch.noteId);
|
||||
const frocaBranch = froca.getBranch(branch.branchId);
|
||||
await froca.getNote(ecBranch.noteId);
|
||||
const frocaBranch = froca.getBranch(ecBranch.branchId);
|
||||
|
||||
// we're forcing lazy since it's not clear if the whole required subtree is in froca
|
||||
parentNode.addChildren([this.prepareNode(frocaBranch, true)]);
|
||||
|
@ -1039,7 +1039,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||
this.sortChildren(parentNode);
|
||||
|
||||
// this might be a first child which would force an icon change
|
||||
noteIdsToUpdate.add(branch.parentNoteId);
|
||||
noteIdsToUpdate.add(ecBranch.parentNoteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||
import AttributeDetailWidget from "../attribute_widgets/attribute_detail.js";
|
||||
import attributeRenderer from "../../services/attribute_renderer.js";
|
||||
import attributeService from "../../services/attributes.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="inherited-attributes-widget">
|
||||
|
@ -88,7 +89,7 @@ export default class InheritedAttributesWidget extends NoteContextAwareWidget {
|
|||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attributeService.isAffecting(attr, this.note))) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||
import AttributeDetailWidget from "../attribute_widgets/attribute_detail.js";
|
||||
import AttributeEditorWidget from "../attribute_widgets/attribute_editor.js";
|
||||
import attributeService from "../../services/attributes.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="attribute-list">
|
||||
|
@ -75,7 +76,7 @@ export default class OwnedAttributeListWidget extends NoteContextAwareWidget {
|
|||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attributeService.isAffecting(attr, this.note))) {
|
||||
this.refreshWithNote(this.note, true);
|
||||
|
||||
this.getTitle(this.note);
|
||||
|
|
|
@ -3,6 +3,7 @@ import ws from "../../services/ws.js";
|
|||
import treeService from "../../services/tree.js";
|
||||
import noteAutocompleteService from "../../services/note_autocomplete.js";
|
||||
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||
import attributeService from "../../services/attributes.js";
|
||||
|
||||
const TPL = `
|
||||
<div>
|
||||
|
@ -294,7 +295,7 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget {
|
|||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) {
|
||||
if (loadResults.getAttributes(this.componentId).find(attr => attributeService.isAffecting(attr, this.note))) {
|
||||
this.refresh();
|
||||
|
||||
this.getTitle(this.note);
|
||||
|
|
|
@ -4,6 +4,7 @@ import utils from "../services/utils.js";
|
|||
import keyboardActionService from "../services/keyboard_actions.js";
|
||||
import appContext from "../services/app_context.js";
|
||||
import froca from "../services/froca.js";
|
||||
import attributeService from "../services/attributes.js";
|
||||
|
||||
/*!
|
||||
* Draggabilly v2.3.0
|
||||
|
@ -668,7 +669,7 @@ export default class TabRowWidget extends BasicWidget {
|
|||
if (loadResults.isNoteReloaded(noteContext.noteId) ||
|
||||
loadResults.getAttributes().find(attr =>
|
||||
['workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor'].includes(attr.name)
|
||||
&& attr.isAffecting(noteContext.note))
|
||||
&& attributeService.isAffecting(attr, noteContext.note))
|
||||
) {
|
||||
const $tab = this.getTabById(noteContext.ntxId);
|
||||
|
||||
|
|
Loading…
Reference in a new issue