dashboard: kolom AKUN/STAKE/VOTE sama lebar di desktop

This commit is contained in:
proitlab committed 2026-08-05 19:58:35 +07:00
1 parent e4fa6bf1dc
commit a3251eebc4
5 files changed
+10 -6

No files matched your search

+1 -1
View File
@@ -29,7 +29,7 @@ Two tools scan the Vexanium blockchain voters table for accounts whose only vote
- The web list shows RANK / AKUN / STAKE (VEX) / VOTE TERAKHIR columns (3 stats cells). Vote weight stays in the DB and `/api/search` JSON but is not rendered as a column. - The web list shows RANK / AKUN / STAKE (VEX) / VOTE TERAKHIR columns (3 stats cells). Vote weight stays in the DB and `/api/search` JSON but is not rendered as a column.
- Token contract is `vex.token` (NOT `eosio.token` — that name doesn't exist on Vexanium), 4-decimal VEX, chain_id `f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f`. Distribution signs `vex.token::transfer` with the BP `active` key. - Token contract is `vex.token` (NOT `eosio.token` — that name doesn't exist on Vexanium), 4-decimal VEX, chain_id `f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f`. Distribution signs `vex.token::transfer` with the BP `active` key.
- Distribution (spec §V19–V27): each run pays the whole liquid balance pro-rata by stored `staked`, shares floored at 4 decimals with dust left in the account, one transfer per voter. A txid that can't be confirmed (`GET {DATABISNIS_API}/v2/history/get_transaction?id=<txid>` returns no `executed`) is never re-sent the same run — that payment stays `failed` and rejoins the next day. No-op (exit 0, no writes) when the voters table is empty or balance < 0.0001. The dashboard's `/history` view renders `distribute_runs` + `distribute_payments` read-only. - Distribution (spec §V19–V27): each run pays the whole liquid balance pro-rata by stored `staked`, shares floored at 4 decimals with dust left in the account, one transfer per voter. A txid that can't be confirmed (`GET {DATABISNIS_API}/v2/history/get_transaction?id=<txid>` returns no `executed`) is never re-sent the same run — that payment stays `failed` and rejoins the next day. No-op (exit 0, no writes) when the voters table is empty or balance < 0.0001. The dashboard's `/history` view renders `distribute_runs` + `distribute_payments` read-only.
- Dashboard layout (spec §V28): desktop/tablet balances the STAKE column near page center; `/history` uses six-column run/payment grids; mobile turns history rows into labeled cards, including MEMO and TXID. HTML responses use `Cache-Control: no-store`; stylesheet URL is versioned with `?v=` for deploy cache-busting. - Dashboard layout (spec §V28): desktop gives AKUN/STAKE/VOTE equal width with AKUN left and STAKE/VOTE centered; tablet keeps the fixed STAKE column near page center; `/history` uses six-column run/payment grids; mobile turns history rows into labeled cards, including MEMO and TXID. HTML responses use `Cache-Control: no-store`; stylesheet URL is versioned with `?v=` for deploy cache-busting.
- Liquid balance (spec §V16): a 4th stat cell "SALDO LIQUID" shows the BP account's liquid VEX (`account.core_liquid_balance`) fetched from `GET {DATABISNIS_API}/v2/state/get_account?account=<BP>`. The dashboard fetches it live but caches per-worker in memory for `DASH_LIQUID_TTL` (default 60s); a failed fetch keeps the last value (or renders `—` if none ever succeeded) and the failure is also cooled-down so the API isn't hammered. The dashboard still never writes to the DB. - Liquid balance (spec §V16): a 4th stat cell "SALDO LIQUID" shows the BP account's liquid VEX (`account.core_liquid_balance`) fetched from `GET {DATABISNIS_API}/v2/state/get_account?account=<BP>`. The dashboard fetches it live but caches per-worker in memory for `DASH_LIQUID_TTL` (default 60s); a failed fetch keeps the last value (or renders `—` if none ever succeeded) and the failure is also cooled-down so the API isn't hammered. The dashboard still never writes to the DB.
## Layout ## Layout
+2 -1
View File
@@ -84,7 +84,7 @@ V24: run harian `DISTRIBUTE_HOUR` (default 10) waktu lokal `TZ`; ⊥ beku/carryo
V25: pemilih kosong | saldo < 1 unit shareable → no-op senyap, ⊥ tulis DB V25: pemilih kosong | saldo < 1 unit shareable → no-op senyap, ⊥ tulis DB
V26: `VEX_BP_PRIVATE_KEY` ⊥ pernah di-log/print; `--dry-run` utk uji lokal (⊥ sign) V26: `VEX_BP_PRIVATE_KEY` ⊥ pernah di-log/print; `--dry-run` utk uji lokal (⊥ sign)
V27: dashboard read-only; `/history` baca `distribute_*` via `db.py`; ⊥ mutasi V27: dashboard read-only; `/history` baca `distribute_*` via `db.py`; ⊥ mutasi
V28: web list → kolom STAKE/JUMLAH text center; STAKE dekat pusat halaman via grid seimbang; history runs/payments 6 kolom desktop/tablet; mobile → kartu berlabel ∀ field termasuk MEMO/TXID; HTML `no-store` + stylesheet versioned V28: web list desktop → kolom AKUN/STAKE/VOTE sama lebar (RANK tetap 72px); AKUN kiri; STAKE & VOTE TERAKHIR center; tablet grid lama; history runs/payments 6 kolom desktop/tablet; mobile → kartu berlabel ∀ field termasuk MEMO/TXID; HTML `no-store` + stylesheet versioned
## §T — Tasks ## §T — Tasks
id|status|task|cites id|status|task|cites
@@ -117,6 +117,7 @@ T26|x|dashboard: route `/history` (runs + per-voter log) + template, gaya DESIGN
T27|x|tests: test_distribute.py (mock chain+pyntelope, temp DB: math share, memo, no-op, status/retry, guard duplikat) + extend test_dashboard.py (`/history`)|V20,V21,V22,V25,V26,V27,I.db T27|x|tests: test_distribute.py (mock chain+pyntelope, temp DB: math share, memo, no-op, status/retry, guard duplikat) + extend test_dashboard.py (`/history`)|V20,V21,V22,V25,V26,V27,I.db
T28|x|hygiene: .gitignore += `.oc/`; stage penghapusan README.md (stub kosong)| T28|x|hygiene: .gitignore += `.oc/`; stage penghapusan README.md (stub kosong)|
T29|x|dashboard layout: grid STAKE seimbang desktop/tablet; `/history` 6-kolom + kartu mobile berlabel; CSS cache-bust + HTML no-store|V28,I.web T29|x|dashboard layout: grid STAKE seimbang desktop/tablet; `/history` 6-kolom + kartu mobile berlabel; CSS cache-bust + HTML no-store|V28,I.web
T30|x|dashboard desktop: kolom AKUN/STAKE/VOTE sama lebar, AKUN kiri, STAKE+VOTE center|V28,I.web
## §B — Bug log ## §B — Bug log
id|date|cause|fix id|date|cause|fix
+5 -2
View File
@@ -181,7 +181,7 @@ button.pill {
.list-header, .list-header,
.list-row { .list-row {
display: grid; display: grid;
grid-template-columns: 72px 1fr 200px 1fr; grid-template-columns: 72px repeat(3, 1fr);
gap: var(--sp-lg); gap: var(--sp-lg);
align-items: baseline; align-items: baseline;
padding: var(--sp-lg) var(--sp-sm); padding: var(--sp-lg) var(--sp-sm);
@@ -226,7 +226,9 @@ button.pill {
color: var(--on-dark); color: var(--on-dark);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.list-header span:nth-child(3) { text-align: center; } .list-row .vote-date { text-align: center; }
.list-header span:nth-child(3),
.list-header span:nth-child(4) { text-align: center; }
.txid { .txid {
font-size: 12px; font-size: 12px;
letter-spacing: 1px; letter-spacing: 1px;
@@ -319,6 +321,7 @@ button.pill {
.list-row .vote-date, .list-row .vote-date,
.list-row .txid { grid-column: 2; } .list-row .txid { grid-column: 2; }
.list-row .stake { text-align: left; } .list-row .stake { text-align: left; }
.list-row .vote-date { text-align: left; }
.list-row .txid { font-size: 12px; } .list-row .txid { font-size: 12px; }
.list-row .stake { overflow-wrap: anywhere; } .list-row .stake { overflow-wrap: anywhere; }
.list-row .stake::before, .list-row .stake::before,
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400&family=EB+Garamond:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400&family=EB+Garamond:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=3) }}"> <link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=4) }}">
</head> </head>
<body> <body>
<header class="top-nav"> <header class="top-nav">
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400&family=EB+Garamond:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400&family=EB+Garamond:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=3) }}"> <link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=4) }}">
</head> </head>
<body> <body>
<header class="top-nav"> <header class="top-nav">