Browse Source

Bump OTB Billing to v2.0.1 with reconcile toast cleanup

main v2.0.1
def 1 month ago
parent
commit
f7d5f1f599
  1. 18
      PROJECT_STATE.md
  2. 12
      README.md
  3. 2
      VERSION
  4. 79
      templates/health.html

18
PROJECT_STATE.md

@ -1,5 +1,23 @@
# PROJECT_STATE - OTB Billing
## v2.0.1 - 2026-05-18
Current state:
- Current version: v2.0.1.
- /health Crypto Reconcile card remains compact and in the normal health grid.
- Reconcile Now button starts the existing crypto reconciliation worker.
- Manual reconcile feedback is now shown only as a temporary bottom-right toast.
- No persistent manual reconcile status text is rendered inside the Crypto Reconcile card.
- Toast feedback auto-hides after 3 seconds and removes the reconcile query string from the URL.
- Previous v2.0.0 functionality remains:
- Operations Bal and Treasury Bal cards
- clickable explorer links for payment assets
- Crypto Reconcile timer/service status
- Last Run and Last Result fields
- pending / confirmed today / stale pending stats
# PROJECT_STATE - OTB Billing
## v2.0.0 - 2026-05-18
Current state:

12
README.md

@ -1,3 +1,15 @@
# OTB Billing - v2.0.1
Build date: 2026-05-18
## v2.0.1 changes
- Fixed Reconcile Now feedback on /health.
- Removed the persistent "Manual reconcile started" message from the Crypto Reconcile card.
- Kept the bottom-right temporary toast notification for manual reconcile feedback.
- Toast automatically disappears after 3 seconds and cleans the reconcile query string from the browser URL.
- Footer/app version bumped from v2.0.0 to v2.0.1.
# OTB Billing - v2.0.0
Build date: 2026-05-18

2
VERSION

@ -1 +1 @@
v2.0.0
v2.0.1

79
templates/health.html

@ -105,6 +105,40 @@
.monoish {
word-break: break-word;
}
.health-toast {
position: fixed;
right: 1.25rem;
bottom: 1.25rem;
z-index: 9999;
min-width: 220px;
max-width: 360px;
padding: 0.8rem 1rem;
border: 1px solid rgba(255,255,255,0.22);
border-radius: 0.55rem;
background: rgba(20, 24, 38, 0.96);
color: inherit;
box-shadow: 0 10px 28px rgba(0,0,0,0.35);
opacity: 0;
transform: translateY(12px);
transition: opacity 180ms ease, transform 180ms ease;
pointer-events: none;
}
.health-toast.show {
opacity: 1;
transform: translateY(0);
}
.health-toast.ok {
border-color: rgba(105, 219, 124, 0.55);
}
.health-toast.bad {
border-color: rgba(255, 135, 135, 0.55);
}
</style>
<link rel="icon" type="image/png" href="/static/favicon.png">
</head>
@ -243,14 +277,6 @@
<form method="post" action="/health/reconcile-now">
<button class="health-action-button" type="submit">Reconcile Now</button>
</form>
{% if request.args.get("reconcile") == "started" %}
<p class="health-note ok">Manual reconcile started.</p>
{% elif request.args.get("reconcile") == "failed" %}
<p class="health-note bad">Manual reconcile failed to start.</p>
{% elif request.args.get("reconcile") == "missing-worker" %}
<p class="health-note bad">Worker script missing.</p>
{% endif %}
{% else %}
<p>Not available</p>
{% endif %}
@ -260,5 +286,42 @@
</div>
{% include "footer.html" %}
<div id="health-toast" class="health-toast" role="status" aria-live="polite"></div>
<script>
(function () {
const params = new URLSearchParams(window.location.search);
const result = params.get("reconcile");
if (!result) return;
const messages = {
"started": { text: "Manual reconcile started.", cls: "ok" },
"failed": { text: "Manual reconcile failed to start.", cls: "bad" },
"missing-worker": { text: "Worker script missing.", cls: "bad" }
};
const reconcileToastMessage = messages[result];
if (!reconcileToastMessage) return;
const toast = document.getElementById("health-toast");
if (!toast) return;
toast.textContent = reconcileToastMessage.text;
toast.classList.add(reconcileToastMessage.cls);
requestAnimationFrame(function () {
toast.classList.add("show");
});
setTimeout(function () {
toast.classList.remove("show");
const cleanUrl = window.location.pathname + window.location.hash;
window.history.replaceState({}, document.title, cleanUrl);
}, 3000);
})();
</script>
</body>
</html>

Loading…
Cancel
Save