forked from bitcoinafterlife/bal-welist-website
Compare commits
18 Commits
main
...
f9ffc383a0
| Author | SHA1 | Date | |
|---|---|---|---|
| f9ffc383a0 | |||
| d223404a86 | |||
| b79ee2fdd8 | |||
| 131e5ffabf | |||
| ce66b0de3f | |||
| ff4e46858b | |||
| 6c942e58c6 | |||
| 616c0d1285 | |||
| 03d41dd25d | |||
| adcd4cde94 | |||
| 8bdef5d18f | |||
| 5536d8b14e | |||
| 6cfa521adc | |||
| 560a4d1cbe | |||
| 221bfec74e | |||
| c9749bfed1 | |||
| 756ab98c41 | |||
| 098ca48e9d |
153
README.md
153
README.md
@@ -1,2 +1,153 @@
|
||||
welist html
|
||||
# Server Status: Complete Explanation and Reference Guide
|
||||
|
||||
This page explains all the **Will Executor server health statuses** used throughout the BAL Web Interface. Each status type provides critical information about server operation, health checks, and potential issues for administrators monitoring the Bitcoin After Life network.
|
||||
|
||||
## Status Code Overview
|
||||
|
||||
| Status | Description | When It Occurs |
|
||||
|--------|-------------|----------------|
|
||||
| `OK` | Health check passed | Server is online, functioning normally |
|
||||
| `TIMEOUT: <message>` | Connection timeout | Server response took too long |
|
||||
| `CONNECTION: <message>` | Connection error | Network connectivity issues |
|
||||
| `STATUS: <code>` | HTTP error (from server) | Server returned non-200 status |
|
||||
| `WRONG REPLY: <message>` | Invalid JSON response | Server response couldn't be parsed |
|
||||
| `REQUEST: <message>` | Request error | Client-side request failed |
|
||||
| `BODY: <message>` | Body read error | Failed to read response body |
|
||||
| `DECODE: <message>` | Decode error | Failed to decode response content |
|
||||
| `KO` | Generic error | Unknown or unspecified error |
|
||||
|
||||
## Status Types Explained
|
||||
|
||||
### 🟢 Good Statuses
|
||||
**`OK`** - Everything is functioning correctly:
|
||||
- Server is online and responding
|
||||
- Health check completed successfully
|
||||
- Ready for new registration/processing
|
||||
|
||||
### 🟡 Warning/Moderate Issues
|
||||
**`TIMEOUT: <message>`** - Connection timed out:
|
||||
- Server took too than expected to respond
|
||||
- Could indicate server overload or network issues
|
||||
- Requires attention but server may still be functional
|
||||
|
||||
**`CONNECTION: <message>`** - Connection error:
|
||||
- Network connectivity problems
|
||||
- Server might be reachable but cannot communicate
|
||||
- Potential infrastructure or configuration issue
|
||||
|
||||
**`STATUS: <code>`** - HTTP error:
|
||||
- Server responded with an error code (4xx or 5xx)
|
||||
- Could indicate misconfiguration, maintenance, or issues |
|
||||
- Different error codes mean different things
|
||||
|
||||
### 🔴 Critical Issues
|
||||
**`WRONG REPLY`** - Invalid JSON response:
|
||||
- Server response format is incorrect
|
||||
- May indicate server software bug or corruption
|
||||
- Prevents proper data processing
|
||||
|
||||
**`REQUEST`** - Request error:
|
||||
- Client request failed
|
||||
- Network or protocol issue
|
||||
- Server may be unreachable
|
||||
|
||||
**`BODY`** - Body read error:
|
||||
- Failed to read response body after successful connection
|
||||
- Could indicate server processing issues
|
||||
- Data corruption or transmission problems
|
||||
|
||||
**`DECODE`** - Decode error:
|
||||
- Failed to decode response content
|
||||
- Encoding mismatch or corrupted data
|
||||
- Prevents proper data interpretation
|
||||
|
||||
**`KO`** - Generic error:
|
||||
- Unknown or unspecified error
|
||||
- Fallback for all other unidentified issues
|
||||
- Indicates something went wrong but exact cause unknown
|
||||
|
||||
## Example Status Messages
|
||||
|
||||
### Normal Operations
|
||||
```
|
||||
Status: OK
|
||||
Meaning: Health check passed
|
||||
Display: Server is healthy and ready
|
||||
```
|
||||
|
||||
### Network/Time Issues
|
||||
```
|
||||
Status: TIMEOUT: Connection timed out after 30 seconds
|
||||
Meaning: Server took too long to respond
|
||||
Display: "Connection timeout (Connection timed out after 30 seconds)"
|
||||
```
|
||||
|
||||
### HTTP Errors
|
||||
```
|
||||
Status: STATUS: 500
|
||||
Meaning: Server returned HTTP 500 Internal Server Error
|
||||
Display: "HTTP error (HTTP error)"
|
||||
```
|
||||
|
||||
### Response Processing Issues
|
||||
```
|
||||
Status: WRONG REPLY: Invalid JSON
|
||||
Meaning: Server response could not be parsed as JSON
|
||||
Display: "Invalid JSON response (Invalid JSON)"
|
||||
```
|
||||
|
||||
## Practical Usage Guide
|
||||
|
||||
### For Server Administrators
|
||||
- **OK**: Check server resources and logs if needed
|
||||
- **TIMEOUT/CONNECTION**: Check server network connectivity
|
||||
- **STATUS**: Review server logs and restart if needed
|
||||
- **WRONG REPLY/DECODE/REQUEST**: Investigate server software issues
|
||||
- **KO**: Review server errors and restart
|
||||
|
||||
### For Users
|
||||
- **OK**: Server is working correctly
|
||||
- **TIMEOUT/CONNECTION**: Temporary issue, try again later
|
||||
- **STATUS**: Server may be down for maintenance
|
||||
- **Other errors**: Server issue, contact support if persistent
|
||||
|
||||
## Monitoring Tips
|
||||
|
||||
1. **Continuous Monitoring**: Regular checks of status codes help detect issues early
|
||||
2. **Alert Setup**: Configure alerts for non-OK statuses
|
||||
3. **Log Analysis**: Correlate status codes with server logs
|
||||
4. **Capacity Planning**: Address persistent timeouts/connections with infrastructure improvements
|
||||
|
||||
## Status Processing Logic
|
||||
|
||||
### Status Code Processing
|
||||
```javascript
|
||||
const statusMap = {
|
||||
'OK': 'Health check passed',
|
||||
'TIMEOUT': 'Connection timeout',
|
||||
'CONNECTION': 'Connection error',
|
||||
'STATUS': 'HTTP error',
|
||||
'WRONG REPLY': 'Invalid JSON response',
|
||||
'REQUEST': 'Request error',
|
||||
'BODY': 'Body read error',
|
||||
'DECODE': 'Decode error',
|
||||
'KO': 'Generic error'
|
||||
};
|
||||
|
||||
// Extract base status from status message
|
||||
const st = (data.status||'').split(':')[0];
|
||||
|
||||
// Display only the description (e.g., "Connection timeout" instead of "TIMEOUT: Connection timeout")
|
||||
statusDisplay = statusMap[st] || '—';
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
For more details on server setup, monitoring, and troubleshooting, refer to:
|
||||
- [Server Administration Guide](./administration)
|
||||
- [Status Monitoring Setup](./monitoring-setup)
|
||||
- [Error Resolution Handbook](./error-resolve)
|
||||
|
||||
## Additional Information
|
||||
|
||||
This status system provides a clear, human-readable way to understand server health at a glance, making it easier for administrators to quickly identify and respond to issues.
|
||||
109
index.html
109
index.html
@@ -139,6 +139,11 @@ tbody tr:hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}
|
||||
.btn:disabled{opacity:.45;cursor:not-allowed;filter:none}
|
||||
.note{font-size:13px;color:var(--muted);margin-top:16px;line-height:1.55}
|
||||
.note strong{color:var(--ink)}
|
||||
.btn-share{
|
||||
display:block;margin:0 auto 8px;font:inherit;font-size:13px;cursor:pointer;
|
||||
padding:8px 16px;border-radius:8px;border:1px solid var(--line-strong);
|
||||
background:var(--panel);color:var(--accent);
|
||||
}
|
||||
|
||||
.invoice{display:none}
|
||||
.invoice.show{display:block}
|
||||
@@ -146,8 +151,18 @@ tbody tr:hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}
|
||||
.invoice .row:last-child{border-bottom:0}
|
||||
.invoice .row span:first-child{color:var(--muted)}
|
||||
.invoice .row span:last-child{font-family:var(--mono);text-align:right;word-break:break-all}
|
||||
#qrcode{margin:18px auto 4px;width:160px;height:160px}
|
||||
#qrcode img{width:160px;height:160px}
|
||||
.invoice .row a{color:var(--accent);text-decoration:none}
|
||||
.invoice .row a:hover{text-decoration:underline}
|
||||
#qrcode{margin:18px auto 4px;width:160px}
|
||||
#qrcode canvas,#qrcode img{width:160px!important;height:160px!important;max-width:100%}
|
||||
#qr-overlay{
|
||||
display:none;position:fixed;inset:0;z-index:999;
|
||||
background:rgba(0,0,0,.7);cursor:pointer;
|
||||
align-items:center;justify-content:center;
|
||||
}
|
||||
#qr-overlay.show{display:flex}
|
||||
#qr-big{padding:24px;background:#fff;border-radius:12px}
|
||||
#qr-big canvas,#qr-big img{width:280px!important;height:280px!important;max-width:90vw}
|
||||
.ok-line{color:var(--ok);font-weight:600;font-size:14px;margin-bottom:14px}
|
||||
.err-line{color:#d32f2f;font-weight:600;font-size:14px;margin-bottom:14px}
|
||||
.terms-box{display:none;margin:16px 0;padding:20px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius)}
|
||||
@@ -252,7 +267,6 @@ footer a{color:var(--accent);text-decoration:none}
|
||||
<th>Info</th>
|
||||
<th class="num">Fee</th>
|
||||
<th>Version</th>
|
||||
<th class="num">Balance</th>
|
||||
<th class="num">Height</th>
|
||||
<th class="num">Wins</th>
|
||||
<th class="num">Score</th>
|
||||
@@ -274,9 +288,12 @@ footer a{color:var(--accent);text-decoration:none}
|
||||
<h2>Add your Will Executor</h2>
|
||||
<p class="lead">Enter your server URL. It will be checked online before it appears in the list.</p>
|
||||
<div class="form-row">
|
||||
<input type="text" id="url" placeholder="https://bitcoin-after.life:9137">
|
||||
<button class="btn" id="submit">Add server</button>
|
||||
<input type="text" id="url" placeholder="https://we.bitcoin-after.life">
|
||||
</div>
|
||||
<div style="margin-top:8px">
|
||||
<input type="text" id="contact" placeholder="Email, npub or Telegram (optional)" style="width:100%;font:inherit;font-size:14px;padding:9px 12px;border:1px solid var(--line-strong);border-radius:8px;background:var(--panel);color:var(--ink)">
|
||||
</div>
|
||||
<button class="btn" id="submit" style="margin-top:8px">Add server</button>
|
||||
|
||||
<div class="ok-line" id="iv-status"></div>
|
||||
|
||||
@@ -294,20 +311,23 @@ footer a{color:var(--accent);text-decoration:none}
|
||||
</div>
|
||||
|
||||
<div class="invoice" id="invoice">
|
||||
<div class="row"><span>Minimum amount</span><span id="iv-min">—</span></div>
|
||||
<div class="row"><span>Annual fee</span><span id="iv-min">—</span></div>
|
||||
<div class="row"><span>Chain</span><span id="iv-chain">—</span></div>
|
||||
<div class="row"><span>Address</span><span id="iv-addr">—</span></div>
|
||||
<div class="row"><span>Balance</span><span id="iv-balance">—</span></div>
|
||||
<div class="row"><span>Status</span><span id="iv-status2">—</span></div>
|
||||
<div class="row"><span>Status</span><span id="iv-status">—</span></div>
|
||||
<div class="row"><span>Contact</span><span id="iv-contact">—</span></div>
|
||||
<div class="row"><span>Server</span><span id="iv-url">—</span></div>
|
||||
<div class="row"><span>Will Executor</span><span><a id="iv-weinfo" href="#" target="_blank">—</a></span></div>
|
||||
<div id="qrcode"></div>
|
||||
</div>
|
||||
|
||||
<button class="btn-share" id="share-btn">Share invoice</button>
|
||||
<p class="note">
|
||||
<strong>Please make sure your server is online before you attempt to add it.</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>How ranking works</h2>
|
||||
<p class="lead">Bid-based ranking: higher contributions rank higher.</p>
|
||||
@@ -363,6 +383,18 @@ let minAmount = 50000;
|
||||
const fmt = n => (n != null ? Number(n).toLocaleString('en-US') : '—');
|
||||
const trunc = (s, m=40) => s && s.length > m ? s.slice(0, m) + '…' : s;
|
||||
|
||||
const statusMap = {
|
||||
'OK': 'Health check passed',
|
||||
'TIMEOUT': 'Connection timeout',
|
||||
'CONNECTION': 'Connection error',
|
||||
'STATUS': 'HTTP error',
|
||||
'WRONG REPLY': 'Invalid JSON response',
|
||||
'REQUEST': 'Request error',
|
||||
'BODY': 'Body read error',
|
||||
'DECODE': 'Decode error',
|
||||
'KO': 'Generic error'
|
||||
};
|
||||
|
||||
function getChain() {
|
||||
const btn = document.querySelector('#chainSeg [aria-pressed="true"]');
|
||||
return btn ? btn.dataset.c : 'bitcoin';
|
||||
@@ -372,7 +404,7 @@ function getFiltered() {
|
||||
return allServers
|
||||
.filter(d => withTor ? true : !d.onion)
|
||||
.filter(d => (d.url + " " + (d.info||"")).toLowerCase().includes(q.toLowerCase()))
|
||||
.sort((a, b) => (b.balance||0) - (a.balance||0) || (a.base_fee||0) - (b.base_fee||0) || (b.points||0) - (a.points||0));
|
||||
.sort((a, b) => (b.last_block||0) - (a.last_block||0) || (b.points||0) - (a.points||0) || (b.count_win||0) - (a.count_win||0) || (a.base_fee||0) - (b.base_fee||0) || (b.version||'').localeCompare(a.version||''));
|
||||
}
|
||||
|
||||
function render() {
|
||||
@@ -382,7 +414,7 @@ function render() {
|
||||
tb.innerHTML = ""; ml.innerHTML = "";
|
||||
|
||||
if (!list.length) {
|
||||
tb.innerHTML = '<tr><td colspan="9" style="padding:28px;text-align:center;color:var(--muted)">No servers found.</td></tr>';
|
||||
tb.innerHTML = '<tr><td colspan="8" style="padding:28px;text-align:center;color:var(--muted)">No servers found.</td></tr>';
|
||||
}
|
||||
|
||||
list.forEach((d, i) => {
|
||||
@@ -396,7 +428,6 @@ function render() {
|
||||
<td class="info">${DOMPurify.sanitize(d.info||'—')}</td>
|
||||
<td class="num">${fmt(d.base_fee)}</td>
|
||||
<td class="mono">${DOMPurify.sanitize(d.version||'—')}</td>
|
||||
<td class="num">${fmt(d.balance)}</td>
|
||||
<td class="num">${fmt(d.last_block)}</td>
|
||||
<td class="num">${d.count_win != null ? d.count_win : '—'}</td>
|
||||
<td class="num"><span class="score">${fmt(d.points)}</span></td>
|
||||
@@ -411,7 +442,6 @@ function render() {
|
||||
<div><span>Score</span><b>${fmt(d.points)}</b></div>
|
||||
<div><span>Wins</span><b>${d.count_win != null ? d.count_win : '—'}</b></div>
|
||||
<div><span>Fee</span><b>${fmt(d.base_fee)} sat</b></div>
|
||||
<div><span>Balance</span><b>${fmt(d.balance)}</b></div>
|
||||
<div><span>Version</span><b>${DOMPurify.sanitize(d.version||'—')}</b></div>
|
||||
<div><span>Height</span><b>${fmt(d.last_block)}</b></div>
|
||||
</div>
|
||||
@@ -491,9 +521,14 @@ document.getElementById('submit').addEventListener('click', async () => {
|
||||
document.getElementById('iv-chain').textContent = '—';
|
||||
document.getElementById('iv-addr').textContent = '—';
|
||||
document.getElementById('iv-balance').textContent = '—';
|
||||
document.getElementById('iv-status2').textContent = '—';
|
||||
document.getElementById('iv-url').textContent = '—';
|
||||
document.getElementById('iv-contact').textContent = '—';
|
||||
document.getElementById('iv-weinfo').href = '#';
|
||||
document.getElementById('iv-weinfo').textContent = '—';
|
||||
document.getElementById('qrcode').innerHTML = '';
|
||||
document.getElementById('qrcode').style.cursor = '';
|
||||
document.getElementById('qr-overlay').classList.remove('show');
|
||||
document.getElementById('share-btn').textContent = 'Share invoice';
|
||||
document.getElementById('terms-box').classList.remove('show');
|
||||
document.getElementById('terms-check').checked = false;
|
||||
document.getElementById('terms-accept').disabled = true;
|
||||
@@ -502,7 +537,7 @@ document.getElementById('submit').addEventListener('click', async () => {
|
||||
const response = await fetch('/data', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url, chain })
|
||||
body: JSON.stringify({ url, chain, contact: document.getElementById('contact').value.trim() || undefined })
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok) {
|
||||
@@ -514,11 +549,48 @@ document.getElementById('submit').addEventListener('click', async () => {
|
||||
document.getElementById('iv-chain').textContent = result.chain || chain;
|
||||
document.getElementById('iv-addr').textContent = result.address || '—';
|
||||
document.getElementById('iv-balance').textContent = result.balance != null ? fmt(result.balance) : '—';
|
||||
document.getElementById('iv-status2').textContent = result.status || '—';
|
||||
const invoiceuri = `bitcoin:${result.address}?label=BAL&message=Order+For+url+%26+${encodeURIComponent(url)}`;
|
||||
const statusVal = result.status || '—';
|
||||
const st = (statusVal||'').split(':')[0];
|
||||
document.getElementById('iv-status').textContent = statusMap[st] || '—';
|
||||
document.getElementById('iv-contact').textContent = document.getElementById('contact').value.trim() || '—';
|
||||
const weLink = result.id ? `/weinfo/${result.chain || chain}/${result.id}` : null;
|
||||
const weinfoEl = document.getElementById('iv-weinfo');
|
||||
if (weLink) {
|
||||
weinfoEl.href = weLink;
|
||||
weinfoEl.textContent = 'View page';
|
||||
} else {
|
||||
weinfoEl.href = '#';
|
||||
weinfoEl.textContent = '—';
|
||||
}
|
||||
const amountSats = result.amount != null ? result.amount : minAmount;
|
||||
const amountBtc = (amountSats / 1e8).toFixed(8).replace(/\.?0+$/, '');
|
||||
const invoiceuri = `bitcoin:${result.address}?amount=${amountBtc}&label=BAL&message=Order+For+url+%26+${encodeURIComponent(url)}`;
|
||||
const qrEl = document.getElementById('qrcode');
|
||||
qrEl.innerHTML = '';
|
||||
new QRCode(qrEl, invoiceuri);
|
||||
new QRCode(qrEl, { text: invoiceuri, width: 160, height: 160 });
|
||||
qrEl.style.cursor = 'pointer';
|
||||
qrEl.onclick = function () {
|
||||
const overlay = document.getElementById('qr-overlay');
|
||||
const big = document.getElementById('qr-big');
|
||||
big.innerHTML = '';
|
||||
new QRCode(big, { text: invoiceuri, width: 280, height: 280 });
|
||||
overlay.classList.add('show');
|
||||
};
|
||||
document.getElementById('qr-overlay').onclick = function () {
|
||||
this.classList.remove('show');
|
||||
};
|
||||
const shareBtn = document.getElementById('share-btn');
|
||||
shareBtn.textContent = 'Share invoice';
|
||||
shareBtn.onclick = function () {
|
||||
if (navigator.share) {
|
||||
navigator.share({ title: 'BAL Invoice', text: invoiceuri });
|
||||
} else {
|
||||
navigator.clipboard.writeText(invoiceuri).then(() => {
|
||||
this.textContent = 'Copied!';
|
||||
setTimeout(() => this.textContent = 'Share invoice', 2000);
|
||||
});
|
||||
}
|
||||
};
|
||||
const serverUrl = result.url || url;
|
||||
const infoUrl = serverUrl + '/' + (result.chain || chain) + '/info';
|
||||
document.getElementById('iv-url').textContent = serverUrl;
|
||||
@@ -556,5 +628,6 @@ document.getElementById('url').addEventListener('keydown', e => {
|
||||
fetchMinAmount();
|
||||
})();
|
||||
</script>
|
||||
<div id="qr-overlay"><div id="qr-big"></div></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
61
weinfo.html
61
weinfo.html
@@ -1,8 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-<|begin▁of▁sentence|>8" />
|
||||
<meta name="viewport" content="width=device-w, initial-scale=1.0" />
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Bal Server List</title>
|
||||
<link rel="icon" href="Logo_nero.ico" type="image/x-icon">
|
||||
<script src="/qrcode.min.js"></script>
|
||||
@@ -81,38 +81,53 @@
|
||||
const chain = path[1];
|
||||
const cdate=new Date().toISOString().replace(/[-:T.Z]/g, '').slice(0, 14);
|
||||
fetchDataAndPopulateTable('/weinfodata/'+chain+"/"+we_id, new URLSearchParams(),(data) => {
|
||||
document.getElementById('wename').innerHTML = DOMPurify.sanitize(data.url);
|
||||
document.getElementById('wechain').innerHTML = DOMPurify.sanitize(data.chain);
|
||||
document.getElementById('weinfo').innerHTML = DOMPurify.sanitize(data.info);
|
||||
document.getElementById('wefees').innerHTML = data.base_fee;
|
||||
document.getElementById('weheight').innerHTML = data.last_block;
|
||||
document.getElementById('wepoints').innerHTML = data.points;
|
||||
document.getElementById('wewin').innerHTML = data.count_win;
|
||||
document.getElementById('wetld').innerHTML = DOMPurify.sanitize(data.tld);
|
||||
document.getElementById('webalance').innerHTML = data.balance;
|
||||
document.getElementById('weversion').innerHTML = data.version;;
|
||||
document.getElementById('westatus').innerHTML = DOMPurify.sanitize(data.status);
|
||||
document.getElementById('weupdate').innerHTML = data.last_update;
|
||||
document.getElementById('wename').innerHTML = DOMPurify.sanitize(data.url||'—');
|
||||
document.getElementById('wechain').innerHTML = DOMPurify.sanitize(data.chain||'—');
|
||||
document.getElementById('weinfo').innerHTML = DOMPurify.sanitize(data.info||'—');
|
||||
document.getElementById('wefees').innerHTML = data.base_fee != null ? data.base_fee : '—';
|
||||
document.getElementById('weheight').innerHTML = data.last_block != null ? data.last_block : '—';
|
||||
document.getElementById('wepoints').innerHTML = data.points != null ? data.points : '—';
|
||||
document.getElementById('wewin').innerHTML = data.count_win != null ? data.count_win : '—';
|
||||
document.getElementById('wetld').innerHTML = DOMPurify.sanitize(data.tld||'—');
|
||||
document.getElementById('webalance').innerHTML = data.balance != null ? data.balance : '—';
|
||||
document.getElementById('weversion').innerHTML = data.version||'—';
|
||||
const statusMap = {
|
||||
'OK': 'Health check passed',
|
||||
'TIMEOUT': 'Connection timeout',
|
||||
'CONNECTION': 'Connection error',
|
||||
'STATUS': 'HTTP error',
|
||||
'WRONG REPLY': 'Invalid JSON response',
|
||||
'REQUEST': 'Request error',
|
||||
'BODY': 'Body read error',
|
||||
'DECODE': 'Decode error',
|
||||
'KO': 'Generic error'
|
||||
};
|
||||
const st = (data.status||'').split(':')[0];
|
||||
document.getElementById('westatus').innerHTML = statusMap[st] || '—';
|
||||
|
||||
const tableBody = document.querySelector('#wetimes tbody');
|
||||
tableBody.innerHTML ='';
|
||||
if (data.times && data.times.length) {
|
||||
Object.entries(data.times).forEach(([key,wetime]) => {
|
||||
const row = document.createElement('tr');
|
||||
const d = new Date(wetime.time/1000);
|
||||
row.innerHTML = `
|
||||
<td>${wetime.blockHeight}</td>
|
||||
<td>${DOMPurify.sanitize(wetime.blockHash)}</td>
|
||||
<td>${wetime.blockHeight != null ? wetime.blockHeight : '—'}</td>
|
||||
<td>${DOMPurify.sanitize(wetime.blockHash||'—')}</td>
|
||||
<td>${d}</td>
|
||||
<td>${wetime.diff/1000000} s</td>
|
||||
<td>${wetime.position+1}</td>
|
||||
<td>${wetime.participants}</td>
|
||||
<td>${wetime.points}</td>
|
||||
<td>${wetime.diff != null ? wetime.diff/1000000 + ' s' : '—'}</td>
|
||||
<td>${wetime.position != null ? wetime.position+1 : '—'}</td>
|
||||
<td>${wetime.participants != null ? wetime.participants : '—'}</td>
|
||||
<td>${wetime.points != null ? wetime.points : '—'}</td>
|
||||
`;
|
||||
tableBody.appendChild(row);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
tableBody.innerHTML = '<tr><td colspan="7" style="padding:20px;text-align:center;color:#999">No rounds yet.</td></tr>';
|
||||
}
|
||||
var prev=0;
|
||||
var next=0;
|
||||
if (data.times.length > 0){
|
||||
if (data.times && data.times.length > 0){
|
||||
prev = data.times[0].blockHeight+data.times.length;
|
||||
next = data.times[data.times.length-1].blockHeight;
|
||||
if (prev < 0 ){
|
||||
@@ -126,8 +141,6 @@
|
||||
}
|
||||
|
||||
getWeInfo();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user