feat(v2)(ui): tx_type chip in operator settlements table (S8 UI)
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) <noreply@anthropic.com>
This commit is contained in:
parent
eca6e961b7
commit
ecf432c6a0
2 changed files with 40 additions and 0 deletions
|
|
@ -159,6 +159,7 @@ window.app = Vue.createApp({
|
||||||
settlementsTable: {
|
settlementsTable: {
|
||||||
columns: [
|
columns: [
|
||||||
{name: 'status', label: 'Status', field: 'status', align: 'left'},
|
{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: 'created_at', label: 'Time', field: 'created_at', align: 'left'},
|
||||||
{name: 'wire_sats', label: 'Wire', field: 'wire_sats', align: 'right'},
|
{name: 'wire_sats', label: 'Wire', field: 'wire_sats', align: 'right'},
|
||||||
{name: 'principal_sats', label: 'Principal (→ LPs)', field: 'principal_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'
|
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
|
// Settlement actions: retry, partial-dispense, force-reset, note
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -874,6 +874,17 @@
|
||||||
<q-badge :color="settlementStatusColor(props.row.status)"
|
<q-badge :color="settlementStatusColor(props.row.status)"
|
||||||
:label="props.row.status"></q-badge>
|
:label="props.row.status"></q-badge>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
<q-td key="tx_type">
|
||||||
|
<q-chip dense square size="sm"
|
||||||
|
:color="txTypeChip(props.row.tx_type).color"
|
||||||
|
text-color="white"
|
||||||
|
:icon="txTypeChip(props.row.tx_type).icon">
|
||||||
|
<span v-text="txTypeChip(props.row.tx_type).label"></span>
|
||||||
|
<q-tooltip>
|
||||||
|
<span v-text="txTypeChip(props.row.tx_type).tooltip"></span>
|
||||||
|
</q-tooltip>
|
||||||
|
</q-chip>
|
||||||
|
</q-td>
|
||||||
<q-td key="created_at">
|
<q-td key="created_at">
|
||||||
<span :style="{fontSize: '0.85em'}"
|
<span :style="{fontSize: '0.85em'}"
|
||||||
v-text="formatTime(props.row.created_at)"></span>
|
v-text="formatTime(props.row.created_at)"></span>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue