From ecf432c6a0a60976398afdc8e2353bf5512cb967 Mon Sep 17 00:00:00 2001 From: Padreug Date: Tue, 26 May 2026 23:28:42 +0200 Subject: [PATCH] feat(v2)(ui): tx_type chip in operator settlements table (S8 UI) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a "Direction" column to the per-machine settlements table that renders a coloured Quasar chip with a directional icon: - cash-out (green-8, south_west arrow) — customer paid ATM invoice in BTC, operator wallet received sats. Principal distributes to LPs. - cash-in (orange-8, north_east arrow) — customer redeemed LNURL- withdraw at the ATM, operator wallet sent sats. No DCA leg; liquidity stays in the operator wallet. Tooltips spell out the meaning so the operator doesn't have to remember the canonical mapping (cash_out ↔ inbound, cash_in ↔ outbound) on sight. Defaults to cash_out for any unknown / legacy row, which is safe because pre-S6 rows are all cash_out and the rejection-record path also stamps cash_out. Closes the UI half of aiolabs/satmachineadmin#22 (S8 cash-in path); the structural half (direction discriminator + DCA skip) shipped in eca6e96. End-to-end test against a live LNURL-withdraw redemption is the remaining S8 acceptance gate. Co-Authored-By: Claude Opus 4.7 (1M context) --- static/js/index.js | 29 ++++++++++++++++++++++++++++ templates/satmachineadmin/index.html | 11 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/static/js/index.js b/static/js/index.js index 0d70405..cdb493f 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -159,6 +159,7 @@ window.app = Vue.createApp({ settlementsTable: { columns: [ {name: 'status', label: 'Status', field: 'status', align: 'left'}, + {name: 'tx_type', label: 'Direction', field: 'tx_type', align: 'left'}, {name: 'created_at', label: 'Time', field: 'created_at', align: 'left'}, {name: 'wire_sats', label: 'Wire', field: 'wire_sats', align: 'right'}, {name: 'principal_sats', label: 'Principal (→ LPs)', field: 'principal_sats', align: 'right'}, @@ -764,6 +765,34 @@ window.app = Vue.createApp({ return SETTLEMENT_STATUS_COLOR[status] || 'grey' }, + txTypeChip(txType) { + // Direction at the ATM (business semantics), not at the operator's + // wallet (Lightning protocol semantics). See the canonical mapping + // in tasks.py:_handle_payment — cash_out ↔ inbound Lightning, + // cash_in ↔ outbound Lightning. + if (txType === 'cash_in') { + return { + color: 'orange-8', + icon: 'north_east', + label: 'cash-in', + tooltip: + 'Cash-in: customer deposited fiat at the ATM, operator wallet ' + + 'sent sats (LNURL-withdraw). No DCA distribution; liquidity ' + + 'stays in the operator wallet.' + } + } + // Default to cash_out — both the only direction shipped pre-S8 and + // the safer "unknown means cash_out" fallback for legacy rows. + return { + color: 'green-8', + icon: 'south_west', + label: 'cash-out', + tooltip: + 'Cash-out: customer paid the ATM\'s invoice in BTC, operator ' + + 'wallet received sats. Principal is distributed to LPs.' + } + }, + // ----------------------------------------------------------------- // Settlement actions: retry, partial-dispense, force-reset, note // ----------------------------------------------------------------- diff --git a/templates/satmachineadmin/index.html b/templates/satmachineadmin/index.html index 4cf80c6..6278ef9 100644 --- a/templates/satmachineadmin/index.html +++ b/templates/satmachineadmin/index.html @@ -874,6 +874,17 @@ + + + + + + + +