EMP-55: Full move to new table2, remove old table code (#406)
Some checks are pending
Main / Deploy (push) Waiting to run
Main / Notify (push) Blocked by required conditions

This commit is contained in:
Rinat Arsaev 2024-10-25 17:37:44 +07:00 committed by GitHub
parent 9e3b6d5ae8
commit 04109ad673
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 721 additions and 1048 deletions

8
package-lock.json generated
View File

@ -26,7 +26,7 @@
"@vality/fistful-proto": "2.0.1-88e69a5.0",
"@vality/machinegun-proto": "1.0.1-3decc8f.0",
"@vality/magista-proto": "2.0.2-ec1bdb9.0",
"@vality/ng-core": "18.4.1-pr-78-9131f9a.0",
"@vality/ng-core": "18.4.1-pr-79-ca9078d.0",
"@vality/ng-thrift": "18.0.1-pr-13-bdb6d51.0",
"@vality/repairer-proto": "2.0.2-07b73e9.0",
"@vality/scrooge-proto": "0.1.1-9ce7fc6.0",
@ -5969,9 +5969,9 @@
"integrity": "sha512-XWF7qM/CARRAey0scGVhfGU6jNq+UdlGE2mg3jn4eIFDuIWQJqsT+Bah300RBUrl+XgFsmj95C6HWRfeA5Q8kw=="
},
"node_modules/@vality/ng-core": {
"version": "18.4.1-pr-78-9131f9a.0",
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-18.4.1-pr-78-9131f9a.0.tgz",
"integrity": "sha512-qmTGnGe+pBWlIQ+cX64pt2aLWdoLM6M2Apc180dQQrLca4VBHB4Oh8yo7vvv/sxws1DLXEzWutgNzi9/bRdtZQ==",
"version": "18.4.1-pr-79-ca9078d.0",
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-18.4.1-pr-79-ca9078d.0.tgz",
"integrity": "sha512-/+GE2QUDUYj8hSZfZijBQAZcb1IBi6TLlTCCAxItDkAG2jVHhcDeW+8fgpchZZKbsFQFyhUHFsU+qttDuvnfDQ==",
"dependencies": {
"@angular/material-date-fns-adapter": "^18.2.2",
"@ng-matero/extensions": "^18.2.0",

View File

@ -35,7 +35,7 @@
"@vality/fistful-proto": "2.0.1-88e69a5.0",
"@vality/machinegun-proto": "1.0.1-3decc8f.0",
"@vality/magista-proto": "2.0.2-ec1bdb9.0",
"@vality/ng-core": "18.4.1-pr-78-9131f9a.0",
"@vality/ng-core": "18.4.1-pr-79-ca9078d.0",
"@vality/ng-thrift": "18.0.1-pr-13-bdb6d51.0",
"@vality/repairer-proto": "2.0.2-07b73e9.0",
"@vality/scrooge-proto": "0.1.1-9ce7fc6.0",

View File

@ -8,13 +8,18 @@ import { MemoizeExpiring } from 'typescript-memoize';
import { PartyManagementService } from '@cc/app/api/payment-processing';
import { createDsl, FistfulStatisticsService } from '../../fistful-stat';
@Injectable({
providedIn: 'root',
})
export class PartiesStoreService {
progress$ = new BehaviorSubject(0);
constructor(private partyManagementService: PartyManagementService) {}
constructor(
private partyManagementService: PartyManagementService,
private fistfulStatisticsService: FistfulStatisticsService,
) {}
@MemoizeExpiring(5 * 60_000)
get(partyId: PartyID) {
@ -34,8 +39,14 @@ export class PartiesStoreService {
@MemoizeExpiring(5 * 60_000)
getWallet(walletId: WalletID, partyId: PartyID) {
return this.get(partyId).pipe(
map((p) => p.wallets.get(walletId)),
// return this.get(partyId).pipe(
// map((p) => p.wallets.get(walletId)),
// progressTo(this.progress$),
// shareReplay({ refCount: true, bufferSize: 1 }),
// );
// TODO: We get it from fistful because wallets are not returned in the party object
return this.getWallets(partyId).pipe(
map((wallets) => wallets.find((w) => w.id === walletId)),
progressTo(this.progress$),
shareReplay({ refCount: true, bufferSize: 1 }),
);
@ -57,4 +68,15 @@ export class PartiesStoreService {
map(([party, shop]) => party.contracts.get(shop.contract_id)),
);
}
@MemoizeExpiring(5 * 60_000)
private getWallets(partyId: PartyID) {
return this.fistfulStatisticsService
.GetWallets({ dsl: createDsl({ wallets: { party_id: partyId } }) })
.pipe(
map(({ data }) => data.wallets),
progressTo(this.progress$),
shareReplay({ refCount: true, bufferSize: 1 }),
);
}
}

View File

@ -1,4 +1,4 @@
<v-table2
<v-table
[columns]="columns"
[data]="data"
[hasMore]="hasMore"
@ -7,4 +7,4 @@
(update)="update.emit($event)"
>
<v-table-actions><ng-content></ng-content></v-table-actions>
</v-table2>
</v-table>

View File

@ -1,11 +1,11 @@
import { Component, Input, Output, EventEmitter, booleanAttribute, input } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { Claim } from '@vality/domain-proto/claim_management';
import { Column2, LoadOptions, createMenuColumn } from '@vality/ng-core';
import { Column, createMenuColumn, LoadOptions } from '@vality/ng-core';
import { getUnionKey } from '@vality/ng-thrift';
import startCase from 'lodash-es/startCase';
import { startCase } from 'lodash-es';
import { createPartyColumn } from '@cc/app/shared/utils/table2';
import { createPartyColumn } from '@cc/app/shared';
@Component({
selector: 'cc-claims-table',
@ -21,21 +21,23 @@ export class ClaimsTableComponent {
@Output() update = new EventEmitter<LoadOptions>();
@Output() more = new EventEmitter<void>();
columns: Column2<Claim>[] = [
columns: Column<Claim>[] = [
{ field: 'id', cell: (d) => ({ link: () => `/party/${d.party_id}/claim/${d.id}` }) },
createPartyColumn((d) => ({ id: d.party_id }), { hidden: toObservable(this.noParty) }),
{
field: 'status',
cell: (d) => ({
value: startCase(getUnionKey(d.status)),
tags: {
color: (
{
pending: 'pending',
review: 'pending',
pending_acceptance: 'pending',
accepted: 'success',
denied: 'warn',
revoked: 'neutral',
},
} as const
)[getUnionKey(d.status)],
}),
},
{ field: 'revision' },

View File

@ -1,6 +1,6 @@
<div style="display: flex; flex-direction: column; gap: 24px">
<h1 class="mat-headline-5">Reverts</h1>
<v-table2
<v-table
[columns]="columns"
[data]="reverts$ | async"
[hasMore]="hasMore$ | async"
@ -18,5 +18,5 @@
Create revert
</button>
</v-table-actions>
</v-table2>
</v-table>
</div>

View File

@ -1,11 +1,11 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { DepositStatus, StatDeposit, StatDepositRevert } from '@vality/fistful-proto/fistful_stat';
import { DialogService, UpdateOptions, Column2 } from '@vality/ng-core';
import { DialogService, UpdateOptions, Column } from '@vality/ng-core';
import { getUnionKey } from '@vality/ng-thrift';
import startCase from 'lodash-es/startCase';
import { filter } from 'rxjs/operators';
import { createCurrencyColumn } from '@cc/app/shared/utils/table2';
import { createCurrencyColumn } from '@cc/app/shared';
import { CreateRevertDialogComponent } from './create-revert-dialog/create-revert-dialog.component';
import { FetchRevertsService } from './services/fetch-reverts/fetch-reverts.service';
@ -23,7 +23,7 @@ export class RevertsComponent implements OnInit {
reverts$ = this.fetchRevertsService.result$;
hasMore$ = this.fetchRevertsService.hasMore$;
isLoading$ = this.fetchRevertsService.isLoading$;
columns: Column2<StatDepositRevert>[] = [
columns: Column<StatDepositRevert>[] = [
{ field: 'id' },
{
field: 'status',

View File

@ -22,7 +22,7 @@
<cc-merchant-field formControlName="party_id"></cc-merchant-field>
</ng-template>
</v-filters>
<v-table2
<v-table
[columns]="columns"
[data]="deposits$ | async"
[hasMore]="hasMore$ | async"
@ -34,5 +34,5 @@
<button mat-raised-button (click)="createByFile()">Create by file</button>
<button color="primary" mat-raised-button (click)="createDeposit()">Create</button>
</v-table-actions>
</v-table2>
</v-table>
</cc-page-layout>

View File

@ -16,7 +16,7 @@ import {
debounceTimeWithFirst,
getValueChanges,
countChanged,
Column2,
Column,
getEnumKey,
createMenuColumn,
} from '@vality/ng-core';
@ -25,7 +25,7 @@ import { endOfDay } from 'date-fns';
import startCase from 'lodash-es/startCase';
import { filter, map, shareReplay } from 'rxjs/operators';
import { createCurrencyColumn } from '@cc/app/shared/utils/table2';
import { createCurrencyColumn } from '@cc/app/shared';
import { QueryDsl } from '../../api/fistful-stat';
import { DATE_RANGE_DAYS, DEBOUNCE_TIME_MS } from '../../tokens';
@ -53,7 +53,7 @@ export class DepositsComponent implements OnInit {
deposits$ = this.fetchDepositsService.result$;
hasMore$ = this.fetchDepositsService.hasMore$;
isLoading$ = this.fetchDepositsService.isLoading$;
columns: Column2<StatDeposit>[] = [
columns: Column<StatDeposit>[] = [
{
field: 'id',
cell: (d) => ({

View File

@ -1,5 +1,4 @@
<v-table2
[(sort)]="sort"
<v-table
[columns]="columns"
[data]="objects$ | async"
[progress]="isLoading$ | async"
@ -17,4 +16,4 @@
style="overflow: auto"
></v-select-field>
</v-table-inputs>
</v-table2>
</v-table>

View File

@ -11,7 +11,7 @@ import {
ActionsModule,
DialogService,
getValueChanges,
Column2,
Column,
createMenuColumn,
} from '@vality/ng-core';
import sortBy from 'lodash-es/sortBy';
@ -76,7 +76,7 @@ export class DomainObjectsTableComponent implements OnInit {
map(([objects, types]) => objects.filter((o) => types.includes(o.type))),
shareReplay({ refCount: true, bufferSize: 1 }),
);
columns: Column2<DomainObjectData>[] = [
columns: Column<DomainObjectData>[] = [
{
field: 'id',
cell: (d) => ({ value: getDomainObjectDetails(d.obj).id }),
@ -140,7 +140,6 @@ export class DomainObjectsTableComponent implements OnInit {
),
);
isLoading$ = this.domainStoreService.isLoading$;
sort = { active: 'id', direction: 'asc' };
constructor(
private domainStoreService: DomainStoreService,

View File

@ -1,5 +1,5 @@
import { Component, input } from '@angular/core';
import { Column2, getEnumKey, TableModule } from '@vality/ng-core';
import { Column, getEnumKey, TableModule } from '@vality/ng-core';
import { repairer } from '@vality/repairer-proto';
import { StatusHistory } from '@vality/repairer-proto/repairer';
import { startCase } from 'lodash-es';
@ -9,7 +9,7 @@ import { SidenavInfoModule } from '@cc/app/shared/components/sidenav-info';
@Component({
standalone: true,
template: `<cc-card title="Machine #{{ id() }} Status History"
><v-table2 [columns]="columns" [data]="history()"></v-table2
><v-table [columns]="columns" [data]="history()"></v-table
></cc-card>`,
imports: [TableModule, SidenavInfoModule],
})
@ -17,7 +17,7 @@ export class MachineStatusHistoryCardComponent {
history = input<StatusHistory[]>([]);
id = input<string>('');
columns: Column2<StatusHistory>[] = [
columns: Column<StatusHistory>[] = [
{ field: 'changed_at', cell: { type: 'datetime' } },
{
field: 'status',

View File

@ -33,7 +33,7 @@
</ng-template>
</v-filters>
<v-table2
<v-table
[columns]="columns"
[data]="machines$ | async"
[hasMore]="hasMore$ | async"
@ -61,5 +61,5 @@
Simple repair
</button>
</v-table-actions>
</v-table2>
</v-table>
</cc-page-layout>

View File

@ -17,7 +17,7 @@ import {
debounceTimeWithFirst,
FetchOptions,
getEnumKey,
Column2,
Column,
} from '@vality/ng-core';
import { repairer } from '@vality/repairer-proto';
import { Namespace, ProviderID, RepairStatus, Machine } from '@vality/repairer-proto/repairer';
@ -27,8 +27,8 @@ import startCase from 'lodash-es/startCase';
import { BehaviorSubject } from 'rxjs';
import { filter, switchMap, map, shareReplay } from 'rxjs/operators';
import { createDomainObjectColumn } from '@cc/app/shared';
import { SidenavInfoService } from '@cc/app/shared/components/sidenav-info';
import { createDomainObjectColumn } from '@cc/app/shared/utils/table2';
import { RepairManagementService } from '../../api/repairer';
import { DATE_RANGE_DAYS, DEBOUNCE_TIME_MS } from '../../tokens';
@ -65,12 +65,12 @@ export class MachinesComponent implements OnInit {
});
selected$ = new BehaviorSubject<Machine[]>([]);
status = repairer.RepairStatus;
columns: Column2<Machine>[] = [
columns: Column<Machine>[] = [
{ field: 'id', sticky: 'start' },
{ header: 'Namespace', field: 'ns' },
{ field: 'created_at', cell: { type: 'datetime' } },
createDomainObjectColumn((d) => ({ ref: { terminal: { id: Number(d.provider_id) } } }), {
header: 'Terminal',
createDomainObjectColumn((d) => ({ ref: { provider: { id: Number(d.provider_id) } } }), {
header: 'Provider',
}),
{
field: 'status',

View File

@ -1,4 +1,4 @@
<cc-page-layout [progress]="isLoading$ | async" title="Refunds">
<cc-page-layout [progress]="isLoading$ | async" fullHeight title="Refunds">
<cc-refunds-table
[invoiceID]="(payment$ | async).invoice_id"
[partyID]="(payment$ | async).owner_id"

View File

@ -4,8 +4,9 @@ import { Column, UpdateOptions } from '@vality/ng-core';
import { getUnionKey } from '@vality/ng-thrift';
import startCase from 'lodash-es/startCase';
import { createCurrencyColumn } from '@cc/app/shared';
import { Refund } from '../../../api/fistful-stat';
import { createCurrencyColumn } from '../../../shared';
import { FetchRefundsService } from './services/fetch-refunds.service';
@ -26,26 +27,24 @@ export class RefundsTableComponent implements OnInit {
refunds$ = this.fetchRefundsService.result$;
columns: Column<Refund>[] = [
{ field: 'created_at', type: 'datetime' },
{ field: 'created_at', cell: { type: 'datetime' } },
{
field: 'status',
type: 'tag',
formatter: (d) => getUnionKey(d.status),
typeParameters: {
label: (d) => startCase(getUnionKey(d.status)),
tags: {
pending: { color: 'pending' },
succeeded: { color: 'success' },
failed: { color: 'warn' },
cell: (d) => ({
value: startCase(getUnionKey(d.status)),
color: (
{
pending: 'pending',
succeeded: 'success',
failed: 'warn',
} as const
)[getUnionKey(d.status)],
}),
},
},
},
createCurrencyColumn(
'amount',
(d) => d.amount,
(d) => d.currency_symbolic_code,
),
'reason',
createCurrencyColumn((d) => ({ amount: d.amount, code: d.currency_symbolic_code }), {
header: 'Amount',
}),
{ field: 'reason' },
];
constructor(private fetchRefundsService: FetchRefundsService) {}

View File

@ -1,4 +1,4 @@
<v-table2
<v-table
[columns]="columns"
[data]="data"
[hasMore]="hasMore"
@ -12,4 +12,4 @@
<v-table-actions>
<ng-content></ng-content>
</v-table-actions>
</v-table2>
</v-table>

View File

@ -1,19 +1,17 @@
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Router } from '@angular/router';
import { StatPayment } from '@vality/magista-proto/magista';
import { LoadOptions, Column2, createMenuColumn } from '@vality/ng-core';
import { LoadOptions, Column, createMenuColumn } from '@vality/ng-core';
import { getUnionKey } from '@vality/ng-thrift';
import startCase from 'lodash-es/startCase';
import { AmountCurrencyService } from '@cc/app/shared/services';
import { createFailureColumn } from '../../../../shared';
import {
createPartyColumn,
createShopColumn,
createDomainObjectColumn,
createCurrencyColumn,
} from '../../../../shared/utils/table2';
createFailureColumn,
} from '@cc/app/shared';
@Component({
selector: 'cc-payments-table',
@ -29,7 +27,7 @@ export class PaymentsTableComponent {
@Output() update = new EventEmitter<LoadOptions>();
@Output() more = new EventEmitter<void>();
columns: Column2<StatPayment>[] = [
columns: Column<StatPayment>[] = [
{
field: 'id',
cell: (d) => ({
@ -89,10 +87,7 @@ export class PaymentsTableComponent {
})),
];
constructor(
private amountCurrencyService: AmountCurrencyService,
private router: Router,
) {}
constructor(private router: Router) {}
private toDetails(data: StatPayment) {
return void this.router.navigate([

View File

@ -1,13 +1,14 @@
<cc-page-layout
[progress]="isLoading$ | async"
[title]="(routingRulesTypeService.routingRulesType$ | async | titlecase) + ' Routing Rules'"
fullHeight
>
<cc-page-layout-actions>
<button color="primary" mat-raised-button (click)="attachNewRuleset()">Add</button>
</cc-page-layout-actions>
<cc-routing-rules-list
[data]="data$ | async"
[displayedColumns]="displayedColumns"
[displayedColumns]="columns"
[progress]="isLoading$ | async"
(toDetails)="navigateToPartyRuleset($event.parentRefId, $event.delegateIdx)"
></cc-routing-rules-list>

View File

@ -1,17 +1,22 @@
import { ChangeDetectionStrategy, Component, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router } from '@angular/router';
import { DialogService, NotifyLogService } from '@vality/ng-core';
import { Column, DialogService, NotifyLogService } from '@vality/ng-core';
import { first, map, catchError } from 'rxjs/operators';
import { DomainStoreService } from '@cc/app/api/domain-config';
import { RoutingRulesType } from '@cc/app/sections/routing-rules/types/routing-rules-type';
import { createDomainObjectColumn } from '@cc/app/shared';
import { RoutingRulesListItem } from '../routing-rules-list';
import { RoutingRulesTypeService } from '../routing-rules-type.service';
import { RoutingRulesService } from '../services/routing-rules';
import { AttachNewRulesetDialogComponent } from './attach-new-ruleset-dialog';
import { PartyDelegateRulesetsService } from './party-delegate-rulesets.service';
import {
DelegateWithPaymentInstitution,
PartyDelegateRulesetsService,
} from './party-delegate-rulesets.service';
@Component({
selector: 'cc-party-delegate-rulesets',
@ -20,31 +25,37 @@ import { PartyDelegateRulesetsService } from './party-delegate-rulesets.service'
providers: [PartyDelegateRulesetsService, RoutingRulesTypeService],
})
export class PartyDelegateRulesetsComponent {
displayedColumns = [
{ key: 'partyDelegate', name: 'Party delegate' },
{ key: 'paymentInstitution', name: 'Payment institution' },
{ key: 'mainRuleset', name: 'Main ruleset' },
columns: Column<RoutingRulesListItem<DelegateWithPaymentInstitution>>[] = [
{
field: 'partyDelegate',
cell: (d) => ({
value: d.item.partyDelegate?.description || `#${d.item.partyDelegate?.ruleset?.id}`,
description: d.item.partyDelegate?.ruleset?.id,
click: () => this.navigateToPartyRuleset(d.parentRefId, d.delegateIdx),
}),
},
createDomainObjectColumn(
(d) => ({
ref: { payment_institution: d.item.paymentInstitution.ref },
}),
{ header: 'Payment Institution' },
),
createDomainObjectColumn(
(d) => ({
ref: { routing_rules: d.item.mainRoutingRule.ref },
}),
{ header: 'Main Ruleset' },
),
];
isLoading$ = this.domainStoreService.isLoading$;
data$ = this.partyDelegateRulesetsService.getDelegatesWithPaymentInstitution().pipe(
map((rules) =>
rules.map(({ mainRoutingRule, partyDelegate, paymentInstitution }) => ({
parentRefId: mainRoutingRule?.ref?.id,
delegateIdx: mainRoutingRule?.data?.decisions?.delegates?.findIndex(
(d) => d === partyDelegate,
map((rules): RoutingRulesListItem<DelegateWithPaymentInstitution>[] =>
rules.map((item) => ({
parentRefId: item.mainRoutingRule?.ref?.id,
delegateIdx: item.mainRoutingRule?.data?.decisions?.delegates?.findIndex(
(d) => d === item.partyDelegate,
),
paymentInstitution: {
text: paymentInstitution?.data?.name,
caption: paymentInstitution?.ref?.id,
},
mainRuleset: {
text: mainRoutingRule?.data?.name,
caption: mainRoutingRule?.ref?.id,
},
partyDelegate: {
text: partyDelegate?.description,
caption: partyDelegate?.ruleset?.id,
},
item,
})),
),
);

View File

@ -7,6 +7,7 @@
'/routing-rules/' +
(routingRulesTypeService.routingRulesType$ | async)
]"
fullHeight
title="Party Routing Rules"
(idLinkClick)="openRefId()"
>

View File

@ -1,15 +1,23 @@
import { Component, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router } from '@angular/router';
import { DialogService, DialogResponseStatus, compareDifferentTypes } from '@vality/ng-core';
import { RoutingDelegate } from '@vality/domain-proto/domain';
import {
DialogService,
DialogResponseStatus,
compareDifferentTypes,
Column,
} from '@vality/ng-core';
import { combineLatest } from 'rxjs';
import { filter, map, shareReplay, startWith, switchMap, take } from 'rxjs/operators';
import { DomainStoreService } from '@cc/app/api/domain-config';
import { createShopColumn, createWalletColumn } from '@cc/app/shared';
import { SidenavInfoService } from '../../../shared/components/sidenav-info';
import { DomainObjectCardComponent } from '../../../shared/components/thrift-api-crud';
import { PartyDelegateRulesetsService } from '../party-delegate-rulesets';
import { RoutingRulesListItem } from '../routing-rules-list';
import { RoutingRulesTypeService } from '../routing-rules-type.service';
import { AddPartyRoutingRuleDialogComponent } from './add-party-routing-rule-dialog';
@ -27,65 +35,69 @@ export class PartyRoutingRulesetComponent {
partyID$ = this.partyRoutingRulesetService.partyID$;
isLoading$ = this.domainStoreService.isLoading$;
shopsDisplayedColumns = [
{ key: 'id', name: 'Delegate (Ruleset Ref ID)' },
{ key: 'shop', name: 'Shop' },
shopsDisplayedColumns: Column<RoutingRulesListItem<RoutingDelegate>>[] = [
{
field: 'id',
header: 'Delegate (Ruleset Ref ID)',
cell: (d) => ({
value: d.item?.description || `#${d.item?.ruleset?.id}`,
description: d.item?.ruleset?.id,
click: () => this.navigateToDelegate(d.parentRefId, d.delegateIdx),
}),
},
createShopColumn((d) =>
this.partyRoutingRulesetService.partyID$.pipe(
map((partyId) => ({
shopId: d.item?.allowed?.condition?.party?.definition?.shop_is,
partyId,
})),
),
),
];
walletsDisplayedColumns = [
{ key: 'id', name: 'Delegate (Ruleset Ref ID)' },
{ key: 'wallet', name: 'Wallet' },
walletsDisplayedColumns: Column<RoutingRulesListItem<RoutingDelegate>>[] = [
{
field: 'id',
header: 'Delegate (Ruleset Ref ID)',
cell: (d) => ({
value: d.item?.description || `#${d.item?.ruleset?.id}`,
description: d.item?.ruleset?.id,
click: () => this.navigateToDelegate(d.parentRefId, d.delegateIdx),
}),
},
createWalletColumn((d) =>
this.partyRoutingRulesetService.partyID$.pipe(
map((partyId) => ({
id: d.item?.allowed?.condition?.party?.definition?.wallet_is,
partyId,
})),
),
),
];
shopsData$ = combineLatest([
this.partyRuleset$,
this.partyRoutingRulesetService.shops$.pipe(startWith([])),
]).pipe(
filter(([r]) => !!r),
map(([ruleset, shops]) =>
shopsData$ = this.partyRuleset$.pipe(
filter(Boolean),
map((ruleset): RoutingRulesListItem<RoutingDelegate>[] =>
ruleset.data.decisions.delegates
.filter((d) => d?.allowed?.condition?.party?.definition?.shop_is)
.map((delegate, delegateIdx) => {
const shopId = delegate?.allowed?.condition?.party?.definition?.shop_is;
return {
.map((delegate, delegateIdx) => ({
parentRefId: ruleset.ref.id,
delegateIdx,
id: {
text: delegate?.description,
caption: delegate?.ruleset?.id,
},
shop: {
text: shops?.find((s) => s?.id === shopId)?.details?.name,
caption: shopId,
},
};
}),
item: delegate,
})),
),
startWith([]),
takeUntilDestroyed(this.destroyRef),
shareReplay(1),
);
walletsData$ = combineLatest([
this.partyRuleset$,
this.partyRoutingRulesetService.wallets$.pipe(startWith([])),
]).pipe(
filter(([r]) => !!r),
map(([ruleset, wallets]) =>
walletsData$ = this.partyRuleset$.pipe(
filter(Boolean),
map((ruleset): RoutingRulesListItem<RoutingDelegate>[] =>
ruleset.data.decisions.delegates
.filter((d) => d?.allowed?.condition?.party?.definition?.wallet_is)
.map((delegate, delegateIdx) => {
const walletId = delegate?.allowed?.condition?.party?.definition?.wallet_is;
return {
.map((delegate, delegateIdx) => ({
parentRefId: ruleset.ref.id,
delegateIdx,
id: {
text: delegate?.description,
caption: delegate?.ruleset?.id,
},
wallet: {
text: wallets?.find((w) => w?.id === walletId)?.name,
caption: walletId,
},
};
}),
item: delegate,
})),
),
startWith([]),
takeUntilDestroyed(this.destroyRef),

View File

@ -1,8 +1,7 @@
<v-table
[columns]="columns"
[columns]="columns()"
[data]="data"
[progress]="progress"
[size]="100"
name="routingRulesList"
noActions
standaloneFilter
></v-table>

View File

@ -4,9 +4,12 @@ import {
EventEmitter,
Input,
Output,
OnChanges,
booleanAttribute,
DestroyRef,
input,
computed,
runInInjectionContext,
Injector,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute } from '@angular/router';
@ -14,10 +17,9 @@ import {
DialogResponseStatus,
DialogService,
ConfirmDialogComponent,
Column,
createOperationColumn,
ComponentChanges,
NotifyLogService,
Column,
createMenuColumn,
} from '@vality/ng-core';
import { filter, switchMap, catchError } from 'rxjs/operators';
@ -30,62 +32,27 @@ type DelegateId = {
delegateIdx: number;
};
export type RoutingRulesListItem<T> = DelegateId & { item: T };
@Component({
selector: 'cc-routing-rules-list',
templateUrl: 'routing-rules-list.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RoutingRulesListComponent<
T extends { [N in PropertyKey]: unknown } & DelegateId = {
[N in PropertyKey]: unknown;
} & DelegateId,
> implements OnChanges
{
export class RoutingRulesListComponent<T> {
@Input() data: T[];
@Input() displayedColumns: { key: keyof T; name: string }[];
displayedColumns = input<Column<RoutingRulesListItem<T>>[]>([]);
@Input({ transform: booleanAttribute }) progress: boolean = false;
@Output() toDetails = new EventEmitter<DelegateId>();
columns: Column<T>[] = [];
constructor(
private dialogService: DialogService,
private log: NotifyLogService,
private routingRulesService: RoutingRulesService,
private route: ActivatedRoute,
private destroyRef: DestroyRef,
) {}
ngOnChanges(changes: ComponentChanges<RoutingRulesListComponent<T>>) {
if (changes.displayedColumns) {
this.columns = [
...this.displayedColumns.map(
(c, idx): Column<T> => ({
field: `${c.key as string}.text`,
formatter:
idx === 0
? (d) => {
const v = d?.[c.key] as { caption: string; text: string };
return v?.text || `#${v?.caption}`;
}
: undefined,
click:
idx === 0
? (d) =>
this.toDetails.emit({
parentRefId: d?.parentRefId,
delegateIdx: d?.delegateIdx,
})
: undefined,
header: c.name,
description: `${c.key as string}.caption`,
}),
),
createOperationColumn([
columns = computed<Column<RoutingRulesListItem<T>>[]>(() =>
runInInjectionContext(this.injector, () => [
...this.displayedColumns(),
createMenuColumn((d) => ({
items: [
{
label: 'Details',
click: (d) =>
click: () =>
this.toDetails.emit({
parentRefId: d?.parentRefId,
delegateIdx: d?.delegateIdx,
@ -93,24 +60,33 @@ export class RoutingRulesListComponent<
},
{
label: 'Change delegate ruleset',
click: (d) => this.changeDelegateRuleset(d),
click: () => this.changeDelegateRuleset(d),
},
{
label: 'Change main ruleset',
click: (d) => this.changeTarget(d),
click: () => this.changeTarget(d),
},
{
label: 'Clone delegate ruleset',
click: (d) => this.cloneDelegateRuleset(d),
click: () => this.cloneDelegateRuleset(d),
},
{
label: 'Delete',
click: (d) => this.delete(d),
click: () => this.delete(d),
},
],
})),
]),
];
}
}
);
constructor(
private dialogService: DialogService,
private log: NotifyLogService,
private routingRulesService: RoutingRulesService,
private route: ActivatedRoute,
private destroyRef: DestroyRef,
private injector: Injector,
) {}
changeDelegateRuleset(delegateId: DelegateId) {
this.dialogService

View File

@ -9,20 +9,19 @@
'/' +
(partyRulesetRefID$ | async)
]"
fullHeight
(idLinkClick)="openRefId()"
>
<cc-page-layout-actions>
<button color="primary" mat-raised-button (click)="addRule()">Add</button>
</cc-page-layout-actions>
<v-table
[(sort)]="sort"
[columns]="columns"
[data]="(candidates$ | async) || []"
[progress]="isLoading$ | async"
[rowDragDrop]="['priority']"
[size]="100"
[sort]="{ active: 'priority', direction: 'desc' }"
noActions
sortOnFront
standaloneFilter
(rowDropped)="drop($event)"
></v-table>
</cc-page-layout>

View File

@ -1,5 +1,6 @@
import { Component, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Sort } from '@angular/material/sort';
import { ActivatedRoute } from '@angular/router';
import { RoutingCandidate } from '@vality/domain-proto/domain';
import { Predicate } from '@vality/domain-proto/internal/domain';
@ -7,10 +8,10 @@ import {
DialogResponseStatus,
DialogService,
NotifyLogService,
Column,
createOperationColumn,
DragDrop,
correctPriorities,
Column,
createMenuColumn,
} from '@vality/ng-core';
import { toJson, getUnionKey } from '@vality/ng-thrift';
import cloneDeep from 'lodash-es/cloneDeep';
@ -19,16 +20,15 @@ import { first, map, switchMap, withLatestFrom, take } from 'rxjs/operators';
import { DomainStoreService } from '@cc/app/api/domain-config';
import { RoutingRulesType } from '@cc/app/sections/routing-rules/types/routing-rules-type';
import { createDomainObjectColumn, createPredicateColumn } from '@cc/app/shared';
import {
DomainThriftFormDialogComponent,
DomainObjectCardComponent,
UpdateThriftDialogComponent,
} from '@cc/app/shared/components/thrift-api-crud';
import { createPredicateColumn } from '../../../shared';
import { CandidateCardComponent } from '../../../shared/components/candidate-card/candidate-card.component';
import { SidenavInfoService } from '../../../shared/components/sidenav-info';
import { createTerminalColumn } from '../../../shared/utils/table/create-terminal-column';
import { RoutingRulesService } from '../services/routing-rules';
import { RoutingRulesetService } from './routing-ruleset.service';
@ -60,39 +60,52 @@ export class RoutingRulesetComponent {
candidates$ = this.routingRulesetService.ruleset$.pipe(map((r) => r.data.decisions.candidates));
isLoading$ = this.domainStoreService.isLoading$;
columns: Column<RoutingCandidate>[] = [
{ field: 'priority', sortable: true },
{ field: 'priority' },
{
field: 'candidate',
description: 'description',
sortable: true,
formatter: (d) => this.getCandidateIdx(d).pipe(map((idx) => `#${idx + 1}`)),
click: (d) => {
combineLatest([this.getCandidateIdx(d), this.routingRulesetService.ruleset$])
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(([idx, ruleset]) => {
cell: (d) =>
this.getCandidateIdx(d).pipe(
map((idx) => ({
value: `#${idx + 1}`,
description: d.description,
click: () => {
this.routingRulesetService.ruleset$
.pipe(first())
.subscribe((ruleset) => {
this.sidenavInfoService.toggle(CandidateCardComponent, {
idx,
ref: ruleset.ref,
});
});
},
})),
),
},
createTerminalColumn((d) => d.terminal.id),
createPredicateColumn('global_allow', (d) =>
createDomainObjectColumn((d) => ({ ref: { terminal: d.terminal } }), {
header: 'Terminal',
}),
createPredicateColumn(
(d) =>
combineLatest([
this.domainStoreService.getObjects('terminal'),
this.routingRulesType$,
]).pipe(
map(([terminals, type]) => {
const terms = terminals.find((t) => t.ref.id === d.terminal.id).data?.terms;
return type === RoutingRulesType.Payment
return {
predicate:
type === RoutingRulesType.Payment
? terms?.payments?.global_allow
: terms?.wallet?.withdrawals?.global_allow;
: terms?.wallet?.withdrawals?.global_allow,
};
}),
),
{ header: 'Global Allow' },
),
createPredicateColumn('allowed', (d) => d.allowed, {
click: (d) => {
createPredicateColumn((d) => ({ predicate: d.allowed }), {
header: 'Allowed',
cell: (d) => ({
click: () => {
this.getCandidateIdx(d)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((idx) => {
@ -100,16 +113,20 @@ export class RoutingRulesetComponent {
});
},
}),
{ field: 'weight', sortable: true },
}),
{ field: 'weight' },
{
field: 'pin',
formatter: (d) => JSON.stringify(toJson(d.pin?.features)),
hide: true,
cell: (d) => ({
value: JSON.stringify(toJson(d.pin?.features)),
}),
hidden: true,
},
createOperationColumn<RoutingCandidate>([
createMenuColumn((d) => ({
items: [
{
label: 'Edit',
click: (d) => {
click: () => {
this.getCandidateIdx(d)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((idx) => {
@ -119,7 +136,7 @@ export class RoutingRulesetComponent {
},
{
label: 'Duplicate',
click: (d) => {
click: () => {
this.getCandidateIdx(d)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((idx) => {
@ -128,8 +145,8 @@ export class RoutingRulesetComponent {
},
},
{
label: (d) => (togglePredicate(d.allowed).prevAllowed ? 'Deny' : 'Allow'),
click: (d) => {
label: togglePredicate(d.allowed).prevAllowed ? 'Deny' : 'Allow',
click: () => {
this.getCandidateIdx(d)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((idx) => {
@ -139,7 +156,7 @@ export class RoutingRulesetComponent {
},
{
label: 'Remove',
click: (d) => {
click: () => {
this.getCandidateIdx(d)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((idx) => {
@ -147,8 +164,10 @@ export class RoutingRulesetComponent {
});
},
},
]),
],
})),
];
sort: Sort = { active: 'priority', direction: 'desc' };
constructor(
private dialog: DialogService,

View File

@ -1,11 +1,11 @@
<cc-page-layout title="Merchants">
<cc-page-layout fullHeight title="Merchants">
<v-table
[columns]="columns"
[data]="parties$ | async"
[filter]="initSearchParams$ | async"
[progress]="inProgress$ | async"
externalFilter
noActions
standaloneFilter
(filterChange)="searchParamsUpdated($event)"
(update)="reload($event)"
></v-table>

View File

@ -1,7 +1,13 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { Party } from '@vality/deanonimus-proto/deanonimus';
import { Column, createOperationColumn, QueryParamsService, UpdateOptions } from '@vality/ng-core';
import {
Column,
createMenuColumn,
DebounceTime,
QueryParamsService,
UpdateOptions,
} from '@vality/ng-core';
import { getUnionKey } from '@vality/ng-thrift';
import startCase from 'lodash-es/startCase';
import { map } from 'rxjs/operators';
@ -21,44 +27,44 @@ export class SearchPartiesComponent {
{ field: 'id' },
{
field: 'email',
link: (party) => `/party/${party.id}`,
cell: (party) => ({ link: () => `/party/${party.id}` }),
},
{
field: 'blocking',
type: 'tag',
formatter: (party) => getUnionKey(party.blocking),
typeParameters: {
label: (party) => startCase(getUnionKey(party.blocking)),
tags: {
blocked: { color: 'warn' },
unblocked: { color: 'success' },
},
},
cell: (party) => ({
value: startCase(getUnionKey(party.blocking)),
color: (
{
blocked: 'warn',
unblocked: 'success',
} as const
)[getUnionKey(party.blocking)],
}),
},
{
field: 'suspension',
type: 'tag',
formatter: (party) => getUnionKey(party.suspension),
typeParameters: {
label: (party) => startCase(getUnionKey(party.suspension)),
tags: {
suspended: { color: 'warn' },
active: { color: 'success' },
},
},
cell: (party) => ({
value: startCase(getUnionKey(party.suspension)),
color: (
{
suspended: 'warn',
active: 'success',
} as const
)[getUnionKey(party.suspension)],
}),
},
{
field: 'shops',
formatter: (party) => party.shops.size,
cell: (party) => ({ value: party.shops.size }),
},
createOperationColumn([
createMenuColumn((party) => ({
items: [
{
label: 'Details',
click: (party) => {
this.router.navigate([`/party/${party.id}`]);
click: () => this.router.navigate([`/party/${party.id}`]),
},
},
]),
],
})),
];
constructor(
@ -67,6 +73,7 @@ export class SearchPartiesComponent {
private router: Router,
) {}
@DebounceTime()
searchParamsUpdated(filter: string) {
void this.qp.set({ text: filter });
this.fetchPartiesService.load(filter);

View File

@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { SearchShopHit } from '@vality/deanonimus-proto/deanonimus';
import { Column, progressTo, NotifyLogService } from '@vality/ng-core';
import { progressTo, NotifyLogService } from '@vality/ng-core';
import { BehaviorSubject, defer, of, combineLatest, Subject, Observable } from 'rxjs';
import {
switchMap,
@ -43,7 +43,6 @@ export class ShopsComponent {
),
shareReplay({ refCount: true, bufferSize: 1 }),
);
columns: Column<SearchShopHit>[] = [{ field: 'shop.details.name', description: 'shop.id' }];
progress$ = new BehaviorSubject(0);
private updateShops$ = new BehaviorSubject<void>(undefined);

View File

@ -2,11 +2,10 @@
<cc-page-layout-actions>
<button color="primary" mat-raised-button (click)="create()">Create</button>
</cc-page-layout-actions>
<v-table2
[(sort)]="sort"
<v-table
[columns]="columns"
[data]="sources$ | async"
[progress]="!!(progress$ | async)"
standaloneFilter
></v-table2>
></v-table>
</cc-page-layout>

View File

@ -1,7 +1,6 @@
import { Component } from '@angular/core';
import { Sort } from '@angular/material/sort';
import { Source } from '@vality/fistful-proto/internal/source';
import { DialogService, Column2 } from '@vality/ng-core';
import { DialogService, Column } from '@vality/ng-core';
import { CreateSourceComponent } from './create-source/create-source.component';
import { FetchSourcesService } from './fetch-sources.service';
@ -12,14 +11,13 @@ import { FetchSourcesService } from './fetch-sources.service';
export class SourcesComponent {
sources$ = this.fetchSourcesService.sources$;
progress$ = this.fetchSourcesService.progress$;
columns: Column2<Source>[] = [
columns: Column<Source>[] = [
{ field: 'id' },
{ field: 'name' },
{ field: 'identity' },
{ field: 'currency_symbolic_code' },
{ field: 'created_at', cell: { type: 'datetime' } },
];
sort: Sort = { direction: 'asc', active: 'name' };
constructor(
private fetchSourcesService: FetchSourcesService,

View File

@ -2,13 +2,12 @@
<cc-page-layout-actions>
<button color="primary" mat-raised-button (click)="create()">Create</button>
</cc-page-layout-actions>
<v-table2
[(sort)]="sort"
<v-table
[columns]="columns"
[data]="data$ | async"
[progress]="progress$ | async"
name="terminals"
standaloneFilter
(update)="update()"
></v-table2>
></v-table>
</cc-page-layout>

View File

@ -1,9 +1,14 @@
import { Component } from '@angular/core';
import { Sort } from '@angular/material/sort';
import { TerminalObject } from '@vality/domain-proto/domain';
import { DialogService, Column2 } from '@vality/ng-core';
import { DialogService, Column } from '@vality/ng-core';
import { map } from 'rxjs/operators';
import {
createCurrencyColumn,
createPredicateColumn,
createDomainObjectColumn,
} from '@cc/app/shared';
import { DomainStoreService } from '../../api/domain-config';
import { AccountBalancesStoreService } from '../../api/terminal-balance';
import { SidenavInfoService } from '../../shared/components/sidenav-info';
@ -14,11 +19,6 @@ import {
CreateDomainObjectDialogComponent,
getDomainObjectDetails,
} from '../../shared/components/thrift-api-crud';
import {
createCurrencyColumn,
createPredicateColumn,
createDomainObjectColumn,
} from '../../shared/utils/table2';
import { getTerminalShopWalletDelegates } from './utils/get-terminal-shop-wallet-delegates';
@ -27,7 +27,7 @@ import { getTerminalShopWalletDelegates } from './utils/get-terminal-shop-wallet
templateUrl: './terminals.component.html',
})
export class TerminalsComponent {
columns: Column2<TerminalObject>[] = [
columns: Column<TerminalObject>[] = [
{ field: 'ref.id', sticky: 'start' },
{
field: 'data.name',
@ -112,7 +112,6 @@ export class TerminalsComponent {
];
data$ = this.domainStoreService.getObjects('terminal');
progress$ = this.domainStoreService.isLoading$;
sort: Sort = { active: 'data.name', direction: 'asc' };
constructor(
private domainStoreService: DomainStoreService,

View File

@ -1,3 +1,3 @@
<cc-card [title]="'Term Sets History'">
<v-table2 [columns]="columns" [treeData]="historyData()"></v-table2>
<v-table [columns]="columns" [treeData]="historyData()"></v-table>
</cc-card>

View File

@ -1,12 +1,13 @@
import { CommonModule } from '@angular/common';
import { Component, input, computed } from '@angular/core';
import { MatTooltip } from '@angular/material/tooltip';
import { TableModule, VSelectPipe, Column2 } from '@vality/ng-core';
import { TableModule, VSelectPipe, Column } from '@vality/ng-core';
import type { TermSetHistory, ShopTermSet } from '@vality/dominator-proto/internal/dominator';
import { createDomainObjectColumn } from '@cc/app/shared';
import { SidenavInfoModule } from '../../../../shared/components/sidenav-info';
import { createDomainObjectColumn } from '../../../../shared/utils/table2';
import { getFlatDecisions } from '../../utils/get-flat-decisions';
import {
getShopCashFlowSelectors,
@ -36,7 +37,7 @@ export class ShopsTermSetHistoryCardComponent {
})),
);
columns: Column2<TermSetHistory>[] = [
columns: Column<TermSetHistory>[] = [
{ field: 'applied_at', cell: { type: 'datetime' } },
createDomainObjectColumn((d) => ({ ref: { term_set_hierarchy: d?.term_set?.ref } }), {
header: 'Term Set',

View File

@ -16,7 +16,7 @@
</ng-template>
</v-filters>
<v-table2
<v-table
[columns]="columns"
[hasMore]="hasMore$ | async"
[maxSize]="250"
@ -24,5 +24,5 @@
[treeData]="terms$ | async"
(more)="more()"
(update)="update($event)"
></v-table2>
></v-table>
</cc-page-layout>

View File

@ -23,24 +23,24 @@ import {
TableModule,
UpdateOptions,
VSelectPipe,
Column2,
Column,
cachedHeadMap,
} from '@vality/ng-core';
import { map, shareReplay } from 'rxjs/operators';
import { Overwrite } from 'utility-types';
import {
createShopColumn,
createPartyColumn,
createContractColumn,
createDomainObjectColumn,
} from '@cc/app/shared';
import { CurrencyFieldComponent } from '@cc/app/shared/components/currency-field';
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
import { SidenavInfoService } from '@cc/app/shared/components/sidenav-info';
import { DEBOUNCE_TIME_MS } from '@cc/app/tokens';
import { PageLayoutModule, ShopFieldModule } from '../../../../shared';
import {
createShopColumn,
createPartyColumn,
createContractColumn,
createDomainObjectColumn,
} from '../../../../shared/utils/table2';
import { getFlatDecisions, FlatDecision } from '../../utils/get-flat-decisions';
import { ShopsTermSetHistoryCardComponent } from '../shops-term-set-history-card';
@ -101,7 +101,7 @@ export class ShopsTermsComponent implements OnInit {
);
hasMore$ = this.shopsTermsService.hasMore$;
isLoading$ = this.shopsTermsService.isLoading$;
columns: Column2<ShopTermSet, FlatDecision>[] = [
columns: Column<ShopTermSet, FlatDecision>[] = [
createShopColumn(
(d) => ({
shopId: d.shop_id,

View File

@ -5,7 +5,7 @@ import {
ShopID,
TermSetHierarchyObject,
} from '@vality/domain-proto/internal/domain';
import { Column2 } from '@vality/ng-core';
import { Column } from '@vality/ng-core';
import { formatCashVolumes } from '../../../../../shared';
import { createFeesColumns } from '../../../utils/create-fees-columns';
@ -57,4 +57,4 @@ export const SHOP_FEES_COLUMNS = [
}),
},
BASE_SHOP_FEES_COLUMNS.at(-1),
] satisfies Column2<object, FlatDecision>[];
] satisfies Column<object, FlatDecision>[];

View File

@ -1,3 +1,3 @@
<cc-card [title]="'Term Sets History'">
<v-table2 [columns]="columns" [treeData]="historyData()"></v-table2>
<v-table [columns]="columns" [treeData]="historyData()"></v-table>
</cc-card>

View File

@ -1,7 +1,7 @@
import { CommonModule } from '@angular/common';
import { Component, input, computed } from '@angular/core';
import { MatTooltip } from '@angular/material/tooltip';
import { TableModule, VSelectPipe, Column2 } from '@vality/ng-core';
import { TableModule, VSelectPipe, Column } from '@vality/ng-core';
import type {
TerminalTermSet,
@ -29,7 +29,7 @@ export class TerminalsTermSetHistoryCardComponent {
),
);
columns: Column2<ProvisionTermSetHistory>[] = [
columns: Column<ProvisionTermSetHistory>[] = [
{ field: 'applied_at', cell: { type: 'datetime' } },
...TERMINAL_FEES_COLUMNS,
];

View File

@ -10,12 +10,12 @@
</ng-template>
</v-filters>
<v-table2
<v-table
[columns]="columns"
[hasMore]="hasMore$ | async"
[progress]="isLoading$ | async"
[treeData]="terms$ | async"
(more)="more()"
(update)="update($event)"
></v-table2>
></v-table>
</cc-page-layout>

View File

@ -10,7 +10,7 @@ import {
} from '@vality/dominator-proto/internal/dominator';
import {
clean,
Column2,
Column,
countChanged,
createControls,
debounceTimeWithFirst,
@ -30,10 +30,9 @@ import { Overwrite } from 'utility-types';
import type { ProviderRef, TerminalRef } from '@vality/dominator-proto/internal/proto/domain';
import { PageLayoutModule } from '@cc/app/shared';
import { PageLayoutModule, createDomainObjectColumn } from '@cc/app/shared';
import { CurrencyFieldComponent } from '@cc/app/shared/components/currency-field';
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
import { createDomainObjectColumn } from '@cc/app/shared/utils/table2/create-domain-object-column';
import { DEBOUNCE_TIME_MS } from '@cc/app/tokens';
import { SidenavInfoService } from '../../../../shared/components/sidenav-info';
@ -80,7 +79,7 @@ export class TerminalsTermsComponent implements OnInit {
);
hasMore$ = this.terminalsTermsService.hasMore$;
isLoading$ = this.terminalsTermsService.isLoading$;
columns: Column2<TerminalTermSet>[] = [
columns: Column<TerminalTermSet>[] = [
createDomainObjectColumn((d) => ({ ref: { terminal: d.terminal_id } }), {
header: 'Terminal',
sticky: 'start',

View File

@ -1,5 +1,5 @@
import { ProvisionTermSet, CashFlowPosting } from '@vality/domain-proto/internal/domain';
import { Column2, TreeDataItem } from '@vality/ng-core';
import { Column, TreeDataItem } from '@vality/ng-core';
import { createFeesColumns } from '../../../utils/create-fees-columns';
import { FlatDecision, getFlatDecisions } from '../../../utils/get-flat-decisions';
@ -55,4 +55,4 @@ export const TERMINAL_FEES_COLUMNS = [
feeFilter: isWithdrawalFee,
selectFlatDecision: (d) => d.withdrawal,
}),
] satisfies Column2<object, TerminalChild>[];
] satisfies Column<object, TerminalChild>[];

View File

@ -1,3 +1,3 @@
<cc-card [title]="'Term Sets History'">
<v-table2 [columns]="columns" [treeData]="historyData()"></v-table2>
<v-table [columns]="columns" [treeData]="historyData()"></v-table>
</cc-card>

View File

@ -1,12 +1,13 @@
import { CommonModule } from '@angular/common';
import { Component, input, computed } from '@angular/core';
import { MatTooltip } from '@angular/material/tooltip';
import { TableModule, VSelectPipe, Column2 } from '@vality/ng-core';
import { TableModule, VSelectPipe, Column } from '@vality/ng-core';
import type { TermSetHistory, WalletTermSet } from '@vality/dominator-proto/internal/dominator';
import { createDomainObjectColumn } from '@cc/app/shared';
import { SidenavInfoModule } from '../../../../shared/components/sidenav-info';
import { createDomainObjectColumn } from '../../../../shared/utils/table2';
import { getFlatDecisions } from '../../utils/get-flat-decisions';
import {
WALLET_FEES_COLUMNS,
@ -36,7 +37,7 @@ export class WalletsTermSetHistoryCardComponent {
})),
);
columns: Column2<TermSetHistory>[] = [
columns: Column<TermSetHistory>[] = [
{ field: 'applied_at', cell: { type: 'datetime' } },
createDomainObjectColumn((d) => ({ ref: { term_set_hierarchy: d?.term_set?.ref } }), {
header: 'Term Set',

View File

@ -13,7 +13,7 @@
</ng-template>
</v-filters>
<v-table2
<v-table
[columns]="columns"
[hasMore]="hasMore$ | async"
[maxSize]="250"
@ -21,5 +21,5 @@
[treeData]="terms$ | async"
(more)="more()"
(update)="update($event)"
></v-table2>
></v-table>
</cc-page-layout>

View File

@ -26,21 +26,22 @@ import {
TableModule,
UpdateOptions,
VSelectPipe,
Column2,
Column,
cachedHeadMap,
} from '@vality/ng-core';
import { map, shareReplay } from 'rxjs/operators';
import { Overwrite } from 'utility-types';
import { PageLayoutModule, WalletFieldModule } from '@cc/app/shared';
import { CurrencyFieldComponent } from '@cc/app/shared/components/currency-field';
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
import { SidenavInfoService } from '@cc/app/shared/components/sidenav-info';
import {
PageLayoutModule,
WalletFieldModule,
createDomainObjectColumn,
createPartyColumn,
createWalletColumn,
} from '@cc/app/shared/utils/table2';
} from '@cc/app/shared';
import { CurrencyFieldComponent } from '@cc/app/shared/components/currency-field';
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
import { SidenavInfoService } from '@cc/app/shared/components/sidenav-info';
import { DEBOUNCE_TIME_MS } from '@cc/app/tokens';
import { FlatDecision, getFlatDecisions } from '../../utils/get-flat-decisions';
@ -104,7 +105,7 @@ export class WalletsTermsComponent implements OnInit {
);
hasMore$ = this.walletsTermsService.hasMore$;
isLoading$ = this.walletsTermsService.isLoading$;
columns: Column2<WalletTermSet, FlatDecision>[] = [
columns: Column<WalletTermSet, FlatDecision>[] = [
createWalletColumn((d) => ({ id: d.wallet_id, name: d.wallet_name, partyId: d.owner_id }), {
sticky: 'start',
}),

View File

@ -1,5 +1,5 @@
import { CashFlowPosting } from '@vality/domain-proto/internal/domain';
import { Column2 } from '@vality/ng-core';
import { Column } from '@vality/ng-core';
import { getCashVolumeParts, formatCashVolumes } from '../../../shared';
@ -20,7 +20,7 @@ export function createFeesColumns<T extends object>({
conditionLabel?: string;
feeFilter?: (v: CashFlowPosting) => boolean;
otherFilter?: (v: CashFlowPosting) => boolean;
} = {}): Column2<object, T>[] {
} = {}): Column<object, T>[] {
function getFeeCashVolumeParts(d: T) {
const decision = selectFlatDecision(d);
return decision

View File

@ -29,7 +29,7 @@
}
@if (isFilterTable$ | async) {
<v-table2
<v-table
[columns]="filterColumns"
[data]="filterWallets$ | async"
[hasMore]="filterHasMore$ | async"
@ -37,9 +37,9 @@
name="filterWallets"
(more)="filterMore()"
(update)="filterSearch($event)"
></v-table2>
></v-table>
} @else {
<v-table2
<v-table
[columns]="fullTextSearchColumns"
[data]="fullTextSearchWallets$ | async"
[progress]="fullTextSearchLoading$ | async"
@ -48,6 +48,6 @@
standaloneFilter
(filterChange)="fullTextSearch($event)"
(update)="fullTextSearchReload()"
></v-table2>
></v-table>
}
</cc-page-layout>

View File

@ -13,7 +13,7 @@ import {
getValueChanges,
countChanged,
debounceTimeWithFirst,
Column2,
Column,
DebounceTime,
} from '@vality/ng-core';
import isNil from 'lodash-es/isNil';
@ -23,9 +23,9 @@ import { MemoizeExpiring } from 'typescript-memoize';
import { WalletParams } from '@cc/app/api/fistful-stat/query-dsl/types/wallet';
import { ManagementService } from '@cc/app/api/wallet';
import { createCurrencyColumn, createPartyColumn } from '@cc/app/shared';
import { IdentityManagementService } from '../../api/identity';
import { createCurrencyColumn, createPartyColumn } from '../../shared/utils/table2';
import { DEBOUNCE_TIME_MS } from '../../tokens';
import { PartyStoreService } from '../party';
@ -47,7 +47,7 @@ export class WalletsComponent implements OnInit {
fullTextSearchWallets$ = this.fetchWalletsTextService.result$;
fullTextSearchLoading$ = this.fetchWalletsTextService.isLoading$;
filterColumns: Column2<StatWallet>[] = [
filterColumns: Column<StatWallet>[] = [
{ field: 'id' },
{ field: 'name' },
{ field: 'currency_symbolic_code' },
@ -92,7 +92,7 @@ export class WalletsComponent implements OnInit {
{ hidden: this.partyStoreService.party$.pipe(map((p) => !p)) },
),
];
fullTextSearchColumns: Column2<SearchWalletHit>[] = [
fullTextSearchColumns: Column<SearchWalletHit>[] = [
{ field: 'wallet.id' },
{ field: 'wallet.name' },
createPartyColumn((d) => ({

View File

@ -24,7 +24,7 @@
</ng-template>
</v-filters>
<v-table2
<v-table
[(rowSelected)]="selected"
[columns]="columns"
[data]="withdrawals$ | async"
@ -47,5 +47,5 @@
Create adjustments
</button>
</v-table-actions>
</v-table2>
</v-table>
</cc-page-layout>

View File

@ -17,7 +17,7 @@ import {
getValueChanges,
countChanged,
debounceTimeWithFirst,
Column2,
Column,
} from '@vality/ng-core';
import { getUnionKey } from '@vality/ng-thrift';
import { endOfDay } from 'date-fns';
@ -25,10 +25,10 @@ import startCase from 'lodash-es/startCase';
import { map, shareReplay } from 'rxjs/operators';
import { WithdrawalParams } from '@cc/app/api/fistful-stat';
import { createDomainObjectColumn, createCurrencyColumn } from '@cc/app/shared';
import { createFailureColumn } from '../../shared';
import { FailMachinesDialogComponent, Type } from '../../shared/components/fail-machines-dialog';
import { createDomainObjectColumn, createCurrencyColumn } from '../../shared/utils/table2';
import { DATE_RANGE_DAYS, DEBOUNCE_TIME_MS } from '../../tokens';
import { CreateAdjustmentDialogComponent } from './components/create-adjustment-dialog/create-adjustment-dialog.component';
@ -70,7 +70,7 @@ export class WithdrawalsComponent implements OnInit {
withdrawals$ = this.fetchWithdrawalsService.result$;
inProgress$ = this.fetchWithdrawalsService.isLoading$;
hasMore$ = this.fetchWithdrawalsService.hasMore$;
columns: Column2<StatWithdrawal>[] = [
columns: Column<StatWithdrawal>[] = [
{ field: 'id', sticky: 'start' },
{ field: 'external_id' },
{ field: 'created_at', cell: { type: 'datetime' } },

View File

@ -1,4 +1,4 @@
<v-table2
<v-table
[(rowSelected)]="selected"
[columns]="columns"
[data]="data"
@ -14,4 +14,4 @@
</button>
<ng-content></ng-content>
</v-table-actions>
</v-table2>
</v-table>

View File

@ -14,7 +14,7 @@ import { MatButtonModule } from '@angular/material/button';
import { StatChargeback } from '@vality/magista-proto/magista';
import {
LoadOptions,
Column2,
Column,
TableModule,
DialogService,
createMenuColumn,
@ -24,7 +24,8 @@ import { getUnionKey } from '@vality/ng-thrift';
import startCase from 'lodash-es/startCase';
import { filter } from 'rxjs';
import { createCurrencyColumn, createPartyColumn, createShopColumn } from '../../utils/table2';
import { createCurrencyColumn, createPartyColumn, createShopColumn } from '@cc/app/shared';
import { ChangeChargebacksStatusDialogComponent } from '../change-chargebacks-status-dialog';
@Component({
@ -44,7 +45,7 @@ export class ChargebacksTableComponent {
@Output() update = new EventEmitter<LoadOptions>();
@Output() more = new EventEmitter<void>();
columns: Column2<StatChargeback>[] = [
columns: Column<StatChargeback>[] = [
{ field: 'chargeback_id', header: 'Id' },
{
field: 'chargeback_reason',

View File

@ -1,5 +1,4 @@
<v-table2
[(sort)]="sort"
<v-table
[columns]="columns"
[data]="shops()"
[externalFilter]="filterChange.observed"
@ -8,4 +7,4 @@
standaloneFilter
(filterChange)="filterChange.emit($event)"
(update)="update.emit()"
></v-table2>
></v-table>

View File

@ -10,7 +10,6 @@ import {
} from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { MatCardModule } from '@angular/material/card';
import { Sort } from '@angular/material/sort';
import { Router } from '@angular/router';
import { Shop, Party, PartyID, RoutingRulesetRef } from '@vality/domain-proto/domain';
import {
@ -20,7 +19,7 @@ import {
NotifyLogService,
ConfirmDialogComponent,
DialogResponseStatus,
Column2,
Column,
createMenuColumn,
} from '@vality/ng-core';
import { getUnionKey } from '@vality/ng-thrift';
@ -30,6 +29,8 @@ import { map, switchMap, combineLatest, of } from 'rxjs';
import { filter, shareReplay, startWith, take, first } from 'rxjs/operators';
import { MemoizeExpiring } from 'typescript-memoize';
import { createPartyColumn } from '@cc/app/shared';
import { DomainStoreService } from '../../../api/domain-config';
import { PartyManagementService } from '../../../api/payment-processing';
import {
@ -37,7 +38,6 @@ import {
DelegateWithPaymentInstitution,
} from '../../../sections/routing-rules/party-delegate-rulesets';
import { RoutingRulesType } from '../../../sections/routing-rules/types/routing-rules-type';
import { createPartyColumn } from '../../utils/table2';
import { ShopCardComponent } from '../shop-card/shop-card.component';
import { ShopContractCardComponent } from '../shop-contract-card/shop-contract-card.component';
import { SidenavInfoService } from '../sidenav-info';
@ -76,7 +76,7 @@ export class ShopsTableComponent {
noPartyColumn = input(false, { transform: booleanAttribute });
columns: Column2<ShopParty>[] = [
columns: Column<ShopParty>[] = [
{
field: 'shop.id',
},
@ -201,7 +201,6 @@ export class ShopsTableComponent {
),
),
];
sort: Sort = { active: 'shop.details.name', direction: 'asc' };
constructor(
private sidenavInfoService: SidenavInfoService,

View File

@ -1,3 +1,3 @@
<cc-card title="Terminal #{{ terminalId() }} balances">
<v-table2 [(sort)]="sort" [columns]="columns" [data]="balances$ | async"></v-table2>
<v-table [columns]="columns" [data]="balances$ | async"></v-table>
</cc-card>

View File

@ -1,14 +1,14 @@
import { CommonModule } from '@angular/common';
import { Component, input } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { Sort } from '@angular/material/sort';
import { TableModule, Column2 } from '@vality/ng-core';
import { TableModule, Column } from '@vality/ng-core';
import { AccountBalance } from '@vality/scrooge-proto/internal/account_balance';
import { combineLatest } from 'rxjs';
import { switchMap, shareReplay } from 'rxjs/operators';
import { createCurrencyColumn } from '@cc/app/shared';
import { AccountBalancesStoreService } from '../../../api/terminal-balance';
import { createCurrencyColumn } from '../../utils/table2';
import { CardComponent } from '../sidenav-info/components/card/card.component';
import { DomainThriftViewerComponent } from '../thrift-api-crud';
@ -21,7 +21,7 @@ import { DomainThriftViewerComponent } from '../thrift-api-crud';
export class TerminalBalancesCardComponent {
terminalId = input<number>();
providerId = input<number>();
columns: Column2<AccountBalance>[] = [
columns: Column<AccountBalance>[] = [
{ field: 'account_id' },
createCurrencyColumn((d) => ({ code: d.balance.currency_code, amount: d.balance.amount }), {
header: 'Balance',
@ -35,7 +35,6 @@ export class TerminalBalancesCardComponent {
),
shareReplay({ refCount: true, bufferSize: 1 }),
);
sort: Sort = { active: 'account_id', direction: 'asc' };
constructor(private accountBalancesStoreService: AccountBalancesStoreService) {}
}

View File

@ -7,13 +7,14 @@ import startCase from 'lodash-es/startCase';
import { ReplaySubject, defer, switchMap } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';
import { createPartyColumn, createPredicateColumn } from '@cc/app/shared';
import { DomainStoreService } from '../../../api/domain-config';
import { PartiesStoreService } from '../../../api/payment-processing';
import {
getTerminalShopWalletDelegates,
TerminalShopWalletDelegate,
} from '../../../sections/terminals/utils/get-terminal-shop-wallet-delegates';
import { createPredicateColumn } from '../../utils';
import { SidenavInfoService } from '../sidenav-info';
import { CardComponent } from '../sidenav-info/components/card/card.component';
import { DomainThriftViewerComponent, DomainObjectCardComponent } from '../thrift-api-crud';
@ -32,48 +33,45 @@ export class TerminalDelegatesCardComponent implements OnChanges {
{
header: 'Routing Rule',
field: 'terminalRule.data.name',
description: 'terminalRule.ref.id',
click: (d) => {
cell: (d) => ({
description: d.terminalRule.ref.id,
click: () => {
this.sidenavInfoService.toggle(DomainObjectCardComponent, {
ref: { routing_rules: { id: d.terminalRule.ref.id } },
});
},
}),
},
{
header: 'Ruleset',
field: 'rule.data.name',
description: 'rule.ref.id',
click: (d) => {
cell: (d) => ({
description: d.rule.ref.id,
click: () => {
this.sidenavInfoService.toggle(DomainObjectCardComponent, {
ref: { routing_rules: { id: d.rule.ref.id } },
});
},
}),
},
createPredicateColumn('allowed', (d) => d.candidates[0].allowed),
{
field: 'party',
formatter: (d) =>
this.partiesStoreService
.get(d.delegate.allowed.condition?.party?.id)
.pipe(map((p) => p.contact_info.registration_email)),
description: (d) => d.delegate.allowed.condition?.party?.id,
link: (d) => `/party/${d.delegate.allowed.condition.party.id}`,
},
createPredicateColumn((d) => ({ predicate: d.candidates[0].allowed }), {
header: 'Allowed',
}),
createPartyColumn((d) => ({ id: d.delegate.allowed.condition?.party?.id })),
{
field: 'type',
formatter: (d) =>
startCase(
cell: (d) => ({
value: startCase(
getUnionKey(d.delegate.allowed.condition?.party?.definition).slice(0, -3),
),
}),
},
{
field: 'definition',
formatter: (d) =>
this.partiesStoreService
.get(d.delegate.allowed.condition?.party?.id)
.pipe(
map(
(p) =>
cell: (d) =>
this.partiesStoreService.get(d.delegate.allowed.condition?.party?.id).pipe(
map((p) => ({
value:
(getUnionKey(d.delegate.allowed.condition?.party?.definition) ===
'shop_is'
? p.shops.get(
@ -86,18 +84,18 @@ export class TerminalDelegatesCardComponent implements OnChanges {
d.delegate.allowed.condition?.party?.definition,
),
)?.name) ??
`#${getUnionValue(
d.delegate.allowed.condition?.party?.definition,
)}`,
),
),
description: (d) => getUnionValue(d.delegate.allowed.condition?.party?.definition),
link: (d) =>
`#${getUnionValue(d.delegate.allowed.condition?.party?.definition)}`,
description: getUnionValue(d.delegate.allowed.condition?.party?.definition),
link: () =>
`/party/${d.delegate.allowed.condition.party.id}/routing-rules/${
getUnionKey(d.delegate.allowed.condition?.party?.definition) === 'shop_is'
getUnionKey(d.delegate.allowed.condition?.party?.definition) ===
'shop_is'
? 'payment'
: 'withdrawal'
}/${d.rule.ref.id}/delegate/${d.delegate.ruleset.id}`,
})),
),
},
];
terminalObj$ = defer(() => this.ref$).pipe(

View File

@ -1,35 +1,18 @@
import { inject } from '@angular/core';
import { ContractID, PartyID, ShopID } from '@vality/domain-proto/domain';
import { Column, PossiblyAsync, getPossiblyAsyncObservable } from '@vality/ng-core';
import { combineLatest } from 'rxjs';
import { take } from 'rxjs/operators';
import { createColumn } from '@vality/ng-core';
import { ShopContractCardComponent } from '../../components/shop-contract-card/shop-contract-card.component';
import { ContractCardComponent } from '../../components/contract-card/contract-card.component';
import { SidenavInfoService } from '../../components/sidenav-info';
export function createContractColumn<T extends object>(
selectContractId: (d: T) => PossiblyAsync<ContractID>,
selectPartyId: (d: T) => PossiblyAsync<PartyID>,
selectShopId: (d: T) => PossiblyAsync<ShopID>,
): Column<T> {
export const createContractColumn = createColumn(
({ id, partyId }: { id: string; partyId: string }) => {
const sidenavInfoService = inject(SidenavInfoService);
return {
field: 'contract',
header: 'Contract',
formatter: selectContractId,
click: (d) => {
combineLatest([
getPossiblyAsyncObservable(selectPartyId(d)),
getPossiblyAsyncObservable(selectShopId(d)),
])
.pipe(take(1))
.subscribe(([partyId, id]) => {
sidenavInfoService.toggle(ShopContractCardComponent, {
partyId,
id,
});
});
value: id,
click: () => {
sidenavInfoService.toggle(ContractCardComponent, { id, partyId });
},
};
}
},
{ header: 'Contract' },
);

View File

@ -1,95 +1,71 @@
import { getCurrencySymbol } from '@angular/common';
import { inject, LOCALE_ID } from '@angular/core';
import {
CurrencyColumn,
PossiblyAsync,
getPossiblyAsyncObservable,
Column,
switchCombineWith,
formatCurrency,
} from '@vality/ng-core';
import isNil from 'lodash-es/isNil';
import { combineLatest, switchMap, of, forkJoin, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { createColumn, formatCurrency } from '@vality/ng-core';
import { groupBy, uniq } from 'lodash-es';
import { of, combineLatest } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { DomainStoreService } from '../../../api/domain-config';
import { AmountCurrencyService } from '../../services';
export function createCurrencyColumn<T extends object>(
field: CurrencyColumn<T>['field'],
selectAmount: (d: T) => PossiblyAsync<number>,
selectSymbolicCode: (d: T) => PossiblyAsync<string>,
params: Partial<CurrencyColumn<T>> = {},
): CurrencyColumn<T> {
const amountCurrencyService = inject(AmountCurrencyService);
return {
field,
type: 'currency',
formatter: (d: T) =>
combineLatest([
getPossiblyAsyncObservable(selectAmount(d)),
getPossiblyAsyncObservable(selectSymbolicCode(d)),
]).pipe(
switchMap(([amount, code]) =>
isNil(amount) ? of(undefined) : amountCurrencyService.toMajor(amount, code),
),
),
typeParameters: {
currencyCode: (d: T) => getPossiblyAsyncObservable(selectSymbolicCode(d)),
exponent: (d: T) =>
getPossiblyAsyncObservable(selectSymbolicCode(d)).pipe(
switchMap((code) => amountCurrencyService.getCurrency(code)),
map((c) => c?.exponent),
),
},
...params,
};
interface CurrencyValue {
amount: number;
code: string;
}
export function createCurrenciesColumn<T extends object>(
field: CurrencyColumn<T>['field'],
selectAmountSymbolicCode: (d: T) => PossiblyAsync<{ amount: number; symbolicCode: string }[]>,
params: Partial<CurrencyColumn<T>> = {},
): Column<T> {
function formatCurrencyValue(value: CurrencyValue) {
const amountCurrencyService = inject(AmountCurrencyService);
const localeId = inject(LOCALE_ID);
const locale = inject(LOCALE_ID);
return amountCurrencyService.getCurrency(value.code).pipe(
map((currencyObj) =>
formatCurrency(value.amount, value.code, 'long', locale, currencyObj?.exponent),
),
startWith(
(value.amount === 0 ? '0' : '…') +
' ' +
getCurrencySymbol(value.code, 'narrow', locale),
),
);
}
function getBalancesList(amountCodes$: Observable<{ amount: number; symbolicCode: string }[]>) {
return amountCodes$.pipe(
switchCombineWith((amountCodes) =>
!amountCodes?.length
? ([] as Observable<number[]>[])
: [
forkJoin(
amountCodes.map((a) =>
amountCurrencyService.toMajor(a.amount, a.symbolicCode),
),
),
],
),
map(([amountCodes, majorAmounts]) =>
amountCodes
.map((a, idx) =>
formatCurrency(
majorAmounts[idx],
a.symbolicCode,
undefined,
localeId,
undefined,
true,
),
)
.join(' / '),
function formatCurrencyValues(values: CurrencyValue[], separator = ' | ') {
return combineLatest(values.map(formatCurrencyValue)).pipe(map((v) => v.join(separator)));
}
export const createCurrencyColumn = createColumn(
(currencyValue: CurrencyValue | { values: CurrencyValue[]; isSum?: boolean }) => {
const isSum = 'isSum' in currencyValue ? currencyValue.isSum : false;
const currencyValues = ('values' in currencyValue ? currencyValue.values : [currencyValue])
.filter(Boolean)
.sort((a, b) => b.amount - a.amount);
if (!currencyValues?.length) {
return of(undefined);
}
const currencyValuesByCode = groupBy(currencyValues, 'code');
let currencyValuesByCodeList = uniq(currencyValues.map((v) => v.code)).map(
(code) => currencyValuesByCode[code],
);
if (isSum) {
currencyValuesByCodeList = currencyValuesByCodeList.map((g) =>
g.reduce(
(sum, v) => {
sum[0].amount += v.amount;
return sum;
},
[{ code: g[0].code, amount: 0 }],
),
);
}
const getAmountCodes = (d: T) =>
getPossiblyAsyncObservable(selectAmountSymbolicCode(d)).pipe(
map((amountCodes) => (amountCodes || []).sort((a, b) => b.amount - a.amount)),
const domainStoreService = inject(DomainStoreService);
return combineLatest([
combineLatest(currencyValuesByCodeList.map((g) => formatCurrencyValues(g))),
domainStoreService.isLoading$,
]).pipe(
map(([currencyValueStrings, inProgress]) => ({
value: currencyValueStrings[0],
description: currencyValueStrings.slice(1).join('; '),
inProgress,
})),
);
return {
field,
formatter: (d: T) => getBalancesList(getAmountCodes(d).pipe(map((a) => a?.slice?.(0, 1)))),
description: (d: T) => getBalancesList(getAmountCodes(d).pipe(map((a) => a?.slice?.(1)))),
...params,
} as Column<T>;
}
},
);

View File

@ -1,42 +1,37 @@
import { inject } from '@angular/core';
import { Reference } from '@vality/domain-proto/domain';
import { PossiblyAsync, getPossiblyAsyncObservable, type ColumnObject } from '@vality/ng-core';
import startCase from 'lodash-es/startCase';
import { map, switchMap, first } from 'rxjs/operators';
import { ValuesType } from 'utility-types';
import { Reference } from '@vality/domain-proto/internal/domain';
import { createColumn } from '@vality/ng-core';
import { getUnionValue, getUnionKey } from '@vality/ng-thrift';
import { map, startWith } from 'rxjs/operators';
import { DomainStoreService } from '../../../api/domain-config';
import { SidenavInfoService } from '../../components/sidenav-info';
import {
getDomainObjectDetails,
DomainObjectCardComponent,
getDomainObjectDetails,
} from '../../components/thrift-api-crud';
export function createDomainObjectColumn<T extends object>(
objectKey: keyof Reference,
selectDomainObjectRef: (d: T) => PossiblyAsync<ValuesType<Reference>>,
params: Partial<ColumnObject<T>> = {},
): ColumnObject<T> {
const domainStoreService = inject(DomainStoreService);
const sidenavInfoService = inject(SidenavInfoService);
const getObjectRef = (d: T) =>
getPossiblyAsyncObservable(selectDomainObjectRef(d)).pipe(
map((ref): Reference => ({ [objectKey]: ref })),
);
const getObject = (d: T) =>
getObjectRef(d).pipe(switchMap((ref) => domainStoreService.getObject(ref)));
return {
field: `domain_object_${objectKey}`,
header: startCase(objectKey),
description: (d) => getObject(d).pipe(map((o) => getDomainObjectDetails(o)?.id)),
formatter: (d) => getObject(d).pipe(map((o) => getDomainObjectDetails(o)?.label)),
click: (d) => {
getObjectRef(d)
.pipe(first())
.subscribe((ref) => {
sidenavInfoService.toggle(DomainObjectCardComponent, { ref });
});
export const createDomainObjectColumn = createColumn(({ ref }: { ref: Reference }) => {
const sourceObj = {
[getUnionKey(ref)]: { ref: getUnionValue(ref), data: {} },
};
return inject(DomainStoreService)
.getObject(ref)
.pipe(
map((obj) => ({
value: getDomainObjectDetails(obj).label || '',
description: getDomainObjectDetails(obj).id || '',
click: () => {
inject(SidenavInfoService).toggle(DomainObjectCardComponent, { ref });
},
...params,
} as ColumnObject<T>;
}
})),
startWith({
value: getDomainObjectDetails(sourceObj).label || '',
description: getDomainObjectDetails(sourceObj).id || '',
click: () => {
inject(SidenavInfoService).toggle(DomainObjectCardComponent, { ref });
},
inProgress: true,
}),
);
});

View File

@ -1,49 +1,32 @@
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { PossiblyAsync, ColumnObject, getPossiblyAsyncObservable } from '@vality/ng-core';
import get from 'lodash-es/get';
import { createColumn } from '@vality/ng-core';
import { of } from 'rxjs';
import { switchMap, map, take } from 'rxjs/operators';
import { map, startWith } from 'rxjs/operators';
import { PartiesStoreService } from '../../../api/payment-processing';
export function createPartyColumn<T extends object>(
field: ColumnObject<T>['field'],
selectPartyId?: (d: T) => PossiblyAsync<string>,
selectPartyEmail?: (d: T) => PossiblyAsync<string>,
params: Partial<ColumnObject<T>> = {},
): ColumnObject<T> {
const partiesStoreService = inject(PartiesStoreService);
const router = inject(Router);
if (!selectPartyId) {
selectPartyId = (d) => get(d, field);
}
if (!selectPartyEmail) {
selectPartyEmail = (d: T) =>
getPossiblyAsyncObservable(selectPartyId(d)).pipe(
switchMap((partyId) =>
partyId
? partiesStoreService.get(partyId)
: of({ contact_info: { registration_email: '' } }),
),
map((p) => p.contact_info.registration_email),
export const createPartyColumn = createColumn(
({ id, ...params }: { id: string; partyName?: string }) => {
const partyName$ =
'partyName' in params
? of(params.partyName)
: inject(PartiesStoreService)
.get(id)
.pipe(map((party) => party.contact_info.registration_email));
const partyCell = {
description: id,
link: () => `/party/${id}`,
};
return partyName$.pipe(
map((partyName) => ({
...partyCell,
value: partyName,
})),
startWith({
...partyCell,
inProgress: true,
}),
);
}
return {
field,
header: 'Party',
description: selectPartyId,
formatter: selectPartyEmail,
click: (d) => {
getPossiblyAsyncObservable(selectPartyId(d))
.pipe(
take(1),
map((id) => `/party/${id}`),
)
.subscribe((url) => {
void router.navigate([url]);
});
},
...params,
} as ColumnObject<T>;
}
{ header: 'Party' },
);

View File

@ -1,35 +1,18 @@
import { Predicate } from '@vality/domain-proto/domain';
import {
ColumnObject,
TagColumn,
PossiblyAsync,
getPossiblyAsyncObservable,
} from '@vality/ng-core';
import { map } from 'rxjs/operators';
import { createColumn } from '@vality/ng-core';
import { formatPredicate } from './format-predicate';
import { formatPredicate } from '.';
export function createPredicateColumn<T extends object>(
field: ColumnObject<T>['field'],
select: (d: T) => PossiblyAsync<Predicate>,
params: Partial<ColumnObject<T>> = {},
): TagColumn<T> {
const formatter = (d: T) =>
getPossiblyAsyncObservable(select(d)).pipe(map((predicate) => formatPredicate(predicate)));
export const createPredicateColumn = createColumn(
({ predicate }: { predicate: Predicate }) => {
const value = formatPredicate(predicate);
return {
field,
formatter,
type: 'tag',
sortable: true,
typeParameters: {
label: formatter,
tags: {
/* eslint-disable @typescript-eslint/naming-convention */
True: { color: 'success' },
False: { color: 'warn' },
/* eslint-enable @typescript-eslint/naming-convention */
value,
color: {
True: 'success',
False: 'warn',
}[value],
};
},
},
...params,
} as TagColumn<T>;
}
{ header: 'Predicate' },
);

View File

@ -1,52 +1,37 @@
import { inject } from '@angular/core';
import { PossiblyAsync, ColumnObject, getPossiblyAsyncObservable } from '@vality/ng-core';
import get from 'lodash-es/get';
import { combineLatest } from 'rxjs';
import { map, switchMap, take } from 'rxjs/operators';
import { createColumn } from '@vality/ng-core';
import { of } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { PartiesStoreService } from '../../../api/payment-processing';
import { ShopCardComponent } from '../../components/shop-card/shop-card.component';
import { SidenavInfoService } from '../../components/sidenav-info';
export function createShopColumn<T extends object>(
field: ColumnObject<T>['field'],
selectPartyId: (d: T) => PossiblyAsync<string>,
selectShopId?: (d: T) => PossiblyAsync<string>,
selectShopName?: (d: T) => PossiblyAsync<string>,
params: Partial<ColumnObject<T>> = {},
): ColumnObject<T> {
if (!selectShopId) {
selectShopId = (d) => get(d, field);
}
if (!selectShopName) {
const partiesStoreService = inject(PartiesStoreService);
selectShopName = (d) =>
getPossiblyAsyncObservable(selectPartyId(d)).pipe(
switchMap((partyId) =>
combineLatest([
partiesStoreService.get(partyId),
getPossiblyAsyncObservable(selectShopId(d)),
]),
),
map(([party, shopId]) => party.shops.get(shopId).details.name),
);
}
export const createShopColumn = createColumn(
({ shopId, partyId, ...params }: { shopId: string; partyId: string; shopName?: string }) => {
const name$ =
'shopName' in params
? of(params.shopName)
: inject(PartiesStoreService)
.get(partyId)
.pipe(map((party) => party.shops.get(shopId).details.name));
const sidenavInfoService = inject(SidenavInfoService);
return {
field,
header: 'Shop',
description: (d) => getPossiblyAsyncObservable(selectShopId(d)),
formatter: (d) => getPossiblyAsyncObservable(selectShopName(d)),
click: (d) => {
combineLatest([
getPossiblyAsyncObservable(selectPartyId(d)),
getPossiblyAsyncObservable(selectShopId(d)),
])
.pipe(take(1))
.subscribe(([partyId, id]) => {
sidenavInfoService.toggle(ShopCardComponent, { id, partyId });
});
const shopCell = {
description: shopId,
click: () => {
sidenavInfoService.toggle(ShopCardComponent, { id: shopId, partyId });
},
...params,
} as ColumnObject<T>;
}
};
return name$.pipe(
map((shopName) => ({
...shopCell,
value: shopName,
})),
startWith({
...shopCell,
inProgress: true,
}),
);
},
{ header: 'Shop' },
);

View File

@ -1,12 +0,0 @@
import { Column, PossiblyAsync, getPossiblyAsyncObservable } from '@vality/ng-core';
import { map } from 'rxjs/operators';
import { createDomainObjectColumn } from './create-domain-object-column';
export function createTerminalColumn<T extends object>(
selectTerminalId: (d: T) => PossiblyAsync<number>,
): Column<T> {
return createDomainObjectColumn('terminal', (d) =>
getPossiblyAsyncObservable(selectTerminalId(d)).pipe(map((id) => ({ id }))),
);
}

View File

@ -1,39 +1,29 @@
import { inject } from '@angular/core';
import { PossiblyAsync, ColumnObject, getPossiblyAsyncObservable } from '@vality/ng-core';
import get from 'lodash-es/get';
import { combineLatest } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { createColumn } from '@vality/ng-core';
import { of } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { PartiesStoreService } from '../../../api/payment-processing';
import { PartiesStoreService } from '@cc/app/api/payment-processing';
export function createWalletColumn<T extends object>(
field: ColumnObject<T>['field'],
selectPartyId: (d: T) => PossiblyAsync<string>,
selectWalletId?: (d: T) => PossiblyAsync<string>,
selectWalletName?: (d: T) => PossiblyAsync<string>,
params: Partial<ColumnObject<T>> = {},
): ColumnObject<T> {
if (!selectWalletId) {
selectWalletId = (d) => get(d, field);
}
if (!selectWalletName) {
const partiesStoreService = inject(PartiesStoreService);
selectWalletName = (d) =>
getPossiblyAsyncObservable(selectPartyId(d)).pipe(
switchMap((partyId) =>
combineLatest([
partiesStoreService.get(partyId),
getPossiblyAsyncObservable(selectWalletId(d)),
]),
),
map(([party, walletId]) => party.wallets.get(walletId)?.name),
export const createWalletColumn = createColumn(
({ id, partyId, ...params }: { id: string; partyId: string; name?: string }) => {
const name$ =
'name' in params
? of(params.name)
: inject(PartiesStoreService)
.getWallet(id, partyId)
.pipe(map((wallet) => wallet?.name));
const cell = { description: id };
return name$.pipe(
map((name) => ({
...cell,
value: name,
})),
startWith({
...cell,
inProgress: true,
}),
);
}
return {
field,
header: 'Wallet',
description: (d) => getPossiblyAsyncObservable(selectWalletId(d)),
formatter: (d) => getPossiblyAsyncObservable(selectWalletName(d)),
...params,
} as ColumnObject<T>;
}
},
{ header: 'Wallet' },
);

View File

@ -1,11 +1,12 @@
export * from './create-currency-column';
export * from './create-party-column';
export * from './create-shop-column';
export * from './create-predicate-column';
export * from './create-failure-column';
export * from './create-contract-column';
export * from './format-cash-volume';
export * from './format-rational';
export * from './format-predicate';
export * from './create-wallet-column';
export * from './get-cash-volume-parts';
export * from './create-contract-column';
export * from './create-currency-column';
export * from './create-domain-object-column';
export * from './create-predicate-column';
export * from './create-shop-column';
export * from './create-wallet-column';
export * from './create-party-column';

View File

@ -1,18 +0,0 @@
import { inject } from '@angular/core';
import { createColumn } from '@vality/ng-core';
import { ContractCardComponent } from '../../components/contract-card/contract-card.component';
import { SidenavInfoService } from '../../components/sidenav-info';
export const createContractColumn = createColumn(
({ id, partyId }: { id: string; partyId: string }) => {
const sidenavInfoService = inject(SidenavInfoService);
return {
value: id,
click: () => {
sidenavInfoService.toggle(ContractCardComponent, { id, partyId });
},
};
},
{ header: 'Contract' },
);

View File

@ -1,71 +0,0 @@
import { getCurrencySymbol } from '@angular/common';
import { inject, LOCALE_ID } from '@angular/core';
import { createColumn, formatCurrency } from '@vality/ng-core';
import { groupBy, uniq } from 'lodash-es';
import { of, combineLatest } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { DomainStoreService } from '../../../api/domain-config';
import { AmountCurrencyService } from '../../services';
interface CurrencyValue {
amount: number;
code: string;
}
function formatCurrencyValue(value: CurrencyValue) {
const amountCurrencyService = inject(AmountCurrencyService);
const locale = inject(LOCALE_ID);
return amountCurrencyService.getCurrency(value.code).pipe(
map((currencyObj) =>
formatCurrency(value.amount, value.code, 'long', locale, currencyObj?.exponent),
),
startWith(
(value.amount === 0 ? '0' : '…') +
' ' +
getCurrencySymbol(value.code, 'narrow', locale),
),
);
}
function formatCurrencyValues(values: CurrencyValue[], separator = ' | ') {
return combineLatest(values.map(formatCurrencyValue)).pipe(map((v) => v.join(separator)));
}
export const createCurrencyColumn = createColumn(
(currencyValue: CurrencyValue | { values: CurrencyValue[]; isSum?: boolean }) => {
const isSum = 'isSum' in currencyValue ? currencyValue.isSum : false;
const currencyValues = ('values' in currencyValue ? currencyValue.values : [currencyValue])
.filter(Boolean)
.sort((a, b) => b.amount - a.amount);
if (!currencyValues?.length) {
return of(undefined);
}
const currencyValuesByCode = groupBy(currencyValues, 'code');
let currencyValuesByCodeList = uniq(currencyValues.map((v) => v.code)).map(
(code) => currencyValuesByCode[code],
);
if (isSum) {
currencyValuesByCodeList = currencyValuesByCodeList.map((g) =>
g.reduce(
(sum, v) => {
sum[0].amount += v.amount;
return sum;
},
[{ code: g[0].code, amount: 0 }],
),
);
}
const domainStoreService = inject(DomainStoreService);
return combineLatest([
combineLatest(currencyValuesByCodeList.map((g) => formatCurrencyValues(g))),
domainStoreService.isLoading$,
]).pipe(
map(([currencyValueStrings, inProgress]) => ({
value: currencyValueStrings[0],
description: currencyValueStrings.slice(1).join('; '),
inProgress,
})),
);
},
);

View File

@ -1,37 +0,0 @@
import { inject } from '@angular/core';
import { Reference } from '@vality/domain-proto/internal/domain';
import { createColumn } from '@vality/ng-core';
import { getUnionValue, getUnionKey } from '@vality/ng-thrift';
import { map, startWith } from 'rxjs/operators';
import { DomainStoreService } from '../../../api/domain-config';
import { SidenavInfoService } from '../../components/sidenav-info';
import {
DomainObjectCardComponent,
getDomainObjectDetails,
} from '../../components/thrift-api-crud';
export const createDomainObjectColumn = createColumn(({ ref }: { ref: Reference }) => {
const sourceObj = {
[getUnionKey(ref)]: { ref: getUnionValue(ref), data: {} },
};
return inject(DomainStoreService)
.getObject(ref)
.pipe(
map((obj) => ({
value: getDomainObjectDetails(obj).label || '',
description: getDomainObjectDetails(obj).id || '',
click: () => {
inject(SidenavInfoService).toggle(DomainObjectCardComponent, { ref });
},
})),
startWith({
value: getDomainObjectDetails(sourceObj).label || '',
description: getDomainObjectDetails(sourceObj).id || '',
click: () => {
inject(SidenavInfoService).toggle(DomainObjectCardComponent, { ref });
},
inProgress: true,
}),
);
});

View File

@ -1,32 +0,0 @@
import { inject } from '@angular/core';
import { createColumn } from '@vality/ng-core';
import { of } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { PartiesStoreService } from '../../../api/payment-processing';
export const createPartyColumn = createColumn(
({ id, ...params }: { id: string; partyName?: string }) => {
const partyName$ =
'partyName' in params
? of(params.partyName)
: inject(PartiesStoreService)
.get(id)
.pipe(map((party) => party.contact_info.registration_email));
const partyCell = {
description: id,
link: () => `/party/${id}`,
};
return partyName$.pipe(
map((partyName) => ({
...partyCell,
value: partyName,
})),
startWith({
...partyCell,
inProgress: true,
}),
);
},
{ header: 'Party' },
);

View File

@ -1,18 +0,0 @@
import { Predicate } from '@vality/domain-proto/domain';
import { createColumn } from '@vality/ng-core';
import { formatPredicate } from '../table';
export const createPredicateColumn = createColumn(
({ predicate }: { predicate: Predicate }) => {
const value = formatPredicate(predicate);
return {
value,
color: {
True: 'success',
False: 'warn',
}[value],
};
},
{ header: 'Predicate' },
);

View File

@ -1,37 +0,0 @@
import { inject } from '@angular/core';
import { createColumn } from '@vality/ng-core';
import { of } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { PartiesStoreService } from '../../../api/payment-processing';
import { ShopCardComponent } from '../../components/shop-card/shop-card.component';
import { SidenavInfoService } from '../../components/sidenav-info';
export const createShopColumn = createColumn(
({ shopId, partyId, ...params }: { shopId: string; partyId: string; shopName?: string }) => {
const shopName$ =
'shopName' in params
? of(params.shopName)
: inject(PartiesStoreService)
.get(partyId)
.pipe(map((party) => party.shops.get(shopId).details.name));
const sidenavInfoService = inject(SidenavInfoService);
const shopCell = {
description: shopId,
click: () => {
sidenavInfoService.toggle(ShopCardComponent, { id: shopId, partyId });
},
};
return shopName$.pipe(
map((shopName) => ({
...shopCell,
value: shopName,
})),
startWith({
...shopCell,
inProgress: true,
}),
);
},
{ header: 'Shop' },
);

View File

@ -1,24 +0,0 @@
import { inject } from '@angular/core';
import { createColumn } from '@vality/ng-core';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
import { PartiesStoreService } from '../../../api/payment-processing';
export const createWalletColumn = createColumn(
({ id, partyId, ...params }: { id: string; partyId: string; name?: string }) => {
const shopName$ =
'name' in params
? of(params.name)
: inject(PartiesStoreService)
.get(partyId)
.pipe(map((party) => party.wallets.get(id).name));
return shopName$.pipe(
map((name) => ({
value: name,
description: id,
})),
);
},
{ header: 'Wallet' },
);

View File

@ -1,7 +0,0 @@
export * from './create-shop-column';
export * from './create-party-column';
export * from './create-wallet-column';
export * from './create-contract-column';
export * from './create-domain-object-column';
export * from './create-currency-column';
export * from './create-predicate-column';

View File

@ -40,7 +40,7 @@
[(rowSelected)]="selectedCsv"
[columns]="columns()"
[data]="data$ | async"
noActions
noDownload
rowSelectable
></v-table>
</div>