Add support for sorting in peer table
This commit is contained in:
@@ -491,7 +491,7 @@ select {
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin: 3px;
|
margin: 3px;
|
||||||
background: var(--input_background);
|
background: var(--input_background);
|
||||||
padding: 5px 5px 5px 5px;
|
padding: 4px 5px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: var(--input_text);
|
color: var(--input_text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -538,7 +538,7 @@ input[type="color"]:active,
|
|||||||
select:active {
|
select:active {
|
||||||
box-shadow: inset 4px 4px 6px var(--shadow_color);
|
box-shadow: inset 4px 4px 6px var(--shadow_color);
|
||||||
/* Exactly 4px offset compared to the inactive padding to give a depth effect */
|
/* Exactly 4px offset compared to the inactive padding to give a depth effect */
|
||||||
padding: 9px 1px 1px 9px;
|
padding: 8px 1px 0px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button_highlight {
|
.button_highlight {
|
||||||
|
@@ -211,10 +211,13 @@ onDestroy(() => {
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h3>Cache nodes</h3>
|
<h3>Cache nodes</h3>
|
||||||
|
</section>
|
||||||
<PeerTable peers={status.peers.reduce((acc, val) => {if (val.role === "cache") {acc.push(val)}; return acc}, [])}/>
|
<PeerTable peers={status.peers.reduce((acc, val) => {if (val.role === "cache") {acc.push(val)}; return acc}, [])}/>
|
||||||
|
<section>
|
||||||
<h3>Storage nodes</h3>
|
<h3>Storage nodes</h3>
|
||||||
|
</section>
|
||||||
<PeerTable peers={status.peers.reduce((acc, val) => {if (val.role === "storage") {acc.push(val)}; return acc}, [])}/>
|
<PeerTable peers={status.peers.reduce((acc, val) => {if (val.role === "storage") {acc.push(val)}; return acc}, [])}/>
|
||||||
|
<section>
|
||||||
|
|
||||||
<h3>Pixelstore stats</h3>
|
<h3>Pixelstore stats</h3>
|
||||||
<table>
|
<table>
|
||||||
|
@@ -1,7 +1,49 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDataVolume } from "../util/Formatting.svelte";
|
import { formatDataVolume } from "../util/Formatting.svelte";
|
||||||
|
import SortButton from "./SortButton.svelte";
|
||||||
|
|
||||||
export let peers = [];
|
export let peers = [];
|
||||||
|
$: update_peers(peers)
|
||||||
|
let update_peers = (peers) => {
|
||||||
|
for (let peer of peers) {
|
||||||
|
peer.avg_network_total = peer.avg_network_tx + peer.avg_network_rx
|
||||||
|
}
|
||||||
|
|
||||||
|
sort("")
|
||||||
|
}
|
||||||
|
|
||||||
|
let sort_field = "address"
|
||||||
|
let asc = true
|
||||||
|
let sort = (field) => {
|
||||||
|
if (field !== "" && field === sort_field) {
|
||||||
|
asc = !asc
|
||||||
|
}
|
||||||
|
if (field === "") {
|
||||||
|
field = sort_field
|
||||||
|
}
|
||||||
|
sort_field = field
|
||||||
|
|
||||||
|
console.log("sorting by", field, "asc", asc)
|
||||||
|
peers.sort((a, b) => {
|
||||||
|
if (typeof (a[field]) === "number") {
|
||||||
|
// Sort ints from high to low
|
||||||
|
if (asc) {
|
||||||
|
return a[field] - b[field]
|
||||||
|
} else {
|
||||||
|
return b[field] - a[field]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Sort strings alphabetically
|
||||||
|
if (asc) {
|
||||||
|
return a[field].localeCompare(b[field])
|
||||||
|
} else {
|
||||||
|
return b[field].localeCompare(a[field])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
peers = peers
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -9,15 +51,17 @@ export let peers = [];
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Address</td>
|
<td><SortButton field="address" active_field={sort_field} asc={asc} sort_func={sort}>Address</SortButton></td>
|
||||||
<td>Err</td>
|
<td><SortButton field="unreachable_count" active_field={sort_field} asc={asc} sort_func={sort}>Err</SortButton></td>
|
||||||
<td>1m</td>
|
<td><SortButton field="load_1_min" active_field={sort_field} asc={asc} sort_func={sort}>1m</SortButton></td>
|
||||||
<td>5m</td>
|
<td><SortButton field="load_5_min" active_field={sort_field} asc={asc} sort_func={sort}>5m</SortButton></td>
|
||||||
<td>15m</td>
|
<td><SortButton field="load_15_min" active_field={sort_field} asc={asc} sort_func={sort}>15m</SortButton></td>
|
||||||
<td>Ping</td>
|
<td><SortButton field="latency" active_field={sort_field} asc={asc} sort_func={sort}>Ping</SortButton></td>
|
||||||
<td>Netload</td>
|
<td><SortButton field="avg_network_tx" active_field={sort_field} asc={asc} sort_func={sort}>TX</SortButton></td>
|
||||||
<td>Free</td>
|
<td><SortButton field="avg_network_rx" active_field={sort_field} asc={asc} sort_func={sort}>RX</SortButton></td>
|
||||||
<td>Min free</td>
|
<td><SortButton field="avg_network_total" active_field={sort_field} asc={asc} sort_func={sort}>Tot</SortButton></td>
|
||||||
|
<td><SortButton field="free_space" active_field={sort_field} asc={asc} sort_func={sort}>Free</SortButton></td>
|
||||||
|
<td><SortButton field="min_free_space" active_field={sort_field} asc={asc} sort_func={sort}>Min free</SortButton></td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -33,7 +77,9 @@ export let peers = [];
|
|||||||
<td>{peer.load_5_min.toFixed(1)}</td>
|
<td>{peer.load_5_min.toFixed(1)}</td>
|
||||||
<td>{peer.load_15_min.toFixed(1)}</td>
|
<td>{peer.load_15_min.toFixed(1)}</td>
|
||||||
<td>{(peer.latency/1000).toPrecision(3)}</td>
|
<td>{(peer.latency/1000).toPrecision(3)}</td>
|
||||||
<td>{formatDataVolume(peer.avg_network_load, 4)}/s</td>
|
<td>{formatDataVolume(peer.avg_network_tx, 3)}/s</td>
|
||||||
|
<td>{formatDataVolume(peer.avg_network_rx, 3)}/s</td>
|
||||||
|
<td>{formatDataVolume(peer.avg_network_tx+peer.avg_network_rx, 3)}/s</td>
|
||||||
<td>{formatDataVolume(peer.free_space, 4)}</td>
|
<td>{formatDataVolume(peer.free_space, 4)}</td>
|
||||||
<td>{formatDataVolume(peer.min_free_space, 3)}</td>
|
<td>{formatDataVolume(peer.min_free_space, 3)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -46,7 +92,9 @@ export let peers = [];
|
|||||||
<td>{peers.reduce((acc, val) => acc += val.load_5_min, 0).toFixed(1)}</td>
|
<td>{peers.reduce((acc, val) => acc += val.load_5_min, 0).toFixed(1)}</td>
|
||||||
<td>{peers.reduce((acc, val) => acc += val.load_15_min, 0).toFixed(1)}</td>
|
<td>{peers.reduce((acc, val) => acc += val.load_15_min, 0).toFixed(1)}</td>
|
||||||
<td>{(peers.reduce((acc, val) => acc += val.latency, 0)/1000).toFixed(0)}</td>
|
<td>{(peers.reduce((acc, val) => acc += val.latency, 0)/1000).toFixed(0)}</td>
|
||||||
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_load, 0), 4)}/s</td>
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_tx, 0), 3)}/s</td>
|
||||||
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_rx, 0), 3)}/s</td>
|
||||||
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_tx+val.avg_network_rx, 0), 3)}/s</td>
|
||||||
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.free_space, 0), 4)}</td>
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.free_space, 0), 4)}</td>
|
||||||
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.min_free_space, 0), 3)}</td>
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.min_free_space, 0), 3)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -57,10 +105,20 @@ export let peers = [];
|
|||||||
<td>{(peers.reduce((acc, val) => acc += val.load_5_min, 0) / peers.length).toFixed(1)}</td>
|
<td>{(peers.reduce((acc, val) => acc += val.load_5_min, 0) / peers.length).toFixed(1)}</td>
|
||||||
<td>{(peers.reduce((acc, val) => acc += val.load_15_min, 0) / peers.length).toFixed(1)}</td>
|
<td>{(peers.reduce((acc, val) => acc += val.load_15_min, 0) / peers.length).toFixed(1)}</td>
|
||||||
<td>{(peers.reduce((acc, val) => acc += val.latency, 0) / 1000 / peers.length).toFixed(0)}</td>
|
<td>{(peers.reduce((acc, val) => acc += val.latency, 0) / 1000 / peers.length).toFixed(0)}</td>
|
||||||
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_load, 0) / peers.length, 4)}/s</td>
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_tx, 0) / peers.length, 3)}/s</td>
|
||||||
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_rx, 0) / peers.length, 3)}/s</td>
|
||||||
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.avg_network_tx+val.avg_network_rx, 3) / peers.length, 4)}/s</td>
|
||||||
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.free_space, 0) / peers.length, 4)}</td>
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.free_space, 0) / peers.length, 4)}</td>
|
||||||
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.min_free_space, 0) / peers.length, 3)}</td>
|
<td>{formatDataVolume(peers.reduce((acc, val) => acc += val.min_free_space, 0) / peers.length, 3)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.table_scroll {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: auto;
|
||||||
|
text-align: initial;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
22
svelte/src/admin_panel/SortButton.svelte
Normal file
22
svelte/src/admin_panel/SortButton.svelte
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script>
|
||||||
|
export let field = ""
|
||||||
|
export let active_field = ""
|
||||||
|
export let asc = true
|
||||||
|
export let sort_func
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button class:button_highlight={active_field === field} on:click={() => sort_func(field)}>
|
||||||
|
{#if asc}
|
||||||
|
↓
|
||||||
|
{:else}
|
||||||
|
↑
|
||||||
|
{/if}
|
||||||
|
<slot></slot>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
button {
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -17,7 +17,7 @@ export let fs_navigator
|
|||||||
{#if shared}
|
{#if shared}
|
||||||
<i class="icon small">share</i>
|
<i class="icon small">share</i>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="node_name" class:nopad={shared} class:base={state.base_index === i}>
|
<div class="node_name" class:base={state.base_index === i}>
|
||||||
{node.name}
|
{node.name}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@@ -38,23 +38,22 @@ export let fs_navigator
|
|||||||
.breadcrumb {
|
.breadcrumb {
|
||||||
min-width: 1em;
|
min-width: 1em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 1em;
|
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
line-height: 1em;
|
||||||
}
|
}
|
||||||
.node_name {
|
.node_name {
|
||||||
margin: 2px;
|
/* This padding makes sure that characters which extend below the
|
||||||
|
line-height do not get cut off */
|
||||||
|
padding: 4px 2px;
|
||||||
max-width: 20vw;
|
max-width: 20vw;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.node_name.base {
|
.base {
|
||||||
/* The base name uses all available space */
|
/* The base name uses all available space */
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
}
|
}
|
||||||
.nopad {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@@ -104,8 +104,8 @@ onMount(() => {
|
|||||||
|
|
||||||
€ 8 / 30.4375 = € 0.2628 per day<br/>
|
€ 8 / 30.4375 = € 0.2628 per day<br/>
|
||||||
|
|
||||||
Similarly the subscription charge of €2 per month is also charged at € 2
|
Similarly the subscription charge of €2 per month is also charged at € 1
|
||||||
/ 30.4375 = € 0.065708 per day.
|
/ 30.4375 = € 0.032854 per day.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>{month_str}</h3>
|
<h3>{month_str}</h3>
|
||||||
|
Reference in New Issue
Block a user