@@ -513,6 +550,8 @@ sudo apt-get install -y taler-wallet-cli
set("st-coins-live", d.coins_live);
set("st-coins-spent", d.coins_spent);
setAmt("st-remaining", d.coins_remaining_amount, "coins_remaining_amount_alt", d);
+ set("st-withdraw-coins", d.withdraw_ops);
+ setAmt("st-withdraw-amt-coins", d.withdraw_amount, "withdraw_amount_alt", d);
set("st-withdraw", d.withdraw_ops);
setAmt("st-withdraw-amt", d.withdraw_amount, "withdraw_amount_alt", d);
set("st-refresh", d.refresh_ops);
@@ -529,16 +568,48 @@ sudo apt-get install -y taler-wallet-cli
setAmt("st-wire-in-amt", d.wire_in_amount, "wire_in_amount_alt", d);
set("st-wire-out", d.wire_out);
+ var recent = document.getElementById("st-recent");
+ if (recent) {
+ recent.innerHTML = "";
+ var rows = (d.recent_activity || []).slice(0, 12);
+ if (!rows.length) {
+ var empty = document.createElement("li");
+ empty.className = "meta";
+ empty.textContent = "—";
+ recent.appendChild(empty);
+ } else {
+ rows.forEach(function (row) {
+ var li = document.createElement("li");
+ var amt = document.createElement("span");
+ amt.className = "amt";
+ if (window.GoaAmount) {
+ var af = GoaAmount.pick(row, d.alt_unit_names);
+ amt.textContent = af.display;
+ if (af.title && af.title !== af.display) amt.setAttribute("title", af.title);
+ } else {
+ amt.textContent = row.amount_alt || row.amount || "?";
+ }
+ var meta = document.createElement("span");
+ meta.className = "meta";
+ meta.textContent = (row.ts_human || "") + (row.kind ? " · " + row.kind : "");
+ li.appendChild(amt);
+ li.appendChild(meta);
+ recent.appendChild(li);
+ });
+ }
+ }
+ if (window.GoaAmount && GoaAmount.fillLegend) GoaAmount.fillLegend("st-unit-legend", d);
+
var ladder = document.getElementById("st-ladder");
if (ladder) {
ladder.innerHTML = "";
(d.denom_ladder || []).forEach(function (x) {
var s = document.createElement("span");
s.className = "pill";
- var lab = x.value_alt || x.value || "?";
- if (window.GoaAmount && !x.value_alt) {
+ var lab = x.value || "?";
+ if (window.GoaAmount) {
lab = GoaAmount.format(x.value, d.alt_unit_names).display;
- }
+ } else if (x.value_alt) lab = x.value_alt;
s.textContent = lab + (x.keys > 1 ? " ×" + x.keys : "");
if (x.value && lab !== x.value) s.title = x.value;
ladder.appendChild(s);
@@ -553,10 +624,10 @@ sudo apt-get install -y taler-wallet-cli
wrap.hidden = false;
var html = "
| Value | Coins | Live |
";
by.forEach(function (r) {
- var v = r.value_alt || r.value || "?";
- if (window.GoaAmount && !r.value_alt) {
+ var v = r.value || "?";
+ if (window.GoaAmount) {
v = GoaAmount.format(r.value, d.alt_unit_names).display;
- }
+ } else if (r.value_alt) v = r.value_alt;
html += "| " + v + " | " + r.coins + " | " + r.live + " |
";
});
html += "
";
@@ -569,25 +640,38 @@ sudo apt-get install -y taler-wallet-cli
(d.generated_at_human || d.generated_at || "");
}
+ function escHtml(s) {
+ return String(s == null ? "" : s)
+ .replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
+ }
function setMem(id, human, n, bytes) {
var el = document.getElementById(id);
if (!el) return;
- if (!human && human !== 0) {
+ var b = bytes != null && bytes !== "" ? Number(bytes) : NaN;
+ var nn = n != null && n !== "" ? Number(n) : NaN;
+ var empty =
+ human == null || human === "" || human === "—" ||
+ human === "0 B" || human === "0B" ||
+ (isFinite(b) && b <= 0 && (!isFinite(nn) || nn <= 0));
+ if (empty) {
el.textContent = "—";
el.removeAttribute("title");
return;
}
var h = String(human);
- if (n != null && n !== "" && Number(n) > 0) h += " · " + n + "p";
+ if (isFinite(nn) && nn > 0) h += " · " + nn + "p";
el.textContent = h;
- if (bytes != null && bytes !== "" && Number(bytes) > 0) {
- el.setAttribute("title", Number(bytes).toLocaleString("en-US") + " B");
+ if (isFinite(b) && b > 0) {
+ el.setAttribute("title", b.toLocaleString("en-US") + " B");
} else el.removeAttribute("title");
}
var p = d.performance || {};
set("st-keys-ms", msLabel(p.keys_ms, p.keys_http));
set("st-config-ms", msLabel(p.config_ms, p.config_http));
+ set("st-cpu", p.cpu_percent_label || (p.cpu_percent != null ? (Number(p.cpu_percent).toFixed(2) + "%") : "—"));
set("st-load", p.loadavg || "—");
+ set("st-pids", p.pids != null ? p.pids : ((p.memory && p.memory.pids) != null ? p.memory.pids : "—"));
var mem = p.memory || {};
setMem("st-mem-ctr", mem.container_rss_label || mem.container_rss_human || "—", null, mem.container_rss_bytes);
setMem("st-mem-pg", mem.postgres_rss_human, mem.postgres_n, mem.postgres_rss_bytes);
@@ -604,11 +688,11 @@ sudo apt-get install -y taler-wallet-cli
var cmd = t.cmd || "";
var cmdFull = t.cmd_full || cmd;
if (cmd.length > 64) cmd = cmd.slice(0, 61) + "…";
- th += "
| " +
- (t.rss_human || "?") + " | " +
- (t.comm || "") + " | " +
- cmd + " |
";
+ th += "
| " +
+ escHtml(t.rss_human || "?") + " | " +
+ escHtml(t.comm || "") + " | " +
+ escHtml(cmd) + " |
";
});
th += "";
topBox.innerHTML = th;
@@ -616,9 +700,11 @@ sudo apt-get install -y taler-wallet-cli
}
var pf = document.getElementById("st-perf-foot");
if (pf) {
- pf.textContent = "Container RSS + process groups" +
- (mem.source ? " · " + mem.source : "") + " · " +
- (d.generated_at_human || d.generated_at || "");
+ var basis = mem.memory_basis === "cgroup" ? "cgroup" : "proc RSS sum";
+ pf.textContent = "Memory: " + basis +
+ (mem.source ? " · " + mem.source : "") +
+ (p.loadavg_source ? " · loadavg=" + p.loadavg_source : "") +
+ " · " + (d.generated_at_human || d.generated_at || "");
}
return fetch("/intro/stats-run.json", { cache: "no-store" })
.then(function (r) { return r.ok ? r.json() : null; })
diff --git a/configs/merchant-landing/goa-amount.js b/configs/merchant-landing/goa-amount.js
index 67c3859..cfaaad3 100644
--- a/configs/merchant-landing/goa-amount.js
+++ b/configs/merchant-landing/goa-amount.js
@@ -1,29 +1,63 @@
-/* Compact GOA / CUR:amount display using currency alt_unit_names.
- * Large values → "1.23 Mega-GOA" (title = full GOA:n) so landing tiles fit.
+/* Compact GOA / CUR:amount display using SI-style alt units (kGOA, MGOA, …).
+ * Large values → "1.23 MGOA" (title = full GOA:n) so landing tiles fit.
*/
(function (global) {
"use strict";
var DEFAULT_ALT = {
- "24": "Yotta-GOA",
- "21": "Zetta-GOA",
- "18": "Exa-GOA",
- "15": "Peta-GOA",
- "12": "Tera-GOA",
- "9": "Giga-GOA",
- "6": "Mega-GOA",
- "3": "Kilo-GOA",
+ "24": "YGOA",
+ "21": "ZGOA",
+ "18": "EGOA",
+ "15": "PGOA",
+ "12": "TGOA",
+ "9": "GGOA",
+ "6": "MGOA",
+ "3": "kGOA",
"0": "GOA",
- "-1": "Deci-GOA",
- "-2": "Centi-GOA",
- "-3": "Milli-GOA",
- "-6": "Micro-GOA",
- "-7": "Deci-Micro-GOA",
- "-8": "Atomic-GOA"
+ "-1": "dGOA",
+ "-2": "cGOA",
+ "-3": "mGOA",
+ "-6": "µGOA",
+ "-7": "dµGOA",
+ "-8": "aGOA"
+ };
+
+ var LONG_TO_COMPACT = {
+ "yotta-goa": "YGOA",
+ "zetta-goa": "ZGOA",
+ "exa-goa": "EGOA",
+ "peta-goa": "PGOA",
+ "tera-goa": "TGOA",
+ "giga-goa": "GGOA",
+ "mega-goa": "MGOA",
+ "kilo-goa": "kGOA",
+ "goa": "GOA",
+ "deci-goa": "dGOA",
+ "centi-goa": "cGOA",
+ "milli-goa": "mGOA",
+ "micro-goa": "µGOA",
+ "deci-micro-goa": "dµGOA",
+ "atomic-goa": "aGOA"
};
var THRESHOLD = 1000;
+ function compactAlt(altMap) {
+ var out = {};
+ var src = altMap || DEFAULT_ALT;
+ Object.keys(DEFAULT_ALT).forEach(function (k) {
+ out[k] = DEFAULT_ALT[k];
+ });
+ Object.keys(src).forEach(function (k) {
+ var name = String(src[k] || "").trim();
+ var low = name.toLowerCase().replace(/\s+/g, "");
+ if (LONG_TO_COMPACT[low]) out[k] = LONG_TO_COMPACT[low];
+ else if (DEFAULT_ALT[k] && /goa/i.test(name)) out[k] = DEFAULT_ALT[k];
+ else out[k] = name || DEFAULT_ALT[k] || name;
+ });
+ return out;
+ }
+
function parseAmount(s) {
if (s == null || s === "") return { cur: "GOA", val: 0 };
if (typeof s === "number") return { cur: "GOA", val: s };
@@ -51,7 +85,7 @@
}
/**
- * @param {string|number} amount
+ * @param {string|number|object} amount
* @param {object} [altMap]
* @returns {{ display: string, title: string, raw: string, usedAlt: boolean }}
*/
@@ -59,24 +93,17 @@
if (amount == null || amount === "") {
return { display: "—", title: "", raw: "", usedAlt: false };
}
- // Prefer server-provided alt if caller passes object {amount, amount_alt}
+ // Prefer re-format from canonical amount (keeps kGOA even if server sent Kilo-GOA)
if (typeof amount === "object" && amount) {
- if (amount.amount_alt) {
- var rawO = amount.amount || amount.amount_full || String(amount.amount_alt);
- return {
- display: String(amount.amount_alt),
- title: amount.amount_full || rawO,
- raw: String(rawO),
- usedAlt: true
- };
+ if (amount.amount) {
+ return format(amount.amount, altMap);
}
- amount = amount.amount || amount.amount_full || "";
+ amount = amount.amount_full || amount.amount_alt || "";
}
- var alt = altMap || global.__GOA_ALT_UNITS || DEFAULT_ALT;
+ var alt = compactAlt(altMap || global.__GOA_ALT_UNITS || DEFAULT_ALT);
var p = parseAmount(amount);
var raw = baseStr(p.cur, p.val);
- // Foreign currencies must not pick up Kilo-GOA / Mega-GOA labels
var baseName = (alt && alt["0"]) || p.cur;
var curU = String(p.cur || "").toUpperCase();
var baseU = String(baseName || "").toUpperCase();
@@ -95,7 +122,9 @@
var n = parseInt(k, 10);
if (!isNaN(n)) scales.push({ sc: n, name: String(alt[k]) });
});
- scales.sort(function (a, b) { return b.sc - a.sc; });
+ scales.sort(function (a, b) {
+ return b.sc - a.sc;
+ });
var abs = Math.abs(p.val);
var chosen = null;
@@ -136,33 +165,80 @@
setText(document.getElementById(id), amount, altMap);
}
- /** Prefer amount_alt from stats row, else format amount. */
+ /** Prefer formatting from amount field; fall back to amount_alt string. */
function pick(rowOrAmount, altMap) {
if (rowOrAmount && typeof rowOrAmount === "object") {
+ var a =
+ rowOrAmount.amount ||
+ rowOrAmount.total_amount ||
+ rowOrAmount.amount_paid_sum ||
+ rowOrAmount.amount_sum;
+ if (a) return format(a, altMap);
if (rowOrAmount.amount_alt) {
- return format({
- amount: rowOrAmount.amount,
- amount_alt: rowOrAmount.amount_alt,
- amount_full: rowOrAmount.amount_full
- }, altMap);
+ return {
+ display: String(rowOrAmount.amount_alt),
+ title: String(rowOrAmount.amount_full || rowOrAmount.amount_alt),
+ raw: String(rowOrAmount.amount_full || rowOrAmount.amount_alt),
+ usedAlt: true
+ };
}
- return format(rowOrAmount.amount || rowOrAmount.total_amount, altMap);
+ return format("", altMap);
}
return format(rowOrAmount, altMap);
}
function rememberAlt(stats) {
if (stats && stats.alt_unit_names && typeof stats.alt_unit_names === "object") {
- global.__GOA_ALT_UNITS = stats.alt_unit_names;
+ global.__GOA_ALT_UNITS = compactAlt(stats.alt_unit_names);
}
}
+ /** Small legend HTML (positive scales). */
+ function legendHtml(stats) {
+ var alt = compactAlt((stats && stats.alt_unit_names) || global.__GOA_ALT_UNITS || DEFAULT_ALT);
+ var rows = [];
+ Object.keys(alt)
+ .map(function (k) {
+ return parseInt(k, 10);
+ })
+ .filter(function (n) {
+ return !isNaN(n) && n > 0;
+ })
+ .sort(function (a, b) {
+ return a - b;
+ })
+ .forEach(function (sc) {
+ rows.push(
+ "
| 10" +
+ sc +
+ " | " +
+ alt[String(sc)] +
+ " |
"
+ );
+ });
+ if (!rows.length) return "";
+ return (
+ '
| ×base | name |
' +
+ rows.join("") +
+ "
"
+ );
+ }
+
+ function fillLegend(elOrId, stats) {
+ var el = typeof elOrId === "string" ? document.getElementById(elOrId) : elOrId;
+ if (!el) return;
+ el.innerHTML = legendHtml(stats);
+ }
+
global.GoaAmount = {
format: format,
setText: setText,
setById: setById,
pick: pick,
rememberAlt: rememberAlt,
+ compactAlt: compactAlt,
+ legendHtml: legendHtml,
+ fillLegend: fillLegend,
DEFAULT_ALT: DEFAULT_ALT,
THRESHOLD: THRESHOLD
};
diff --git a/configs/merchant-landing/index.html b/configs/merchant-landing/index.html
index c14ee0c..1a14014 100644
--- a/configs/merchant-landing/index.html
+++ b/configs/merchant-landing/index.html
@@ -273,6 +273,15 @@
.stats-run-note {
margin: 0.35rem 0 0; font-size: 0.7rem; color: #f0a090; text-align: center;
}
+ .unit-legend {
+ margin: 0.45rem auto 0; border-collapse: collapse; font-size: 0.68rem; color: var(--muted);
+ display: inline-table;
+ }
+ .unit-legend th, .unit-legend td {
+ padding: 0.1rem 0.4rem; border-bottom: 1px solid rgba(167, 139, 250, 0.15); text-align: left;
+ }
+ .unit-legend th { font-weight: 700; font-size: 0.6rem; text-transform: uppercase; }
+ .unit-legend strong { color: var(--goa); }
.step-card {
background: var(--card); border: 1px solid var(--border); border-radius: 18px;
padding: 1.3rem 1.25rem 1.4rem; margin-bottom: 1.2rem;
@@ -704,12 +713,12 @@ sudo apt-get install -y taler-wallet-cli
- Merchant stats
- From merchant DB · dual currency side by side
+ Merchant stats · all payments
+ From merchant DB · dual currency · large GOA as kGOA / MGOA / …
Instances—
-
Orders—
-
Paid—
+
All orders—
+
All paid—
Unpaid—
Wired—
Refunds—
@@ -721,29 +730,31 @@ sudo apt-get install -y taler-wallet-cli
GOA
explorational · hacktivism
—
-
paid volume
+
all paid volume
-
all orders —
+
all orders volume —
CHF
taler-ops
—
-
paid volume
+
all paid volume
-
all orders —
+
all orders volume —
+