History fetching from server
This commit is contained in:
parent
9506b89453
commit
aeca9d8559
4 changed files with 149 additions and 65 deletions
20
main.go
20
main.go
|
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
const VERSION = "v11"
|
const VERSION = "v11"
|
||||||
const CONTEXT_USER = 1
|
const CONTEXT_USER = 1
|
||||||
const SYNC_PAGINATION = 20
|
const SYNC_PAGINATION = 200
|
||||||
|
|
||||||
var (
|
var (
|
||||||
FlagGenerate bool
|
FlagGenerate bool
|
||||||
|
|
@ -141,6 +141,7 @@ func main() { // {{{
|
||||||
|
|
||||||
http.HandleFunc("/node/retrieve/{uuid}", authenticated(actionNodeRetrieve))
|
http.HandleFunc("/node/retrieve/{uuid}", authenticated(actionNodeRetrieve))
|
||||||
http.HandleFunc("/node/history/retrieve/{uuid}/{offset}", authenticated(actionNodeHistoryRetrieve))
|
http.HandleFunc("/node/history/retrieve/{uuid}/{offset}", authenticated(actionNodeHistoryRetrieve))
|
||||||
|
http.HandleFunc("/node/history/count/{uuid}", authenticated(actionNodeHistoryCount))
|
||||||
|
|
||||||
http.HandleFunc("/service_worker.js", pageServiceWorker)
|
http.HandleFunc("/service_worker.js", pageServiceWorker)
|
||||||
|
|
||||||
|
|
@ -352,6 +353,23 @@ func actionNodeHistoryRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
|
||||||
"HasMore": hasMore,
|
"HasMore": hasMore,
|
||||||
})
|
})
|
||||||
} // }}}
|
} // }}}
|
||||||
|
func actionNodeHistoryCount(w http.ResponseWriter, r *http.Request) { // {{{
|
||||||
|
user := getUser(r)
|
||||||
|
var err error
|
||||||
|
|
||||||
|
uuid := r.PathValue("uuid")
|
||||||
|
|
||||||
|
count, err := RetrieveNodeHistoryCount(user.UserID, uuid)
|
||||||
|
if err != nil {
|
||||||
|
responseError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData(w, map[string]any{
|
||||||
|
"OK": true,
|
||||||
|
"Count": count,
|
||||||
|
})
|
||||||
|
} // }}}
|
||||||
func actionSyncToServer(w http.ResponseWriter, r *http.Request) { // {{{
|
func actionSyncToServer(w http.ResponseWriter, r *http.Request) { // {{{
|
||||||
user := getUser(r)
|
user := getUser(r)
|
||||||
|
|
||||||
|
|
|
||||||
20
node.go
20
node.go
|
|
@ -293,6 +293,26 @@ func RetrieveNodeHistory(userID int, nodeUUID string, offset int) (nodes []Node,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} // }}}
|
} // }}}
|
||||||
|
func RetrieveNodeHistoryCount(userID int, nodeUUID string) (count int, err error) { // {{{
|
||||||
|
var row *sql.Row
|
||||||
|
row = db.QueryRow(`
|
||||||
|
SELECT
|
||||||
|
COUNT(*)
|
||||||
|
FROM node_history
|
||||||
|
WHERE
|
||||||
|
user_id = $1 AND
|
||||||
|
uuid = $2
|
||||||
|
`,
|
||||||
|
userID,
|
||||||
|
nodeUUID,
|
||||||
|
)
|
||||||
|
if err = row.Scan(&count); err != nil {
|
||||||
|
err = werr.Wrap(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
} // }}}
|
||||||
func NodeCrumbs(nodeUUID string) (nodes []Node, err error) { // {{{
|
func NodeCrumbs(nodeUUID string) (nodes []Node, err error) { // {{{
|
||||||
var rows *sqlx.Rows
|
var rows *sqlx.Rows
|
||||||
rows, err = db.Queryx(`
|
rows, err = db.Queryx(`
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,10 @@ html {
|
||||||
filter: var(--colorize);
|
filter: var(--colorize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 1e m;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------- *
|
/* ------------------------------------- *
|
||||||
* Default application grid in wide mode *
|
* Default application grid in wide mode *
|
||||||
* ------------------------------------- */
|
* ------------------------------------- */
|
||||||
|
|
@ -550,6 +554,18 @@ n2-pagehistory {
|
||||||
rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
|
rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-stats {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content 1fr;
|
||||||
|
grid-gap: 8px 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-fetch-history-progress {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-back-image,
|
.el-back-image,
|
||||||
.el-back-text {
|
.el-back-text {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ import { Node } from './page_node.mjs'
|
||||||
|
|
||||||
export class N2PageHistory extends CustomHTMLElement {
|
export class N2PageHistory extends CustomHTMLElement {
|
||||||
static PAGESIZE = 15
|
static PAGESIZE = 15
|
||||||
|
static {// {{{
|
||||||
static {
|
|
||||||
this.tmpl = document.createElement('template')
|
this.tmpl = document.createElement('template')
|
||||||
this.tmpl.innerHTML = `
|
this.tmpl.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -26,11 +25,20 @@ export class N2PageHistory extends CustomHTMLElement {
|
||||||
<div class="group-label">Actions</div>
|
<div class="group-label">Actions</div>
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<button data-el="download-history">Fetch all history from server</button>
|
<button data-el="download-history">Fetch all history from server</button>
|
||||||
|
<div data-el="fetch-history-progress"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="group-label">History</div>
|
<div class="group-label">History</div>
|
||||||
<div class="group">
|
<div class="group">
|
||||||
|
<div data-el="stats">
|
||||||
|
<div>History on server:</div>
|
||||||
|
<div data-el="stats-on-server"></div>
|
||||||
|
|
||||||
|
<div>History on client:</div>
|
||||||
|
<div data-el="stats-on-client"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div data-el="nodes"></div>
|
<div data-el="nodes"></div>
|
||||||
|
|
||||||
<div data-el="pagination">
|
<div data-el="pagination">
|
||||||
|
|
@ -40,9 +48,9 @@ export class N2PageHistory extends CustomHTMLElement {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}// }}}
|
||||||
|
|
||||||
constructor() {
|
constructor() {// {{{
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.setAttribute('tabindex', '-1')
|
this.setAttribute('tabindex', '-1')
|
||||||
|
|
@ -53,66 +61,23 @@ export class N2PageHistory extends CustomHTMLElement {
|
||||||
this.elBackText.addEventListener('click', () => _mbus.dispatch('SHOW_PAGE', { page: 'node' }))
|
this.elBackText.addEventListener('click', () => _mbus.dispatch('SHOW_PAGE', { page: 'node' }))
|
||||||
this.elPrev.addEventListener('click', () => this.prevPage())
|
this.elPrev.addEventListener('click', () => this.prevPage())
|
||||||
this.elNext.addEventListener('click', () => this.nextPage())
|
this.elNext.addEventListener('click', () => this.nextPage())
|
||||||
this.elDownloadHistory.addEventListener('click', () => this.downloadHistory())
|
this.elDownloadHistory.addEventListener('click', async () => {
|
||||||
|
await this.downloadHistory()
|
||||||
|
await this.useNode(this.node)
|
||||||
|
this.render(true)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
_mbus.subscribe('NODE_UI_OPEN', async (event) => {
|
_mbus.subscribe('NODE_UI_OPEN', async (event) => {
|
||||||
await this.useNode(event.detail.data)
|
await this.useNode(event.detail.data)
|
||||||
this.render()
|
this.render()
|
||||||
})
|
})
|
||||||
}
|
}// }}}
|
||||||
|
async render(keepFetchHistoryProgress) {// {{{
|
||||||
async useNode(node) {
|
|
||||||
this.node = node
|
|
||||||
this.page = 1
|
|
||||||
|
|
||||||
this.nodesTotal = await nodeStore.nodesHistory.count(this.node.UUID)
|
|
||||||
this.pages = Math.ceil(this.nodesTotal / N2PageHistory.PAGESIZE)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyHandler(event) {
|
|
||||||
switch (event.key) {
|
|
||||||
case 'ArrowLeft':
|
|
||||||
this.prevPage()
|
|
||||||
break
|
|
||||||
case 'ArrowRight':
|
|
||||||
this.nextPage()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prevPage() {
|
|
||||||
if (this.page == 1)
|
|
||||||
return
|
|
||||||
this.page--
|
|
||||||
this.render()
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPage() {
|
|
||||||
if (this.page >= this.pages)
|
|
||||||
return
|
|
||||||
this.page++
|
|
||||||
this.render()
|
|
||||||
}
|
|
||||||
|
|
||||||
formatSize(s) {
|
|
||||||
let div = 1
|
|
||||||
let unit = 'B'
|
|
||||||
if (s >= 1048576) {
|
|
||||||
div = 1048576
|
|
||||||
unit = 'MB'
|
|
||||||
} else if (s >= 1024) {
|
|
||||||
div = 1024
|
|
||||||
unit = 'kB'
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Intl.NumberFormat(undefined, {
|
|
||||||
maximumFractionDigits: 0
|
|
||||||
}).format(Math.round(s / div)) + ' ' + unit
|
|
||||||
}
|
|
||||||
|
|
||||||
async render() {
|
|
||||||
this.elNodeName.innerText = this.node.get('Name')
|
this.elNodeName.innerText = this.node.get('Name')
|
||||||
this.elPage.innerText = `${this.page} / ${this.pages}`
|
this.elPage.innerText = `${this.page} / ${this.pages}`
|
||||||
|
this.elStatsOnClient.innerText = `${this.nodesTotal}`
|
||||||
|
this.elStatsOnServer.innerText = `${this.historyOnServerTotal}`
|
||||||
|
|
||||||
if (this.nodesTotal <= N2PageHistory.PAGESIZE)
|
if (this.nodesTotal <= N2PageHistory.PAGESIZE)
|
||||||
this.elPagination.style.display = 'none'
|
this.elPagination.style.display = 'none'
|
||||||
|
|
@ -138,9 +103,59 @@ export class N2PageHistory extends CustomHTMLElement {
|
||||||
return div
|
return div
|
||||||
})
|
})
|
||||||
this.elNodes.replaceChildren(...divs)
|
this.elNodes.replaceChildren(...divs)
|
||||||
}
|
|
||||||
|
|
||||||
async downloadHistory() {
|
if (!keepFetchHistoryProgress)
|
||||||
|
this.elFetchHistoryProgress.innerText = ''
|
||||||
|
}// }}}
|
||||||
|
|
||||||
|
async useNode(node) {// {{{
|
||||||
|
this.node = node
|
||||||
|
this.page = 1
|
||||||
|
|
||||||
|
this.nodesTotal = await nodeStore.nodesHistory.count(this.node.UUID)
|
||||||
|
this.historyOnServerTotal = await this.getServerTotal()
|
||||||
|
this.pages = Math.ceil(this.nodesTotal / N2PageHistory.PAGESIZE)
|
||||||
|
}// }}}
|
||||||
|
keyHandler(event) {// {{{
|
||||||
|
switch (event.key) {
|
||||||
|
case 'ArrowLeft':
|
||||||
|
this.prevPage()
|
||||||
|
break
|
||||||
|
case 'ArrowRight':
|
||||||
|
this.nextPage()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}// }}}
|
||||||
|
|
||||||
|
prevPage() {// {{{
|
||||||
|
if (this.page == 1)
|
||||||
|
return
|
||||||
|
this.page--
|
||||||
|
this.render()
|
||||||
|
}// }}}
|
||||||
|
nextPage() {// {{{
|
||||||
|
if (this.page >= this.pages)
|
||||||
|
return
|
||||||
|
this.page++
|
||||||
|
this.render()
|
||||||
|
}// }}}
|
||||||
|
|
||||||
|
async getServerTotal() {// {{{
|
||||||
|
const res = await fetch(`/node/history/count/${this.node.UUID}`, {
|
||||||
|
headers: {
|
||||||
|
"Authorization": 'Bearer ' + localStorage.getItem('token'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const json = await res.json()
|
||||||
|
|
||||||
|
if (!json.OK) {
|
||||||
|
alert(json.Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Count
|
||||||
|
}// }}}
|
||||||
|
async downloadHistory() {// {{{
|
||||||
try {
|
try {
|
||||||
const nodes = []
|
const nodes = []
|
||||||
let offset = 0
|
let offset = 0
|
||||||
|
|
@ -153,6 +168,7 @@ export class N2PageHistory extends CustomHTMLElement {
|
||||||
nodes.push(new Node(nodeData))
|
nodes.push(new Node(nodeData))
|
||||||
}
|
}
|
||||||
offset = nodes.length
|
offset = nodes.length
|
||||||
|
this.elFetchHistoryProgress.innerText = `${nodes.length} fetched.`
|
||||||
}
|
}
|
||||||
|
|
||||||
let num = 0
|
let num = 0
|
||||||
|
|
@ -161,15 +177,14 @@ export class N2PageHistory extends CustomHTMLElement {
|
||||||
if (ok) num++
|
if (ok) num++
|
||||||
await nodeStore.nodesHistory.add(node)
|
await nodeStore.nodesHistory.add(node)
|
||||||
}
|
}
|
||||||
console.log(num)
|
|
||||||
|
|
||||||
|
this.elFetchHistoryProgress.innerText = `${nodes.length} fetched - all history fetched.`
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
alert(e)
|
alert(e)
|
||||||
}
|
}
|
||||||
}
|
}// }}}
|
||||||
|
async downloadHistoryPage(offset) {// {{{
|
||||||
async downloadHistoryPage(offset) {
|
|
||||||
const res = await fetch(`/node/history/retrieve/${this.node.UUID}/${offset}`, {
|
const res = await fetch(`/node/history/retrieve/${this.node.UUID}/${offset}`, {
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": 'Bearer ' + localStorage.getItem('token'),
|
"Authorization": 'Bearer ' + localStorage.getItem('token'),
|
||||||
|
|
@ -183,6 +198,21 @@ export class N2PageHistory extends CustomHTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
return json
|
return json
|
||||||
}
|
}// }}}
|
||||||
|
formatSize(s) {// {{{
|
||||||
|
let div = 1
|
||||||
|
let unit = 'B'
|
||||||
|
if (s >= 1048576) {
|
||||||
|
div = 1048576
|
||||||
|
unit = 'MB'
|
||||||
|
} else if (s >= 1024) {
|
||||||
|
div = 1024
|
||||||
|
unit = 'kB'
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Intl.NumberFormat(undefined, {
|
||||||
|
maximumFractionDigits: 0
|
||||||
|
}).format(Math.round(s / div)) + ' ' + unit
|
||||||
|
}// }}}
|
||||||
}
|
}
|
||||||
customElements.define('n2-pagehistory', N2PageHistory)
|
customElements.define('n2-pagehistory', N2PageHistory)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue