mirror of
https://github.com/valitydev/control-center.git
synced 2024-11-06 02:25:17 +00:00
IMP-32: New predicates in payment routing rules (#91)
This commit is contained in:
parent
53ac6091e8
commit
ed44c4c608
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"include": "node_modules/@rbkmoney/angular-templates/**",
|
|
||||||
"template": {
|
|
||||||
"prefix": "cc"
|
|
||||||
}
|
|
||||||
}
|
|
@ -34,7 +34,6 @@ import { PaymentAdjustmentModule } from './sections/payment-adjustment/payment-a
|
|||||||
import { PayoutsModule } from './sections/payouts';
|
import { PayoutsModule } from './sections/payouts';
|
||||||
import { SearchClaimsModule } from './sections/search-claims/search-claims.module';
|
import { SearchClaimsModule } from './sections/search-claims/search-claims.module';
|
||||||
import { SearchPartiesModule } from './sections/search-parties/search-parties.module';
|
import { SearchPartiesModule } from './sections/search-parties/search-parties.module';
|
||||||
import { SettingsModule } from './settings';
|
|
||||||
import { ThemeManager, ThemeManagerModule, ThemeName } from './theme-manager';
|
import { ThemeManager, ThemeManagerModule, ThemeName } from './theme-manager';
|
||||||
import {
|
import {
|
||||||
DEFAULT_DIALOG_CONFIG,
|
DEFAULT_DIALOG_CONFIG,
|
||||||
@ -69,7 +68,6 @@ moment.locale('en');
|
|||||||
DomainModule,
|
DomainModule,
|
||||||
RepairingModule,
|
RepairingModule,
|
||||||
ThemeManagerModule,
|
ThemeManagerModule,
|
||||||
SettingsModule,
|
|
||||||
PartyModule,
|
PartyModule,
|
||||||
SearchPartiesModule,
|
SearchPartiesModule,
|
||||||
SearchClaimsModule,
|
SearchClaimsModule,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<cc-metadata-form
|
<cc-metadata-form
|
||||||
[formControl]="control"
|
[formControl]="control"
|
||||||
[metadata]="metadata$ | async"
|
[metadata]="metadata$ | async"
|
||||||
[extensions]="extensions"
|
[extensions]="extensions$ | async"
|
||||||
namespace="claim_management"
|
namespace="claim_management"
|
||||||
[type]="type"
|
[type]="type"
|
||||||
></cc-metadata-form>
|
></cc-metadata-form>
|
||||||
|
@ -3,19 +3,19 @@ import { ValidationErrors, Validator } from '@angular/forms';
|
|||||||
import { WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
import { WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
||||||
import { Claim } from '@vality/domain-proto/lib/claim_management';
|
import { Claim } from '@vality/domain-proto/lib/claim_management';
|
||||||
import { Party } from '@vality/domain-proto/lib/domain';
|
import { Party } from '@vality/domain-proto/lib/domain';
|
||||||
import { from } from 'rxjs';
|
import { from, Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ComponentChanges, MetadataFormExtension } from '@cc/app/shared';
|
import { ComponentChanges, MetadataFormExtension } from '@cc/app/shared';
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services/domain-metadata-form-extensions';
|
||||||
|
import { createControlProviders } from '@cc/utils';
|
||||||
|
|
||||||
import { DomainStoreService } from '../../../../thrift-services/damsel/domain-store.service';
|
|
||||||
import { createDomainObjectMetadataFormExtension } from './utils/create-domain-object-metadata-form.extension';
|
|
||||||
import { createPartyClaimMetadataFormExtensions } from './utils/create-party-claim-metadata-form-extensions';
|
import { createPartyClaimMetadataFormExtensions } from './utils/create-party-claim-metadata-form-extensions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-modification-form',
|
selector: 'cc-modification-form',
|
||||||
templateUrl: './modification-form.component.html',
|
templateUrl: './modification-form.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(ModificationFormComponent),
|
providers: createControlProviders(ModificationFormComponent),
|
||||||
})
|
})
|
||||||
export class ModificationFormComponent
|
export class ModificationFormComponent
|
||||||
extends WrappedFormControlSuperclass<unknown>
|
extends WrappedFormControlSuperclass<unknown>
|
||||||
@ -26,37 +26,28 @@ export class ModificationFormComponent
|
|||||||
@Input() type: string;
|
@Input() type: string;
|
||||||
|
|
||||||
metadata$ = from(import('@vality/domain-proto/lib/metadata.json').then((m) => m.default));
|
metadata$ = from(import('@vality/domain-proto/lib/metadata.json').then((m) => m.default));
|
||||||
extensions: MetadataFormExtension[];
|
extensions$: Observable<MetadataFormExtension[]>;
|
||||||
|
|
||||||
constructor(injector: Injector, private domainStoreService: DomainStoreService) {
|
constructor(
|
||||||
|
injector: Injector,
|
||||||
|
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService
|
||||||
|
) {
|
||||||
super(injector);
|
super(injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: ComponentChanges<ModificationFormComponent>) {
|
ngOnChanges(changes: ComponentChanges<ModificationFormComponent>) {
|
||||||
super.ngOnChanges(changes);
|
super.ngOnChanges(changes);
|
||||||
if (changes.party || changes.claim) {
|
if (changes.party || changes.claim) {
|
||||||
this.extensions = [
|
this.extensions$ = this.domainMetadataFormExtensionsService.extensions$.pipe(
|
||||||
|
map((e) => [
|
||||||
...createPartyClaimMetadataFormExtensions(this.party, this.claim),
|
...createPartyClaimMetadataFormExtensions(this.party, this.claim),
|
||||||
...this.createDomainMetadataFormExtensions(),
|
...e,
|
||||||
];
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
validate(): ValidationErrors | null {
|
||||||
return this.control.errors;
|
return this.control.errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createDomainMetadataFormExtensions(): MetadataFormExtension[] {
|
|
||||||
return [
|
|
||||||
createDomainObjectMetadataFormExtension('ContractTemplateRef', () =>
|
|
||||||
this.domainStoreService.getObjects('contract_template')
|
|
||||||
),
|
|
||||||
createDomainObjectMetadataFormExtension('PaymentInstitutionRef', () =>
|
|
||||||
this.domainStoreService.getObjects('payment_institution')
|
|
||||||
),
|
|
||||||
createDomainObjectMetadataFormExtension('CategoryRef', () =>
|
|
||||||
this.domainStoreService.getObjects('category')
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
<div fxLayout="column" fxLayoutGap="32px">
|
<cc-base-dialog title="Change Delegate Ruleset">
|
||||||
<div class="cc-headline">Change Delegate Ruleset</div>
|
|
||||||
|
|
||||||
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Delegate Ruleset</mat-label>
|
<mat-label>Delegate Ruleset</mat-label>
|
||||||
@ -16,10 +14,9 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxLayout fxLayoutAlign="space-between">
|
<cc-base-dialog-actions>
|
||||||
<button mat-button (click)="cancel()">CANCEL</button>
|
|
||||||
<button mat-button color="primary" (click)="changeRuleset()" [disabled]="form.invalid">
|
<button mat-button color="primary" (click)="changeRuleset()" [disabled]="form.invalid">
|
||||||
CHANGE RULESET
|
CHANGE RULESET
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</cc-base-dialog-actions>
|
||||||
</div>
|
</cc-base-dialog>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { BaseDialogSuperclass } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { RoutingRulesService } from '../../../thrift-services';
|
import { RoutingRulesService } from '../../../thrift-services';
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@ -12,7 +13,13 @@ import { RoutingRulesService } from '../../../thrift-services';
|
|||||||
templateUrl: 'change-delegate-ruleset-dialog.component.html',
|
templateUrl: 'change-delegate-ruleset-dialog.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ChangeDelegateRulesetDialogComponent implements OnInit {
|
export class ChangeDelegateRulesetDialogComponent
|
||||||
|
extends BaseDialogSuperclass<
|
||||||
|
ChangeDelegateRulesetDialogComponent,
|
||||||
|
{ mainRulesetRefID: number; delegateIdx: number }
|
||||||
|
>
|
||||||
|
implements OnInit
|
||||||
|
{
|
||||||
form = this.fb.group({
|
form = this.fb.group({
|
||||||
rulesetRefId: [],
|
rulesetRefId: [],
|
||||||
description: '',
|
description: '',
|
||||||
@ -21,17 +28,18 @@ export class ChangeDelegateRulesetDialogComponent implements OnInit {
|
|||||||
rulesets$ = this.routingRulesService.rulesets$;
|
rulesets$ = this.routingRulesService.rulesets$;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
injector: Injector,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dialogRef: MatDialogRef<ChangeDelegateRulesetDialogComponent>,
|
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { mainRulesetRefID: number; delegateIdx: number },
|
|
||||||
private routingRulesService: RoutingRulesService
|
private routingRulesService: RoutingRulesService
|
||||||
) {}
|
) {
|
||||||
|
super(injector);
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.routingRulesService
|
this.routingRulesService
|
||||||
.getRuleset(this.data.mainRulesetRefID)
|
.getRuleset(this.dialogData.mainRulesetRefID)
|
||||||
.pipe(
|
.pipe(
|
||||||
map((r) => r?.data?.decisions?.delegates?.[this.data?.delegateIdx]),
|
map((r) => r?.data?.decisions?.delegates?.[this.dialogData?.delegateIdx]),
|
||||||
untilDestroyed(this)
|
untilDestroyed(this)
|
||||||
)
|
)
|
||||||
.subscribe((delegate) => {
|
.subscribe((delegate) => {
|
||||||
@ -42,15 +50,11 @@ export class ChangeDelegateRulesetDialogComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
changeRuleset() {
|
changeRuleset() {
|
||||||
this.routingRulesService
|
this.routingRulesService
|
||||||
.changeDelegateRuleset({
|
.changeDelegateRuleset({
|
||||||
mainRulesetRefID: this.data.mainRulesetRefID,
|
mainRulesetRefID: this.dialogData.mainRulesetRefID,
|
||||||
delegateIdx: this.data.delegateIdx,
|
delegateIdx: this.dialogData.delegateIdx,
|
||||||
newDelegateRulesetRefID: this.form.value.rulesetRefId,
|
newDelegateRulesetRefID: this.form.value.rulesetRefId,
|
||||||
description: this.form.value.description,
|
description: this.form.value.description,
|
||||||
})
|
})
|
||||||
|
@ -6,6 +6,8 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
|
import { BaseDialogModule } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { ChangeDelegateRulesetDialogComponent } from './change-delegate-ruleset-dialog.component';
|
import { ChangeDelegateRulesetDialogComponent } from './change-delegate-ruleset-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -17,6 +19,7 @@ import { ChangeDelegateRulesetDialogComponent } from './change-delegate-ruleset-
|
|||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
|
BaseDialogModule,
|
||||||
],
|
],
|
||||||
declarations: [ChangeDelegateRulesetDialogComponent],
|
declarations: [ChangeDelegateRulesetDialogComponent],
|
||||||
exports: [ChangeDelegateRulesetDialogComponent],
|
exports: [ChangeDelegateRulesetDialogComponent],
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
<div fxLayout="column" fxLayoutGap="32px">
|
<cc-base-dialog title="Change main ruleset">
|
||||||
<div class="cc-headline">Change main ruleset</div>
|
|
||||||
|
|
||||||
<cc-target-ruleset-form
|
<cc-target-ruleset-form
|
||||||
(valueChanges)="targetRuleset$.next($event)"
|
(valueChanges)="targetRuleset$.next($event)"
|
||||||
[value]="initValue"
|
[value]="initValue"
|
||||||
(valid)="targetRulesetValid$.next($event)"
|
(valid)="targetRulesetValid$.next($event)"
|
||||||
></cc-target-ruleset-form>
|
></cc-target-ruleset-form>
|
||||||
|
|
||||||
<div fxLayout fxLayoutAlign="space-between">
|
<cc-base-dialog-actions>
|
||||||
<button mat-button (click)="cancel()">CANCEL</button>
|
|
||||||
<button
|
<button
|
||||||
mat-button
|
mat-button
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -17,5 +14,5 @@
|
|||||||
>
|
>
|
||||||
CHANGE TARGET
|
CHANGE TARGET
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</cc-base-dialog-actions>
|
||||||
</div>
|
</cc-base-dialog>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Injector } from '@angular/core';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
|
import { BaseDialogSuperclass } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { ErrorService } from '../../../shared/services/error';
|
import { ErrorService } from '../../../shared/services/error';
|
||||||
import { RoutingRulesService } from '../../../thrift-services';
|
import { RoutingRulesService } from '../../../thrift-services';
|
||||||
import { TargetRuleset } from '../target-ruleset-form';
|
import { TargetRuleset } from '../target-ruleset-form';
|
||||||
@ -12,32 +13,36 @@ import { TargetRuleset } from '../target-ruleset-form';
|
|||||||
templateUrl: 'change-target-dialog.component.html',
|
templateUrl: 'change-target-dialog.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ChangeTargetDialogComponent {
|
export class ChangeTargetDialogComponent extends BaseDialogSuperclass<
|
||||||
|
ChangeTargetDialogComponent,
|
||||||
|
{ mainRulesetRefID: number; delegateIdx: number }
|
||||||
|
> {
|
||||||
targetRuleset$ = new BehaviorSubject<TargetRuleset>(undefined);
|
targetRuleset$ = new BehaviorSubject<TargetRuleset>(undefined);
|
||||||
targetRulesetValid$ = new BehaviorSubject<boolean>(undefined);
|
targetRulesetValid$ = new BehaviorSubject<boolean>(undefined);
|
||||||
initValue: Partial<TargetRuleset> = {};
|
initValue: Partial<TargetRuleset> = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dialogRef: MatDialogRef<ChangeTargetDialogComponent>,
|
injector: Injector,
|
||||||
private routingRulesService: RoutingRulesService,
|
private routingRulesService: RoutingRulesService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { mainRulesetRefID: number; delegateIdx: number },
|
|
||||||
private errorService: ErrorService
|
private errorService: ErrorService
|
||||||
) {
|
) {
|
||||||
|
super(injector);
|
||||||
this.routingRulesService
|
this.routingRulesService
|
||||||
.getRuleset(data?.mainRulesetRefID)
|
.getRuleset(this.dialogData?.mainRulesetRefID)
|
||||||
.pipe(untilDestroyed(this))
|
.pipe(untilDestroyed(this))
|
||||||
.subscribe((ruleset) => {
|
.subscribe((ruleset) => {
|
||||||
this.initValue = {
|
this.initValue = {
|
||||||
mainRulesetRefID: ruleset.ref.id,
|
mainRulesetRefID: ruleset.ref.id,
|
||||||
mainDelegateDescription:
|
mainDelegateDescription:
|
||||||
ruleset?.data?.decisions?.delegates?.[data?.delegateIdx]?.description,
|
ruleset?.data?.decisions?.delegates?.[this.dialogData?.delegateIdx]
|
||||||
|
?.description,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
changeTarget() {
|
changeTarget() {
|
||||||
const { mainRulesetRefID, mainDelegateDescription } = this.targetRuleset$.value;
|
const { mainRulesetRefID, mainDelegateDescription } = this.targetRuleset$.value;
|
||||||
const { mainRulesetRefID: previousMainRulesetRefID, delegateIdx } = this.data;
|
const { mainRulesetRefID: previousMainRulesetRefID, delegateIdx } = this.dialogData;
|
||||||
this.routingRulesService
|
this.routingRulesService
|
||||||
.changeMainRuleset({
|
.changeMainRuleset({
|
||||||
previousMainRulesetRefID,
|
previousMainRulesetRefID,
|
||||||
@ -48,8 +53,4 @@ export class ChangeTargetDialogComponent {
|
|||||||
.pipe(untilDestroyed(this))
|
.pipe(untilDestroyed(this))
|
||||||
.subscribe(() => this.dialogRef.close(), this.errorService.error);
|
.subscribe(() => this.dialogRef.close(), this.errorService.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,19 @@ import { FlexLayoutModule } from '@angular/flex-layout';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
|
||||||
import { ErrorModule } from '../../../shared/services/error';
|
import { BaseDialogModule } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { TargetRulesetFormModule } from '../target-ruleset-form';
|
import { TargetRulesetFormModule } from '../target-ruleset-form';
|
||||||
import { ChangeTargetDialogComponent } from './change-target-dialog.component';
|
import { ChangeTargetDialogComponent } from './change-target-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
ErrorModule,
|
|
||||||
TargetRulesetFormModule,
|
TargetRulesetFormModule,
|
||||||
FlexLayoutModule,
|
FlexLayoutModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
BaseDialogModule,
|
||||||
],
|
],
|
||||||
declarations: [ChangeTargetDialogComponent],
|
declarations: [ChangeTargetDialogComponent],
|
||||||
exports: [ChangeTargetDialogComponent],
|
exports: [ChangeTargetDialogComponent],
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<form [formGroup]="form" fxLayout="column" fxLayoutGap="32px">
|
<cc-base-dialog title="Attach party delegate ruleset">
|
||||||
<div class="cc-headline">Attach party delegate ruleset</div>
|
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||||
|
|
||||||
<div fxLayout="column" fxLayoutGap="24px">
|
|
||||||
<cc-target-ruleset-form
|
<cc-target-ruleset-form
|
||||||
(valueChanges)="targetRuleset$.next($event)"
|
(valueChanges)="targetRuleset$.next($event)"
|
||||||
(valid)="targetRulesetValid$.next($event)"
|
(valid)="targetRulesetValid$.next($event)"
|
||||||
@ -25,8 +23,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxLayout fxLayoutAlign="space-between">
|
<cc-base-dialog-actions>
|
||||||
<button mat-button (click)="cancel()">CANCEL</button>
|
|
||||||
<button
|
<button
|
||||||
mat-button
|
mat-button
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -35,5 +32,5 @@
|
|||||||
>
|
>
|
||||||
ATTACH
|
ATTACH
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</cc-base-dialog-actions>
|
||||||
</form>
|
</cc-base-dialog>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Injector } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
|
import { BaseDialogSuperclass } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { ErrorService } from '../../../../shared/services/error';
|
import { ErrorService } from '../../../../shared/services/error';
|
||||||
import { RoutingRulesService } from '../../../../thrift-services';
|
import { RoutingRulesService } from '../../../../thrift-services';
|
||||||
import { TargetRuleset } from '../../target-ruleset-form';
|
import { TargetRuleset } from '../../target-ruleset-form';
|
||||||
@ -13,7 +14,10 @@ import { TargetRuleset } from '../../target-ruleset-form';
|
|||||||
templateUrl: 'attach-new-ruleset-dialog.component.html',
|
templateUrl: 'attach-new-ruleset-dialog.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class AttachNewRulesetDialogComponent {
|
export class AttachNewRulesetDialogComponent extends BaseDialogSuperclass<
|
||||||
|
AttachNewRulesetDialogComponent,
|
||||||
|
{ partyID: string }
|
||||||
|
> {
|
||||||
form = this.fb.group({
|
form = this.fb.group({
|
||||||
ruleset: this.fb.group({
|
ruleset: this.fb.group({
|
||||||
name: 'submain ruleset[by shop id]',
|
name: 'submain ruleset[by shop id]',
|
||||||
@ -25,27 +29,27 @@ export class AttachNewRulesetDialogComponent {
|
|||||||
targetRulesetValid$ = new BehaviorSubject<boolean>(undefined);
|
targetRulesetValid$ = new BehaviorSubject<boolean>(undefined);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
injector: Injector,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dialogRef: MatDialogRef<AttachNewRulesetDialogComponent>,
|
|
||||||
private paymentRoutingRulesService: RoutingRulesService,
|
private paymentRoutingRulesService: RoutingRulesService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { partyID: string },
|
|
||||||
private errorService: ErrorService
|
private errorService: ErrorService
|
||||||
) {}
|
) {
|
||||||
|
super(injector);
|
||||||
|
}
|
||||||
|
|
||||||
attach() {
|
attach() {
|
||||||
const { mainRulesetRefID, mainDelegateDescription } = this.targetRuleset$.value;
|
const { mainRulesetRefID, mainDelegateDescription } = this.targetRuleset$.value;
|
||||||
this.paymentRoutingRulesService
|
this.paymentRoutingRulesService
|
||||||
.attachPartyDelegateRuleset({
|
.attachPartyDelegateRuleset({
|
||||||
partyID: this.data.partyID,
|
partyID: this.dialogData.partyID,
|
||||||
mainRulesetRefID,
|
mainRulesetRefID,
|
||||||
mainDelegateDescription,
|
mainDelegateDescription,
|
||||||
ruleset: this.form.value.ruleset,
|
ruleset: this.form.value.ruleset,
|
||||||
})
|
})
|
||||||
.pipe(untilDestroyed(this))
|
.pipe(untilDestroyed(this))
|
||||||
.subscribe(() => this.dialogRef.close(), this.errorService.error);
|
.subscribe({
|
||||||
}
|
next: () => this.dialogRef.close(),
|
||||||
|
error: (err) => this.errorService.error(err),
|
||||||
cancel() {
|
});
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { combineLatest } from 'rxjs';
|
import { combineLatest } from 'rxjs';
|
||||||
import { first, map, switchMap, take } from 'rxjs/operators';
|
import { first, map, switchMap, take } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { BaseDialogService } from '@cc/components/base-dialog/services/base-dialog.service';
|
||||||
|
|
||||||
import { handleError } from '../../../../utils/operators/handle-error';
|
import { handleError } from '../../../../utils/operators/handle-error';
|
||||||
import { ErrorService } from '../../../shared/services/error';
|
import { ErrorService } from '../../../shared/services/error';
|
||||||
import { RoutingRulesService } from '../../../thrift-services';
|
import { RoutingRulesService } from '../../../thrift-services';
|
||||||
import { DomainStoreService } from '../../../thrift-services/damsel/domain-store.service';
|
import { DomainStoreService } from '../../../thrift-services/damsel/domain-store.service';
|
||||||
import { DialogConfig, DIALOG_CONFIG } from '../../../tokens';
|
|
||||||
import { AttachNewRulesetDialogComponent } from './attach-new-ruleset-dialog';
|
import { AttachNewRulesetDialogComponent } from './attach-new-ruleset-dialog';
|
||||||
import { PartyDelegateRulesetsService } from './party-delegate-rulesets.service';
|
import { PartyDelegateRulesetsService } from './party-delegate-rulesets.service';
|
||||||
|
|
||||||
@ -54,10 +54,9 @@ export class PartyDelegateRulesetsComponent {
|
|||||||
private partyDelegateRulesetsService: PartyDelegateRulesetsService,
|
private partyDelegateRulesetsService: PartyDelegateRulesetsService,
|
||||||
private paymentRoutingRulesService: RoutingRulesService,
|
private paymentRoutingRulesService: RoutingRulesService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private dialog: MatDialog,
|
private baseDialogService: BaseDialogService,
|
||||||
private domainStoreService: DomainStoreService,
|
private domainStoreService: DomainStoreService,
|
||||||
private errorService: ErrorService,
|
private errorService: ErrorService
|
||||||
@Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
attachNewRuleset() {
|
attachNewRuleset() {
|
||||||
@ -65,11 +64,8 @@ export class PartyDelegateRulesetsComponent {
|
|||||||
.pipe(
|
.pipe(
|
||||||
take(1),
|
take(1),
|
||||||
switchMap((partyID) =>
|
switchMap((partyID) =>
|
||||||
this.dialog
|
this.baseDialogService
|
||||||
.open(AttachNewRulesetDialogComponent, {
|
.open(AttachNewRulesetDialogComponent, { partyID })
|
||||||
...this.dialogConfig.medium,
|
|
||||||
data: { partyID },
|
|
||||||
})
|
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
),
|
),
|
||||||
handleError(this.errorService.error),
|
handleError(this.errorService.error),
|
||||||
|
@ -15,9 +15,9 @@ import { MatRadioModule } from '@angular/material/radio';
|
|||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { BaseDialogModule } from '@cc/components/base-dialog';
|
||||||
import { DetailsItemModule } from '@cc/components/details-item';
|
import { DetailsItemModule } from '@cc/components/details-item';
|
||||||
|
|
||||||
import { ErrorModule } from '../../../shared/services/error';
|
|
||||||
import { ChangeTargetDialogModule } from '../change-target-dialog';
|
import { ChangeTargetDialogModule } from '../change-target-dialog';
|
||||||
import { PaymentRoutingRulesetHeaderModule } from '../payment-routing-ruleset-header';
|
import { PaymentRoutingRulesetHeaderModule } from '../payment-routing-ruleset-header';
|
||||||
import { RoutingRulesListModule } from '../routing-rules-list';
|
import { RoutingRulesListModule } from '../routing-rules-list';
|
||||||
@ -48,10 +48,10 @@ const EXPORTED_DECLARATIONS = [PartyDelegateRulesetsComponent, AttachNewRulesetD
|
|||||||
DetailsItemModule,
|
DetailsItemModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
ErrorModule,
|
|
||||||
ChangeTargetDialogModule,
|
ChangeTargetDialogModule,
|
||||||
TargetRulesetFormModule,
|
TargetRulesetFormModule,
|
||||||
RoutingRulesListModule,
|
RoutingRulesListModule,
|
||||||
|
BaseDialogModule,
|
||||||
],
|
],
|
||||||
declarations: EXPORTED_DECLARATIONS,
|
declarations: EXPORTED_DECLARATIONS,
|
||||||
exports: EXPORTED_DECLARATIONS,
|
exports: EXPORTED_DECLARATIONS,
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
<form [formGroup]="form" fxLayout="column" fxLayoutGap="32px">
|
<cc-base-dialog title="Party payment routing rule params">
|
||||||
<div class="cc-headline">Party payment routing rule params</div>
|
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||||
|
|
||||||
<div fxLayout="column" fxLayoutGap="24px">
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Shop</mat-label>
|
<mat-label>Shop</mat-label>
|
||||||
<mat-select formControlName="shopID" required>
|
<mat-select formControlName="shopID" required>
|
||||||
<mat-option *ngFor="let shop of data.shops" [value]="shop.id">
|
<mat-option *ngFor="let shop of dialogData.shops" [value]="shop.id">
|
||||||
{{ shop.details.name }}
|
{{ shop.details.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
@ -26,8 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxLayout fxLayoutAlign="space-between">
|
<cc-base-dialog-actions>
|
||||||
<button mat-button (click)="cancel()">CANCEL</button>
|
|
||||||
<button mat-button color="primary" (click)="add()" [disabled]="form.invalid">ADD</button>
|
<button mat-button color="primary" (click)="add()" [disabled]="form.invalid">ADD</button>
|
||||||
</div>
|
</cc-base-dialog-actions>
|
||||||
</form>
|
</cc-base-dialog>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Injector } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { Shop } from '@vality/domain-proto/lib/domain';
|
import { Shop } from '@vality/domain-proto/lib/domain';
|
||||||
|
|
||||||
|
import { BaseDialogSuperclass } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { ErrorService } from '../../../../shared/services/error';
|
import { ErrorService } from '../../../../shared/services/error';
|
||||||
import { RoutingRulesService } from '../../../../thrift-services';
|
import { RoutingRulesService } from '../../../../thrift-services';
|
||||||
|
|
||||||
@ -11,7 +12,10 @@ import { RoutingRulesService } from '../../../../thrift-services';
|
|||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'add-party-payment-routing-rule-dialog.component.html',
|
templateUrl: 'add-party-payment-routing-rule-dialog.component.html',
|
||||||
})
|
})
|
||||||
export class AddPartyPaymentRoutingRuleDialogComponent {
|
export class AddPartyPaymentRoutingRuleDialogComponent extends BaseDialogSuperclass<
|
||||||
|
AddPartyPaymentRoutingRuleDialogComponent,
|
||||||
|
{ refID: number; partyID: string; shops: Shop[] }
|
||||||
|
> {
|
||||||
form = this.fb.group({
|
form = this.fb.group({
|
||||||
shopID: '',
|
shopID: '',
|
||||||
name: 'Ruleset[candidates]',
|
name: 'Ruleset[candidates]',
|
||||||
@ -19,13 +23,13 @@ export class AddPartyPaymentRoutingRuleDialogComponent {
|
|||||||
});
|
});
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
injector: Injector,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dialogRef: MatDialogRef<AddPartyPaymentRoutingRuleDialogComponent>,
|
|
||||||
private paymentRoutingRulesService: RoutingRulesService,
|
private paymentRoutingRulesService: RoutingRulesService,
|
||||||
@Inject(MAT_DIALOG_DATA)
|
|
||||||
public data: { refID: number; partyID: string; shops: Shop[] },
|
|
||||||
private errorService: ErrorService
|
private errorService: ErrorService
|
||||||
) {}
|
) {
|
||||||
|
super(injector);
|
||||||
|
}
|
||||||
|
|
||||||
add() {
|
add() {
|
||||||
const { shopID, name, description } = this.form.value;
|
const { shopID, name, description } = this.form.value;
|
||||||
@ -33,15 +37,11 @@ export class AddPartyPaymentRoutingRuleDialogComponent {
|
|||||||
.addShopRuleset({
|
.addShopRuleset({
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
partyRulesetRefID: this.data.refID,
|
partyRulesetRefID: this.dialogData.refID,
|
||||||
partyID: this.data.partyID,
|
partyID: this.dialogData.partyID,
|
||||||
shopID,
|
shopID,
|
||||||
})
|
})
|
||||||
.pipe(untilDestroyed(this))
|
.pipe(untilDestroyed(this))
|
||||||
.subscribe(() => this.dialogRef.close(), this.errorService.error);
|
.subscribe(() => this.dialogRef.close(), this.errorService.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ import { MatInputModule } from '@angular/material/input';
|
|||||||
import { MatRadioModule } from '@angular/material/radio';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
import { ErrorModule } from '../../../../shared/services/error';
|
import { BaseDialogModule } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { AddPartyPaymentRoutingRuleDialogComponent } from './add-party-payment-routing-rule-dialog.component';
|
import { AddPartyPaymentRoutingRuleDialogComponent } from './add-party-payment-routing-rule-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -29,7 +30,7 @@ import { AddPartyPaymentRoutingRuleDialogComponent } from './add-party-payment-r
|
|||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
ErrorModule,
|
BaseDialogModule,
|
||||||
],
|
],
|
||||||
declarations: [AddPartyPaymentRoutingRuleDialogComponent],
|
declarations: [AddPartyPaymentRoutingRuleDialogComponent],
|
||||||
exports: [AddPartyPaymentRoutingRuleDialogComponent],
|
exports: [AddPartyPaymentRoutingRuleDialogComponent],
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<form [formGroup]="form" fxLayout="column" fxLayoutGap="32px">
|
<cc-base-dialog title="Payment rules init params">
|
||||||
<div class="cc-headline">Payment rules init params</div>
|
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||||
|
|
||||||
<div fxLayout="column" fxLayoutGap="24px">
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
@ -25,8 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxLayout fxLayoutAlign="space-between">
|
<cc-base-dialog-actions>
|
||||||
<button mat-button (click)="cancel()">CANCEL</button>
|
|
||||||
<button mat-button color="primary" (click)="init()" [disabled]="form.invalid">INIT</button>
|
<button mat-button color="primary" (click)="init()" [disabled]="form.invalid">INIT</button>
|
||||||
</div>
|
</cc-base-dialog-actions>
|
||||||
</form>
|
</cc-base-dialog>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Injector } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
|
|
||||||
|
import { BaseDialogSuperclass } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { ErrorService } from '../../../../shared/services/error';
|
import { ErrorService } from '../../../../shared/services/error';
|
||||||
import { RoutingRulesService } from '../../../../thrift-services';
|
import { RoutingRulesService } from '../../../../thrift-services';
|
||||||
|
|
||||||
@ -11,7 +12,10 @@ import { RoutingRulesService } from '../../../../thrift-services';
|
|||||||
selector: 'cc-initialize-payment-routing-rules-dialog',
|
selector: 'cc-initialize-payment-routing-rules-dialog',
|
||||||
templateUrl: 'initialize-payment-routing-rules-dialog.component.html',
|
templateUrl: 'initialize-payment-routing-rules-dialog.component.html',
|
||||||
})
|
})
|
||||||
export class InitializePaymentRoutingRulesDialogComponent {
|
export class InitializePaymentRoutingRulesDialogComponent extends BaseDialogSuperclass<
|
||||||
|
InitializePaymentRoutingRulesDialogComponent,
|
||||||
|
{ partyID: string; refID: number }
|
||||||
|
> {
|
||||||
form = this.fb.group({
|
form = this.fb.group({
|
||||||
delegateDescription: 'Main delegate[party]',
|
delegateDescription: 'Main delegate[party]',
|
||||||
name: 'submain ruleset[by shop id]',
|
name: 'submain ruleset[by shop id]',
|
||||||
@ -19,28 +23,25 @@ export class InitializePaymentRoutingRulesDialogComponent {
|
|||||||
});
|
});
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
injector: Injector,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dialogRef: MatDialogRef<InitializePaymentRoutingRulesDialogComponent>,
|
|
||||||
private paymentRoutingRulesService: RoutingRulesService,
|
private paymentRoutingRulesService: RoutingRulesService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { partyID: string; refID: number },
|
|
||||||
private errorService: ErrorService
|
private errorService: ErrorService
|
||||||
) {}
|
) {
|
||||||
|
super(injector);
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
const { delegateDescription, name, description } = this.form.value;
|
const { delegateDescription, name, description } = this.form.value;
|
||||||
this.paymentRoutingRulesService
|
this.paymentRoutingRulesService
|
||||||
.addPartyRuleset({
|
.addPartyRuleset({
|
||||||
name,
|
name,
|
||||||
partyID: this.data.partyID,
|
partyID: this.dialogData.partyID,
|
||||||
mainRulesetRefID: this.data.refID,
|
mainRulesetRefID: this.dialogData.refID,
|
||||||
description,
|
description,
|
||||||
delegateDescription,
|
delegateDescription,
|
||||||
})
|
})
|
||||||
.pipe(untilDestroyed(this))
|
.pipe(untilDestroyed(this))
|
||||||
.subscribe(() => this.dialogRef.close(), this.errorService.error);
|
.subscribe(() => this.dialogRef.close(), this.errorService.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ import { MatInputModule } from '@angular/material/input';
|
|||||||
import { MatRadioModule } from '@angular/material/radio';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
import { ErrorModule } from '../../../../shared/services/error';
|
import { BaseDialogModule } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { InitializePaymentRoutingRulesDialogComponent } from './initialize-payment-routing-rules-dialog.component';
|
import { InitializePaymentRoutingRulesDialogComponent } from './initialize-payment-routing-rules-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -29,7 +30,7 @@ import { InitializePaymentRoutingRulesDialogComponent } from './initialize-payme
|
|||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
ErrorModule,
|
BaseDialogModule,
|
||||||
],
|
],
|
||||||
declarations: [InitializePaymentRoutingRulesDialogComponent],
|
declarations: [InitializePaymentRoutingRulesDialogComponent],
|
||||||
exports: [InitializePaymentRoutingRulesDialogComponent],
|
exports: [InitializePaymentRoutingRulesDialogComponent],
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { combineLatest } from 'rxjs';
|
import { combineLatest } from 'rxjs';
|
||||||
import { filter, map, shareReplay, switchMap, take } from 'rxjs/operators';
|
import { filter, map, shareReplay, switchMap, take } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { BaseDialogService } from '@cc/components/base-dialog/services/base-dialog.service';
|
||||||
|
|
||||||
import { DomainStoreService } from '../../../thrift-services/damsel/domain-store.service';
|
import { DomainStoreService } from '../../../thrift-services/damsel/domain-store.service';
|
||||||
import { DialogConfig, DIALOG_CONFIG } from '../../../tokens';
|
|
||||||
import { AddPartyPaymentRoutingRuleDialogComponent } from './add-party-payment-routing-rule-dialog';
|
import { AddPartyPaymentRoutingRuleDialogComponent } from './add-party-payment-routing-rule-dialog';
|
||||||
import { InitializePaymentRoutingRulesDialogComponent } from './initialize-payment-routing-rules-dialog';
|
import { InitializePaymentRoutingRulesDialogComponent } from './initialize-payment-routing-rules-dialog';
|
||||||
import { PartyPaymentRoutingRulesetService } from './party-payment-routing-ruleset.service';
|
import { PartyPaymentRoutingRulesetService } from './party-payment-routing-ruleset.service';
|
||||||
@ -54,11 +54,10 @@ export class PaymentRoutingRulesComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dialog: MatDialog,
|
private baseDialogService: BaseDialogService,
|
||||||
private partyPaymentRoutingRulesetService: PartyPaymentRoutingRulesetService,
|
private partyPaymentRoutingRulesetService: PartyPaymentRoutingRulesetService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private domainStoreService: DomainStoreService,
|
private domainStoreService: DomainStoreService
|
||||||
@Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
@ -69,11 +68,8 @@ export class PaymentRoutingRulesComponent {
|
|||||||
.pipe(
|
.pipe(
|
||||||
take(1),
|
take(1),
|
||||||
switchMap(([partyID, refID]) =>
|
switchMap(([partyID, refID]) =>
|
||||||
this.dialog
|
this.baseDialogService
|
||||||
.open(InitializePaymentRoutingRulesDialogComponent, {
|
.open(InitializePaymentRoutingRulesDialogComponent, { partyID, refID })
|
||||||
...this.dialogConfig.medium,
|
|
||||||
data: { partyID, refID },
|
|
||||||
})
|
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
),
|
),
|
||||||
untilDestroyed(this)
|
untilDestroyed(this)
|
||||||
@ -90,11 +86,8 @@ export class PaymentRoutingRulesComponent {
|
|||||||
.pipe(
|
.pipe(
|
||||||
take(1),
|
take(1),
|
||||||
switchMap(([refID, shops, partyID]) =>
|
switchMap(([refID, shops, partyID]) =>
|
||||||
this.dialog
|
this.baseDialogService
|
||||||
.open(AddPartyPaymentRoutingRuleDialogComponent, {
|
.open(AddPartyPaymentRoutingRuleDialogComponent, { refID, shops, partyID })
|
||||||
...this.dialogConfig.medium,
|
|
||||||
data: { refID, shops, partyID },
|
|
||||||
})
|
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
),
|
),
|
||||||
untilDestroyed(this)
|
untilDestroyed(this)
|
||||||
|
@ -18,7 +18,6 @@ import { MatSelectModule } from '@angular/material/select';
|
|||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { ErrorModule } from '../../../shared/services/error';
|
|
||||||
import { DamselModule } from '../../../thrift-services';
|
import { DamselModule } from '../../../thrift-services';
|
||||||
import { ChangeTargetDialogModule } from '../change-target-dialog';
|
import { ChangeTargetDialogModule } from '../change-target-dialog';
|
||||||
import { PaymentRoutingRulesetHeaderModule } from '../payment-routing-ruleset-header';
|
import { PaymentRoutingRulesetHeaderModule } from '../payment-routing-ruleset-header';
|
||||||
@ -53,7 +52,6 @@ import { PaymentRoutingRulesComponent } from './party-payment-routing-ruleset.co
|
|||||||
AddPartyPaymentRoutingRuleDialogModule,
|
AddPartyPaymentRoutingRuleDialogModule,
|
||||||
InitializePaymentRoutingRulesDialogModule,
|
InitializePaymentRoutingRulesDialogModule,
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
ErrorModule,
|
|
||||||
ChangeTargetDialogModule,
|
ChangeTargetDialogModule,
|
||||||
RoutingRulesListModule,
|
RoutingRulesListModule,
|
||||||
],
|
],
|
||||||
|
@ -2,12 +2,10 @@ import {
|
|||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Inject,
|
|
||||||
Input,
|
Input,
|
||||||
Output,
|
Output,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
@ -21,7 +19,6 @@ import { ConfirmActionDialogComponent } from '../../../../components/confirm-act
|
|||||||
import { handleError } from '../../../../utils/operators/handle-error';
|
import { handleError } from '../../../../utils/operators/handle-error';
|
||||||
import { ErrorService } from '../../../shared/services/error';
|
import { ErrorService } from '../../../shared/services/error';
|
||||||
import { RoutingRulesService } from '../../../thrift-services';
|
import { RoutingRulesService } from '../../../thrift-services';
|
||||||
import { DIALOG_CONFIG, DialogConfig } from '../../../tokens';
|
|
||||||
import { ChangeDelegateRulesetDialogComponent } from '../change-delegate-ruleset-dialog';
|
import { ChangeDelegateRulesetDialogComponent } from '../change-delegate-ruleset-dialog';
|
||||||
import { ChangeTargetDialogComponent } from '../change-target-dialog';
|
import { ChangeTargetDialogComponent } from '../change-target-dialog';
|
||||||
|
|
||||||
@ -54,10 +51,7 @@ export class RoutingRulesListComponent<T extends { [N in PropertyKey]: any } & D
|
|||||||
private paginator$ = new ReplaySubject<MatPaginator>(1);
|
private paginator$ = new ReplaySubject<MatPaginator>(1);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||||
dataSource$ = combineLatest([
|
dataSource$ = combineLatest([this.data$, this.paginator$.pipe(startWith(null))]).pipe(
|
||||||
this.data$,
|
|
||||||
this.paginator$.pipe(startWith<any, null>(null)),
|
|
||||||
]).pipe(
|
|
||||||
map(([d, paginator]) => {
|
map(([d, paginator]) => {
|
||||||
const data = new MatTableDataSource(d);
|
const data = new MatTableDataSource(d);
|
||||||
data.paginator = paginator;
|
data.paginator = paginator;
|
||||||
@ -81,25 +75,16 @@ export class RoutingRulesListComponent<T extends { [N in PropertyKey]: any } & D
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dialog: MatDialog,
|
|
||||||
private baseDialogService: BaseDialogService,
|
private baseDialogService: BaseDialogService,
|
||||||
private errorService: ErrorService,
|
private errorService: ErrorService,
|
||||||
private routingRulesService: RoutingRulesService,
|
private routingRulesService: RoutingRulesService
|
||||||
@Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getColumnsKeys(col) {
|
|
||||||
return col.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
changeDelegateRuleset(delegateId: DelegateId) {
|
changeDelegateRuleset(delegateId: DelegateId) {
|
||||||
this.dialog
|
this.baseDialogService
|
||||||
.open(ChangeDelegateRulesetDialogComponent, {
|
.open(ChangeDelegateRulesetDialogComponent, {
|
||||||
...this.dialogConfig.medium,
|
|
||||||
data: {
|
|
||||||
mainRulesetRefID: delegateId.parentRefId,
|
mainRulesetRefID: delegateId.parentRefId,
|
||||||
delegateIdx: delegateId.delegateIdx,
|
delegateIdx: delegateId.delegateIdx,
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
.pipe(handleError(this.errorService.error), untilDestroyed(this))
|
.pipe(handleError(this.errorService.error), untilDestroyed(this))
|
||||||
@ -107,13 +92,10 @@ export class RoutingRulesListComponent<T extends { [N in PropertyKey]: any } & D
|
|||||||
}
|
}
|
||||||
|
|
||||||
changeTarget(delegateId: DelegateId) {
|
changeTarget(delegateId: DelegateId) {
|
||||||
this.dialog
|
this.baseDialogService
|
||||||
.open(ChangeTargetDialogComponent, {
|
.open(ChangeTargetDialogComponent, {
|
||||||
...this.dialogConfig.medium,
|
|
||||||
data: {
|
|
||||||
mainRulesetRefID: delegateId.parentRefId,
|
mainRulesetRefID: delegateId.parentRefId,
|
||||||
delegateIdx: delegateId.delegateIdx,
|
delegateIdx: delegateId.delegateIdx,
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
.pipe(untilDestroyed(this))
|
.pipe(untilDestroyed(this))
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<form [formGroup]="form" fxLayout="column" fxLayoutGap="32px">
|
<cc-base-dialog title="Shop payment routing rule params">
|
||||||
<div class="cc-headline">Shop payment routing rule params</div>
|
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||||
|
|
||||||
<div fxLayout="column" fxLayoutGap="24px">
|
|
||||||
<div fxLayout="column" fxLayoutGap="16px">
|
<div fxLayout="column" fxLayoutGap="16px">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input
|
<input
|
||||||
@ -32,10 +30,7 @@
|
|||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
<div class="cc-title">Predicate</div>
|
<div class="cc-title">Predicate</div>
|
||||||
<cc-predicate
|
<cc-predicate [formControl]="predicateControl"></cc-predicate>
|
||||||
(validationChange)="predicateValid = $event"
|
|
||||||
(predicateChange)="predicate = $event"
|
|
||||||
></cc-predicate>
|
|
||||||
|
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
@ -115,15 +110,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxLayout fxLayoutAlign="space-between">
|
<cc-base-dialog-actions>
|
||||||
<button mat-button (click)="cancel()">CANCEL</button>
|
|
||||||
<button
|
<button
|
||||||
mat-button
|
mat-button
|
||||||
color="primary"
|
color="primary"
|
||||||
(click)="add()"
|
(click)="add()"
|
||||||
[disabled]="form.invalid || !predicateValid"
|
[disabled]="form.invalid || predicateControl.invalid"
|
||||||
>
|
>
|
||||||
ADD
|
ADD
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</cc-base-dialog-actions>
|
||||||
</form>
|
</cc-base-dialog>
|
||||||
|
@ -1,43 +1,50 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Injector } from '@angular/core';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
import { Validators } from '@angular/forms';
|
||||||
|
import { FormBuilder } from '@ngneat/reactive-forms';
|
||||||
|
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||||
import { Predicate, RiskScore } from '@vality/domain-proto/lib/domain';
|
import { Predicate, RiskScore } from '@vality/domain-proto/lib/domain';
|
||||||
|
|
||||||
|
import { BaseDialogSuperclass } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { DomainStoreService } from '../../../../thrift-services/damsel/domain-store.service';
|
import { DomainStoreService } from '../../../../thrift-services/damsel/domain-store.service';
|
||||||
import {
|
import {
|
||||||
AddShopPaymentRoutingRuleDialogService,
|
AddShopPaymentRoutingRuleDialogService,
|
||||||
TerminalType,
|
TerminalType,
|
||||||
} from './add-shop-payment-routing-rule-dialog.service';
|
} from './add-shop-payment-routing-rule-dialog.service';
|
||||||
|
|
||||||
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-add-shop-payment-routing-rule-dialog',
|
selector: 'cc-add-shop-payment-routing-rule-dialog',
|
||||||
templateUrl: 'add-shop-payment-routing-rule-dialog.component.html',
|
templateUrl: 'add-shop-payment-routing-rule-dialog.component.html',
|
||||||
styleUrls: ['add-shop-payment-routing-rule-dialog.component.scss'],
|
styleUrls: ['add-shop-payment-routing-rule-dialog.component.scss'],
|
||||||
providers: [AddShopPaymentRoutingRuleDialogService],
|
providers: [AddShopPaymentRoutingRuleDialogService],
|
||||||
})
|
})
|
||||||
export class AddShopPaymentRoutingRuleDialogComponent {
|
export class AddShopPaymentRoutingRuleDialogComponent extends BaseDialogSuperclass<
|
||||||
|
AddShopPaymentRoutingRuleDialogComponent,
|
||||||
|
{ refID: number }
|
||||||
|
> {
|
||||||
form = this.addShopPaymentRoutingRuleDialogService.form;
|
form = this.addShopPaymentRoutingRuleDialogService.form;
|
||||||
newTerminalOptionsForm = this.addShopPaymentRoutingRuleDialogService.newTerminalOptionsForm;
|
newTerminalOptionsForm = this.addShopPaymentRoutingRuleDialogService.newTerminalOptionsForm;
|
||||||
|
predicateControl = this.fb.control<Predicate>(null, Validators.required);
|
||||||
|
|
||||||
terminalType = TerminalType;
|
terminalType = TerminalType;
|
||||||
riskScore = RiskScore;
|
riskScore = RiskScore;
|
||||||
terminals$ = this.domainStoreService.getObjects('terminal');
|
terminals$ = this.domainStoreService.getObjects('terminal');
|
||||||
|
|
||||||
predicate: Predicate;
|
|
||||||
predicateValid: boolean;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
injector: Injector,
|
||||||
private addShopPaymentRoutingRuleDialogService: AddShopPaymentRoutingRuleDialogService,
|
private addShopPaymentRoutingRuleDialogService: AddShopPaymentRoutingRuleDialogService,
|
||||||
private dialogRef: MatDialogRef<AddShopPaymentRoutingRuleDialogComponent>,
|
|
||||||
private domainStoreService: DomainStoreService,
|
private domainStoreService: DomainStoreService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { partyID: string; refID: number }
|
private fb: FormBuilder
|
||||||
) {}
|
) {
|
||||||
|
super(injector);
|
||||||
add() {
|
|
||||||
this.addShopPaymentRoutingRuleDialogService.add(this.predicate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
add() {
|
||||||
this.dialogRef.close();
|
this.addShopPaymentRoutingRuleDialogService.add(
|
||||||
|
this.predicateControl.value,
|
||||||
|
this.dialogData.refID
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addOption() {
|
addOption() {
|
||||||
|
@ -12,6 +12,9 @@ import { MatInputModule } from '@angular/material/input';
|
|||||||
import { MatRadioModule } from '@angular/material/radio';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
|
import { MetadataFormModule } from '@cc/app/shared';
|
||||||
|
import { BaseDialogModule } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { AddShopPaymentRoutingRuleDialogComponent } from './add-shop-payment-routing-rule-dialog.component';
|
import { AddShopPaymentRoutingRuleDialogComponent } from './add-shop-payment-routing-rule-dialog.component';
|
||||||
import { ExpanderComponent } from './expander';
|
import { ExpanderComponent } from './expander';
|
||||||
import { PredicateComponent } from './predicate';
|
import { PredicateComponent } from './predicate';
|
||||||
@ -30,6 +33,8 @@ import { PredicateComponent } from './predicate';
|
|||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
|
MetadataFormModule,
|
||||||
|
BaseDialogModule,
|
||||||
],
|
],
|
||||||
declarations: [AddShopPaymentRoutingRuleDialogComponent, PredicateComponent, ExpanderComponent],
|
declarations: [AddShopPaymentRoutingRuleDialogComponent, PredicateComponent, ExpanderComponent],
|
||||||
exports: [AddShopPaymentRoutingRuleDialogComponent],
|
exports: [AddShopPaymentRoutingRuleDialogComponent],
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { Inject, Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { FormArray, FormBuilder, Validators } from '@angular/forms';
|
import { FormArray, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
import { MatDialogRef } from '@angular/material/dialog';
|
||||||
import { Predicate } from '@vality/domain-proto/lib/domain';
|
import { Predicate } from '@vality/domain-proto/lib/domain';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { startWith, switchMap, take } from 'rxjs/operators';
|
import { startWith, switchMap, take } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { BaseDialogResponseStatus } from '@cc/components/base-dialog';
|
||||||
|
|
||||||
import { RoutingRulesService, TerminalService } from '../../../../thrift-services';
|
import { RoutingRulesService, TerminalService } from '../../../../thrift-services';
|
||||||
import { AddShopPaymentRoutingRuleDialogComponent } from './add-shop-payment-routing-rule-dialog.component';
|
import { AddShopPaymentRoutingRuleDialogComponent } from './add-shop-payment-routing-rule-dialog.component';
|
||||||
|
|
||||||
@ -37,8 +39,7 @@ export class AddShopPaymentRoutingRuleDialogService {
|
|||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dialogRef: MatDialogRef<AddShopPaymentRoutingRuleDialogComponent>,
|
private dialogRef: MatDialogRef<AddShopPaymentRoutingRuleDialogComponent>,
|
||||||
private paymentRoutingRulesService: RoutingRulesService,
|
private paymentRoutingRulesService: RoutingRulesService,
|
||||||
private terminalService: TerminalService,
|
private terminalService: TerminalService
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { partyID: string; refID: number }
|
|
||||||
) {
|
) {
|
||||||
this.form
|
this.form
|
||||||
.get('terminalType')
|
.get('terminalType')
|
||||||
@ -62,7 +63,7 @@ export class AddShopPaymentRoutingRuleDialogService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
add(predicate: Predicate) {
|
add(predicate: Predicate, refID: number) {
|
||||||
const { description, weight, priority, terminalType, existentTerminalID, newTerminal } =
|
const { description, weight, priority, terminalType, existentTerminalID, newTerminal } =
|
||||||
this.form.value;
|
this.form.value;
|
||||||
(terminalType === TerminalType.New
|
(terminalType === TerminalType.New
|
||||||
@ -82,12 +83,12 @@ export class AddShopPaymentRoutingRuleDialogService {
|
|||||||
weight,
|
weight,
|
||||||
priority,
|
priority,
|
||||||
terminalID,
|
terminalID,
|
||||||
refID: this.data.refID,
|
refID,
|
||||||
predicate,
|
predicate,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.subscribe(() => this.dialogRef.close());
|
.subscribe(() => this.dialogRef.close({ status: BaseDialogResponseStatus.Success }));
|
||||||
}
|
}
|
||||||
|
|
||||||
addOption() {
|
addOption() {
|
||||||
|
@ -1,203 +1,7 @@
|
|||||||
<div fxLayout="column" fxLayoutGap="24px" [formGroup]="form">
|
<cc-metadata-form
|
||||||
<mat-radio-group formControlName="type" fxLayout="column" fxLayoutGap="16px">
|
[formControl]="control"
|
||||||
<mat-radio-button [value]="predicateType.condition">Condition</mat-radio-button>
|
[metadata]="metadata$ | async"
|
||||||
<div fxLayout>
|
[extensions]="extensions$ | async"
|
||||||
<mat-radio-button [value]="predicateType.constant" fxFlex>Constant</mat-radio-button>
|
namespace="domain"
|
||||||
<mat-radio-button [value]="predicateType.allOf" fxFlex>All of</mat-radio-button>
|
type="Predicate"
|
||||||
</div>
|
></cc-metadata-form>
|
||||||
<div fxLayout>
|
|
||||||
<mat-radio-button [value]="predicateType.anyOf" fxFlex>Any of</mat-radio-button>
|
|
||||||
<mat-radio-button [value]="predicateType.isNot" fxFlex>Is not</mat-radio-button>
|
|
||||||
</div>
|
|
||||||
</mat-radio-group>
|
|
||||||
|
|
||||||
<div
|
|
||||||
*ngIf="
|
|
||||||
[predicateType.anyOf, predicateType.allOf, predicateType.isNot].includes(
|
|
||||||
form.value.type
|
|
||||||
) && childrenForm?.controls?.length
|
|
||||||
"
|
|
||||||
fxLayout
|
|
||||||
fxLayoutGap="24px"
|
|
||||||
>
|
|
||||||
<mat-divider vertical></mat-divider>
|
|
||||||
<div fxLayout="column" fxLayoutGap="24px" fxFlex>
|
|
||||||
<cc-expander
|
|
||||||
*ngIf="form.value.type === predicateType.isNot; else allNAnyOf"
|
|
||||||
title="Is not predicate"
|
|
||||||
(remove)="removeAll()"
|
|
||||||
>
|
|
||||||
<cc-predicate [form]="childrenForm.controls[0]"></cc-predicate>
|
|
||||||
</cc-expander>
|
|
||||||
<ng-template #allNAnyOf>
|
|
||||||
<cc-expander
|
|
||||||
*ngFor="let childForm of childrenForm.controls; let idx = index"
|
|
||||||
[title]="
|
|
||||||
(form.value.type === predicateType.anyOf ? 'Any' : 'All') +
|
|
||||||
' of predicate #' +
|
|
||||||
(idx + 1)
|
|
||||||
"
|
|
||||||
(remove)="removeChild(idx)"
|
|
||||||
>
|
|
||||||
<cc-predicate [form]="childForm"></cc-predicate>
|
|
||||||
</cc-expander>
|
|
||||||
<mat-icon class="action" fxFlexAlign="end" (click)="addChild()">add</mat-icon>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-container *ngIf="form.value.type === predicateType.constant">
|
|
||||||
<div class="cc-subheading-2">Constant</div>
|
|
||||||
<mat-radio-group formControlName="constant" fxLayout>
|
|
||||||
<mat-radio-button [value]="true" fxFlex>True</mat-radio-button>
|
|
||||||
<mat-radio-button [value]="false" fxFlex>False</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container *ngIf="form.value.type === predicateType.condition" formGroupName="condition">
|
|
||||||
<div class="cc-subheading-2">Condition</div>
|
|
||||||
<mat-radio-group formControlName="type" fxLayout="column" fxLayoutGap="16px">
|
|
||||||
<mat-radio-button [value]="conditionType.paymentTool">Payment tool</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
<ng-container
|
|
||||||
formGroupName="paymentTool"
|
|
||||||
*ngIf="form.value.condition.type === conditionType.paymentTool"
|
|
||||||
>
|
|
||||||
<div class="cc-subheading-2">Payment tool condition</div>
|
|
||||||
<mat-radio-group formControlName="type" fxLayout="column" fxLayoutGap="16px">
|
|
||||||
<mat-radio-button [value]="paymentToolType.bankCard">Bank Card</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
<ng-container
|
|
||||||
formGroupName="bankCard"
|
|
||||||
*ngIf="form.value.condition.paymentTool.type === paymentToolType.bankCard"
|
|
||||||
>
|
|
||||||
<div class="cc-subheading-2">Bank card condition</div>
|
|
||||||
<mat-radio-group formControlName="type" fxLayout="column" fxLayoutGap="16px">
|
|
||||||
<div fxLayout>
|
|
||||||
<mat-radio-button [value]="bankCardType.issuerCountryIs" fxFlex
|
|
||||||
>Issuer country is</mat-radio-button
|
|
||||||
>
|
|
||||||
<mat-radio-button [value]="bankCardType.paymentSystem" fxFlex
|
|
||||||
>Payment system</mat-radio-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<mat-radio-button [value]="bankCardType.paymentSystemIs"
|
|
||||||
>Payment system is (deprecated)</mat-radio-button
|
|
||||||
>
|
|
||||||
</mat-radio-group>
|
|
||||||
<div fxLayout="column">
|
|
||||||
<mat-form-field
|
|
||||||
*ngIf="
|
|
||||||
form.value.condition.paymentTool.bankCard.type ===
|
|
||||||
bankCardType.issuerCountryIs
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
placeholder="Residence"
|
|
||||||
formControlName="residence"
|
|
||||||
[matAutocomplete]="residenceAuto"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<mat-autocomplete autoActiveFirstOption #residenceAuto="matAutocomplete">
|
|
||||||
<mat-option *ngFor="let option of residences$ | async" [value]="option">
|
|
||||||
{{ option }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-autocomplete>
|
|
||||||
<mat-hint>ISO_3166-1 Alpha-3 Code</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field
|
|
||||||
*ngIf="
|
|
||||||
form.value.condition.paymentTool.bankCard.type ===
|
|
||||||
bankCardType.paymentSystemIs
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
placeholder="Payment system"
|
|
||||||
formControlName="paymentSystemIs"
|
|
||||||
[matAutocomplete]="paymentSystemAuto"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<mat-autocomplete
|
|
||||||
autoActiveFirstOption
|
|
||||||
#paymentSystemAuto="matAutocomplete"
|
|
||||||
>
|
|
||||||
<mat-option
|
|
||||||
*ngFor="let option of deprecatedPaymentSystems$ | async"
|
|
||||||
[value]="option"
|
|
||||||
>
|
|
||||||
{{ option }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-autocomplete>
|
|
||||||
</mat-form-field>
|
|
||||||
<ng-container
|
|
||||||
*ngIf="
|
|
||||||
form.value.condition.paymentTool.bankCard.type ===
|
|
||||||
bankCardType.paymentSystem
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<mat-form-field>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
placeholder="Payment system"
|
|
||||||
formControlName="paymentSystem"
|
|
||||||
[matAutocomplete]="paymentSystemAuto"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<mat-autocomplete
|
|
||||||
autoActiveFirstOption
|
|
||||||
#paymentSystemAuto="matAutocomplete"
|
|
||||||
>
|
|
||||||
<mat-option
|
|
||||||
*ngFor="let option of paymentSystems$ | async"
|
|
||||||
[value]="option.ref.id"
|
|
||||||
>
|
|
||||||
{{ option.data?.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-autocomplete>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
placeholder="Token provider"
|
|
||||||
formControlName="tokenProvider"
|
|
||||||
[matAutocomplete]="tokenProviderAuto"
|
|
||||||
/>
|
|
||||||
<mat-autocomplete
|
|
||||||
autoActiveFirstOption
|
|
||||||
#tokenProviderAuto="matAutocomplete"
|
|
||||||
>
|
|
||||||
<mat-option
|
|
||||||
*ngFor="let option of tokenProviders$ | async"
|
|
||||||
[value]="option"
|
|
||||||
>
|
|
||||||
{{ option }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-autocomplete>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
placeholder="Tokenization method"
|
|
||||||
formControlName="tokenizationMethod"
|
|
||||||
[matAutocomplete]="tokenizationMethodAuto"
|
|
||||||
/>
|
|
||||||
<mat-autocomplete
|
|
||||||
autoActiveFirstOption
|
|
||||||
#tokenizationMethodAuto="matAutocomplete"
|
|
||||||
>
|
|
||||||
<mat-option
|
|
||||||
*ngFor="let option of tokenizationMethods$ | async"
|
|
||||||
[value]="option"
|
|
||||||
>
|
|
||||||
{{ option }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-autocomplete>
|
|
||||||
</mat-form-field>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
.action {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
@ -1,302 +1,26 @@
|
|||||||
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
|
import { Component, Injector, OnChanges } from '@angular/core';
|
||||||
import {
|
import { Predicate } from '@vality/domain-proto/lib/domain';
|
||||||
AbstractControl,
|
import { from } from 'rxjs';
|
||||||
FormArray,
|
|
||||||
FormBuilder,
|
|
||||||
FormGroup,
|
|
||||||
ValidatorFn,
|
|
||||||
Validators,
|
|
||||||
} from '@angular/forms';
|
|
||||||
import {
|
|
||||||
BankCardConditionDefinition,
|
|
||||||
LegacyBankCardPaymentSystem,
|
|
||||||
LegacyBankCardTokenProvider,
|
|
||||||
Predicate,
|
|
||||||
CountryCode,
|
|
||||||
TokenizationMethod,
|
|
||||||
} from '@vality/domain-proto/lib/domain';
|
|
||||||
import identity from 'lodash-es/identity';
|
|
||||||
import pickBy from 'lodash-es/pickBy';
|
|
||||||
import { merge, Observable, Subscription } from 'rxjs';
|
|
||||||
import { distinctUntilChanged, map, shareReplay, startWith, tap } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { ComponentChanges } from '@cc/app/shared/utils';
|
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
||||||
|
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||||
import { DomainStoreService } from '../../../../../thrift-services/damsel/domain-store.service';
|
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
|
||||||
enum PredicateType {
|
|
||||||
constant = 'constant',
|
|
||||||
condition = 'condition',
|
|
||||||
anyOf = 'anyOf',
|
|
||||||
allOf = 'allOf',
|
|
||||||
isNot = 'isNot',
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ConditionType {
|
|
||||||
paymentTool = 'paymentTool',
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PaymentToolType {
|
|
||||||
bankCard = 'bankCard',
|
|
||||||
}
|
|
||||||
|
|
||||||
enum BankCardType {
|
|
||||||
issuerCountryIs = 'issuerCountryIs',
|
|
||||||
paymentSystem = 'paymentSystem',
|
|
||||||
paymentSystemIs = 'paymentSystemIs',
|
|
||||||
}
|
|
||||||
/* eslint-enable @typescript-eslint/naming-convention */
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-predicate',
|
selector: 'cc-predicate',
|
||||||
templateUrl: 'predicate.component.html',
|
templateUrl: 'predicate.component.html',
|
||||||
styleUrls: ['predicate.component.scss'],
|
providers: createControlProviders(PredicateComponent),
|
||||||
})
|
})
|
||||||
export class PredicateComponent implements OnChanges {
|
export class PredicateComponent
|
||||||
@Input() form = this.createForm();
|
extends ValidatedFormControlSuperclass<Predicate>
|
||||||
@Output() validationChange = new EventEmitter<boolean>();
|
implements OnChanges
|
||||||
@Output() predicateChange = new EventEmitter<Predicate>();
|
|
||||||
|
|
||||||
predicateType = PredicateType;
|
|
||||||
conditionType = ConditionType;
|
|
||||||
paymentToolType = PaymentToolType;
|
|
||||||
bankCardType = BankCardType;
|
|
||||||
|
|
||||||
deprecatedPaymentSystems$: Observable<string[]>;
|
|
||||||
paymentSystems$ = this.domainStoreService.getObjects('payment_system');
|
|
||||||
tokenProviders$: Observable<string[]>;
|
|
||||||
tokenizationMethods$: Observable<string[]>;
|
|
||||||
residences$: Observable<string[]>;
|
|
||||||
|
|
||||||
private outputSub: Subscription;
|
|
||||||
|
|
||||||
get childrenForm() {
|
|
||||||
return this.form?.controls?.children as FormArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(private fb: FormBuilder, private domainStoreService: DomainStoreService) {
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges({ form }: ComponentChanges<PredicateComponent>): void {
|
|
||||||
if (form) {
|
|
||||||
this.init(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addChild() {
|
|
||||||
this.childrenForm.push(this.createForm());
|
|
||||||
}
|
|
||||||
|
|
||||||
removeChild(idx: number) {
|
|
||||||
this.childrenForm.removeAt(idx);
|
|
||||||
if (!this.childrenForm.controls.length) {
|
|
||||||
this.addChild();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAll() {
|
|
||||||
this.childrenForm.clear();
|
|
||||||
this.addChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
private init(isInternal = false) {
|
|
||||||
if (this.childrenForm && !this.childrenForm.controls.length) {
|
|
||||||
this.addChild();
|
|
||||||
}
|
|
||||||
const { condition, constant, type } = this.form.controls;
|
|
||||||
type.valueChanges.pipe(startWith(type.value), distinctUntilChanged()).subscribe((t) => {
|
|
||||||
switch (t) {
|
|
||||||
case PredicateType.allOf:
|
|
||||||
case PredicateType.anyOf:
|
|
||||||
case PredicateType.isNot:
|
|
||||||
this.childrenForm.enable();
|
|
||||||
constant.disable();
|
|
||||||
condition.disable();
|
|
||||||
break;
|
|
||||||
case PredicateType.constant:
|
|
||||||
this.childrenForm.disable();
|
|
||||||
constant.enable();
|
|
||||||
condition.disable();
|
|
||||||
break;
|
|
||||||
case PredicateType.condition:
|
|
||||||
this.childrenForm.disable();
|
|
||||||
constant.disable();
|
|
||||||
condition.enable();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.childrenForm.disable();
|
|
||||||
constant.disable();
|
|
||||||
condition.disable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const {
|
|
||||||
residence,
|
|
||||||
paymentSystemIs,
|
|
||||||
paymentSystem,
|
|
||||||
type: bankCardType,
|
|
||||||
tokenProvider,
|
|
||||||
tokenizationMethod,
|
|
||||||
} = (this.form.get('condition.paymentTool.bankCard') as FormGroup).controls;
|
|
||||||
bankCardType.valueChanges
|
|
||||||
.pipe(startWith(bankCardType.value), distinctUntilChanged())
|
|
||||||
.subscribe((t) => {
|
|
||||||
switch (t) {
|
|
||||||
case BankCardType.issuerCountryIs:
|
|
||||||
paymentSystem.disable();
|
|
||||||
paymentSystemIs.disable();
|
|
||||||
residence.enable();
|
|
||||||
break;
|
|
||||||
case BankCardType.paymentSystem:
|
|
||||||
residence.disable();
|
|
||||||
paymentSystemIs.disable();
|
|
||||||
paymentSystem.enable();
|
|
||||||
break;
|
|
||||||
case BankCardType.paymentSystemIs:
|
|
||||||
residence.disable();
|
|
||||||
paymentSystem.disable();
|
|
||||||
paymentSystemIs.enable();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
residence.disable();
|
|
||||||
paymentSystem.disable();
|
|
||||||
paymentSystemIs.disable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (this.outputSub) {
|
|
||||||
this.outputSub.unsubscribe();
|
|
||||||
delete this.outputSub;
|
|
||||||
}
|
|
||||||
if (!isInternal) {
|
|
||||||
this.outputSub = merge(
|
|
||||||
this.form.valueChanges.pipe(
|
|
||||||
startWith(this.form.value),
|
|
||||||
map(() => this.valueToPredicate()),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
tap((v) => this.predicateChange.next(v))
|
|
||||||
),
|
|
||||||
this.form.statusChanges.pipe(
|
|
||||||
startWith(this.form.status),
|
|
||||||
map(() => this.form.valid),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
tap((s) => this.validationChange.next(s))
|
|
||||||
)
|
|
||||||
).subscribe();
|
|
||||||
}
|
|
||||||
this.deprecatedPaymentSystems$ = this.getFilteredKeys(
|
|
||||||
paymentSystemIs,
|
|
||||||
LegacyBankCardPaymentSystem
|
|
||||||
);
|
|
||||||
this.tokenProviders$ = this.getFilteredKeys(tokenProvider, LegacyBankCardTokenProvider);
|
|
||||||
this.tokenizationMethods$ = this.getFilteredKeys(tokenizationMethod, TokenizationMethod);
|
|
||||||
this.residences$ = this.getFilteredKeys(residence, CountryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private createForm() {
|
|
||||||
return this.fb.group({
|
|
||||||
type: ['', Validators.required],
|
|
||||||
condition: this.fb.group({
|
|
||||||
type: [ConditionType.paymentTool, Validators.required],
|
|
||||||
paymentTool: this.fb.group({
|
|
||||||
type: [PaymentToolType.bankCard, Validators.required],
|
|
||||||
bankCard: this.fb.group({
|
|
||||||
type: ['', Validators.required],
|
|
||||||
residence: ['', [Validators.required, this.enumValidator(CountryCode)]],
|
|
||||||
paymentSystemIs: [
|
|
||||||
'',
|
|
||||||
[Validators.required, this.enumValidator(LegacyBankCardPaymentSystem)],
|
|
||||||
],
|
|
||||||
paymentSystem: ['', [Validators.required]],
|
|
||||||
tokenProvider: ['', this.enumValidator(LegacyBankCardTokenProvider)],
|
|
||||||
tokenizationMethod: ['', this.enumValidator(TokenizationMethod)],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
constant: ['', Validators.required],
|
|
||||||
children: this.fb.array([]),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private valueToPredicate(value = this.form.value): Predicate {
|
|
||||||
if (this.form.invalid) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
switch (value.type) {
|
|
||||||
case PredicateType.allOf:
|
|
||||||
return { all_of: value.children.map((c) => this.valueToPredicate(c)) };
|
|
||||||
case PredicateType.anyOf:
|
|
||||||
return { any_of: value.children.map((c) => this.valueToPredicate(c)) };
|
|
||||||
case PredicateType.isNot:
|
|
||||||
return { is_not: this.valueToPredicate(value.children[0]) };
|
|
||||||
case PredicateType.constant:
|
|
||||||
return { constant: value.constant };
|
|
||||||
case PredicateType.condition:
|
|
||||||
if (!value.condition) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
condition: {
|
|
||||||
payment_tool: {
|
|
||||||
bank_card: {
|
|
||||||
definition: this.bankCardValueToBankCardConditionDefinition(
|
|
||||||
value.condition.paymentTool.bankCard
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bankCardValueToBankCardConditionDefinition(value: any): BankCardConditionDefinition {
|
|
||||||
switch (value.type) {
|
|
||||||
case BankCardType.issuerCountryIs:
|
|
||||||
return { issuer_country_is: CountryCode[value.residence as string] };
|
|
||||||
case BankCardType.paymentSystem:
|
|
||||||
return {
|
|
||||||
payment_system: pickBy(
|
|
||||||
{
|
{
|
||||||
tokenization_method_is:
|
metadata$ = from(import('@vality/domain-proto/lib/metadata.json').then((m) => m.default));
|
||||||
TokenizationMethod[value.tokenizationMethod as string],
|
extensions$ = this.domainMetadataFormExtensionsService.extensions$;
|
||||||
payment_system_is: { id: value.paymentSystem },
|
|
||||||
token_provider_is_deprecated:
|
|
||||||
LegacyBankCardTokenProvider[value.tokenProvider as string],
|
|
||||||
},
|
|
||||||
identity
|
|
||||||
),
|
|
||||||
};
|
|
||||||
case BankCardType.paymentSystemIs:
|
|
||||||
return {
|
|
||||||
payment_system_is:
|
|
||||||
LegacyBankCardPaymentSystem[
|
|
||||||
value.paymentSystemIs as keyof LegacyBankCardPaymentSystem
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getFilteredKeys(control: AbstractControl, enumObj: any) {
|
constructor(
|
||||||
return control.valueChanges.pipe(
|
injector: Injector,
|
||||||
startWith(control.value),
|
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService
|
||||||
map((v) => v.trim().toLowerCase()),
|
) {
|
||||||
map((v) =>
|
super(injector);
|
||||||
this.getKeys(enumObj).filter((option) => option.toLowerCase().indexOf(v) === 0)
|
|
||||||
),
|
|
||||||
shareReplay(1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getKeys(enumObj: any) {
|
|
||||||
return Object.keys(enumObj).filter((k) => isNaN(+k));
|
|
||||||
}
|
|
||||||
|
|
||||||
private enumValidator(enumObj: any): ValidatorFn {
|
|
||||||
return (control: AbstractControl): { [key: string]: any } | null =>
|
|
||||||
!control.value || Object.keys(enumObj).includes(control.value)
|
|
||||||
? null
|
|
||||||
: { enumNotIncludeKey: { value: control.value } };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { Predicate, TerminalObject } from '@vality/domain-proto/lib/domain';
|
import { Predicate, TerminalObject } from '@vality/domain-proto/lib/domain';
|
||||||
import { combineLatest } from 'rxjs';
|
import { first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||||
import { map, shareReplay, switchMap, take } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { objectToJSON } from '@cc/app/api/utils';
|
import { objectToJSON } from '@cc/app/api/utils';
|
||||||
|
import { NotificationService } from '@cc/app/shared/services/notification';
|
||||||
|
import { BaseDialogResponseStatus } from '@cc/components/base-dialog';
|
||||||
|
import { BaseDialogService } from '@cc/components/base-dialog/services/base-dialog.service';
|
||||||
|
|
||||||
import { handleError } from '../../../../utils/operators/handle-error';
|
|
||||||
import { ErrorService } from '../../../shared/services/error';
|
import { ErrorService } from '../../../shared/services/error';
|
||||||
import { damselInstanceToObject } from '../../../thrift-services';
|
import { damselInstanceToObject } from '../../../thrift-services';
|
||||||
import { DomainStoreService } from '../../../thrift-services/damsel/domain-store.service';
|
import { DomainStoreService } from '../../../thrift-services/damsel/domain-store.service';
|
||||||
import { AddShopPaymentRoutingRuleDialogComponent } from './add-shop-payment-routing-rule-dialog';
|
import { AddShopPaymentRoutingRuleDialogComponent } from './add-shop-payment-routing-rule-dialog';
|
||||||
import { ShopPaymentRoutingRulesetService } from './shop-payment-routing-ruleset.service';
|
import { ShopPaymentRoutingRulesetService } from './shop-payment-routing-ruleset.service';
|
||||||
|
|
||||||
const DIALOG_WIDTH = '548px';
|
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-shop-payment-routing-ruleset',
|
selector: 'cc-shop-payment-routing-ruleset',
|
||||||
@ -44,30 +42,40 @@ export class ShopPaymentRoutingRulesetComponent {
|
|||||||
isLoading$ = this.domainStoreService.isLoading$;
|
isLoading$ = this.domainStoreService.isLoading$;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dialog: MatDialog,
|
private baseDialogService: BaseDialogService,
|
||||||
private shopPaymentRoutingRulesetService: ShopPaymentRoutingRulesetService,
|
private shopPaymentRoutingRulesetService: ShopPaymentRoutingRulesetService,
|
||||||
private domainStoreService: DomainStoreService,
|
private domainStoreService: DomainStoreService,
|
||||||
private errorService: ErrorService
|
private errorService: ErrorService,
|
||||||
|
private notificationService: NotificationService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
addShopRule() {
|
addShopRule() {
|
||||||
combineLatest([this.partyID$, this.shopPaymentRoutingRulesetService.refID$])
|
this.shopPaymentRoutingRulesetService.refID$
|
||||||
.pipe(
|
.pipe(
|
||||||
take(1),
|
first(),
|
||||||
switchMap(([partyID, refID]) =>
|
switchMap((refID) =>
|
||||||
this.dialog
|
this.baseDialogService
|
||||||
.open(AddShopPaymentRoutingRuleDialogComponent, {
|
.open(AddShopPaymentRoutingRuleDialogComponent, { refID })
|
||||||
disableClose: true,
|
|
||||||
width: DIALOG_WIDTH,
|
|
||||||
maxHeight: '90vh',
|
|
||||||
data: { partyID, refID },
|
|
||||||
})
|
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
),
|
|
||||||
handleError(this.errorService.error),
|
|
||||||
untilDestroyed(this)
|
|
||||||
)
|
)
|
||||||
.subscribe();
|
)
|
||||||
|
.pipe(untilDestroyed(this))
|
||||||
|
.subscribe({
|
||||||
|
next: (res) => {
|
||||||
|
if (res.status === BaseDialogResponseStatus.Success) {
|
||||||
|
this.domainStoreService.forceReload();
|
||||||
|
this.notificationService.success(
|
||||||
|
'Shop payment routing ruleset successfully added'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.errorService.error(err);
|
||||||
|
this.notificationService.success(
|
||||||
|
'Error while adding shop payment routing ruleset'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeShopRule(idx: number) {
|
removeShopRule(idx: number) {
|
||||||
|
@ -21,7 +21,6 @@ import { RouterModule } from '@angular/router';
|
|||||||
|
|
||||||
import { PrettyJsonModule } from '@cc/components/pretty-json';
|
import { PrettyJsonModule } from '@cc/components/pretty-json';
|
||||||
|
|
||||||
import { ErrorModule } from '../../../shared/services/error';
|
|
||||||
import { DamselModule } from '../../../thrift-services';
|
import { DamselModule } from '../../../thrift-services';
|
||||||
import { PaymentRoutingRulesetHeaderModule } from '../payment-routing-ruleset-header';
|
import { PaymentRoutingRulesetHeaderModule } from '../payment-routing-ruleset-header';
|
||||||
import { AddShopPaymentRoutingRuleDialogModule } from './add-shop-payment-routing-rule-dialog';
|
import { AddShopPaymentRoutingRuleDialogModule } from './add-shop-payment-routing-rule-dialog';
|
||||||
@ -54,7 +53,6 @@ import { ShopPaymentRoutingRulesetComponent } from './shop-payment-routing-rules
|
|||||||
AddShopPaymentRoutingRuleDialogModule,
|
AddShopPaymentRoutingRuleDialogModule,
|
||||||
PrettyJsonModule,
|
PrettyJsonModule,
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
ErrorModule,
|
|
||||||
],
|
],
|
||||||
declarations: [ShopPaymentRoutingRulesetComponent],
|
declarations: [ShopPaymentRoutingRulesetComponent],
|
||||||
})
|
})
|
||||||
|
@ -10,13 +10,11 @@ import { MatRadioModule } from '@angular/material/radio';
|
|||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
import { DetailsItemModule } from '../../../../components/details-item';
|
import { DetailsItemModule } from '../../../../components/details-item';
|
||||||
import { ErrorModule } from '../../../shared/services/error';
|
|
||||||
import { TargetRulesetFormComponent } from './target-ruleset-form.component';
|
import { TargetRulesetFormComponent } from './target-ruleset-form.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
ErrorModule,
|
|
||||||
FlexLayoutModule,
|
FlexLayoutModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
|
@ -6,10 +6,7 @@ import { Party, Shop } from '@vality/magista-proto/lib/domain';
|
|||||||
import { Moment } from 'moment';
|
import { Moment } from 'moment';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
import {
|
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils/forms';
|
||||||
createValidatedAbstractControlProviders,
|
|
||||||
ValidatedWrappedAbstractControlSuperclass,
|
|
||||||
} from '@cc/utils/forms';
|
|
||||||
import { getEnumKeys } from '@cc/utils/get-enum-keys';
|
import { getEnumKeys } from '@cc/utils/get-enum-keys';
|
||||||
|
|
||||||
export interface PayoutsSearchForm {
|
export interface PayoutsSearchForm {
|
||||||
@ -25,9 +22,9 @@ export interface PayoutsSearchForm {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-payouts-search-form',
|
selector: 'cc-payouts-search-form',
|
||||||
templateUrl: './payouts-search-form.component.html',
|
templateUrl: './payouts-search-form.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(PayoutsSearchFormComponent),
|
providers: createControlProviders(PayoutsSearchFormComponent),
|
||||||
})
|
})
|
||||||
export class PayoutsSearchFormComponent extends ValidatedWrappedAbstractControlSuperclass<PayoutsSearchForm> {
|
export class PayoutsSearchFormComponent extends ValidatedControlSuperclass<PayoutsSearchForm> {
|
||||||
control = this.fb.group<PayoutsSearchForm>({
|
control = this.fb.group<PayoutsSearchForm>({
|
||||||
payoutId: null,
|
payoutId: null,
|
||||||
partyId: null,
|
partyId: null,
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
export * from './settings.module';
|
|
||||||
export * from './settings.service';
|
|
@ -1,8 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
|
|
||||||
import { SettingsService } from './settings.service';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
providers: [SettingsService],
|
|
||||||
})
|
|
||||||
export class SettingsModule {}
|
|
@ -1,22 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class SettingsService {
|
|
||||||
set(key: string, value: string) {
|
|
||||||
localStorage.setItem(this.getKeyName(key), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setAll(keyValue: { [name: string]: string }) {
|
|
||||||
for (const [k, v] of Object.entries(keyValue)) {
|
|
||||||
this.set(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key: string): string {
|
|
||||||
return localStorage.getItem(this.getKeyName(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
private getKeyName(name: string) {
|
|
||||||
return `cc-${name}`;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +1,17 @@
|
|||||||
<div gdColumns="1fr" gdGap="16px">
|
<div gdColumns="1fr" gdGap="16px">
|
||||||
<span class="cc-body-1">
|
<span class="cc-body-1" *ngIf="hasLabel">
|
||||||
<cc-field-label [field]="data.field" [type]="data.type"></cc-field-label>
|
<cc-field-label [field]="data.field" [type]="data.type"></cc-field-label>
|
||||||
({{ data.type.name | titlecase }})
|
({{ data.type.name | titlecase }})
|
||||||
</span>
|
</span>
|
||||||
<mat-accordion>
|
<mat-accordion [ngStyle]="{ 'padding-left': hasLabel && '16px' }">
|
||||||
<mat-expansion-panel
|
<mat-expansion-panel
|
||||||
class="mat-elevation-z0"
|
class="mat-elevation-z0"
|
||||||
*ngFor="let control of controls.controls; let i = index"
|
*ngFor="let valueControl of valueControls.controls; let i = index"
|
||||||
>
|
>
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title fxLayoutAlign=" center">
|
<mat-panel-title fxLayoutAlign=" center">
|
||||||
{{ i + 1 }}.
|
{{ i + 1 }}.
|
||||||
{{
|
{{ hasKeys ? (keyType | valueTypeTitle | titlecase) + ' - ' : '' }}
|
||||||
data.type.name === 'map'
|
|
||||||
? (data.type.keyType | valueTypeTitle | titlecase) + ' - '
|
|
||||||
: ''
|
|
||||||
}}
|
|
||||||
{{ data.type.valueType | valueTypeTitle | titlecase }}
|
{{ data.type.valueType | valueTypeTitle | titlecase }}
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
<mat-panel-description fxLayoutAlign="end">
|
<mat-panel-description fxLayoutAlign="end">
|
||||||
@ -25,18 +21,20 @@
|
|||||||
</mat-panel-description>
|
</mat-panel-description>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<div gdColumns="1fr" gdGap="16px">
|
<div gdColumns="1fr" gdGap="16px">
|
||||||
<ng-container *ngIf="data.type.name === 'map'">
|
<ng-container *ngIf="hasKeys">
|
||||||
<span class="cc-body-2">Key</span>
|
<span class="cc-body-2">Key</span>
|
||||||
<cc-metadata-form
|
<cc-metadata-form
|
||||||
|
[formControl]="keyControls.controls[i]"
|
||||||
[metadata]="data.metadata"
|
[metadata]="data.metadata"
|
||||||
[namespace]="data.namespace"
|
[namespace]="data.namespace"
|
||||||
[type]="data.type.keyType"
|
[type]="keyType"
|
||||||
[parent]="data"
|
[parent]="data"
|
||||||
[extensions]="data.extensions"
|
[extensions]="data.extensions"
|
||||||
></cc-metadata-form>
|
></cc-metadata-form>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<span class="cc-body-2" *ngIf="data.type.name === 'map'">Value</span>
|
<span class="cc-body-2" *ngIf="data.type.name === 'map'">Value</span>
|
||||||
<cc-metadata-form
|
<cc-metadata-form
|
||||||
|
[formControl]="valueControl"
|
||||||
[metadata]="data.metadata"
|
[metadata]="data.metadata"
|
||||||
[namespace]="data.namespace"
|
[namespace]="data.namespace"
|
||||||
[type]="data.type.valueType"
|
[type]="data.type.valueType"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
mat-expansion-panel-body {
|
::ng-deep .mat-expansion-panel-body {
|
||||||
padding: 0;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-expansion-panel-header {
|
mat-expansion-panel-header {
|
||||||
|
@ -1,38 +1,75 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { ValidationErrors, Validator } from '@angular/forms';
|
import { ValidationErrors, Validator } from '@angular/forms';
|
||||||
import { FormArray, FormControl } from '@ngneat/reactive-forms';
|
import { FormArray, FormControl } from '@ngneat/reactive-forms';
|
||||||
import { WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
|
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
||||||
import { MapType, SetType, ListType } from '@vality/thrift-ts';
|
import { MapType, SetType, ListType } from '@vality/thrift-ts';
|
||||||
|
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-complex-form',
|
selector: 'cc-complex-form',
|
||||||
templateUrl: './complex-form.component.html',
|
templateUrl: './complex-form.component.html',
|
||||||
styleUrls: ['complex-form.component.scss'],
|
styleUrls: ['complex-form.component.scss'],
|
||||||
providers: createValidatedAbstractControlProviders(ComplexFormComponent),
|
providers: createControlProviders(ComplexFormComponent),
|
||||||
})
|
})
|
||||||
export class ComplexFormComponent
|
export class ComplexFormComponent<T extends unknown[] | Map<unknown, unknown> | Set<unknown>>
|
||||||
extends WrappedFormControlSuperclass<unknown>
|
extends FormComponentSuperclass<T>
|
||||||
implements Validator
|
implements OnInit, Validator
|
||||||
{
|
{
|
||||||
@Input() data: MetadataFormData<SetType | MapType | ListType>;
|
@Input() data: MetadataFormData<SetType | MapType | ListType>;
|
||||||
|
|
||||||
controls = new FormArray([]);
|
valueControls = new FormArray([]);
|
||||||
|
keyControls = new FormArray([]);
|
||||||
|
|
||||||
add() {
|
get hasLabel() {
|
||||||
this.controls.push(new FormControl());
|
return !!this.data.trueParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(idx: number) {
|
get hasKeys() {
|
||||||
this.controls.removeAt(idx);
|
return this.data.type.name === 'map';
|
||||||
|
}
|
||||||
|
|
||||||
|
get keyType() {
|
||||||
|
if ('keyType' in this.data.type) return this.data.type.keyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.valueControls.valueChanges.pipe(untilDestroyed(this)).subscribe((value) => {
|
||||||
|
switch (this.data.type.name) {
|
||||||
|
case 'list':
|
||||||
|
this.emitOutgoingValue(value as never);
|
||||||
|
break;
|
||||||
|
case 'map':
|
||||||
|
this.emitOutgoingValue(
|
||||||
|
new Map(value.map((v, idx) => [this.keyControls.value[idx], v])) as never
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'set':
|
||||||
|
this.emitOutgoingValue(new Set(value) as never);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleIncomingValue(value: T) {
|
||||||
|
this.valueControls.patchValue(value as never, { emitEvent: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
validate(): ValidationErrors | null {
|
||||||
return this.control.invalid || this.controls.invalid
|
return getErrorsTree(this.keyControls) || getErrorsTree(this.valueControls);
|
||||||
? { [this.data.type.name + 'Invalid']: true }
|
}
|
||||||
: null;
|
|
||||||
|
add() {
|
||||||
|
this.valueControls.push(new FormControl());
|
||||||
|
if (this.hasKeys) this.keyControls.push(new FormControl());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(idx: number) {
|
||||||
|
this.valueControls.removeAt(idx);
|
||||||
|
if (this.hasKeys) this.keyControls.removeAt(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
<cc-field-label [field]="data.field" [type]="data.type"></cc-field-label>
|
<cc-field-label [field]="data.field" [type]="data.type"></cc-field-label>
|
||||||
</mat-label>
|
</mat-label>
|
||||||
<mat-select [formControl]="control" [required]="data.isRequired">
|
<mat-select [formControl]="control" [required]="data.isRequired">
|
||||||
<mat-option *ngFor="let item of data.ast.items" [value]="item.value">{{
|
<mat-option
|
||||||
item.name
|
*ngFor="let item of data.ast.items; let idx = index"
|
||||||
}}</mat-option>
|
[value]="item.value ?? idx"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
<button
|
<button
|
||||||
matSuffix
|
matSuffix
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { ValidationErrors, Validator } from '@angular/forms';
|
|
||||||
import { WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
|
||||||
import { Enums } from '@vality/thrift-ts/src/thrift-parser';
|
import { Enums } from '@vality/thrift-ts/src/thrift-parser';
|
||||||
|
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-enum-field',
|
selector: 'cc-enum-field',
|
||||||
templateUrl: './enum-field.component.html',
|
templateUrl: './enum-field.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(EnumFieldComponent),
|
providers: createControlProviders(EnumFieldComponent),
|
||||||
})
|
})
|
||||||
export class EnumFieldComponent extends WrappedFormControlSuperclass<unknown> implements Validator {
|
export class EnumFieldComponent<T> extends ValidatedFormControlSuperclass<T> {
|
||||||
@Input() data: MetadataFormData<string, Enums[string]>;
|
@Input() data: MetadataFormData<string, Enums[string]>;
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
|
||||||
return this.control.errors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,32 @@
|
|||||||
<div gdColumns="1fr" gdGap="16px">
|
<div gdColumns="1fr" gdGap="16px">
|
||||||
|
<ng-container *ngIf="data.type === 'bool'; else input">
|
||||||
|
<div gdColumns="1fr" gdGap="16px">
|
||||||
|
<cc-field-label
|
||||||
|
class="cc-body-1"
|
||||||
|
[field]="data.field"
|
||||||
|
[type]="data.type"
|
||||||
|
></cc-field-label>
|
||||||
|
<div fxLayoutGap="4px" fxLayoutAlign=" center">
|
||||||
|
<mat-radio-group fxFlex gdColumns="1fr 1fr" gdGap="8px" [formControl]="control">
|
||||||
|
<mat-radio-button [value]="false">False</mat-radio-button>
|
||||||
|
<mat-radio-button [value]="true">True</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
*ngIf="
|
||||||
|
!data.isRequired && control.value !== null && control.value !== undefined
|
||||||
|
"
|
||||||
|
(click)="clear($event)"
|
||||||
|
>
|
||||||
|
<mat-icon>clear</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="generate$ | async" mat-icon-button (click)="generate($event)">
|
||||||
|
<mat-icon>loop</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-template #input>
|
||||||
<div fxLayoutGap="4px">
|
<div fxLayoutGap="4px">
|
||||||
<mat-form-field fxFlex>
|
<mat-form-field fxFlex>
|
||||||
<mat-label>
|
<mat-label>
|
||||||
@ -14,7 +42,11 @@
|
|||||||
[ngClass]="{ 'cc-code': (data.extensionResult$ | async)?.isIdentifier }"
|
[ngClass]="{ 'cc-code': (data.extensionResult$ | async)?.isIdentifier }"
|
||||||
/>
|
/>
|
||||||
<div matSuffix fxLayoutGap="4px">
|
<div matSuffix fxLayoutGap="4px">
|
||||||
<button mat-icon-button *ngIf="control.value" (click)="clear($event)">
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
*ngIf="!data.isRequired && control.value"
|
||||||
|
(click)="clear($event)"
|
||||||
|
>
|
||||||
<mat-icon>clear</mat-icon>
|
<mat-icon>clear</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@ -49,6 +81,7 @@
|
|||||||
<mat-icon>loop</mat-icon>
|
<mat-icon>loop</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
<ng-container *ngIf="selected$ | async as selected">
|
<ng-container *ngIf="selected$ | async as selected">
|
||||||
<mat-expansion-panel *ngIf="selected.details">
|
<mat-expansion-panel *ngIf="selected.details">
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import { Component, Input, OnChanges } from '@angular/core';
|
||||||
import { ValidationErrors, Validator } from '@angular/forms';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
|
||||||
import { ThriftType } from '@vality/thrift-ts';
|
import { ThriftType } from '@vality/thrift-ts';
|
||||||
import { combineLatest, defer, ReplaySubject, switchMap } from 'rxjs';
|
import { combineLatest, defer, ReplaySubject, switchMap } from 'rxjs';
|
||||||
import { map, pluck, shareReplay, startWith } from 'rxjs/operators';
|
import { map, pluck, shareReplay, startWith } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ComponentChanges, getAliases, getValueTypeTitle } from '@cc/app/shared';
|
import { ComponentChanges, getAliases, getValueTypeTitle } from '@cc/app/shared';
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
@ -15,11 +13,11 @@ import { MetadataFormData } from '../../types/metadata-form-data';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-primitive-field',
|
selector: 'cc-primitive-field',
|
||||||
templateUrl: './primitive-field.component.html',
|
templateUrl: './primitive-field.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(PrimitiveFieldComponent),
|
providers: createControlProviders(PrimitiveFieldComponent),
|
||||||
})
|
})
|
||||||
export class PrimitiveFieldComponent
|
export class PrimitiveFieldComponent<T>
|
||||||
extends WrappedFormControlSuperclass<unknown>
|
extends ValidatedFormControlSuperclass<T>
|
||||||
implements OnChanges, Validator
|
implements OnChanges
|
||||||
{
|
{
|
||||||
@Input() data: MetadataFormData<ThriftType>;
|
@Input() data: MetadataFormData<ThriftType>;
|
||||||
|
|
||||||
@ -71,22 +69,18 @@ export class PrimitiveFieldComponent
|
|||||||
|
|
||||||
private data$ = new ReplaySubject<MetadataFormData<ThriftType>>(1);
|
private data$ = new ReplaySubject<MetadataFormData<ThriftType>>(1);
|
||||||
|
|
||||||
ngOnChanges(changes: ComponentChanges<PrimitiveFieldComponent>) {
|
ngOnChanges(changes: ComponentChanges<PrimitiveFieldComponent<T>>) {
|
||||||
super.ngOnChanges(changes);
|
super.ngOnChanges(changes);
|
||||||
if (changes.data) this.data$.next(this.data);
|
if (changes.data) this.data$.next(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
|
||||||
return this.control.errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
generate(event: MouseEvent) {
|
generate(event: MouseEvent) {
|
||||||
this.generate$
|
this.generate$
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap((generate) => generate()),
|
switchMap((generate) => generate()),
|
||||||
untilDestroyed(this)
|
untilDestroyed(this)
|
||||||
)
|
)
|
||||||
.subscribe((value) => this.control.setValue(value));
|
.subscribe((value) => this.control.setValue(value as T));
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div gdColumns="1fr" gdGap="16px">
|
<div gdColumns="1fr" gdGap="16px">
|
||||||
<ng-container *ngIf="data.trueParent?.objectType !== 'union'">
|
<ng-container *ngIf="hasLabel">
|
||||||
<mat-checkbox *ngIf="!labelControl.disabled; else label" [formControl]="labelControl">
|
<mat-checkbox *ngIf="!labelControl.disabled; else label" [formControl]="labelControl">
|
||||||
<ng-container [ngTemplateOutlet]="label"></ng-container>
|
<ng-container [ngTemplateOutlet]="label"></ng-container>
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
@ -14,6 +14,7 @@
|
|||||||
<ng-container *ngIf="labelControl.value">
|
<ng-container *ngIf="labelControl.value">
|
||||||
<cc-metadata-form
|
<cc-metadata-form
|
||||||
*ngFor="let field of data.ast"
|
*ngFor="let field of data.ast"
|
||||||
|
[ngStyle]="{ 'padding-left': hasLabel && '16px' }"
|
||||||
[formControl]="control.get(field.name)"
|
[formControl]="control.get(field.name)"
|
||||||
[metadata]="data.metadata"
|
[metadata]="data.metadata"
|
||||||
[namespace]="data.namespace"
|
[namespace]="data.namespace"
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { Component, Injector, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
import { Component, Injector, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||||
import { ValidationErrors, Validator, Validators } from '@angular/forms';
|
import { Validators } from '@angular/forms';
|
||||||
import { FormBuilder } from '@ngneat/reactive-forms';
|
import { FormBuilder } from '@ngneat/reactive-forms';
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
|
||||||
import { Field } from '@vality/thrift-ts';
|
import { Field } from '@vality/thrift-ts';
|
||||||
import isNil from 'lodash-es/isNil';
|
import isNil from 'lodash-es/isNil';
|
||||||
import omitBy from 'lodash-es/omitBy';
|
import omitBy from 'lodash-es/omitBy';
|
||||||
import { merge } from 'rxjs';
|
import { merge } from 'rxjs';
|
||||||
import { delay } from 'rxjs/operators';
|
import { delay } from 'rxjs/operators';
|
||||||
|
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils';
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
@ -17,17 +16,25 @@ import { MetadataFormData } from '../../types/metadata-form-data';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-struct-form',
|
selector: 'cc-struct-form',
|
||||||
templateUrl: './struct-form.component.html',
|
templateUrl: './struct-form.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(StructFormComponent),
|
providers: createControlProviders(StructFormComponent),
|
||||||
})
|
})
|
||||||
export class StructFormComponent
|
export class StructFormComponent<T extends { [N in string]: unknown }>
|
||||||
extends FormComponentSuperclass<{ [N in string]: unknown }>
|
extends ValidatedControlSuperclass<T>
|
||||||
implements OnChanges, Validator, OnInit
|
implements OnChanges, OnInit
|
||||||
{
|
{
|
||||||
@Input() data: MetadataFormData<string, Field[]>;
|
@Input() data: MetadataFormData<string, Field[]>;
|
||||||
|
|
||||||
control = this.fb.group<{ [N in string]: unknown }>({});
|
control = this.fb.group<T>({} as T);
|
||||||
labelControl = this.fb.control(false);
|
labelControl = this.fb.control(false);
|
||||||
|
|
||||||
|
get hasLabel() {
|
||||||
|
return (
|
||||||
|
!!this.data.trueParent &&
|
||||||
|
this.data.trueParent.objectType !== 'union' &&
|
||||||
|
this.data.trueParent.typeGroup !== 'complex'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(injector: Injector, private fb: FormBuilder) {
|
constructor(injector: Injector, private fb: FormBuilder) {
|
||||||
super(injector);
|
super(injector);
|
||||||
}
|
}
|
||||||
@ -38,52 +45,46 @@ export class StructFormComponent
|
|||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.emitOutgoingValue(
|
this.emitOutgoingValue(
|
||||||
this.control.value && this.labelControl.value
|
this.control.value && this.labelControl.value
|
||||||
? omitBy(this.control.value, isNil)
|
? (omitBy(this.control.value, isNil) as T)
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
return super.ngOnInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const newControlsNames = new Set(this.data.ast.map(({ name }) => name));
|
const newControlsNames = new Set(this.data.ast.map(({ name }) => name));
|
||||||
Object.keys(this.control.controls).forEach((name) => {
|
Object.keys(this.control.controls).forEach((name) => {
|
||||||
if (newControlsNames.has(name)) newControlsNames.delete(name);
|
if (newControlsNames.has(name)) newControlsNames.delete(name);
|
||||||
else this.control.removeControl(name);
|
else this.control.removeControl(name as never);
|
||||||
});
|
});
|
||||||
newControlsNames.forEach((name) =>
|
newControlsNames.forEach((name) =>
|
||||||
this.control.addControl(
|
this.control.addControl(
|
||||||
name,
|
name as never,
|
||||||
this.fb.control(null, {
|
this.fb.control(null, {
|
||||||
validators:
|
validators:
|
||||||
this.data.ast.find((f) => f.name === name)?.option === 'required'
|
this.data.ast.find((f) => f.name === name)?.option === 'required'
|
||||||
? [Validators.required]
|
? [Validators.required]
|
||||||
: [],
|
: [],
|
||||||
})
|
}) as never
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
this.setLabelControl();
|
||||||
if (this.data.isRequired) {
|
|
||||||
this.labelControl.setValue(true);
|
|
||||||
this.labelControl.disable();
|
|
||||||
} else {
|
|
||||||
this.labelControl.setValue(false);
|
|
||||||
this.labelControl.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
super.ngOnChanges(changes);
|
super.ngOnChanges(changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleIncomingValue(value: { [N in string]: unknown }) {
|
handleIncomingValue(value: T) {
|
||||||
this.control.patchValue(value, { emitEvent: false });
|
this.control.patchValue(value as never, { emitEvent: false });
|
||||||
const newValue = this.labelControl.disabled || !!(value && Object.keys(value).length);
|
this.setLabelControl(!!(value && Object.keys(value).length));
|
||||||
if (this.labelControl.value !== newValue) {
|
|
||||||
this.labelControl.setValue(newValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
private setLabelControl(value: boolean = false) {
|
||||||
return this.labelControl.value && this.control.invalid
|
if (!this.hasLabel || this.data.isRequired) {
|
||||||
? this.control.errors || { structInvalid: true }
|
if (!this.labelControl.value) this.labelControl.setValue(true);
|
||||||
: null;
|
if (this.labelControl.enabled) this.labelControl.disable();
|
||||||
|
} else {
|
||||||
|
if (this.labelControl.value !== value) this.labelControl.setValue(value);
|
||||||
|
if (this.labelControl.disabled) this.labelControl.enable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,15 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { ValidationErrors, Validator } from '@angular/forms';
|
|
||||||
import { WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
|
||||||
import { TypeDefs } from '@vality/thrift-ts';
|
import { TypeDefs } from '@vality/thrift-ts';
|
||||||
|
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-typedef-form',
|
selector: 'cc-typedef-form',
|
||||||
templateUrl: './typedef-form.component.html',
|
templateUrl: './typedef-form.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(TypedefFormComponent),
|
providers: createControlProviders(TypedefFormComponent),
|
||||||
})
|
})
|
||||||
export class TypedefFormComponent
|
export class TypedefFormComponent<T> extends ValidatedFormControlSuperclass<T> {
|
||||||
extends WrappedFormControlSuperclass<unknown>
|
|
||||||
implements Validator
|
|
||||||
{
|
|
||||||
@Input() data: MetadataFormData<string, TypeDefs[string]>;
|
@Input() data: MetadataFormData<string, TypeDefs[string]>;
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
|
||||||
return this.control.errors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { Field } from '@vality/thrift-ts';
|
|||||||
import { merge } from 'rxjs';
|
import { merge } from 'rxjs';
|
||||||
import { delay, distinctUntilChanged, map } from 'rxjs/operators';
|
import { delay, distinctUntilChanged, map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
import { getDefaultValue } from '../../utils/get-default-value';
|
import { getDefaultValue } from '../../utils/get-default-value';
|
||||||
@ -16,23 +16,23 @@ import { getDefaultValue } from '../../utils/get-default-value';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-union-field',
|
selector: 'cc-union-field',
|
||||||
templateUrl: './union-field.component.html',
|
templateUrl: './union-field.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(UnionFieldComponent),
|
providers: createControlProviders(UnionFieldComponent),
|
||||||
})
|
})
|
||||||
export class UnionFieldComponent
|
export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
||||||
extends FormComponentSuperclass<{ [N in string]: unknown }>
|
extends FormComponentSuperclass<T>
|
||||||
implements OnInit, Validator
|
implements OnInit, Validator
|
||||||
{
|
{
|
||||||
@Input() data: MetadataFormData<string, Field[]>;
|
@Input() data: MetadataFormData<string, Field[]>;
|
||||||
|
|
||||||
fieldControl = new FormControl<Field>();
|
fieldControl = new FormControl<Field>();
|
||||||
internalControl = new FormControl<unknown>();
|
internalControl = new FormControl<T[keyof T]>();
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
merge(this.fieldControl.valueChanges, this.internalControl.valueChanges)
|
merge(this.fieldControl.valueChanges, this.internalControl.valueChanges)
|
||||||
.pipe(
|
.pipe(
|
||||||
map(() => {
|
map(() => {
|
||||||
const field = this.fieldControl.value;
|
const field = this.fieldControl.value;
|
||||||
return field ? { [field.name]: this.internalControl.value } : null;
|
return field ? ({ [field.name]: this.internalControl.value } as T) : null;
|
||||||
}),
|
}),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
delay(0),
|
delay(0),
|
||||||
@ -44,14 +44,14 @@ export class UnionFieldComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
validate(): ValidationErrors | null {
|
||||||
return this.fieldControl.invalid || this.internalControl.invalid
|
return (
|
||||||
? { unionInvalid: true }
|
(this.fieldControl.errors as ValidationErrors) || getErrorsTree(this.internalControl)
|
||||||
: null;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleIncomingValue(value: { [N in string]: unknown }) {
|
handleIncomingValue(value: T) {
|
||||||
if (value) {
|
if (value) {
|
||||||
const name = Object.keys(value)[0];
|
const name: keyof T = Object.keys(value)[0];
|
||||||
this.fieldControl.setValue(
|
this.fieldControl.setValue(
|
||||||
this.data.ast.find((f) => f.name === name),
|
this.data.ast.find((f) => f.name === name),
|
||||||
{ emitEvent: false }
|
{ emitEvent: false }
|
||||||
@ -66,11 +66,11 @@ export class UnionFieldComponent
|
|||||||
cleanInternal() {
|
cleanInternal() {
|
||||||
this.internalControl.reset(
|
this.internalControl.reset(
|
||||||
this.fieldControl.value
|
this.fieldControl.value
|
||||||
? getDefaultValue(
|
? (getDefaultValue(
|
||||||
this.data.metadata,
|
this.data.metadata,
|
||||||
this.data.namespace,
|
this.data.namespace,
|
||||||
this.fieldControl.value.type
|
this.fieldControl.value.type
|
||||||
)
|
) as T[keyof T])
|
||||||
: null,
|
: null,
|
||||||
{ emitEvent: false }
|
{ emitEvent: false }
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
<div
|
<div [ngSwitch]="data?.typeGroup">
|
||||||
[ngSwitch]="data?.typeGroup"
|
|
||||||
[style]="data?.parent?.objectType === 'struct' ? 'padding-left: 16px' : ''"
|
|
||||||
>
|
|
||||||
<cc-primitive-field
|
<cc-primitive-field
|
||||||
*ngSwitchCase="'primitive'"
|
*ngSwitchCase="'primitive'"
|
||||||
[formControl]="control"
|
[formControl]="control"
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import { Component, Input, OnChanges } from '@angular/core';
|
||||||
import { ValidationErrors, Validator } from '@angular/forms';
|
import { Validator } from '@angular/forms';
|
||||||
import { WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
|
||||||
import { Field, ValueType } from '@vality/thrift-ts';
|
import { Field, ValueType } from '@vality/thrift-ts';
|
||||||
|
|
||||||
import { ThriftAstMetadata } from '@cc/app/api/utils';
|
import { ThriftAstMetadata } from '@cc/app/api/utils';
|
||||||
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form/types/metadata-form-extension';
|
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form/types/metadata-form-extension';
|
||||||
import { createValidatedAbstractControlProviders } from '@cc/utils';
|
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||||
|
|
||||||
import { MetadataFormData } from './types/metadata-form-data';
|
import { MetadataFormData } from './types/metadata-form-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-metadata-form',
|
selector: 'cc-metadata-form',
|
||||||
templateUrl: './metadata-form.component.html',
|
templateUrl: './metadata-form.component.html',
|
||||||
providers: createValidatedAbstractControlProviders(MetadataFormComponent),
|
providers: createControlProviders(MetadataFormComponent),
|
||||||
})
|
})
|
||||||
export class MetadataFormComponent
|
export class MetadataFormComponent<T>
|
||||||
extends WrappedFormControlSuperclass<unknown>
|
extends ValidatedFormControlSuperclass<T>
|
||||||
implements OnChanges, Validator
|
implements OnChanges, Validator
|
||||||
{
|
{
|
||||||
@Input() metadata: ThriftAstMetadata[];
|
@Input() metadata: ThriftAstMetadata[];
|
||||||
@ -39,8 +38,4 @@ export class MetadataFormComponent
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
|
||||||
return this.control.errors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import { MatChipsModule } from '@angular/material/chips';
|
|||||||
import { MatExpansionModule } from '@angular/material/expansion';
|
import { MatExpansionModule } from '@angular/material/expansion';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ import { MetadataFormComponent } from './metadata-form.component';
|
|||||||
ValueTypeTitleModule,
|
ValueTypeTitleModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatChipsModule,
|
MatChipsModule,
|
||||||
|
MatRadioModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
MetadataFormComponent,
|
MetadataFormComponent,
|
||||||
|
@ -9,20 +9,17 @@ import { catchError, map, pluck, shareReplay, startWith } from 'rxjs/operators';
|
|||||||
import { PartyManagementWithUserService } from '@cc/app/api/payment-processing';
|
import { PartyManagementWithUserService } from '@cc/app/api/payment-processing';
|
||||||
import { NotificationService } from '@cc/app/shared/services/notification';
|
import { NotificationService } from '@cc/app/shared/services/notification';
|
||||||
import { Option } from '@cc/components/select-search-field';
|
import { Option } from '@cc/components/select-search-field';
|
||||||
import {
|
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils/forms';
|
||||||
createValidatedAbstractControlProviders,
|
|
||||||
ValidatedWrappedAbstractControlSuperclass,
|
|
||||||
} from '@cc/utils/forms';
|
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-payout-tool-field',
|
selector: 'cc-payout-tool-field',
|
||||||
templateUrl: 'payout-tool-field.component.html',
|
templateUrl: 'payout-tool-field.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
providers: createValidatedAbstractControlProviders(PayoutToolFieldComponent),
|
providers: createControlProviders(PayoutToolFieldComponent),
|
||||||
})
|
})
|
||||||
export class PayoutToolFieldComponent
|
export class PayoutToolFieldComponent
|
||||||
extends ValidatedWrappedAbstractControlSuperclass<PartyID>
|
extends ValidatedControlSuperclass<PartyID>
|
||||||
implements OnInit
|
implements OnInit
|
||||||
{
|
{
|
||||||
@Input() label: string;
|
@Input() label: string;
|
||||||
|
@ -15,10 +15,7 @@ import { filter, map, share, switchMap } from 'rxjs/operators';
|
|||||||
|
|
||||||
import { PartyManagementWithUserService } from '@cc/app/api/payment-processing';
|
import { PartyManagementWithUserService } from '@cc/app/api/payment-processing';
|
||||||
import { ComponentChanges } from '@cc/app/shared/utils';
|
import { ComponentChanges } from '@cc/app/shared/utils';
|
||||||
import {
|
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils/forms';
|
||||||
createValidatedAbstractControlProviders,
|
|
||||||
ValidatedWrappedAbstractControlSuperclass,
|
|
||||||
} from '@cc/utils/forms';
|
|
||||||
import { RequiredSuper } from '@cc/utils/required-super';
|
import { RequiredSuper } from '@cc/utils/required-super';
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@ -26,11 +23,11 @@ import { RequiredSuper } from '@cc/utils/required-super';
|
|||||||
selector: 'cc-shop-field',
|
selector: 'cc-shop-field',
|
||||||
templateUrl: './shop-field.component.html',
|
templateUrl: './shop-field.component.html',
|
||||||
styleUrls: ['./shop-field.component.scss'],
|
styleUrls: ['./shop-field.component.scss'],
|
||||||
providers: createValidatedAbstractControlProviders(ShopFieldComponent),
|
providers: createControlProviders(ShopFieldComponent),
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ShopFieldComponent<M extends boolean = boolean>
|
export class ShopFieldComponent<M extends boolean = boolean>
|
||||||
extends ValidatedWrappedAbstractControlSuperclass<
|
extends ValidatedControlSuperclass<
|
||||||
M extends true ? Shop[] : Shop,
|
M extends true ? Shop[] : Shop,
|
||||||
M extends true ? ShopID[] : ShopID
|
M extends true ? ShopID[] : ShopID
|
||||||
>
|
>
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { DomainObject } from '@vality/domain-proto/lib/domain';
|
||||||
|
import { Field } from '@vality/thrift-ts';
|
||||||
|
import { from, Observable } from 'rxjs';
|
||||||
|
import { map, shareReplay } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { ThriftAstMetadata } from '@cc/app/api/utils';
|
||||||
|
|
||||||
|
import { DomainStoreService } from '../../../thrift-services/damsel/domain-store.service';
|
||||||
|
import { MetadataFormData, MetadataFormExtension } from '../../components/metadata-form';
|
||||||
|
import { createDomainObjectExtension } from './utils/create-domain-object-extension';
|
||||||
|
import {
|
||||||
|
defaultDomainObjectToOption,
|
||||||
|
DOMAIN_OBJECTS_TO_OPTIONS,
|
||||||
|
OtherDomainObjects,
|
||||||
|
} from './utils/domains-objects-to-options';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class DomainMetadataFormExtensionsService {
|
||||||
|
extensions$: Observable<MetadataFormExtension[]> = from(
|
||||||
|
import('@vality/domain-proto/lib/metadata.json').then(
|
||||||
|
(m) => m.default as never as ThriftAstMetadata[]
|
||||||
|
)
|
||||||
|
).pipe(
|
||||||
|
map((metadata) => this.createDomainObjectsOptions(metadata)),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(private domainStoreService: DomainStoreService) {}
|
||||||
|
|
||||||
|
private createDomainObjectsOptions(metadata: ThriftAstMetadata[]): MetadataFormExtension[] {
|
||||||
|
const domainFields = new MetadataFormData<string, Field[]>(
|
||||||
|
metadata,
|
||||||
|
'domain',
|
||||||
|
'DomainObject'
|
||||||
|
).ast;
|
||||||
|
return domainFields
|
||||||
|
.filter(
|
||||||
|
(f) => !(f.name in DOMAIN_OBJECTS_TO_OPTIONS) || DOMAIN_OBJECTS_TO_OPTIONS[f.name]
|
||||||
|
)
|
||||||
|
.map((f) =>
|
||||||
|
this.createFieldOptions(metadata, f.type as string, f.name as keyof DomainObject)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createFieldOptions(
|
||||||
|
metadata: ThriftAstMetadata[],
|
||||||
|
objectType: string,
|
||||||
|
objectKey: keyof DomainObject
|
||||||
|
): MetadataFormExtension {
|
||||||
|
const objectFields = new MetadataFormData<string, Field[]>(metadata, 'domain', objectType)
|
||||||
|
.ast;
|
||||||
|
const refType = objectFields.find((n) => n.name === 'ref').type as string;
|
||||||
|
return createDomainObjectExtension(refType, () =>
|
||||||
|
this.domainStoreService.getObjects(objectKey).pipe(
|
||||||
|
map((objects) => {
|
||||||
|
const domainObjectToOption =
|
||||||
|
objectKey in DOMAIN_OBJECTS_TO_OPTIONS
|
||||||
|
? DOMAIN_OBJECTS_TO_OPTIONS[objectKey as keyof OtherDomainObjects]
|
||||||
|
: defaultDomainObjectToOption;
|
||||||
|
return objects.map(domainObjectToOption);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export * from './domain-metadata-form-extensions.service';
|
@ -1,11 +1,15 @@
|
|||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { isTypeWithAliases, MetadataFormExtension } from '@cc/app/shared';
|
import {
|
||||||
|
isTypeWithAliases,
|
||||||
|
MetadataFormExtension,
|
||||||
|
MetadataFormExtensionOption,
|
||||||
|
} from '../../../components';
|
||||||
|
|
||||||
export function createDomainObjectMetadataFormExtension(
|
export function createDomainObjectExtension(
|
||||||
refType: string,
|
refType: string,
|
||||||
getObjects: () => Observable<{ ref: { id: number }; data: { name?: string } }[]>
|
options: () => Observable<MetadataFormExtensionOption[]>
|
||||||
): MetadataFormExtension {
|
): MetadataFormExtension {
|
||||||
return {
|
return {
|
||||||
determinant: (data) =>
|
determinant: (data) =>
|
||||||
@ -14,14 +18,17 @@ export function createDomainObjectMetadataFormExtension(
|
|||||||
isTypeWithAliases(data, 'ObjectID', 'domain')
|
isTypeWithAliases(data, 'ObjectID', 'domain')
|
||||||
),
|
),
|
||||||
extension: () =>
|
extension: () =>
|
||||||
getObjects().pipe(
|
options().pipe(
|
||||||
map((objects) => ({
|
map((objects) => ({
|
||||||
options: objects
|
options: objects
|
||||||
.sort((a, b) => a.ref.id - b.ref.id)
|
.sort((a, b) =>
|
||||||
|
typeof a.value === 'number' && typeof b.value === 'number'
|
||||||
|
? a.value - b.value
|
||||||
|
: 0
|
||||||
|
)
|
||||||
.map((o) => ({
|
.map((o) => ({
|
||||||
label: o.data.name,
|
|
||||||
value: o.ref.id,
|
|
||||||
details: o,
|
details: o,
|
||||||
|
...o,
|
||||||
})),
|
})),
|
||||||
isIdentifier: true,
|
isIdentifier: true,
|
||||||
}))
|
}))
|
@ -0,0 +1,31 @@
|
|||||||
|
import { DomainObject } from '@vality/domain-proto';
|
||||||
|
import { PickByValue } from 'utility-types';
|
||||||
|
|
||||||
|
import { MetadataFormExtensionOption } from '../../../components';
|
||||||
|
|
||||||
|
type DomainRefDataObjects = PickByValue<
|
||||||
|
DomainObject,
|
||||||
|
{
|
||||||
|
ref: { id: number | string };
|
||||||
|
data: { name?: string; id?: string };
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
export type OtherDomainObjects = Omit<DomainObject, keyof DomainRefDataObjects>;
|
||||||
|
export const DOMAIN_OBJECTS_TO_OPTIONS: {
|
||||||
|
[N in keyof OtherDomainObjects]-?: (o: OtherDomainObjects[N]) => MetadataFormExtensionOption;
|
||||||
|
} = {
|
||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
currency: (o) => ({ value: o.ref.symbolic_code, label: o.data.name }),
|
||||||
|
payment_method: null,
|
||||||
|
globals: null,
|
||||||
|
identity_provider: (o) => ({ value: o.ref.id }),
|
||||||
|
dummy_link: (o) => ({ value: o.ref.id, label: o.data.link.id }),
|
||||||
|
/* eslint-enable @typescript-eslint/naming-convention */
|
||||||
|
};
|
||||||
|
|
||||||
|
export function defaultDomainObjectToOption(o: DomainRefDataObjects[keyof DomainRefDataObjects]) {
|
||||||
|
let label: string;
|
||||||
|
if ('name' in o.data) label = o.data.name;
|
||||||
|
if ('id' in o.data && !label) label = o.data.id;
|
||||||
|
return { value: o.ref.id, label };
|
||||||
|
}
|
@ -1,8 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
|
|
||||||
import { ErrorService } from './error.service';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
providers: [ErrorService],
|
|
||||||
})
|
|
||||||
export class ErrorModule {}
|
|
@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { NotificationService } from '../notification';
|
import { NotificationService } from '../notification';
|
||||||
|
|
||||||
// TODO: collect error information
|
// TODO: collect error information
|
||||||
@Injectable()
|
@Injectable({ providedIn: 'root' })
|
||||||
export class ErrorService {
|
export class ErrorService {
|
||||||
constructor(private notificationService: NotificationService) {}
|
constructor(private notificationService: NotificationService) {}
|
||||||
|
|
||||||
|
@ -1,2 +1 @@
|
|||||||
export * from './error.module';
|
|
||||||
export * from './error.service';
|
export * from './error.service';
|
||||||
|
@ -6,3 +6,4 @@ export * from './user-info-based-id-generator';
|
|||||||
export * from './partial-fetcher';
|
export * from './partial-fetcher';
|
||||||
export * from './query-params';
|
export * from './query-params';
|
||||||
export * from './moment-utc-date-adapter';
|
export * from './moment-utc-date-adapter';
|
||||||
|
export * from './domain-metadata-form-extensions';
|
||||||
|
@ -16,8 +16,14 @@ export class BaseDialogService {
|
|||||||
|
|
||||||
open<C, D, R, S>(
|
open<C, D, R, S>(
|
||||||
dialogComponent: ComponentType<BaseDialogSuperclass<C, D, R, S>>,
|
dialogComponent: ComponentType<BaseDialogSuperclass<C, D, R, S>>,
|
||||||
data: D = null,
|
/**
|
||||||
configOrConfigName: Omit<MatDialogConfig<D>, 'data'> | keyof DialogConfig = {}
|
* Workaround when both conditions for the 'data' argument must be true:
|
||||||
|
* - typing did not require passing when it is optional (for example: {param: number} | void)
|
||||||
|
* - typing required to pass when it is required (for example: {param: number})
|
||||||
|
*/
|
||||||
|
...[data, configOrConfigName]: D extends void
|
||||||
|
? []
|
||||||
|
: [data: D, configOrConfigName?: Omit<MatDialogConfig<D>, 'data'> | keyof DialogConfig]
|
||||||
): MatDialogRef<C, BaseDialogResponse<R, S>> {
|
): MatDialogRef<C, BaseDialogResponse<R, S>> {
|
||||||
return this.dialog.open(dialogComponent as never, {
|
return this.dialog.open(dialogComponent as never, {
|
||||||
data,
|
data,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<cc-base-dialog [title]="dialogData?.title || 'Confirm this action'" noContent>
|
<cc-base-dialog [title]="title || 'Confirm this action'" noContent>
|
||||||
<cc-base-dialog-actions>
|
<cc-base-dialog-actions>
|
||||||
<button mat-button (click)="cancel()">CANCEL</button>
|
<button mat-button (click)="cancel()">CANCEL</button>
|
||||||
<button mat-raised-button color="primary" (click)="confirm()">CONFIRM</button>
|
<button mat-raised-button color="primary" (click)="confirm()">CONFIRM</button>
|
||||||
|
@ -9,8 +9,12 @@ import { BaseDialogResponseStatus, BaseDialogSuperclass } from '@cc/components/b
|
|||||||
})
|
})
|
||||||
export class ConfirmActionDialogComponent extends BaseDialogSuperclass<
|
export class ConfirmActionDialogComponent extends BaseDialogSuperclass<
|
||||||
ConfirmActionDialogComponent,
|
ConfirmActionDialogComponent,
|
||||||
{ title?: string }
|
{ title?: string } | void
|
||||||
> {
|
> {
|
||||||
|
get title() {
|
||||||
|
return typeof this.dialogData === 'object' ? this.dialogData.title : '';
|
||||||
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.dialogRef.close({ status: BaseDialogResponseStatus.Cancelled });
|
this.dialogRef.close({ status: BaseDialogResponseStatus.Cancelled });
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
import { AbstractControl } from '@angular/forms';
|
import { AbstractControl } from '@angular/forms';
|
||||||
import { FormGroup, FormArray } from '@ngneat/reactive-forms';
|
|
||||||
import { ControlsValue } from '@ngneat/reactive-forms/lib/types';
|
import { ControlsValue } from '@ngneat/reactive-forms/lib/types';
|
||||||
|
|
||||||
function hasControls<T>(control: AbstractControl): control is FormGroup<T> | FormArray<T> {
|
import { hasControls } from './has-controls';
|
||||||
return !!(control as any)?.controls;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getValue<T extends AbstractControl>(control: T): T['value'] {
|
export function getValue<T extends AbstractControl>(control: T): T['value'] {
|
||||||
if (!hasControls(control)) {
|
if (!hasControls(control)) {
|
||||||
return control.value;
|
return control.value as never;
|
||||||
}
|
}
|
||||||
if (Array.isArray(control.controls)) {
|
if (Array.isArray(control.controls)) {
|
||||||
const result: ControlsValue<T>[] = [];
|
const result: ControlsValue<T>[] = [];
|
||||||
for (const v of control.controls) {
|
for (const v of control.controls) {
|
||||||
result.push(getValue(v as any));
|
result.push(getValue(v) as ControlsValue<T>);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const result: Partial<ControlsValue<T>> = {};
|
const result: Partial<ControlsValue<T>> = {};
|
||||||
for (const [k, v] of Object.entries(control.controls)) {
|
for (const [k, v] of Object.entries(control.controls)) {
|
||||||
result[k] = getValue(v as any);
|
result[k] = getValue(v as AbstractControl) as ControlsValue<T>;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
6
src/utils/forms/has-controls.ts
Normal file
6
src/utils/forms/has-controls.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { AbstractControl } from '@angular/forms';
|
||||||
|
import { FormArray, FormGroup } from '@ngneat/reactive-forms';
|
||||||
|
|
||||||
|
export function hasControls<T>(control: AbstractControl): control is FormGroup<T> | FormArray<T> {
|
||||||
|
return 'controls' in control;
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
export * from './set-form-array-value';
|
export * from './set-form-array-value';
|
||||||
export * from './get-form-value-changes';
|
export * from './get-form-value-changes';
|
||||||
export * from './get-form-validation-changes';
|
export * from './get-form-validation-changes';
|
||||||
export * from './validated-wrapped-abstract-control-superclass';
|
export * from './validated-control-superclass';
|
||||||
export * from './switch-control';
|
export * from './switch-control';
|
||||||
|
@ -4,6 +4,7 @@ import { provideValueAccessor } from '@s-libs/ng-core';
|
|||||||
|
|
||||||
import { provideValidator } from './provide-validator';
|
import { provideValidator } from './provide-validator';
|
||||||
|
|
||||||
export const createValidatedAbstractControlProviders = (
|
export const createControlProviders = (component: ComponentType<unknown>): Provider[] => [
|
||||||
component: ComponentType<unknown>
|
provideValueAccessor(component),
|
||||||
): Provider[] => [provideValueAccessor(component), provideValidator(component)];
|
provideValidator(component),
|
||||||
|
];
|
4
src/utils/forms/validated-control-superclass/index.ts
Normal file
4
src/utils/forms/validated-control-superclass/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './validated-control-superclass.directive';
|
||||||
|
export * from './provide-validator';
|
||||||
|
export * from './create-control-providers';
|
||||||
|
export { getErrorsTree } from '@cc/utils/forms/validated-control-superclass/utils/get-errors-tree';
|
@ -0,0 +1,27 @@
|
|||||||
|
import { AbstractControl, ValidationErrors } from '@angular/forms';
|
||||||
|
|
||||||
|
import { hasControls } from '../../has-controls';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FormGroup/FormArray don't return internal control errors,
|
||||||
|
* so you need to get internal errors manually
|
||||||
|
*/
|
||||||
|
export function getErrorsTree(control: AbstractControl): ValidationErrors | null {
|
||||||
|
if (control.valid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const errors: ValidationErrors = Object.assign({}, control.errors);
|
||||||
|
if (hasControls(control)) {
|
||||||
|
if (Array.isArray(control.controls)) {
|
||||||
|
errors.formArrayErrors = control.controls.map((c) => getErrorsTree(c));
|
||||||
|
} else {
|
||||||
|
errors.formGroupErrors = Object.fromEntries(
|
||||||
|
Array.from(Object.entries(control.controls)).map(([k, c]) => [
|
||||||
|
k,
|
||||||
|
getErrorsTree(c as AbstractControl),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
@ -1,12 +1,14 @@
|
|||||||
import { Directive, OnInit } from '@angular/core';
|
import { Directive, OnInit } from '@angular/core';
|
||||||
import { ValidationErrors, Validator } from '@angular/forms';
|
import { ValidationErrors, Validator } from '@angular/forms';
|
||||||
|
import { FormControl } from '@ngneat/reactive-forms';
|
||||||
import { WrappedControlSuperclass } from '@s-libs/ng-core';
|
import { WrappedControlSuperclass } from '@s-libs/ng-core';
|
||||||
|
|
||||||
import { RequiredSuper, REQUIRED_SUPER } from '../../required-super';
|
import { REQUIRED_SUPER, RequiredSuper } from '../../required-super';
|
||||||
import { getValue } from '../get-value';
|
import { getValue } from '../get-value';
|
||||||
|
import { getErrorsTree } from './utils/get-errors-tree';
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export abstract class ValidatedWrappedAbstractControlSuperclass<OuterType, InnerType = OuterType>
|
export abstract class ValidatedControlSuperclass<OuterType, InnerType = OuterType>
|
||||||
extends WrappedControlSuperclass<OuterType, InnerType>
|
extends WrappedControlSuperclass<OuterType, InnerType>
|
||||||
implements OnInit, Validator
|
implements OnInit, Validator
|
||||||
{
|
{
|
||||||
@ -19,14 +21,21 @@ export abstract class ValidatedWrappedAbstractControlSuperclass<OuterType, Inner
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
validate(): ValidationErrors | null {
|
||||||
return this.control.errors;
|
return getErrorsTree(this.control);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected outerToInner(outer: OuterType): InnerType {
|
protected outerToInner(outer: OuterType): InnerType {
|
||||||
if (typeof this.emptyValue === 'object') {
|
if (!outer && 'controls' in this.control) {
|
||||||
if (!outer) return this.emptyValue;
|
return this.emptyValue;
|
||||||
return { ...this.emptyValue, ...outer };
|
|
||||||
}
|
}
|
||||||
return outer as unknown as InnerType;
|
return outer as never;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Directive()
|
||||||
|
export class ValidatedFormControlSuperclass<
|
||||||
|
OuterType,
|
||||||
|
InnerType = OuterType
|
||||||
|
> extends ValidatedControlSuperclass<OuterType, InnerType> {
|
||||||
|
control = new FormControl<InnerType>();
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
export * from './validated-wrapped-abstract-control-superclass';
|
|
||||||
export * from './provide-validator';
|
|
||||||
export * from './create-validated-abstract-control-providers';
|
|
Loading…
Reference in New Issue
Block a user