Fixed tree reset after sync, optimized sync with IndexedDB
This commit is contained in:
parent
454d065baa
commit
26ca510785
5 changed files with 72 additions and 52 deletions
|
|
@ -6,13 +6,13 @@ import { Node } from 'node'
|
|||
export class App {
|
||||
constructor() {// {{{
|
||||
this.currentNode = null
|
||||
this.treeNative = new N2Tree()
|
||||
this.tree = new N2Tree()
|
||||
this.crumbs = new N2Crumbs()
|
||||
this.crumbsElement = document.getElementById('crumbs')
|
||||
this.nodeUI = document.getElementById('note')
|
||||
|
||||
_mbus.subscribe('TREE_TRUNK_FETCHED', async () => {
|
||||
document.getElementById('tree').append(this.treeNative.render())
|
||||
document.getElementById('tree').append(this.tree.render())
|
||||
document.getElementById('tree-nodes')?.focus()
|
||||
|
||||
const startNode = await this.getStartNode()
|
||||
|
|
@ -188,7 +188,7 @@ export class App {
|
|||
node.reset() // any modifications are discarded.
|
||||
|
||||
this.currentNode = node
|
||||
this.treeNative.setSelected(node, dontExpand)
|
||||
this.tree.setSelected(node, dontExpand)
|
||||
|
||||
const ancestors = await nodeStore.getNodeAncestry(node)
|
||||
_mbus.dispatch('CRUMBS_SET', ancestors, () => this.crumbsElement.replaceChildren(this.crumbs.render()))
|
||||
|
|
@ -196,7 +196,7 @@ export class App {
|
|||
_mbus.dispatch('NODE_UNMODIFIED')
|
||||
|
||||
// Scrolls node into view.
|
||||
this.treeNative.makeVisible(node)
|
||||
this.tree.makeVisible(node)
|
||||
}//}}}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export class Node {
|
|||
if (a.data.Name > b.data.Name) return 0
|
||||
return 0
|
||||
}//}}}
|
||||
static create(name, parentUUID) {
|
||||
static create(name, parentUUID) {// {{{
|
||||
return new Node({
|
||||
UUID: uuidv7(),
|
||||
Created: (new Date()).toISOString(),
|
||||
|
|
@ -64,7 +64,7 @@ export class Node {
|
|||
Markdown: false,
|
||||
History: false,
|
||||
})
|
||||
}
|
||||
}// }}}
|
||||
|
||||
constructor(nodeData, level) {//{{{
|
||||
|
||||
|
|
@ -123,9 +123,6 @@ export class Node {
|
|||
return this._children_fetched
|
||||
}//}}}
|
||||
async fetchChildren() {//{{{
|
||||
if (this._children_fetched)
|
||||
return this.Children
|
||||
|
||||
this.Children = await nodeStore.getTreeNodes(this.UUID, this.Level + 1)
|
||||
this._children_fetched = true
|
||||
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ export class NodeStore {
|
|||
})
|
||||
}//}}}
|
||||
|
||||
/*
|
||||
upsertNodeRecords(records) {//{{{
|
||||
return new Promise((resolve, reject) => {
|
||||
const t = this.db.transaction('nodes', 'readwrite')
|
||||
|
|
@ -187,16 +188,10 @@ export class NodeStore {
|
|||
record.modified = 0
|
||||
addReq = nodeStore.put(record)
|
||||
}
|
||||
addReq.onsuccess = () => {
|
||||
console.debug(`${op} ${record.UUID} (${record.Name})`)
|
||||
}
|
||||
addReq.onerror = (event) => {
|
||||
console.log(`error ${op} ${record.UUID}`, event.target.error)
|
||||
reject(event.target.error)
|
||||
}
|
||||
}
|
||||
})
|
||||
}//}}}
|
||||
*/
|
||||
getTreeNodes(parent, newLevel) {//{{{
|
||||
return new Promise((resolve, reject) => {
|
||||
// Parent of toplevel nodes is ROOT_NODE in indexedDB.
|
||||
|
|
@ -219,7 +214,7 @@ export class NodeStore {
|
|||
req.onerror = (event) => reject(event.target.error)
|
||||
})
|
||||
}//}}}
|
||||
async search(searchfor, parent) {//{{{
|
||||
search(searchfor, parent) {//{{{
|
||||
return new Promise((resolve, reject) => {
|
||||
const trx = this.db.transaction('nodes', 'readonly')
|
||||
const nodeStore = trx.objectStore('nodes')
|
||||
|
|
@ -249,43 +244,55 @@ export class NodeStore {
|
|||
})
|
||||
}//}}}
|
||||
|
||||
add(records) {//{{{
|
||||
add(records, objstore) {//{{{
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const t = this.db.transaction('nodes', 'readwrite')
|
||||
const nodeStore = t.objectStore('nodes')
|
||||
// A nodestore can be provided in order to
|
||||
// avoid creating new transactions.
|
||||
let nodeStore = objstore
|
||||
let t
|
||||
|
||||
if (nodeStore === undefined) {
|
||||
t = this.db.transaction('nodes', 'readwrite')
|
||||
nodeStore = t.objectStore('nodes')
|
||||
|
||||
t.oncomplete = (_event) => {
|
||||
resolve()
|
||||
}
|
||||
|
||||
t.onerror = (event) => {
|
||||
console.error('transaction error', event.target.error)
|
||||
reject(event.target.error)
|
||||
}
|
||||
}
|
||||
|
||||
// records is an object, not an array.
|
||||
const promises = []
|
||||
for (const recordIdx in records) {
|
||||
const record = records[recordIdx]
|
||||
const addReq = nodeStore.put(record.data)
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
addReq.onsuccess = () => resolve()
|
||||
addReq.onerror = (event) => {
|
||||
console.error('Error!', event.target.error, record.ID)
|
||||
reject(event.target.error)
|
||||
}
|
||||
})
|
||||
promises.push(promise)
|
||||
nodeStore.put(record.data)
|
||||
}
|
||||
|
||||
Promise.all(promises).then(() => resolve())
|
||||
resolve()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
console.error(e)
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
}//}}}
|
||||
get(uuid) {//{{{
|
||||
get(uuid, suppliedNodestore) {//{{{
|
||||
return new Promise((resolve, reject) => {
|
||||
const trx = this.db.transaction('nodes', 'readonly')
|
||||
const nodeStore = trx.objectStore('nodes')
|
||||
// A nodestore can be provided in order to
|
||||
// avoid creating new transactions.
|
||||
let trx
|
||||
let nodeStore = suppliedNodestore
|
||||
|
||||
if (nodeStore === undefined) {
|
||||
trx = this.db.transaction('nodes', 'readonly')
|
||||
nodeStore = trx.objectStore('nodes')
|
||||
}
|
||||
|
||||
const getRequest = nodeStore.get(uuid)
|
||||
|
||||
getRequest.onsuccess = (event) => {
|
||||
// Node not found in IndexedDB.
|
||||
if (event.target.result === undefined) {
|
||||
|
|
@ -328,6 +335,9 @@ export class NodeStore {
|
|||
})
|
||||
|
||||
}//}}}
|
||||
newTransaction(objectStore, mode) {// {{{
|
||||
return this.db.transaction(objectStore, mode)
|
||||
}// }}}
|
||||
|
||||
nodeCount() {//{{{
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
|||
|
|
@ -65,9 +65,16 @@ export class Sync {
|
|||
* sync be preserved in the backend. */
|
||||
|
||||
let backendNode = null
|
||||
|
||||
// Create a single transaction to be used in the chain of
|
||||
// this sync. Otherwise it would take more time to create
|
||||
// transactions for each node.
|
||||
const trx = nodeStore.newTransaction('nodes', 'readwrite')
|
||||
const objstore = trx.objectStore('nodes')
|
||||
|
||||
for (const i in res.Nodes) {
|
||||
backendNode = new Node(res.Nodes[i], -1)
|
||||
await window._sync.handleNode(backendNode)
|
||||
await this.handleNode(backendNode, objstore)
|
||||
|
||||
handled++
|
||||
if (handled % 100 === 0)
|
||||
|
|
@ -88,16 +95,16 @@ export class Sync {
|
|||
}
|
||||
return (syncEnd - syncStart)
|
||||
}//}}}
|
||||
async handleNode(backendNode) {//{{{
|
||||
async handleNode(backendNode, objstore) {//{{{
|
||||
try {
|
||||
/* Retrieving the local copy of this node from IndexedDB.
|
||||
* The backend node can be discarded if it is older than
|
||||
* the local copy since it is considered history preserved
|
||||
* in the backend. */
|
||||
return nodeStore.get(backendNode.UUID)
|
||||
.then(async localNode => {
|
||||
return nodeStore.get(backendNode.UUID, objstore)
|
||||
.then(localNode => {
|
||||
if (localNode.updated() >= backendNode.updated()) {
|
||||
console.log(`History from backend: ${backendNode.UUID}`)
|
||||
console.debug(`History from backend: ${backendNode.UUID}`)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -107,12 +114,12 @@ export class Sync {
|
|||
*
|
||||
* If the local node has seen change, the change is already
|
||||
* placed into the send_queue anyway. */
|
||||
return nodeStore.add([backendNode])
|
||||
return nodeStore.add([backendNode], objstore)
|
||||
|
||||
})
|
||||
.catch(async () => {
|
||||
.catch(() => {
|
||||
// Not found in IndexedDB - OK to just insert since it only exists in backend.
|
||||
return nodeStore.add([backendNode])
|
||||
return nodeStore.add([backendNode], objstore)
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
|
@ -198,10 +205,7 @@ export class N2SyncProgress extends CustomHTMLElement {
|
|||
break
|
||||
|
||||
// Reload the tree nodes to reflect the new/updated nodes.
|
||||
if (window._notes2?.current?.reloadTree.value !== null) {
|
||||
nodeStore.purgeCache()
|
||||
window._notes2.current.reloadTree.value = window._notes2.current.reloadTree.value + 1
|
||||
}
|
||||
window._app.tree.reset()
|
||||
break
|
||||
}
|
||||
this.render()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export class N2Tree extends CustomHTMLElement {
|
|||
<img data-el="search" class='search' src="/images/${_VERSION}/icon_search.svg" style="height: 22px" />
|
||||
<img data-el="sync" class='sync' src="/images/${_VERSION}/icon_refresh.svg" />
|
||||
</div>
|
||||
<div data-el="treenodes"></div>
|
||||
`
|
||||
}// }}}
|
||||
|
||||
|
|
@ -39,12 +40,20 @@ export class N2Tree extends CustomHTMLElement {
|
|||
for (const node of this.treeTrunk) {
|
||||
const treenode = new N2TreeNode(this, node)
|
||||
this.treeNodeComponents[node.UUID] = treenode
|
||||
this.appendChild(treenode.render())
|
||||
this.elTreenodes.appendChild(treenode.render())
|
||||
}
|
||||
|
||||
this.rendered = true
|
||||
return this
|
||||
}// }}}
|
||||
reset() {
|
||||
console.log('tree reset')
|
||||
this.treeNodeComponents = {}
|
||||
this.treeTrunk = []
|
||||
this.rendered = false
|
||||
this.elTreenodes.replaceChildren()
|
||||
this.populateFirstLevel()
|
||||
}
|
||||
populateFirstLevel() {//{{{
|
||||
nodeStore.get(ROOT_NODE)
|
||||
.then(node => node.fetchChildren())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue