diff --git a/addon/components/gateway/hub.hbs b/addon/components/gateway/hub.hbs
index 56a0c90..9ac2251 100644
--- a/addon/components/gateway/hub.hbs
+++ b/addon/components/gateway/hub.hbs
@@ -34,6 +34,7 @@
this.sendInvoice(),
@@ -69,6 +72,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller {
// Record Payment — for open / overdue / partially-paid invoices.
if (['sent', 'viewed', 'overdue', 'partial'].includes(invoice?.status)) {
dropdownItems.push({
+ id: 'record-payment',
text: this.intl.t('invoice.actions.record-payment'),
icon: 'check-circle',
fn: () => this.recordPayment(),
@@ -77,6 +81,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller {
if (this.hasRefunds) {
dropdownItems.push({
+ id: 'view-refunds',
text: 'View Refunds',
icon: 'receipt',
fn: () => this.viewRefunds(),
@@ -86,6 +91,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller {
// Refund - paid or partially refunded invoices with remaining paid funds.
if (this.canIssueRefund) {
dropdownItems.push({
+ id: 'issue-refund',
text: 'Issue Refund',
icon: 'undo',
class: 'text-red-500 hover:text-red-700',
@@ -96,6 +102,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller {
// Void — for any non-terminal status.
if (!['paid', 'refunded', 'refund_pending', 'partial_refund_pending', 'void', 'cancelled'].includes(invoice?.status)) {
dropdownItems.push({
+ id: 'void-invoice',
text: this.intl.t('invoice.actions.void'),
icon: 'ban',
class: 'text-red-500 hover:text-red-700',
@@ -110,6 +117,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller {
// Copy Invoice URL — always available.
dropdownItems.push({
+ id: 'copy-invoice-url',
text: this.intl.t('invoice.actions.copy-invoice-url'),
icon: 'link',
fn: () => this.invoiceActions.copyInvoiceUrl(invoice),
@@ -117,6 +125,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller {
if (dropdownItems.length > 0) {
buttons.push({
+ id: 'more',
icon: 'ellipsis-h',
iconPrefix: 'fas',
renderInPlace: true,
diff --git a/addon/controllers/payments/gateways/details.js b/addon/controllers/payments/gateways/details.js
index c808ad6..58ee419 100644
--- a/addon/controllers/payments/gateways/details.js
+++ b/addon/controllers/payments/gateways/details.js
@@ -32,8 +32,15 @@ export default class PaymentsGatewaysDetailsController extends Controller {
get actionButtons() {
return [
- { label: 'Edit', icon: 'pencil', helpText: 'Edit this payment gateway configuration.', onClick: this.editGateway },
- { label: 'Delete', icon: 'trash', type: 'danger', helpText: 'Permanently remove this payment gateway. This cannot be undone.', onClick: this.deleteGateway },
+ { id: 'edit-gateway', label: 'Edit', icon: 'pencil', helpText: 'Edit this payment gateway configuration.', onClick: this.editGateway },
+ {
+ id: 'delete-gateway',
+ label: 'Delete',
+ icon: 'trash',
+ type: 'danger',
+ helpText: 'Permanently remove this payment gateway. This cannot be undone.',
+ onClick: this.deleteGateway,
+ },
];
}
diff --git a/addon/controllers/payments/gateways/index.js b/addon/controllers/payments/gateways/index.js
index ca4d5f2..41e2f97 100644
--- a/addon/controllers/payments/gateways/index.js
+++ b/addon/controllers/payments/gateways/index.js
@@ -10,7 +10,7 @@ export default class PaymentsGatewaysIndexController extends Controller {
@service fetch;
@service notifications;
- @tracked queryParams = ['page', 'limit', 'sort', 'query', 'public_id', 'name', 'code', 'driver', 'environment', 'status', 'created_at', 'updated_at'];
+ @tracked queryParams = this.gatewayActions.queryParamsFor(['page', 'limit', 'sort', 'query', 'public_id', 'name', 'code', 'driver', 'environment', 'status', 'created_at', 'updated_at']);
@tracked page = 1;
@tracked limit = 30;
@tracked sort = '-created_at';
@@ -35,11 +35,13 @@ export default class PaymentsGatewaysIndexController extends Controller {
get actionButtons() {
return [
{
+ id: 'refresh',
icon: 'refresh',
onClick: this.gatewayActions.refresh,
helpText: this.intl.t('common.refresh'),
},
{
+ id: 'create',
text: this.intl.t('common.new'),
type: 'primary',
icon: 'plus',
@@ -52,6 +54,7 @@ export default class PaymentsGatewaysIndexController extends Controller {
const selected = this.tableContext.getSelectedRows();
return [
{
+ id: 'bulk-delete',
label: this.intl.t('common.delete-selected-count', { count: selected.length }),
class: 'text-red-500',
fn: this.gatewayActions.bulkDelete,
@@ -60,162 +63,179 @@ export default class PaymentsGatewaysIndexController extends Controller {
}
get columns() {
- return [
- // ── Default visible columns ──────────────────────────────────────
- {
- sticky: true,
- label: this.intl.t('column.name'),
- valuePath: 'name',
- cellComponent: 'table/cell/gateway-provider',
- action: this.gatewayActions.transition.view,
- width: 320,
- resizable: true,
- sortable: true,
- filterable: true,
- filterParam: 'name',
- filterComponent: 'filter/string',
- },
- {
- label: this.intl.t('column.driver'),
- valuePath: 'driver',
- cellComponent: 'table/cell/base',
- humanize: true,
- width: 130,
- resizable: true,
- sortable: true,
- filterable: true,
- filterParam: 'driver',
- filterComponent: 'filter/multi-option',
- filterOptions: ['taler', 'stripe', 'cash', 'qpay'],
- },
- {
- label: this.intl.t('column.environment'),
- valuePath: 'environment',
- cellComponent: 'table/cell/base',
- humanize: true,
- width: 110,
- resizable: true,
- sortable: true,
- filterable: true,
- filterParam: 'environment',
- filterComponent: 'filter/select',
- filterOptionLabel: 'label',
- filterOptionValue: 'value',
- filterOptions: [
- { label: 'Live', value: 'live' },
- { label: 'Sandbox', value: 'sandbox' },
- ],
- },
- {
- label: this.intl.t('column.status'),
- valuePath: 'status',
- cellComponent: 'table/cell/status',
- width: 100,
- resizable: true,
- sortable: true,
- filterable: true,
- filterParam: 'status',
- filterComponent: 'filter/select',
- filterOptionLabel: 'label',
- filterOptionValue: 'value',
- filterOptions: [
- { label: 'Active', value: 'active' },
- { label: 'Inactive', value: 'inactive' },
- ],
- },
- {
- label: this.intl.t('column.created-at'),
- valuePath: 'createdAt',
- sortParam: 'created_at',
- filterParam: 'created_at',
- width: 150,
- resizable: true,
- sortable: true,
- filterable: true,
- filterComponent: 'filter/date',
- },
- // ── Hidden / toggleable columns ──────────────────────────────────
- {
- label: this.intl.t('column.id'),
- valuePath: 'public_id',
- width: 120,
- hidden: true,
- resizable: true,
- sortable: false,
- filterable: true,
- filterParam: 'public_id',
- filterComponent: 'filter/string',
- },
- {
- label: this.intl.t('column.code'),
- valuePath: 'code',
- hidden: true,
- resizable: true,
- sortable: true,
- filterable: true,
- filterParam: 'code',
- filterComponent: 'filter/string',
- },
- {
- label: this.intl.t('column.description'),
- valuePath: 'description',
- hidden: true,
- resizable: true,
- sortable: false,
- filterable: true,
- filterParam: 'description',
- filterComponent: 'filter/string',
- },
- {
- label: this.intl.t('column.updated-at'),
- valuePath: 'updatedAt',
- sortParam: 'updated_at',
- filterParam: 'updated_at',
- hidden: true,
- resizable: true,
- sortable: true,
- filterable: true,
- filterComponent: 'filter/date',
- },
- // ── Row actions dropdown ─────────────────────────────────────────
- {
- label: '',
- cellComponent: 'table/cell/dropdown',
- ddButtonText: false,
- ddButtonIcon: 'ellipsis-h',
- ddButtonIconPrefix: 'fas',
- ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.gateway') }),
- cellClassNames: 'overflow-visible',
- wrapperClass: 'flex items-center justify-end mx-2',
- sticky: 'right',
- width: 60,
- actions: [
- {
- label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.gateway') }),
- icon: 'eye',
- fn: this.gatewayActions.transition.view,
- permission: 'ledger view gateway',
- },
- {
- label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.gateway') }),
- icon: 'pencil',
- fn: this.gatewayActions.edit,
- permission: 'ledger update gateway',
- },
- {
- label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.gateway') }),
- icon: 'trash',
- fn: this.gatewayActions.delete,
- className: 'text-red-500 hover:text-red-700',
- permission: 'ledger delete gateway',
- },
- ],
- sortable: false,
- filterable: false,
- resizable: false,
- searchable: false,
- },
- ];
+ // Gateway::Hub renders its own column picker, so registered columns are merged here once.
+ return this.gatewayActions.mergeRegisteredColumns(
+ [
+ // ── Default visible columns ──────────────────────────────────────
+ {
+ id: 'name',
+ sticky: true,
+ label: this.intl.t('column.name'),
+ valuePath: 'name',
+ cellComponent: 'table/cell/gateway-provider',
+ action: this.gatewayActions.transition.view,
+ width: 320,
+ resizable: true,
+ sortable: true,
+ filterable: true,
+ filterParam: 'name',
+ filterComponent: 'filter/string',
+ },
+ {
+ id: 'driver',
+ label: this.intl.t('column.driver'),
+ valuePath: 'driver',
+ cellComponent: 'table/cell/base',
+ humanize: true,
+ width: 130,
+ resizable: true,
+ sortable: true,
+ filterable: true,
+ filterParam: 'driver',
+ filterComponent: 'filter/multi-option',
+ filterOptions: ['taler', 'stripe', 'cash', 'qpay'],
+ },
+ {
+ id: 'environment',
+ label: this.intl.t('column.environment'),
+ valuePath: 'environment',
+ cellComponent: 'table/cell/base',
+ humanize: true,
+ width: 110,
+ resizable: true,
+ sortable: true,
+ filterable: true,
+ filterParam: 'environment',
+ filterComponent: 'filter/select',
+ filterOptionLabel: 'label',
+ filterOptionValue: 'value',
+ filterOptions: [
+ { label: 'Live', value: 'live' },
+ { label: 'Sandbox', value: 'sandbox' },
+ ],
+ },
+ {
+ id: 'status',
+ label: this.intl.t('column.status'),
+ valuePath: 'status',
+ cellComponent: 'table/cell/status',
+ width: 100,
+ resizable: true,
+ sortable: true,
+ filterable: true,
+ filterParam: 'status',
+ filterComponent: 'filter/select',
+ filterOptionLabel: 'label',
+ filterOptionValue: 'value',
+ filterOptions: [
+ { label: 'Active', value: 'active' },
+ { label: 'Inactive', value: 'inactive' },
+ ],
+ },
+ {
+ id: 'created-at',
+ label: this.intl.t('column.created-at'),
+ valuePath: 'createdAt',
+ sortParam: 'created_at',
+ filterParam: 'created_at',
+ width: 150,
+ resizable: true,
+ sortable: true,
+ filterable: true,
+ filterComponent: 'filter/date',
+ },
+ // ── Hidden / toggleable columns ──────────────────────────────────
+ {
+ id: 'public-id',
+ label: this.intl.t('column.id'),
+ valuePath: 'public_id',
+ width: 120,
+ hidden: true,
+ resizable: true,
+ sortable: false,
+ filterable: true,
+ filterParam: 'public_id',
+ filterComponent: 'filter/string',
+ },
+ {
+ id: 'code',
+ label: this.intl.t('column.code'),
+ valuePath: 'code',
+ hidden: true,
+ resizable: true,
+ sortable: true,
+ filterable: true,
+ filterParam: 'code',
+ filterComponent: 'filter/string',
+ },
+ {
+ id: 'description',
+ label: this.intl.t('column.description'),
+ valuePath: 'description',
+ hidden: true,
+ resizable: true,
+ sortable: false,
+ filterable: true,
+ filterParam: 'description',
+ filterComponent: 'filter/string',
+ },
+ {
+ id: 'updated-at',
+ label: this.intl.t('column.updated-at'),
+ valuePath: 'updatedAt',
+ sortParam: 'updated_at',
+ filterParam: 'updated_at',
+ hidden: true,
+ resizable: true,
+ sortable: true,
+ filterable: true,
+ filterComponent: 'filter/date',
+ },
+ // ── Row actions dropdown ─────────────────────────────────────────
+ {
+ id: 'row-actions',
+ label: '',
+ cellComponent: 'table/cell/dropdown',
+ ddButtonText: false,
+ ddButtonIcon: 'ellipsis-h',
+ ddButtonIconPrefix: 'fas',
+ ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.gateway') }),
+ cellClassNames: 'overflow-visible',
+ wrapperClass: 'flex items-center justify-end mx-2',
+ sticky: 'right',
+ width: 60,
+ actions: [
+ {
+ id: 'view',
+ label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.gateway') }),
+ icon: 'eye',
+ fn: this.gatewayActions.transition.view,
+ permission: 'ledger view gateway',
+ },
+ {
+ id: 'edit',
+ label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.gateway') }),
+ icon: 'pencil',
+ fn: this.gatewayActions.edit,
+ permission: 'ledger update gateway',
+ },
+ {
+ id: 'delete',
+ label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.gateway') }),
+ icon: 'trash',
+ fn: this.gatewayActions.delete,
+ className: 'text-red-500 hover:text-red-700',
+ permission: 'ledger delete gateway',
+ },
+ ],
+ sortable: false,
+ filterable: false,
+ resizable: false,
+ searchable: false,
+ },
+ ],
+ { controller: this }
+ );
}
@task({ restartable: true })
diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js
index 5d959bd..0deff15 100644
--- a/addon/controllers/payments/transactions/index.js
+++ b/addon/controllers/payments/transactions/index.js
@@ -7,7 +7,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
@service tableContext;
@service intl;
- @tracked queryParams = [
+ @tracked queryParams = this.transactionActions.queryParamsFor([
'page',
'limit',
'sort',
@@ -27,7 +27,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
'created_at',
'updated_at',
'settled_at',
- ];
+ ]);
@tracked page = 1;
@tracked limit = 30;
@tracked sort = '-created_at';
@@ -52,6 +52,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
get actionButtons() {
return [
{
+ id: 'refresh',
icon: 'refresh',
onClick: this.transactionActions.refresh,
helpText: this.intl.t('common.refresh'),
@@ -67,6 +68,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
return [
// ── Default visible columns ──────────────────────────────────────
{
+ id: 'public-id',
sticky: true,
label: this.intl.t('column.id'),
valuePath: 'public_id',
@@ -80,6 +82,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'created-at',
label: this.intl.t('column.date'),
valuePath: 'createdAt',
sortParam: 'created_at',
@@ -90,6 +93,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/date',
},
{
+ id: 'description',
label: this.intl.t('column.description'),
valuePath: 'description',
resizable: true,
@@ -99,6 +103,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'type',
label: this.intl.t('column.type'),
valuePath: 'type',
resizable: true,
@@ -109,6 +114,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterOptions: ['wallet_deposit', 'wallet_withdrawal', 'wallet_transfer', 'gateway_charge', 'gateway_refund', 'gateway_payout', 'adjustment', 'earning', 'fee'],
},
{
+ id: 'direction',
label: this.intl.t('column.direction'),
valuePath: 'direction',
cellComponent: 'table/cell/base',
@@ -126,6 +132,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
],
},
{
+ id: 'amount',
label: this.intl.t('column.amount'),
valuePath: 'amount',
cellComponent: 'table/cell/currency',
@@ -135,6 +142,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterable: false,
},
{
+ id: 'status',
label: this.intl.t('column.status'),
valuePath: 'status',
cellComponent: 'table/cell/status',
@@ -146,6 +154,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterOptions: ['pending', 'success', 'failed', 'cancelled', 'voided', 'reversed', 'expired'],
},
{
+ id: 'settlement-status',
label: 'Settlement',
valuePath: 'settlement_status',
cellComponent: 'table/cell/status',
@@ -159,6 +168,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
},
// ── Hidden / toggleable columns ──────────────────────────────────
{
+ id: 'net-amount',
label: this.intl.t('column.net-amount'),
valuePath: 'net_amount',
cellComponent: 'table/cell/currency',
@@ -169,6 +179,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterable: false,
},
{
+ id: 'fee-amount',
label: this.intl.t('column.fee'),
valuePath: 'fee_amount',
cellComponent: 'table/cell/currency',
@@ -178,6 +189,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterable: false,
},
{
+ id: 'tax-amount',
label: this.intl.t('column.tax'),
valuePath: 'tax_amount',
cellComponent: 'table/cell/currency',
@@ -187,6 +199,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterable: false,
},
{
+ id: 'currency',
label: this.intl.t('column.currency'),
valuePath: 'currency',
hidden: true,
@@ -197,6 +210,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'gateway',
label: this.intl.t('column.gateway'),
valuePath: 'gateway',
hidden: true,
@@ -207,6 +221,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'payment-method',
label: this.intl.t('column.payment-method'),
valuePath: 'payment_method',
hidden: true,
@@ -225,6 +240,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
],
},
{
+ id: 'reference',
label: this.intl.t('column.reference'),
valuePath: 'reference',
hidden: true,
@@ -235,6 +251,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'period',
label: this.intl.t('column.period'),
valuePath: 'period',
hidden: true,
@@ -245,6 +262,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'settled-at',
label: this.intl.t('column.settled-at'),
valuePath: 'settled_at',
sortParam: 'settled_at',
@@ -256,6 +274,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/date',
},
{
+ id: 'failure-reason',
label: this.intl.t('column.failure-reason'),
valuePath: 'failure_reason',
hidden: true,
@@ -266,6 +285,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'updated-at',
label: this.intl.t('column.updated-at'),
valuePath: 'updatedAt',
sortParam: 'updated_at',
@@ -278,6 +298,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
},
// ── Row actions dropdown ─────────────────────────────────────────
{
+ id: 'row-actions',
label: '',
cellComponent: 'table/cell/dropdown',
ddButtonText: false,
@@ -290,6 +311,7 @@ export default class PaymentsTransactionsIndexController extends Controller {
width: 60,
actions: [
{
+ id: 'view',
label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.transaction') }),
icon: 'eye',
fn: this.transactionActions.transition.view,
diff --git a/addon/controllers/payments/wallets/index.js b/addon/controllers/payments/wallets/index.js
index 2b39819..865e8ee 100644
--- a/addon/controllers/payments/wallets/index.js
+++ b/addon/controllers/payments/wallets/index.js
@@ -7,7 +7,22 @@ export default class PaymentsWalletsIndexController extends Controller {
@service tableContext;
@service intl;
- @tracked queryParams = ['page', 'limit', 'sort', 'query', 'public_id', 'name', 'type', 'status', 'currency', 'is_frozen', 'subject', 'subject_type', 'created_at', 'updated_at'];
+ @tracked queryParams = this.walletActions.queryParamsFor([
+ 'page',
+ 'limit',
+ 'sort',
+ 'query',
+ 'public_id',
+ 'name',
+ 'type',
+ 'status',
+ 'currency',
+ 'is_frozen',
+ 'subject',
+ 'subject_type',
+ 'created_at',
+ 'updated_at',
+ ]);
@tracked page = 1;
@tracked limit = 30;
@tracked sort = '-created_at';
@@ -27,6 +42,7 @@ export default class PaymentsWalletsIndexController extends Controller {
get actionButtons() {
return [
{
+ id: 'refresh',
icon: 'refresh',
onClick: this.walletActions.refresh,
helpText: this.intl.t('common.refresh'),
@@ -38,6 +54,7 @@ export default class PaymentsWalletsIndexController extends Controller {
const selected = this.tableContext.getSelectedRows();
return [
{
+ id: 'bulk-delete',
label: this.intl.t('common.delete-selected-count', { count: selected.length }),
class: 'text-red-500',
fn: this.walletActions.bulkDelete,
@@ -49,6 +66,7 @@ export default class PaymentsWalletsIndexController extends Controller {
return [
// ── Owner (subject) column ───────────────────────────────────────
{
+ id: 'subject-name',
sticky: true,
label: this.intl.t('column.owner'),
valuePath: 'subject.name',
@@ -63,6 +81,7 @@ export default class PaymentsWalletsIndexController extends Controller {
},
// ── Default visible columns ──────────────────────────────────────
{
+ id: 'name',
label: this.intl.t('column.name'),
valuePath: 'name',
cellComponent: 'table/cell/anchor',
@@ -75,6 +94,7 @@ export default class PaymentsWalletsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'type',
label: this.intl.t('column.type'),
valuePath: 'type',
cellComponent: 'table/cell/base',
@@ -95,6 +115,7 @@ export default class PaymentsWalletsIndexController extends Controller {
],
},
{
+ id: 'currency',
label: this.intl.t('column.currency'),
valuePath: 'currency',
width: 90,
@@ -105,6 +126,7 @@ export default class PaymentsWalletsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'balance',
label: this.intl.t('column.balance'),
valuePath: 'balance',
cellComponent: 'table/cell/currency',
@@ -115,6 +137,7 @@ export default class PaymentsWalletsIndexController extends Controller {
filterable: false,
},
{
+ id: 'status',
label: this.intl.t('column.status'),
valuePath: 'status',
cellComponent: 'table/cell/status',
@@ -134,6 +157,7 @@ export default class PaymentsWalletsIndexController extends Controller {
],
},
{
+ id: 'created-at',
label: this.intl.t('column.created-at'),
valuePath: 'createdAt',
sortParam: 'created_at',
@@ -146,6 +170,7 @@ export default class PaymentsWalletsIndexController extends Controller {
},
// ── Hidden / toggleable columns ──────────────────────────────────
{
+ id: 'public-id',
label: this.intl.t('column.id'),
valuePath: 'public_id',
width: 120,
@@ -157,6 +182,7 @@ export default class PaymentsWalletsIndexController extends Controller {
filterComponent: 'filter/string',
},
{
+ id: 'description',
label: this.intl.t('column.description'),
valuePath: 'description',
width: 200,
@@ -166,6 +192,7 @@ export default class PaymentsWalletsIndexController extends Controller {
filterable: false,
},
{
+ id: 'is-frozen-label',
label: this.intl.t('column.frozen'),
valuePath: 'is_frozen_label',
cellComponent: 'table/cell/base',
@@ -184,6 +211,7 @@ export default class PaymentsWalletsIndexController extends Controller {
],
},
{
+ id: 'updated-at',
label: this.intl.t('column.updated-at'),
valuePath: 'updatedAt',
sortParam: 'updated_at',
@@ -196,6 +224,7 @@ export default class PaymentsWalletsIndexController extends Controller {
},
// ── Row actions dropdown ─────────────────────────────────────────
{
+ id: 'row-actions',
label: '',
cellComponent: 'table/cell/dropdown',
ddButtonText: false,
@@ -208,12 +237,14 @@ export default class PaymentsWalletsIndexController extends Controller {
width: 60,
actions: [
{
+ id: 'view',
label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.wallet') }),
icon: 'eye',
fn: this.walletActions.transition.view,
permission: 'ledger view wallet',
},
{
+ id: 'delete',
label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.wallet') }),
icon: 'trash',
fn: this.walletActions.delete,
diff --git a/addon/controllers/payments/wallets/index/details.js b/addon/controllers/payments/wallets/index/details.js
index 70f9ead..32f1652 100644
--- a/addon/controllers/payments/wallets/index/details.js
+++ b/addon/controllers/payments/wallets/index/details.js
@@ -20,9 +20,10 @@ export default class PaymentsWalletsIndexDetailsController extends Controller {
const frozen = wallet?.is_frozen;
return [
- { label: 'Add Funds', icon: 'plus-circle', type: 'primary', helpText: 'Add funds to this wallet balance.', onClick: this.topUpWallet },
- { label: 'Transfer', icon: 'exchange-alt', helpText: 'Transfer funds from this wallet to another wallet.', onClick: this.transferFunds },
+ { id: 'top-up-wallet', label: 'Add Funds', icon: 'plus-circle', type: 'primary', helpText: 'Add funds to this wallet balance.', onClick: this.topUpWallet },
+ { id: 'transfer-funds', label: 'Transfer', icon: 'exchange-alt', helpText: 'Transfer funds from this wallet to another wallet.', onClick: this.transferFunds },
{
+ id: 'toggle-freeze',
label: frozen ? 'Unfreeze' : 'Freeze',
icon: frozen ? 'unlock' : 'lock',
type: frozen ? 'default' : 'danger',
diff --git a/addon/extension.js b/addon/extension.js
index 1d7fc98..d316ece 100644
--- a/addon/extension.js
+++ b/addon/extension.js
@@ -133,6 +133,10 @@ export default {
// Register dashboard and widgets
this.registerWidgets(widgetService);
+
+ // Declare the registries extensions can add table columns, actions and
+ // buttons to, e.g. `ledger:table:invoice:columns` or `ledger:details:invoice:menu`.
+ universe.getService('universe/resource-view-service')?.declare('ledger', ['account', 'gateway', 'invoice', 'invoice-template', 'journal', 'transaction', 'wallet']);
},
registerWidgets(widgetService) {
diff --git a/addon/services/invoice-template-actions.js b/addon/services/invoice-template-actions.js
index 11df629..6097f18 100644
--- a/addon/services/invoice-template-actions.js
+++ b/addon/services/invoice-template-actions.js
@@ -7,6 +7,7 @@ export default class InvoiceTemplateActionsService extends ResourceActionService
this.initialize('template', {
permissionPrefix: 'ledger',
mountPrefix: 'console.ledger',
+ registryResource: 'invoice-template',
});
}
diff --git a/addon/templates/accounting/accounts/index.hbs b/addon/templates/accounting/accounts/index.hbs
index a34b343..b520625 100644
--- a/addon/templates/accounting/accounts/index.hbs
+++ b/addon/templates/accounting/accounts/index.hbs
@@ -1,4 +1,5 @@