Implemented status bar with some status information: sync process, connected nodes and blockchain height.
This commit is contained in:
@@ -14,6 +14,7 @@ pub struct Blockchain {
|
||||
pub version: u32,
|
||||
pub blocks: Vec<Block>,
|
||||
last_block: Option<Block>,
|
||||
max_height: u64,
|
||||
db: Connection,
|
||||
zones: RefCell<HashSet<String>>
|
||||
}
|
||||
@@ -24,7 +25,7 @@ impl Blockchain {
|
||||
let version = settings.version;
|
||||
|
||||
let db = sqlite::open(DB_NAME).expect("Unable to open blockchain DB");
|
||||
let mut blockchain = Blockchain{ origin, version, blocks: Vec::new(), last_block: None, db, zones: RefCell::new(HashSet::new()) };
|
||||
let mut blockchain = Blockchain{ origin, version, blocks: Vec::new(), last_block: None, max_height: 0, db, zones: RefCell::new(HashSet::new()) };
|
||||
blockchain.init_db();
|
||||
blockchain
|
||||
}
|
||||
@@ -243,6 +244,16 @@ impl Blockchain {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_height(&self) -> u64 {
|
||||
self.max_height
|
||||
}
|
||||
|
||||
pub fn update_max_height(&mut self, height: u64) {
|
||||
if height > self.max_height {
|
||||
self.max_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn check(&self) -> bool {
|
||||
let mut prev_block = None;
|
||||
for block in self.blocks.iter() {
|
||||
|
||||
+6
-3
@@ -4,10 +4,13 @@ pub enum Event {
|
||||
MinerStopped,
|
||||
KeyGeneratorStarted,
|
||||
KeyGeneratorStopped,
|
||||
KeyCreated {path: String, public: String},
|
||||
KeyLoaded {path: String, public: String},
|
||||
KeySaved {path: String, public: String},
|
||||
KeyCreated { path: String, public: String },
|
||||
KeyLoaded { path: String, public: String },
|
||||
KeySaved { path: String, public: String },
|
||||
NewBlockReceived,
|
||||
BlockchainChanged,
|
||||
ActionStopMining,
|
||||
StatsCount { nodes: usize, blocks: u64 },
|
||||
SyncStarted { have: u64, height: u64 },
|
||||
ActionIdle,
|
||||
}
|
||||
|
||||
+39
-30
@@ -56,11 +56,11 @@ fn main() {
|
||||
let program = args[0].clone();
|
||||
|
||||
let mut opts = Options::new();
|
||||
opts.optflag("h","help", "Print this help menu");
|
||||
opts.optflag("n","nogui","Run without graphic user interface");
|
||||
opts.optflag("v","verbose","Show more debug messages");
|
||||
opts.optflag("d","debug","Show trace messages, more than debug");
|
||||
opts.optopt("c","config","Path to config file", "");
|
||||
opts.optflag("h", "help", "Print this help menu");
|
||||
opts.optflag("n", "nogui", "Run without graphic user interface");
|
||||
opts.optflag("v", "verbose", "Show more debug messages");
|
||||
opts.optflag("d", "debug", "Show trace messages, more than debug");
|
||||
opts.optopt("c", "config", "Path to config file", "");
|
||||
|
||||
let opt_matches = match opts.parse(&args[1..]) {
|
||||
Ok(m) => m,
|
||||
@@ -161,8 +161,8 @@ fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Min
|
||||
|
||||
fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
||||
let file_content = include_str!("webview/index.html");
|
||||
let mut styles= inline_style(include_str!("webview/bulma.css"));
|
||||
styles.push_str(&inline_style(include_str!("webview/miner.css")));
|
||||
let mut styles = inline_style(include_str!("webview/bulma.css"));
|
||||
styles.push_str(&inline_style(include_str!("webview/busy_indicator.css")));
|
||||
let scripts = inline_script(include_str!("webview/scripts.js"));
|
||||
|
||||
let html = Content::Html(file_content.to_owned().replace("{styles}", &styles).replace("{scripts}", &scripts));
|
||||
@@ -189,10 +189,19 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
||||
Event::KeyCreated { path, public } => { format!("keystoreChanged('{}', '{}');", &path, &public) }
|
||||
Event::KeyLoaded { path, public } => { format!("keystoreChanged('{}', '{}');", &path, &public) }
|
||||
Event::KeySaved { path, public } => { format!("keystoreChanged('{}', '{}');", &path, &public) }
|
||||
Event::MinerStarted => { format!("showMiningIndicator({});", true) }
|
||||
Event::KeyGeneratorStarted => { format!("showMiningIndicator({});", true) }
|
||||
Event::MinerStopped => { format!("showMiningIndicator({});", false) }
|
||||
Event::KeyGeneratorStopped => { format!("showMiningIndicator({});", false) }
|
||||
Event::MinerStarted => { format!("showMiningIndicator({}, false);", true) }
|
||||
Event::KeyGeneratorStarted => { format!("showMiningIndicator({}, false);", true) }
|
||||
Event::MinerStopped => { format!("showMiningIndicator({}, false);", false) }
|
||||
Event::KeyGeneratorStopped => { format!("showMiningIndicator({}, false);", false) }
|
||||
Event::SyncStarted { have, height } => {
|
||||
format!("setLeftStatusBarText('Synchronizing {}/{}'); showMiningIndicator(true, true);", have, height)
|
||||
}
|
||||
Event::ActionIdle => {
|
||||
format!("setLeftStatusBarText('Idle'); showMiningIndicator(false, true);")
|
||||
}
|
||||
Event::StatsCount { nodes, blocks } => {
|
||||
format!("setRightStatusBarText('Nodes: {}, Blocks: {}')", nodes, blocks)
|
||||
}
|
||||
_ => { String::new() }
|
||||
};
|
||||
|
||||
@@ -216,17 +225,17 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
||||
match Keystore::from_file(&file_name, "") {
|
||||
None => {
|
||||
error!("Error loading keystore '{}'!", &file_name);
|
||||
},
|
||||
}
|
||||
Some(keystore) => {
|
||||
info!("Loaded keystore with key: {:?}", &keystore.get_public());
|
||||
let mut c = context.lock().unwrap();
|
||||
c.bus.post(Event::KeyLoaded {path: keystore.get_path().to_owned(), public: keystore.get_public().to_string()});
|
||||
c.bus.post(Event::KeyLoaded { path: keystore.get_path().to_owned(), public: keystore.get_public().to_string() });
|
||||
c.set_keystore(keystore);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
CreateKey {} => {
|
||||
create_key(context.clone());
|
||||
}
|
||||
@@ -240,11 +249,11 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
||||
let public = c.keystore.get_public().to_string();
|
||||
c.keystore.save(&new_path, "");
|
||||
info!("Key file saved to {}", &path);
|
||||
c.bus.post(Event::KeySaved {path, public });
|
||||
c.bus.post(Event::KeySaved { path, public });
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckDomain { name} => {
|
||||
CheckDomain { name } => {
|
||||
let name = name.to_lowercase();
|
||||
let c = context.lock().unwrap();
|
||||
let available = c.get_blockchain().is_domain_available(&name, &c.get_keystore());
|
||||
@@ -282,7 +291,7 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
||||
ChangeDomain { .. } => {}
|
||||
RenewDomain { .. } => {}
|
||||
TransferDomain { .. } => {}
|
||||
CheckZone { name} => {
|
||||
CheckZone { name } => {
|
||||
let name = name.to_lowercase();
|
||||
if !check_domain(&name, false) {
|
||||
web_view.eval("zoneAvailable(false)").expect("Error evaluating!");
|
||||
@@ -398,8 +407,8 @@ fn create_key(context: Arc<Mutex<Context>>) {
|
||||
Some(keystore) => {
|
||||
info!("Key mined successfully: {:?}", &keystore.get_public());
|
||||
let mut c = context.lock().unwrap();
|
||||
mining.store(false,Ordering::Relaxed);
|
||||
c.bus.post(Event::KeyCreated {path: keystore.get_path().to_owned(), public: keystore.get_public().to_string()});
|
||||
mining.store(false, Ordering::Relaxed);
|
||||
c.bus.post(Event::KeyCreated { path: keystore.get_path().to_owned(), public: keystore.get_public().to_string() });
|
||||
c.set_keystore(keystore);
|
||||
}
|
||||
}
|
||||
@@ -440,7 +449,7 @@ fn create_server_context(context: Arc<Mutex<Context>>, settings: &Settings) -> A
|
||||
server_context.dns_port = settings.dns.port;
|
||||
server_context.resolve_strategy = match settings.dns.forwarders.is_empty() {
|
||||
true => { ResolveStrategy::Recursive }
|
||||
false => { ResolveStrategy::Forward { upstreams: settings.dns.forwarders.clone() }}
|
||||
false => { ResolveStrategy::Forward { upstreams: settings.dns.forwarders.clone() } }
|
||||
};
|
||||
server_context.filters.push(Box::new(BlockchainFilter::new(context)));
|
||||
match server_context.initialize() {
|
||||
@@ -455,16 +464,16 @@ fn create_server_context(context: Arc<Mutex<Context>>, settings: &Settings) -> A
|
||||
#[serde(tag = "cmd", rename_all = "camelCase")]
|
||||
pub enum Cmd {
|
||||
Loaded,
|
||||
LoadKey{},
|
||||
CreateKey{},
|
||||
SaveKey{},
|
||||
CheckZone{name: String},
|
||||
CreateZone{name: String, data: String},
|
||||
CheckDomain{name: String},
|
||||
CreateDomain{name: String, records: String, tags: String},
|
||||
ChangeDomain{name: String, records: String, tags: String},
|
||||
RenewDomain{name: String, days: u16},
|
||||
TransferDomain{name: String, owner: String},
|
||||
LoadKey {},
|
||||
CreateKey {},
|
||||
SaveKey {},
|
||||
CheckZone { name: String },
|
||||
CreateZone { name: String, data: String },
|
||||
CheckDomain { name: String },
|
||||
CreateDomain { name: String, records: String, tags: String },
|
||||
ChangeDomain { name: String, records: String, tags: String },
|
||||
RenewDomain { name: String, days: u16 },
|
||||
TransferDomain { name: String, owner: String },
|
||||
StopMining,
|
||||
}
|
||||
|
||||
|
||||
+33
-6
@@ -91,6 +91,9 @@ impl Network {
|
||||
token => {
|
||||
if !handle_connection_event(context.clone(), &mut peers, &poll.registry(), &event) {
|
||||
let _ = peers.close_peer(poll.registry(), &token);
|
||||
let mut context = context.lock().unwrap();
|
||||
let blocks_count = context.blockchain.height();
|
||||
context.bus.post(crate::event::Event::StatsCount { nodes: peers.get_peers_active_count(), blocks: blocks_count });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,9 +126,10 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
|
||||
let data = data.unwrap();
|
||||
match Message::from_bytes(data) {
|
||||
Ok(message) => {
|
||||
debug!("Got message from socket {}: {:?}", &event.token().0, &message);
|
||||
let m = format!("{:?}", &message);
|
||||
let new_state = handle_message(context.clone(), message, peers, &event.token());
|
||||
let peer = peers.get_mut_peer(&event.token()).unwrap();
|
||||
debug!("Got message from {}: {:?}", &peer.get_addr(), &m);
|
||||
let stream = peer.get_stream();
|
||||
match new_state {
|
||||
State::Message { data } => {
|
||||
@@ -163,17 +167,17 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
|
||||
Some(peer) => {
|
||||
match peer.get_state().clone() {
|
||||
State::Connecting => {
|
||||
debug!("Sending hello to socket {}", event.token().0);
|
||||
debug!("Sending hello to {}", &peer.get_addr());
|
||||
let data: String = {
|
||||
let c = context.lock().unwrap();
|
||||
let message = Message::hand(&c.settings.origin, c.settings.version, c.settings.public);
|
||||
serde_json::to_string(&message).unwrap()
|
||||
};
|
||||
send_message(peer.get_stream(), &data.into_bytes());
|
||||
debug!("Sent hello through socket {}", event.token().0);
|
||||
debug!("Sent hello to {}", &peer.get_addr());
|
||||
}
|
||||
State::Message { data } => {
|
||||
debug!("Sending data to socket {}: {}", event.token().0, &String::from_utf8(data.clone()).unwrap());
|
||||
debug!("Sending data to {}: {}", &peer.get_addr(), &String::from_utf8(data.clone()).unwrap());
|
||||
send_message(peer.get_stream(), &data);
|
||||
}
|
||||
State::Connected => {}
|
||||
@@ -273,9 +277,16 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
|
||||
return State::Error;
|
||||
}
|
||||
if ok {
|
||||
let active_count = peers.get_peers_active_count();
|
||||
let peer = peers.get_mut_peer(token).unwrap();
|
||||
peer.set_height(height);
|
||||
peer.set_active(true);
|
||||
let mut context = context.lock().unwrap();
|
||||
let blocks_count = context.blockchain.height();
|
||||
context.bus.post(crate::event::Event::StatsCount { nodes: active_count, blocks: blocks_count });
|
||||
if peer.is_higher(my_height) {
|
||||
context.blockchain.update_max_height(height);
|
||||
context.bus.post(crate::event::Event::SyncStarted { have: my_height, height});
|
||||
State::message(Message::GetBlock { index: my_height })
|
||||
} else {
|
||||
State::message(Message::GetPeers)
|
||||
@@ -288,6 +299,7 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
|
||||
Message::Ping { height } => {
|
||||
let peer = peers.get_mut_peer(token).unwrap();
|
||||
peer.set_height(height);
|
||||
peer.set_active(true);
|
||||
if peer.is_higher(my_height) {
|
||||
State::message(Message::GetBlock { index: my_height })
|
||||
} else {
|
||||
@@ -297,9 +309,14 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
|
||||
Message::Pong { height } => {
|
||||
let peer = peers.get_mut_peer(token).unwrap();
|
||||
peer.set_height(height);
|
||||
peer.set_active(true);
|
||||
if peer.is_higher(my_height) {
|
||||
State::message(Message::GetBlock { index: my_height })
|
||||
} else {
|
||||
let mut context = context.lock().unwrap();
|
||||
let blocks_count = context.blockchain.height();
|
||||
context.bus.post(crate::event::Event::ActionIdle);
|
||||
context.bus.post(crate::event::Event::StatsCount { nodes: peers.get_peers_active_count(), blocks: blocks_count });
|
||||
State::idle()
|
||||
}
|
||||
}
|
||||
@@ -324,12 +341,22 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
|
||||
Ok(block) => block,
|
||||
Err(_) => return State::Error
|
||||
};
|
||||
// TODO check if the block is good
|
||||
// TODO check here if the block is good before trying to add
|
||||
let context = context.clone();
|
||||
thread::spawn(move || {
|
||||
let mut context = context.lock().unwrap();
|
||||
let max_height = context.blockchain.max_height();
|
||||
match context.blockchain.add_block(block) {
|
||||
Ok(_) => { context.bus.post(crate::event::Event::BlockchainChanged); }
|
||||
Ok(_) => {
|
||||
let my_height = context.blockchain.height();
|
||||
context.bus.post(crate::event::Event::BlockchainChanged);
|
||||
// If it was the last block to sync
|
||||
if my_height == max_height {
|
||||
context.bus.post(crate::event::Event::ActionIdle);
|
||||
} else {
|
||||
context.bus.post(crate::event::Event::SyncStarted { have: my_height, height: max_height});
|
||||
}
|
||||
}
|
||||
Err(_) => { warn!("Discarded received block"); }
|
||||
}
|
||||
});
|
||||
|
||||
+7
-2
@@ -10,11 +10,12 @@ pub struct Peer {
|
||||
height: u64,
|
||||
inbound: bool,
|
||||
public: bool,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl Peer {
|
||||
pub fn new(addr: SocketAddr, stream: TcpStream, state: State, inbound: bool) -> Self {
|
||||
Peer { addr, stream, state, height: 0, inbound, public: false }
|
||||
Peer { addr, stream, state, height: 0, inbound, public: false, active: false }
|
||||
}
|
||||
|
||||
pub fn get_addr(&self) -> SocketAddr {
|
||||
@@ -53,8 +54,12 @@ impl Peer {
|
||||
self.public = public;
|
||||
}
|
||||
|
||||
pub fn set_active(&mut self, active: bool) {
|
||||
self.active = active;
|
||||
}
|
||||
|
||||
pub fn active(&self) -> bool {
|
||||
self.state.active()
|
||||
self.active
|
||||
}
|
||||
|
||||
pub fn disabled(&self) -> bool {
|
||||
|
||||
@@ -45,6 +45,7 @@ impl Peers {
|
||||
|
||||
if !peer.disabled() && !peer.is_inbound() {
|
||||
peer.set_state(State::offline());
|
||||
peer.set_active(false);
|
||||
} else {
|
||||
self.peers.remove(token);
|
||||
}
|
||||
@@ -112,6 +113,16 @@ impl Peers {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_peers_active_count(&self) -> usize {
|
||||
let mut count = 0;
|
||||
for (_, peer) in self.peers.iter() {
|
||||
if peer.active() {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
pub fn skip_peer_connection(&self, addr: &SocketAddr) -> bool {
|
||||
for (_, peer) in self.peers.iter() {
|
||||
if peer.equals(addr) && (!peer.is_public() || peer.active() || peer.disabled()) {
|
||||
|
||||
@@ -26,16 +26,6 @@ impl State {
|
||||
State::Message {data: Vec::from(response.as_bytes()) }
|
||||
}
|
||||
|
||||
pub fn active(&self) -> bool {
|
||||
match self {
|
||||
State::Connecting => { true }
|
||||
State::Connected => { true }
|
||||
State::Idle { .. } => { true }
|
||||
State::Message { .. } => { true }
|
||||
_ => { false }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_idle(&self) -> bool {
|
||||
match self {
|
||||
State::Idle { .. } => { true }
|
||||
|
||||
Vendored
+9
@@ -10846,4 +10846,13 @@ html {
|
||||
width: 50%;
|
||||
top: 10pt;
|
||||
right: 10pt;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: #f4f4f4;
|
||||
padding: 0.2rem 0.5rem 0.2rem 0.5rem;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
z-index: 9;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
.busy_indicator {
|
||||
width:24px;
|
||||
height:24px;
|
||||
display:inline-block;
|
||||
padding:0px;
|
||||
text-align:left;
|
||||
float:left;
|
||||
margin-left: -5px;
|
||||
}
|
||||
.busy_indicator span {
|
||||
position:absolute;
|
||||
display:inline-block;
|
||||
width:24px;
|
||||
height:24px;
|
||||
border-radius:100%;
|
||||
background:#ee3333;
|
||||
-webkit-animation:busy_indicator 1.6s linear infinite;
|
||||
animation:busy_indicator 1.6s linear infinite;
|
||||
}
|
||||
.busy_indicator span:last-child {
|
||||
animation-delay:-0.8s;
|
||||
-webkit-animation-delay:-0.8s;
|
||||
}
|
||||
@keyframes busy_indicator {
|
||||
0% {transform: scale(0, 0);opacity:0.9;}
|
||||
100% {transform: scale(1, 1);opacity:0;}
|
||||
}
|
||||
@-webkit-keyframes busy_indicator {
|
||||
0% {-webkit-transform: scale(0, 0);opacity:0.9;}
|
||||
100% {-webkit-transform: scale(1, 1);opacity:0;}
|
||||
}
|
||||
.busy_blue span {
|
||||
background:#3273dc;
|
||||
}
|
||||
+20
-5
@@ -9,10 +9,6 @@
|
||||
{scripts}
|
||||
</head>
|
||||
<body onload="onLoad();">
|
||||
<div class="mining_indicator" id="mining_indicator" onclick="miningIndicatorClick(this)">
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<div id="modal_dialog" class="modal">
|
||||
<div class="modal-background"></div>
|
||||
@@ -328,6 +324,25 @@
|
||||
</div> <!-- columns -->
|
||||
</div>
|
||||
|
||||
<div class="footer is-hidden">Some footer text is here</div>
|
||||
<div class="footer is-family-code">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item" id="indicator_parent">
|
||||
<div class="busy_indicator busy_blue" id="busy_indicator" onclick="miningIndicatorClick(this)">
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
<div id="status_bar_left">Connecting and syncing...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-right">
|
||||
<div class="level-item" id="status_bar_right">No data</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,34 +0,0 @@
|
||||
.mining_indicator {
|
||||
position:absolute;
|
||||
left:0px;
|
||||
bottom:0px;
|
||||
width:30px;
|
||||
height:30px;
|
||||
display:inline-block;
|
||||
padding:0px;
|
||||
text-align:left;
|
||||
float:left;
|
||||
z-index:10;
|
||||
}
|
||||
.mining_indicator span {
|
||||
position:absolute;
|
||||
display:inline-block;
|
||||
width:30px;
|
||||
height:30px;
|
||||
border-radius:100%;
|
||||
background:#ee3333;
|
||||
-webkit-animation:mining_indicator 1.6s linear infinite;
|
||||
animation:mining_indicator 1.6s linear infinite;
|
||||
}
|
||||
.mining_indicator span:last-child {
|
||||
animation-delay:-0.8s;
|
||||
-webkit-animation-delay:-0.8s;
|
||||
}
|
||||
@keyframes mining_indicator {
|
||||
0% {transform: scale(0, 0);opacity:0.5;}
|
||||
100% {transform: scale(1, 1);opacity:0;}
|
||||
}
|
||||
@-webkit-keyframes mining_indicator {
|
||||
0% {-webkit-transform: scale(0, 0);opacity:0.5;}
|
||||
100% {-webkit-transform: scale(1, 1);opacity:0;}
|
||||
}
|
||||
+21
-4
@@ -249,12 +249,19 @@ function showWarning(text) {
|
||||
setTimeout(button.onclick, 5000);
|
||||
}
|
||||
|
||||
function showMiningIndicator(visible) {
|
||||
indicator = document.getElementById("mining_indicator");
|
||||
function showMiningIndicator(visible, blue) {
|
||||
var indicator = document.getElementById("busy_indicator");
|
||||
var parent = document.getElementById("indicator_parent");
|
||||
var add = "";
|
||||
if (blue) {
|
||||
add = " busy_blue";
|
||||
}
|
||||
if (visible) {
|
||||
indicator.style.visibility = 'visible';
|
||||
indicator.className = 'busy_indicator' + add;
|
||||
parent.style.display = 'flex';
|
||||
} else {
|
||||
indicator.style.visibility = 'hidden';
|
||||
indicator.className = 'busy_indicator is-hidden';
|
||||
parent.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +271,16 @@ function miningIndicatorClick(element) {
|
||||
});
|
||||
}
|
||||
|
||||
function setLeftStatusBarText(text) {
|
||||
var bar = document.getElementById("status_bar_left");
|
||||
bar.innerHTML = text;
|
||||
}
|
||||
|
||||
function setRightStatusBarText(text) {
|
||||
var bar = document.getElementById("status_bar_right");
|
||||
bar.innerHTML = text;
|
||||
}
|
||||
|
||||
function keystoreChanged(path, pub_key) {
|
||||
if (path == '') {
|
||||
path = "In memory";
|
||||
|
||||
Reference in New Issue
Block a user