File count on storage page

This commit is contained in:
Magnus Åhall 2026-06-28 11:17:04 +02:00
parent 6df2be7944
commit 65f8cd14a7
8 changed files with 319 additions and 16 deletions

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="21.333317"
height="24"
viewBox="0 0 5.64444 6.35"
version="1.1"
id="svg1"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
sodipodi:docname="icon_storage.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="1"
inkscape:cx="-56"
inkscape:cy="-9.5"
inkscape:window-width="2190"
inkscape:window-height="1401"
inkscape:window-x="1463"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-288.92499,-115.8875)">
<title
id="title1">database</title>
<path
d="m 291.74722,115.8875 c -1.55928,0 -2.82223,0.63146 -2.82223,1.4111 0,0.77964 1.26295,1.41112 2.82223,1.41112 1.55927,0 2.82221,-0.63148 2.82221,-1.41112 0,-0.77964 -1.26294,-1.4111 -2.82221,-1.4111 m -2.82223,2.11666 v 1.05834 c 0,0.77964 1.26295,1.4111 2.82223,1.4111 1.55927,0 2.82221,-0.63146 2.82221,-1.4111 v -1.05834 c 0,0.77964 -1.26294,1.41111 -2.82221,1.41111 -1.55928,0 -2.82223,-0.63147 -2.82223,-1.41111 m 0,1.7639 v 1.05833 c 0,0.77964 1.26295,1.41111 2.82223,1.41111 1.55927,0 2.82221,-0.63147 2.82221,-1.41111 v -1.05833 c 0,0.77964 -1.26294,1.4111 -2.82221,1.4111 -1.55928,0 -2.82223,-0.63146 -2.82223,-1.4111 z"
id="path1"
style="stroke-width:0.264583" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -98,7 +98,7 @@ export class NodeStore {
this.sendQueue = new SimpleNodeStore(this.db, 'send_queue')
this.nodesHistory = new NodeHistoryStore(this.db, 'nodes_history')
this.files = new SimpleNodeStore(this.db, 'files')
this.filesMetadata = new SimpleNodeStore(this.db, 'files_metadata')
this.filesMetadata = new FilesMetadataStore(this.db, 'files_metadata')
this.filesNodelink = new FileNodesLinkStore(this.db, 'files_nodelink')
resolve()
}
@ -581,6 +581,20 @@ class NodeHistoryStore extends SimpleNodeStore {
}// }}}
}
class FilesMetadataStore extends SimpleNodeStore {
countToUpload() {// {{{
const store = this.db
.transaction(this.storeName, 'readonly')
.objectStore(this.storeName)
.index('byUploaded')
return new Promise((resolve, reject) => {
const request = store.count('only_on_device')
request.onsuccess = (event) => resolve(event.target.result)
request.onerror = (event) => reject(event.target.error)
})
}// }}}
}
class FileNodesLinkStore extends SimpleNodeStore {
async removeFileUUIDs(nodeUUID, fileUUIDs) {// {{{
for (const fileUUID of fileUUIDs) {
@ -597,7 +611,7 @@ class FileNodesLinkStore extends SimpleNodeStore {
// Maintains an index to quickly find orphaned files.
nodelink.NodeCount = nodelink.Nodes.length
await this.add({data: nodelink})
await this.add({ data: nodelink })
}
}// }}}
async addFileUUIDs(nodeUUID, fileUUIDs) {// {{{
@ -619,7 +633,7 @@ class FileNodesLinkStore extends SimpleNodeStore {
// Maintains an index to quickly find orphaned files.
nodelink.NodeCount = nodelink.Nodes.length
await this.add({data: nodelink})
await this.add({ data: nodelink })
}
}// }}}
}

View file

@ -1,17 +1,51 @@
import { CustomHTMLElement } from "./lib/custom_html_element.mjs"
import { API } from 'api'
export class N2PageStorage extends CustomHTMLElement {
static {
this.tmpl = document.createElement('template')
this.tmpl.innerHTML = `
<style>
.table {
display: grid;
grid-template-columns: min-content min-content;
grid-gap: 4px 16px;
align-items: center;
white-space: nowrap;
}
.error {
background-color: #ff2a2a;
color: #fff;
padding: 4px 8px;
border-radius: 4px;
}
</style>
<h1>Local storage</h1>
<div data-el="count-nodes"></div>
<div data-el="count-queued-nodes"></div>
<div data-el="count-history-nodes"></div>
<div class="table">
<div>Local nodes</div>
<div data-el="count-nodes"></div>
<div>Queued to sync</div>
<div data-el="count-queued-nodes"></div>
<div>History nodes</div>
<div data-el="count-history-nodes"></div>
</div>
<h1>Files</h1>
<div class="table">
<div>Files on server</div>
<div data-el="count-files-on-server"></div>
<div>Files to send</div>
<div data-el="count-queued-files"></div>
</div>
`
}
constructor() {
super()
super(true)
window._mbus.subscribe('SHOW_PAGE', event => {
if (event.detail.data?.page == 'storage')
@ -19,13 +53,21 @@ export class N2PageStorage extends CustomHTMLElement {
})
}
async render() {
const countNodes = await globalThis.nodeStore.nodeCount()
const countQueuedNodes = await globalThis.nodeStore.sendQueue.count()
const countHistoryNodes = await globalThis.nodeStore.nodesHistory.count()
API.query('GET', '/file/count')
.then(res => {
this.elCountFilesOnServer.innerText = res.Count
})
.catch(err => {
this.elCountFilesOnServer.classList.add('error')
console.error(err)
this.elCountFilesOnServer.innerText = err.message
})
this.elCountNodes.innerText = countNodes
this.elCountQueuedNodes.innerText = countQueuedNodes
this.elCountHistoryNodes.innerText = countHistoryNodes
this.elCountNodes.innerText = await globalThis.nodeStore.nodeCount()
this.elCountQueuedNodes.innerText = await globalThis.nodeStore.sendQueue.count()
this.elCountHistoryNodes.innerText = await globalThis.nodeStore.nodesHistory.count()
this.elCountQueuedFiles.innerText = await globalThis.nodeStore.filesMetadata.countToUpload()
}
}
customElements.define('n2-pagestorage', N2PageStorage)

View file

@ -82,11 +82,16 @@ export class N2Sidebar extends CustomHTMLElement {
.icons {
display: flex;
justify-content: center;
justify-content: start;
margin-top: 16px;
gap: 8px;
gap: 8px 16px;
padding-left: 40px;
padding-bottom: 16px;
border-bottom: 1px solid var(--line-color);
img {
cursor: pointer;
}
}
@ -104,6 +109,7 @@ export class N2Sidebar extends CustomHTMLElement {
</div>
<div class="icons">
<img data-el="sync" class='sync colorize' src="/images/${_VERSION}/icon_refresh.svg" />
<img data-el="storage" class='storage colorize' src="/images/${_VERSION}/icon_storage.svg" />
<img data-el="search" class='search colorize' src="/images/${_VERSION}/icon_search.svg" style="height: 22px" />
<img data-el="settings" class='settings colorize' src="/images/${_VERSION}/icon_settings.svg" />
</div>
@ -127,6 +133,7 @@ export class N2Sidebar extends CustomHTMLElement {
this.addEventListener('keydown', event => this.keyHandler(event))
this.elSearch.addEventListener('click', () => _mbus.dispatch('op-search'))
this.elSync.addEventListener('click', () => _sync.run())
this.elStorage.addEventListener('click', () => _mbus.dispatch('SHOW_PAGE', { page: 'storage' }))
this.elLogo.addEventListener('click', () => _app.goToNode(ROOT_NODE, false, false))
this.elSettings.addEventListener('click', ()=> _mbus.dispatch('SHOW_PAGE', { page: 'preferences' }))
this.elHideTree.addEventListener('click', event => {

View file

@ -23,6 +23,7 @@ const CACHED_ASSETS = [
'/images/{{ .VERSION }}/icon_save.svg',
'/images/{{ .VERSION }}/icon_search.svg',
'/images/{{ .VERSION }}/icon_settings.svg',
'/images/{{ .VERSION }}/icon_storage.svg',
'/images/{{ .VERSION }}/icon_table.svg',
'/images/{{ .VERSION }}/icon_transfer.svg',
'/images/{{ .VERSION }}/leaf.svg',