diff --git a/www/css/style.css b/www/css/style.css index 6ec81672f35e1d73d8bfd67fca887f8ded98a225..e48547510005a99e35b52b92e2e362d5672da1a9 100644 --- a/www/css/style.css +++ b/www/css/style.css @@ -173,7 +173,9 @@ padding-top: 9px; padding-bottom: 3px; } - +.list .item-peer .col h3 { + margin-bottom: 0 !important; +} .list .item-peer .badge { top: 14px; right: 6%; @@ -202,8 +204,53 @@ .list .item-peer.compacted > * { display: none; } - - +.list .item-peer .col-server { + overflow: hidden; + text-overflow: ellipsis; +} +.list .item-peer .col-api { + vertical-align: center; +} +.list .item-peer .col-api h4 { + min-width: 50px; + height: 100%; + white-space: normal; + padding-top: 5px; +} +.list .item-peer .col-api h4 span { + white-space: nowrap; + font-size: 14px; + line-height: 12px; +} +.list .item-peer .col-api h4 span small { + font-size: 85%; +} +.list .item-peer .col-sandboxes h3 { + display: block; + color: gray; + padding: 0; +} +.list .item-peer .col-sandboxes .progress-bar { + display: inline-block; + width: 50px; + position: relative; + height: 12px; + border-radius: 5px; + border: 1px solid gray; +} +.list .item-peer .col-sandboxes .progress-fill { + height: 100%; + background-color: currentColor; + position: absolute; + left: 0; + top: 0; + border-radius: 5px; +} +.list .item-peer .col-sandboxes .progress-text { + width: 100%; + font-size: 10px; + text-align: center; +} /********** Block items **********/ diff --git a/www/i18n/locale-ca.json b/www/i18n/locale-ca.json index 36899031285ab3170cfddd14cb63b5b61e5972e6..7db48c3f588f1766ccf0dd7a41609a85b19fb2a0 100644 --- a/www/i18n/locale-ca.json +++ b/www/i18n/locale-ca.json @@ -327,6 +327,9 @@ "ALL_PEERS": "Todos los nodos", "DIFFICULTY": "Dificultad", "API": "API", + "SANDBOXES": "Cua", + "PENDING_TX": "{{count}} transacció(ns) / {{size}} mà x, {{free}} espai(s) restant(s)", + "PENDING_MEMBERSHIPS": "{{count}} adhesió(ns) pendents / {{size}} mà x, {{free}} espai(s) restant(s)", "CURRENT_BLOCK": "Bloque #", "POPOVER_FILTER_TITLE": "Filtro", "OFFLINE": "Fuera de lÃnea", diff --git a/www/i18n/locale-de-DE.json b/www/i18n/locale-de-DE.json index e4210d0e465386ddb4f139142fe731900927a142..98a491564b9582de3044ce673fa928a75b23f285 100644 --- a/www/i18n/locale-de-DE.json +++ b/www/i18n/locale-de-DE.json @@ -343,6 +343,9 @@ "ALL_PEERS" : "Alle Knoten", "DIFFICULTY" : "Schwierigkeit", "API" : "API", + "SANDBOXES": "Warteschlange", + "PENDING_TX": "{{count}} Transaktion(en) / {{size}} max, {{free}} Platz(e) verbleibend", + "PENDING_MEMBERSHIPS": "{{count}} ausstehende Mitgliedschaft(en) / {{size}} max, {{free}} Platz(e) verbleibend", "CURRENT_BLOCK": "Block Nr.", "POPOVER_FILTER_TITLE": "Filter", "OFFLINE": "Offline", diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json index d2c9a73bef76c9ec1fbcfde3c38d4b7042cca163..893ff2a9de2232be30dfe36c82074f5c3a538a24 100644 --- a/www/i18n/locale-en-GB.json +++ b/www/i18n/locale-en-GB.json @@ -334,6 +334,9 @@ "ALL_PEERS" : "All peers", "DIFFICULTY" : "Difficulty", "API" : "API", + "SANDBOXES": "Queue", + "PENDING_TX": "{{count}} transaction(s) / {{size}} max, {{free}} space(s) remaining", + "PENDING_MEMBERSHIPS": "{{count}} pending membership(s) / {{size}} max, {{free}} space(s) remaining", "CURRENT_BLOCK" : "Block #", "POPOVER_FILTER_TITLE": "Filter", "OFFLINE": "Offline", diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 1643a2ee500ec4bba57ac6bc6f2d109dea4ee1ab..817b9c948cbb7fefb832eab8c4314e8d0766fce5 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -334,6 +334,9 @@ "ALL_PEERS" : "All peers", "DIFFICULTY" : "Difficulty", "API" : "API", + "SANDBOXES": "Queue", + "PENDING_TX": "{{count}} transaction(s) / {{size}} max, {{free}} space(s) remaining", + "PENDING_MEMBERSHIPS": "{{count}} pending membership(s) / {{size}} max, {{free}} space(s) remaining", "CURRENT_BLOCK" : "Block #", "POPOVER_FILTER_TITLE": "Filter", "OFFLINE": "Offline", diff --git a/www/i18n/locale-eo-EO.json b/www/i18n/locale-eo-EO.json index 3c5ac68ead9eeaf54d791984eb9cee24372e8fb6..fafe943f8665f07f8dff2a4b141588b71843f1ab 100644 --- a/www/i18n/locale-eo-EO.json +++ b/www/i18n/locale-eo-EO.json @@ -333,6 +333,9 @@ "ALL_PEERS" : "Ĉiuj nodoj", "DIFFICULTY" : "Malfacileco", "API" : "API", + "SANDBOXES": "Atendovico", + "PENDING_TX": "{{count}} transakcio(j) / {{size}} maksimume, {{free}} lokoj restantaj", + "PENDING_MEMBERSHIPS": "{{count}} membreco(j) atendantaj / {{size}} maksimume, {{free}} lokoj restantaj", "CURRENT_BLOCK" : "Bloko #", "POPOVER_FILTER_TITLE": "Filtrilo", "OFFLINE": "Nekonektita", diff --git a/www/i18n/locale-es-ES.json b/www/i18n/locale-es-ES.json index bae2c5031bd3cad7674e6365036cc99b9ec3b2b7..8021895d06856055be3a2db80e95bc37d1edf9a4 100644 --- a/www/i18n/locale-es-ES.json +++ b/www/i18n/locale-es-ES.json @@ -327,6 +327,9 @@ "ALL_PEERS": "Todos los nodos", "DIFFICULTY": "Dificultad", "API": "API", + "SANDBOXES": "Cola", + "PENDING_TX": "{{count}} transacción(es) / {{size}} máx, {{free}} espacio(s) restante(s)", + "PENDING_MEMBERSHIPS": "{{count}} membresÃa(s) pendiente(s) / {{size}} máx, {{free}} espacio(s) restante(s)", "CURRENT_BLOCK": "Bloque #", "POPOVER_FILTER_TITLE": "Filtro", "OFFLINE": "Fuera de lÃnea", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index 175d1388ec05e06d9e9e834cb07aaf27999f16cc..a10c5e26db4705342359762a2bd608f46901cf05 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -332,6 +332,11 @@ "MEMBERS" : "Membres", "MEMBER_PEERS" : "NÅ“uds membres", "ALL_PEERS" : "Tous les nÅ“uds", + "SANDBOXES" : "File d'attente", + "PENDING_TX" : "{{count}} transaction(s) / {{size}} max, soit {{free}} place(s) restante(s)", + "PENDING_MEMBERSHIPS" : "{{count}} adhésion(s) en attente / {{size}} max, soit {{free}} place(s) restante(s)", + "STORE_TX_HISTORY": "Archive l'historique des opérations", + "STORE_WOT_WIZARD": "Compatible Wot Wizard", "DIFFICULTY" : "Difficulté", "API" : "API", "CURRENT_BLOCK" : "Bloc #", diff --git a/www/i18n/locale-it-IT.json b/www/i18n/locale-it-IT.json index 5f3d86ba1ec8b14e0cf564ebb8a9a6745e3c3f24..c8739f03ec830bda85be21dc549a2bbe9248e390 100644 --- a/www/i18n/locale-it-IT.json +++ b/www/i18n/locale-it-IT.json @@ -334,6 +334,9 @@ "ALL_PEERS" : "Tutti i nodi", "DIFFICULTY" : "Difficoltà ", "API" : "API", + "SANDBOXES": "Coda", + "PENDING_TX": "{{count}} transazione(i) / {{size}} max, {{free}} posto(i) rimanente(i)", + "PENDING_MEMBERSHIPS": "{{count}} adesione(i) in sospeso / {{size}} max, {{free}} posto(i) rimanente(i)", "CURRENT_BLOCK" : "Blocco #", "POPOVER_FILTER_TITLE": "Filtro", "OFFLINE": "Sconessi", diff --git a/www/i18n/locale-nl-NL.json b/www/i18n/locale-nl-NL.json index 861384cba0dd80c3fc184583c8587c5b277b3882..716698e5a40fd9e3b3827a9837de6e65596c57c2 100644 --- a/www/i18n/locale-nl-NL.json +++ b/www/i18n/locale-nl-NL.json @@ -294,6 +294,9 @@ "PEERS": "Knopen", "SIGNED_ON_BLOCK": "Getekend op blok", "MIRROR": "spiegel", + "SANDBOXES": "Wachtrij", + "PENDING_TX": "{{count}} transactie(s) / {{size}} max, {{free}} plaats(en) over", + "PENDING_MEMBERSHIPS": "{{count}} in afwachting van lidmaatschap(pen) / {{size}} max, {{free}} plaats(en) over", "CURRENT_BLOCK": "Blok #", "VIEW": { "TITLE": "Knoop", diff --git a/www/i18n/locale-pt-PT.json b/www/i18n/locale-pt-PT.json index f3e3ddcacfa5a51115f26150c82cc572746854cc..40c50ecc7b8f1d8bdd7070807c690ba8a01ec97e 100644 --- a/www/i18n/locale-pt-PT.json +++ b/www/i18n/locale-pt-PT.json @@ -327,6 +327,9 @@ "ALL_PEERS": "Todos os nós", "DIFFICULTY": "Dificuldade", "API": "API", + "SANDBOXES": "Fila de espera", + "PENDING_TX": "{{count}} transação(ões) / {{size}} máx, {{free}} lugar(es) restante(s)", + "PENDING_MEMBERSHIPS": "{{count}} adesão(ões) pendente(s) / {{size}} máx, {{free}} lugar(es) restante(s)", "CURRENT_BLOCK": "Bloco #", "POPOVER_FILTER_TITLE": "Filtro", "OFFLINE": "Desligado", diff --git a/www/js/entities/peer.js b/www/js/entities/peer.js index 0a37c098daddb2d626e17e80d221556ec30e4299..0286e6b8f49857021d821f621c9546d6a5db6793 100644 --- a/www/js/entities/peer.js +++ b/www/js/entities/peer.js @@ -144,8 +144,16 @@ Peer.prototype.getHost = function(bma) { Peer.prototype.getPath = function(bma) { bma = bma || this.bma || this.getBMA(); - // Add starting slash to path - return bma.path && bma.path !== '' && !bma.path.startsWith('/') ? ('/' + bma.path) : (bma.path || ''); + var path = bma.path || ''; + if (!path || bma.path === '') return ''; + + // Add starting slash + if (!path.startsWith('/')) path = '/' + path; + + // Remove trailing slash + if (path.endsWith('/')) path = path.substring(0, path.length - 1); + + return path; }; Peer.prototype.getUrl = function(bma) { diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index 6611a64f74825f652f8a7d8ff23ded4e9ffd1048..e187a09c359308ac32fb473591d85f7a4010a6d9 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -1126,7 +1126,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. url: csHttp.getUrl(host, port, path, useSsl), node: { summary: csHttp.getWithCache(host, port, path + '/node/summary', useSsl, csCache.constants.MEDIUM, false/*autoRefresh*/, timeout), - sandbox: csHttp.get(host, port, path + '/node/sandbox', useSsl, timeout), + sandboxes: csHttp.get(host, port, path + '/node/sandboxes', useSsl, timeout), }, network: { peering: { diff --git a/www/js/services/http-services.js b/www/js/services/http-services.js index 9bb7674a1ecde86d7d95fb7ed1e25b19129ad4e1..b0ff0b89b002039a69722a83138274607258841c 100644 --- a/www/js/services/http-services.js +++ b/www/js/services/http-services.js @@ -20,7 +20,7 @@ angular.module('cesium.http.services', ['cesium.cache.services']) ; function getServer(host, port) { - // Remove port if 80 or 443 + // Hide port if =80 or =443 return !host ? null : (host + (port && port != 80 && port != 443 ? (':' + port) : '')); } @@ -33,7 +33,8 @@ angular.module('cesium.http.services', ['cesium.cache.services']) function getWsUrl(host, port, path, useSsl) { var protocol = (port == 443 || useSsl) ? 'wss' : 'ws'; - return protocol + '://' + getServer(host, port) + (path ? path : ''); + path = path && path !== '' && !path.startsWith('/') ? ('/' + path) : (path || ''); + return protocol + '://' + getServer(host, port) + path; } function processError(reject, data, url, status, config, startTime) { diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js index 7173305a2ac91e36b9955c90caaf40b8881ec77b..c317755644dee6ce2f09e2296c8356c338b45c09 100644 --- a/www/js/services/network-services.js +++ b/www/js/services/network-services.js @@ -601,7 +601,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', })); } - // Get Version + // Get software, version and storage if (data.expertMode || data.filter.bma) { jobs.push(peer.api.node.summary() .then(function (res) { @@ -617,6 +617,35 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', })); } + // Get sandboxes + if (data.expertMode) { + jobs.push(peer.api.node.sandboxes() + .catch(function(err) { + return {}; // continue + }) + .then(function(res) { + peer.sandboxes = res || {}; + peer.sandboxes.identities = peer.sandboxes.identities || {}; + peer.sandboxes.memberships = peer.sandboxes.memberships || {}; + peer.sandboxes.transactions = peer.sandboxes.transactions || {}; + + var full = false; + Object.keys(peer.sandboxes).forEach(function (key) { + var sandbox = peer.sandboxes[key]; + sandbox.free = sandbox.free || -1; + sandbox.size = sandbox.size || 0; + if (sandbox.free >= 0 && sandbox.free <= sandbox.size) { + sandbox.count = sandbox.size - sandbox.free; + sandbox.percentage = (sandbox.count / sandbox.size) * 100; + } + full = full || sandbox.free === 0; + }); + // Mark as full, if one sandbox is full + peer.sandboxes.full = full; + }) + ); + } + if (!jobs.length) return peer; return $q.all(jobs) @@ -938,7 +967,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', mainConsensusBlock, Date.now() - now)); - // Exclude peers that are not compatible with Cesium (.e.g 1.9.0, or without TX storage) + // Exclude peers that are not compatible with Cesium peers = _.filter(peers, function(peer) { return isCompatibleBMAPeer(peer); }); @@ -968,23 +997,30 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', isCompatibleBMAPeer = function(peer) { if (!peer && !peer.isBma() || !peer.version) return false; - // Exclude 1.9.0 version (=DEV) - if (peer.version.startsWith('1.9.0')) { + // Exclude beta versions (1.9.0, 1.9.0-dev and 1.8.7-rc4) + if (peer.version.startsWith('1.9.0') || peer.version.startsWith('1.8.7-rc')) { console.debug('[network] BMA endpoint [{0}] is EXCLUDED (incompatible version {1})'.format(peer.getServer(), peer.version)); return false; } - // Exclude g1.duniter.org, because of fail-over config, that can switch node - if (peer.host === 'g1.duniter.org') { - console.debug('[network] BMA endpoint [{0}] is EXCLUDED (fail-over config)'.format(peer.getServer())); - return false; - } - - // Keep only if store transactions + // Exclude if transactions not stored if (!peer.storage && !peer.storage.transactions) { console.debug('[network] BMA endpoint [{0}] is EXCLUDED (no transactions storage)'.format(peer.getServer())); return false; } + + // Exclude g1.duniter.org, because of fail-over config, that can switch node + if (peer.host === 'g1.duniter.org') { + console.debug('[network] BMA endpoint [{0}] is EXCLUDED (fail-over config)'.format(peer.getServer())); + return false; + } + + // Exclude if one sandbox is full + if (peer.sandboxes && peer.sandboxes.full) { + console.debug('[network] BMA endpoint [{0}] is EXCLUDED (one sandbox is full)'.format(peer.getServer())); + return false; + } + return true; }; diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index 646153032e16d409c46998b931f3aa5caebdc26e..c257696b59bcf730c9efa4d6593697fb083d7b82 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -1592,11 +1592,11 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se var bma = BMA.lightInstance(peer.host, peer.port, peer.path, peer.useSsl, timeout); return bma.tx.process({transaction: signedTx}) .then(function() { - return true + return true; }) .catch(function(err) { if (err.ucode === BMA.errorCodes.TX_ALREADY_PROCESSED) { - return true + return true; } return false; }); diff --git a/www/templates/network/item_content_peer.html b/www/templates/network/item_content_peer.html index d7e3a42cb3d0c502fe9eb1374dd5b059926ff65c..0fae14d8959f64e99e2b14e5ba741d9fe48d2f0e 100644 --- a/www/templates/network/item_content_peer.html +++ b/www/templates/network/item_content_peer.html @@ -9,7 +9,7 @@ <b class="icon-secondary assertive ion-close-circled" ng-if=":rebind:!peer.online" style="left: 37px; top: -10px;"></b> <div class="row no-padding"> - <div class="col no-padding"> + <div class="col col-server no-padding"> <h3 class="dark" ng-if=":rebind:!peer.bma.private">{{:rebind:peer.dns || peer.server}}</h3> <h4 class="gray" ng-if=":rebind:peer.bma.private"><i class="ion-flash"></i> {{:locale:'NETWORK.VIEW.PRIVATE_ACCESS'|translate}}</h4> <h4> @@ -22,13 +22,21 @@ <span class="gray" ng-if=":rebind:!compactMode">{{:rebind:peer.dns && (' | ' + peer.server) + (peer.bma.path||'') }}</span> </h4> </div> - <div class="col col-15 no-padding text-center hidden-xs hidden-sm" ng-if="::expertMode"> - <div style="min-width: 50px; padding-top: 5px;" ng-if=":rebind:!compactMode"> + + <!-- API column --> + <div class="col col-15 col-api no-padding text-center hidden-xs hidden-sm" ng-if="::expertMode"> + <h4 class="dark" ng-if=":rebind:!compactMode"> <span ng-if=":rebind:peer.isSsl()" title="SSL"> - <i class="ion-locked"></i><small class="hidden-md"> SSL</small> + <i class="ion-locked"></i><small class="hidden-md"> SSL</small> </span> <span ng-if=":rebind:peer.isBma()" title="BMA"> - <i class="ion-cloud"></i><small class="hidden-md"> BMA</small> + <i class="ion-cloud"></i><small class="hidden-md"> BMA</small> + </span> + <span ng-if=":rebind:peer.storage.transactions" title="{{::'PEER.STORE_TX_HISTORY'|translate}}"> + <i class="ion-card"></i><small class="hidden-md"> TX</small> + </span> + <span ng-if=":rebind:peer.storage.wotwizard" title="{{::'PEER.STORE_WOT_WIZARD'|translate}}"> + <i class="ion-wand"></i><small class="hidden-md"> WW</small> </span> <span ng-if=":rebind:peer.isWs2p()" ng-click="showWs2pPopover($event, peer)" @@ -39,21 +47,25 @@ title="GVA"> <i class="ion-arrow-swap"></i><small class="hidden-md"> GVA</small> </span> - </div> - <div ng-if=":rebind:!peer.isWs2p()&&peer.hasEndpoint('ES_USER_API')" + </h4> + <div ng-if=":rebind:!peer.isWs2p() && peer.hasEndpoint('ES_USER_API')" ng-click="showEndpointsPopover($event, peer, 'ES_USER_API')" title="Cesium+"> + <i class="ion-es-user-api"></i> <b class="ion-plus dark" style="position: relative; left: -14px; top:-17px; font-size : 16px;"></b> </div> - <div ng-if=":rebind:!peer.isWs2p()&&peer.isTor()" ng-click="showEndpointsPopover($event, peer, 'BMATOR')"> + <div ng-if=":rebind:!peer.isWs2p() && peer.isTor()" ng-click="showEndpointsPopover($event, peer, 'BMATOR')"> <i class="ion-bma-tor-api"></i> </div> - <div ng-if=":rebind:peer.isWs2p()&&peer.isTor()" ng-click="showWs2pPopover($event, peer)"> + <div ng-if=":rebind:peer.isWs2p() && peer.isTor()" ng-click="showWs2pPopover($event, peer)"> <i class="ion-bma-tor-api"></i> </div> </div> - <div class="col col-20 no-padding text-center" ng-if="::expertMode && search.type != 'offline'"> + + + <!-- Difficulty column --> + <div class="col col-15 no-padding text-center" ng-if="::expertMode && search.type != 'offline'"> <h3 class="hidden-sm hidden-xs gray"> <span ng-if=":rebind:peer.uid"><i class="ion-lock-combination"></i>{{:rebind:peer.difficulty||'?'}}</span> <span ng-if=":rebind:!peer.uid" translate>PEER.MIRROR</span> @@ -62,6 +74,46 @@ {{:rebind: peer.software !== 'duniter' ? peer.software : ''}} {{:rebind: peer.version ? ('v'+peer.version) : ''}}</h4> </div> + + <!-- Sandboxes column --> + <div class="col col-15 col-sandboxes no-padding text-center" ng-if="::expertMode && search.type != 'offline'"> + <!-- transactions sandbox --> + <h3 ng-if=":rebind:peer.sandboxes.transactions.free!==-1 && peer.isBma()" + title="{{::'PEER.PENDING_TX'|translate: peer.sandboxes.transactions}}"> + <i class="ion-card gray"></i> + <div class="progress-bar" + ng-class=":rebind:{ + 'balanced': peer.sandboxes.transactions.percentage < 50, + 'energized': peer.sandboxes.transactions.percentage >= 50 && peer.sandboxes.transactions.percentage < 80, + 'assertive': peer.sandboxes.transactions.percentage >= 80 + }"> + <div class="progress-fill" style="width: {{peer.sandboxes.transactions.percentage + '%'}}"> + </div> + <div class="progress-text gray"> + {{:rebind:peer.sandboxes.transactions.percentage|formatInteger}} % + </div> + </div> + </h3> + + <!-- memberships sandbox --> + <h3 ng-if=":rebind:peer.sandboxes.memberships.free!==-1 && peer.isBma()" + title="{{::'PEER.PENDING_MEMBERSHIPS'|translate: peer.sandboxes.memberships}}"> + <i class="ion-person gray" style="width: 14px;"></i> + <div class="progress-bar" ng-class=":rebind:{ + 'balanced': peer.sandboxes.memberships.percentage < 50, + 'energized': peer.sandboxes.memberships.percentage >= 50 && peer.sandboxes.memberships.percentage < 80, + 'assertive': peer.sandboxes.memberships.percentage >= 80 + }"> + <div class="progress-fill" style="width: {{peer.sandboxes.memberships.percentage + '%'}}"> + </div> + <div class="progress-text text-center gray"> + {{:rebind:peer.sandboxes.memberships.percentage|formatInteger}} % + </div> + </div> + </h3> + </div> + + <!-- Block column --> <div class="col col-20 no-padding text-center"> <span id="{{$index === 0 ? helptipPrefix + '-peer-0-block' : ''}}" class="badge" ng-class=":rebind:{'badge-balanced': peer.hasMainConsensusBlock, 'badge-energized': peer.hasConsensusBlock, 'ng-hide': !peer.currentNumber && !peer.blockNumber }"> diff --git a/www/templates/network/items_peers.html b/www/templates/network/items_peers.html index 4a11311ed51524d71a86ebc2eae2c9f711f61ea9..20f8f564349a57a8938d636c6ab31803e09a9842 100644 --- a/www/templates/network/items_peers.html +++ b/www/templates/network/items_peers.html @@ -9,6 +9,7 @@ <cs-sort-icon asc="search.asc" sort="search.sort" toggle="'uid'"></cs-sort-icon> {{:locale:'COMMON.UID' | translate}} / {{:locale:'COMMON.PUBKEY' | translate}} </a> + <!-- API header --> <a class="no-padding dark hidden-md col col-15 col-header" ng-click="toggleSort('api')" ng-if=":rebind:!compactMode"> @@ -17,11 +18,21 @@ </a> <div class="no-padding dark hidden-md col col-15 col-header" ng-if=":rebind:compactMode"></div> - <a class="no-padding dark col col-20 col-header" + <!-- Difficulty header --> + <a class="no-padding dark col col-15 col-header" ng-click="toggleSort('difficulty')"> <cs-sort-icon asc="search.asc" sort="search.sort" toggle="'difficulty'"></cs-sort-icon> {{:locale:'PEER.DIFFICULTY' | translate}} </a> + + <!-- Sanboxes header --> + <a class="no-padding dark col col-15 col-header" + ng-click="toggleSort('sandboxes')"> + <cs-sort-icon asc="search.asc" sort="search.sort" toggle="'sandboxes'"></cs-sort-icon> + {{:locale:'PEER.SANDBOXES' | translate}} + </a> + + <!-- Block header --> <a class="col col-20 col-header no-padding dark" ng-click="toggleSort('current_block')"> <cs-sort-icon asc="search.asc" sort="search.sort" toggle="'current_block'"></cs-sort-icon> {{:locale:'PEER.CURRENT_BLOCK' | translate}}