improvements in frontend sync (WIP)

This commit is contained in:
zadam 2021-08-25 22:49:24 +02:00
parent 66374bf95f
commit d0747b125c
10 changed files with 77 additions and 70 deletions

View file

@ -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:'));
}

View file

@ -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
}

View file

@ -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();
}
}

View file

@ -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

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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);