mirror of
https://github.com/valitydev/control-center.git
synced 2024-11-06 02:25:17 +00:00
IMP-145: New domain config create and edit dialogs (#315)
This commit is contained in:
parent
b5f95a3a24
commit
e617dc82ff
9
package-lock.json
generated
9
package-lock.json
generated
@ -20,13 +20,12 @@
|
|||||||
"@angular/platform-server": "17.0.8",
|
"@angular/platform-server": "17.0.8",
|
||||||
"@angular/router": "17.0.8",
|
"@angular/router": "17.0.8",
|
||||||
"@ngneat/input-mask": "6.0.0",
|
"@ngneat/input-mask": "6.0.0",
|
||||||
"@s-libs/ng-core": "17.0.0",
|
|
||||||
"@vality/deanonimus-proto": "2.0.1-2a02d87.0",
|
"@vality/deanonimus-proto": "2.0.1-2a02d87.0",
|
||||||
"@vality/domain-proto": "2.0.1-23211ff.0",
|
"@vality/domain-proto": "2.0.1-23211ff.0",
|
||||||
"@vality/fistful-proto": "2.0.1-3b9a0a7.0",
|
"@vality/fistful-proto": "2.0.1-3b9a0a7.0",
|
||||||
"@vality/machinegun-proto": "1.0.0",
|
"@vality/machinegun-proto": "1.0.0",
|
||||||
"@vality/magista-proto": "2.0.2-4383410.0",
|
"@vality/magista-proto": "2.0.2-4383410.0",
|
||||||
"@vality/ng-core": "^17.1.1-pr-57-1a4e713.0",
|
"@vality/ng-core": "^17.1.1-pr-57-8ca06c2.0",
|
||||||
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
|
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
|
||||||
"@vality/repairer-proto": "2.0.2-07b73e9.0",
|
"@vality/repairer-proto": "2.0.2-07b73e9.0",
|
||||||
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
||||||
@ -6523,9 +6522,9 @@
|
|||||||
"integrity": "sha512-kAiKSTvof+jFuNkQKyAsc2s+Br2NXPWAyKuD0f7mQIk9HrP8uHsKJya5KxdOdng97JYe0MSUlx7seQxWmCgYfA=="
|
"integrity": "sha512-kAiKSTvof+jFuNkQKyAsc2s+Br2NXPWAyKuD0f7mQIk9HrP8uHsKJya5KxdOdng97JYe0MSUlx7seQxWmCgYfA=="
|
||||||
},
|
},
|
||||||
"node_modules/@vality/ng-core": {
|
"node_modules/@vality/ng-core": {
|
||||||
"version": "17.1.1-pr-57-1a4e713.0",
|
"version": "17.1.1-pr-57-8ca06c2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.1.1-pr-57-1a4e713.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.1.1-pr-57-8ca06c2.0.tgz",
|
||||||
"integrity": "sha512-Jar5VUIp5OISoCc0rhmcsk9EkVjzItlT2N/sMCFIKIKD51XDxn6NvYXOOwOiNAyu1LAd71mGPT8GvdWazR12cA==",
|
"integrity": "sha512-io0j/knhIGgqmi8HxfuTZMGycVSO8qE9EYq5KN7lP7ectNeDrpvZdKcsJUg2kfTtWWaG9p8DSR5CHbe36tDxYA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/material-date-fns-adapter": "^17.0.0",
|
"@angular/material-date-fns-adapter": "^17.0.0",
|
||||||
"@ng-matero/extensions": "^17.0.0",
|
"@ng-matero/extensions": "^17.0.0",
|
||||||
|
@ -28,13 +28,12 @@
|
|||||||
"@angular/platform-server": "17.0.8",
|
"@angular/platform-server": "17.0.8",
|
||||||
"@angular/router": "17.0.8",
|
"@angular/router": "17.0.8",
|
||||||
"@ngneat/input-mask": "6.0.0",
|
"@ngneat/input-mask": "6.0.0",
|
||||||
"@s-libs/ng-core": "17.0.0",
|
|
||||||
"@vality/deanonimus-proto": "2.0.1-2a02d87.0",
|
"@vality/deanonimus-proto": "2.0.1-2a02d87.0",
|
||||||
"@vality/domain-proto": "2.0.1-23211ff.0",
|
"@vality/domain-proto": "2.0.1-23211ff.0",
|
||||||
"@vality/fistful-proto": "2.0.1-3b9a0a7.0",
|
"@vality/fistful-proto": "2.0.1-3b9a0a7.0",
|
||||||
"@vality/machinegun-proto": "1.0.0",
|
"@vality/machinegun-proto": "1.0.0",
|
||||||
"@vality/magista-proto": "2.0.2-4383410.0",
|
"@vality/magista-proto": "2.0.2-4383410.0",
|
||||||
"@vality/ng-core": "^17.1.1-pr-57-1a4e713.0",
|
"@vality/ng-core": "^17.1.1-pr-57-8ca06c2.0",
|
||||||
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
|
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
|
||||||
"@vality/repairer-proto": "2.0.2-07b73e9.0",
|
"@vality/repairer-proto": "2.0.2-07b73e9.0",
|
||||||
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
||||||
|
@ -4,19 +4,23 @@ import { Domain, DomainObject, Reference } from '@vality/domain-proto/domain';
|
|||||||
import { Commit, Snapshot, Version } from '@vality/domain-proto/domain_config';
|
import { Commit, Snapshot, Version } from '@vality/domain-proto/domain_config';
|
||||||
import { NotifyLogService } from '@vality/ng-core';
|
import { NotifyLogService } from '@vality/ng-core';
|
||||||
import isEqual from 'lodash-es/isEqual';
|
import isEqual from 'lodash-es/isEqual';
|
||||||
import { BehaviorSubject, defer, Observable, of, ReplaySubject } from 'rxjs';
|
import { BehaviorSubject, defer, Observable, of, ReplaySubject, filter, combineLatest } from 'rxjs';
|
||||||
import { map, shareReplay, startWith, switchMap, take, tap } from 'rxjs/operators';
|
import { map, shareReplay, startWith, switchMap, take, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { inProgressFrom, progressTo, getUnionKey } from '../../../../utils';
|
import { inProgressFrom, progressTo, getUnionKey } from '../../../../utils';
|
||||||
import { DomainSecretService } from '../../../shared/services';
|
import { DomainSecretService } from '../../../shared/services';
|
||||||
import { handleError } from '../../../shared/services/notification-error';
|
import { handleError } from '../../../shared/services/notification-error';
|
||||||
import { RepositoryService } from '../index';
|
import { RepositoryService } from '../repository.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class DomainStoreService {
|
export class DomainStoreService {
|
||||||
version$ = defer(() => this.snapshot$).pipe(map((s) => s?.version));
|
version$ = combineLatest([defer(() => this.snapshot$), defer(() => this.progress$)]).pipe(
|
||||||
|
filter(([, p]) => !p),
|
||||||
|
map(([s]) => s.version),
|
||||||
|
take(1),
|
||||||
|
);
|
||||||
isLoading$ = inProgressFrom(
|
isLoading$ = inProgressFrom(
|
||||||
() => this.progress$,
|
() => this.progress$,
|
||||||
defer(() => this.snapshot$),
|
defer(() => this.snapshot$),
|
||||||
|
@ -2,12 +2,11 @@ import { Component, Input, OnChanges } from '@angular/core';
|
|||||||
import { Validator } from '@angular/forms';
|
import { Validator } from '@angular/forms';
|
||||||
import { Claim } from '@vality/domain-proto/claim_management';
|
import { Claim } from '@vality/domain-proto/claim_management';
|
||||||
import { Party } from '@vality/domain-proto/domain';
|
import { Party } from '@vality/domain-proto/domain';
|
||||||
import { ComponentChanges } from '@vality/ng-core';
|
import { ComponentChanges, createControlProviders, FormControlSuperclass } from '@vality/ng-core';
|
||||||
import { from, combineLatest, ReplaySubject, defer } from 'rxjs';
|
import { from, combineLatest, ReplaySubject, defer } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services/domain-metadata-form-extensions';
|
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services/domain-metadata-form-extensions';
|
||||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
|
||||||
|
|
||||||
import { createPartyClaimMetadataFormExtensions } from './utils/create-party-claim-metadata-form-extensions';
|
import { createPartyClaimMetadataFormExtensions } from './utils/create-party-claim-metadata-form-extensions';
|
||||||
|
|
||||||
@ -17,7 +16,7 @@ import { createPartyClaimMetadataFormExtensions } from './utils/create-party-cla
|
|||||||
providers: createControlProviders(() => ModificationFormComponent),
|
providers: createControlProviders(() => ModificationFormComponent),
|
||||||
})
|
})
|
||||||
export class ModificationFormComponent
|
export class ModificationFormComponent
|
||||||
extends ValidatedFormControlSuperclass<unknown>
|
extends FormControlSuperclass<unknown>
|
||||||
implements Validator, OnChanges
|
implements Validator, OnChanges
|
||||||
{
|
{
|
||||||
@Input() party: Party;
|
@Input() party: Party;
|
||||||
|
@ -3,14 +3,11 @@
|
|||||||
title="Domain config"
|
title="Domain config"
|
||||||
>
|
>
|
||||||
<cc-page-layout-actions>
|
<cc-page-layout-actions>
|
||||||
<button
|
<button color="primary" mat-raised-button style="white-space: nowrap" (click)="create()">
|
||||||
color="primary"
|
Create
|
||||||
mat-raised-button
|
|
||||||
routerLink="/domain/create"
|
|
||||||
style="white-space: nowrap"
|
|
||||||
>
|
|
||||||
Create object
|
|
||||||
</button>
|
</button>
|
||||||
</cc-page-layout-actions>
|
</cc-page-layout-actions>
|
||||||
<cc-domain-objects-table></cc-domain-objects-table>
|
<cc-domain-objects-table
|
||||||
|
(selectedChange)="selectedTypes$.next($event)"
|
||||||
|
></cc-domain-objects-table>
|
||||||
</cc-page-layout>
|
</cc-page-layout>
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, DestroyRef } from '@angular/core';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { DialogService } from '@vality/ng-core';
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||||
|
|
||||||
|
import { CreateDomainObjectDialogComponent } from '../../../shared/components/thrift-api-crud';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './domain-info.component.html',
|
templateUrl: './domain-info.component.html',
|
||||||
styleUrls: ['./domain-info.component.scss'],
|
styleUrls: ['./domain-info.component.scss'],
|
||||||
@ -9,6 +15,26 @@ import { DomainStoreService } from '@cc/app/api/domain-config';
|
|||||||
export class DomainInfoComponent {
|
export class DomainInfoComponent {
|
||||||
version$ = this.domainStoreService.version$;
|
version$ = this.domainStoreService.version$;
|
||||||
progress$ = this.domainStoreService.isLoading$;
|
progress$ = this.domainStoreService.isLoading$;
|
||||||
|
selectedTypes$ = new BehaviorSubject<string[]>([]);
|
||||||
|
|
||||||
constructor(private domainStoreService: DomainStoreService) {}
|
constructor(
|
||||||
|
private domainStoreService: DomainStoreService,
|
||||||
|
private dialogService: DialogService,
|
||||||
|
private destroyRef: DestroyRef,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
this.selectedTypes$
|
||||||
|
.pipe(first(), takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe((types) => {
|
||||||
|
this.dialogService.open(
|
||||||
|
CreateDomainObjectDialogComponent,
|
||||||
|
types?.length === 1
|
||||||
|
? {
|
||||||
|
objectType: types[0],
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, DestroyRef, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { Sort } from '@angular/material/sort';
|
import { Sort } from '@angular/material/sort';
|
||||||
@ -11,6 +12,8 @@ import {
|
|||||||
SelectFieldModule,
|
SelectFieldModule,
|
||||||
TableModule,
|
TableModule,
|
||||||
ActionsModule,
|
ActionsModule,
|
||||||
|
DialogService,
|
||||||
|
getValueChanges,
|
||||||
} from '@vality/ng-core';
|
} from '@vality/ng-core';
|
||||||
import sortBy from 'lodash-es/sortBy';
|
import sortBy from 'lodash-es/sortBy';
|
||||||
import startCase from 'lodash-es/startCase';
|
import startCase from 'lodash-es/startCase';
|
||||||
@ -25,6 +28,7 @@ import {
|
|||||||
DomainThriftViewerComponent,
|
DomainThriftViewerComponent,
|
||||||
DomainObjectCardComponent,
|
DomainObjectCardComponent,
|
||||||
DomainObjectService,
|
DomainObjectService,
|
||||||
|
EditDomainObjectDialogComponent,
|
||||||
} from '../../../../shared/components/thrift-api-crud';
|
} from '../../../../shared/components/thrift-api-crud';
|
||||||
import { MetadataService } from '../../services/metadata.service';
|
import { MetadataService } from '../../services/metadata.service';
|
||||||
|
|
||||||
@ -49,6 +53,8 @@ interface DomainObjectData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class DomainObjectsTableComponent implements OnInit {
|
export class DomainObjectsTableComponent implements OnInit {
|
||||||
|
@Output() selectedChange = new EventEmitter<string[]>();
|
||||||
|
|
||||||
typesControl = new FormControl<string[]>(
|
typesControl = new FormControl<string[]>(
|
||||||
(this.qp.params.types as (keyof DomainObject)[]) || [],
|
(this.qp.params.types as (keyof DomainObject)[]) || [],
|
||||||
);
|
);
|
||||||
@ -105,7 +111,11 @@ export class DomainObjectsTableComponent implements OnInit {
|
|||||||
{
|
{
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
click: (d) => {
|
click: (d) => {
|
||||||
void this.domainObjectService.edit(d.ref);
|
this.dialogService
|
||||||
|
.open(EditDomainObjectDialogComponent, { domainObject: d.obj })
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -138,12 +148,21 @@ export class DomainObjectsTableComponent implements OnInit {
|
|||||||
private qp: QueryParamsService<{ types?: string[] }>,
|
private qp: QueryParamsService<{ types?: string[] }>,
|
||||||
private sidenavInfoService: SidenavInfoService,
|
private sidenavInfoService: SidenavInfoService,
|
||||||
private domainObjectService: DomainObjectService,
|
private domainObjectService: DomainObjectService,
|
||||||
|
private destroyRef: DestroyRef,
|
||||||
|
private dialogService: DialogService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.typesControl.valueChanges.subscribe((types) => {
|
this.typesControl.valueChanges
|
||||||
void this.qp.patch({ types });
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
});
|
.subscribe((types) => {
|
||||||
|
void this.qp.patch({ types });
|
||||||
|
});
|
||||||
|
getValueChanges(this.typesControl)
|
||||||
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe((types) => {
|
||||||
|
this.selectedChange.emit(types);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
<cc-page-layout title="Create">
|
|
||||||
<mat-card>
|
|
||||||
<mat-card-content class="content">
|
|
||||||
<cc-thrift-editor
|
|
||||||
*ngIf="!review"
|
|
||||||
[extensions]="extensions$ | async"
|
|
||||||
[formControl]="control"
|
|
||||||
[metadata]="metadata$ | async"
|
|
||||||
class="editor"
|
|
||||||
namespace="domain"
|
|
||||||
type="DomainObject"
|
|
||||||
></cc-thrift-editor>
|
|
||||||
<cc-thrift-viewer
|
|
||||||
*ngIf="review"
|
|
||||||
[extensions]="viewerExtensions$ | async"
|
|
||||||
[metadata]="metadata$ | async"
|
|
||||||
[value]="control.value"
|
|
||||||
class="editor"
|
|
||||||
namespace="domain"
|
|
||||||
type="DomainObject"
|
|
||||||
></cc-thrift-viewer>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
<v-actions>
|
|
||||||
<button *ngIf="!review" [disabled]="!!(progress$ | async)" mat-button routerLink="/domain">
|
|
||||||
<mat-icon aria-label="Login">keyboard_arrow_left</mat-icon>
|
|
||||||
Back to domain
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
*ngIf="review"
|
|
||||||
[disabled]="!!(progress$ | async)"
|
|
||||||
mat-button
|
|
||||||
(click)="review = false"
|
|
||||||
>
|
|
||||||
<mat-icon aria-label="Login">keyboard_arrow_left</mat-icon>
|
|
||||||
Back to edit
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
[disabled]="control.invalid || !!(progress$ | async)"
|
|
||||||
color="primary"
|
|
||||||
mat-button
|
|
||||||
(click)="review ? commit() : reviewChanges()"
|
|
||||||
>
|
|
||||||
{{ review ? 'Commit' : 'Review' }}
|
|
||||||
<mat-icon aria-label="Login">keyboard_arrow_right</mat-icon>
|
|
||||||
</button>
|
|
||||||
</v-actions>
|
|
||||||
</cc-page-layout>
|
|
@ -1,64 +0,0 @@
|
|||||||
import { Component, DestroyRef } from '@angular/core';
|
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
||||||
import { FormControl, Validators } from '@angular/forms';
|
|
||||||
import { DomainObject } from '@vality/domain-proto/domain';
|
|
||||||
import { NotifyLogService } from '@vality/ng-core';
|
|
||||||
import { BehaviorSubject } from 'rxjs';
|
|
||||||
import { withLatestFrom } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
|
||||||
import { DomainMetadataViewExtensionsService } from '@cc/app/shared/components/thrift-api-crud/domain/domain-thrift-viewer/services/domain-metadata-view-extensions';
|
|
||||||
|
|
||||||
import { progressTo, getUnionKey } from '../../../../utils';
|
|
||||||
import { DomainMetadataFormExtensionsService } from '../../../shared/services';
|
|
||||||
import { NotificationService } from '../../../shared/services/notification';
|
|
||||||
import { DomainNavigateService } from '../services/domain-navigate.service';
|
|
||||||
import { MetadataService } from '../services/metadata.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
templateUrl: './domain-obj-creation.component.html',
|
|
||||||
styleUrls: ['../editor-container.scss'],
|
|
||||||
})
|
|
||||||
export class DomainObjCreationComponent {
|
|
||||||
control = new FormControl<DomainObject>(null, Validators.required);
|
|
||||||
review = false;
|
|
||||||
|
|
||||||
metadata$ = this.metadataService.metadata;
|
|
||||||
extensions$ = this.domainMetadataFormExtensionsService.extensions$;
|
|
||||||
viewerExtensions$ = this.domainMetadataViewExtensionsService.extensions$;
|
|
||||||
progress$ = new BehaviorSubject(0);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService,
|
|
||||||
private domainMetadataViewExtensionsService: DomainMetadataViewExtensionsService,
|
|
||||||
private domainStoreService: DomainStoreService,
|
|
||||||
private notificationService: NotificationService,
|
|
||||||
private log: NotifyLogService,
|
|
||||||
private domainNavigateService: DomainNavigateService,
|
|
||||||
private metadataService: MetadataService,
|
|
||||||
private destroyRef: DestroyRef,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
reviewChanges() {
|
|
||||||
this.review = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
commit() {
|
|
||||||
this.domainStoreService
|
|
||||||
.commit({ ops: [{ insert: { object: this.control.value } }] })
|
|
||||||
.pipe(
|
|
||||||
withLatestFrom(
|
|
||||||
this.metadataService.getDomainFieldByFieldName(getUnionKey(this.control.value)),
|
|
||||||
),
|
|
||||||
progressTo(this.progress$),
|
|
||||||
takeUntilDestroyed(this.destroyRef),
|
|
||||||
)
|
|
||||||
.subscribe({
|
|
||||||
next: ([, field]) => {
|
|
||||||
this.notificationService.success('Successfully created');
|
|
||||||
void this.domainNavigateService.toType(String(field.type));
|
|
||||||
},
|
|
||||||
error: this.log.error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { MatCardModule } from '@angular/material/card';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import { ActionsModule } from '@vality/ng-core';
|
|
||||||
|
|
||||||
import { ThriftEditorModule } from '@cc/app/shared/components/thrift-editor';
|
|
||||||
|
|
||||||
import { PageLayoutModule } from '../../../shared';
|
|
||||||
import { ThriftViewerModule } from '../../../shared/components/thrift-viewer';
|
|
||||||
|
|
||||||
import { DomainObjCreationComponent } from './domain-obj-creation.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [DomainObjCreationComponent],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
RouterModule,
|
|
||||||
MatProgressSpinnerModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatIconModule,
|
|
||||||
MatDialogModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
ThriftEditorModule,
|
|
||||||
ActionsModule,
|
|
||||||
ThriftViewerModule,
|
|
||||||
PageLayoutModule,
|
|
||||||
],
|
|
||||||
exports: [DomainObjCreationComponent],
|
|
||||||
})
|
|
||||||
export class DomainObjCreationModule {}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './domain-obj-creation.module';
|
|
||||||
export * from './domain-obj-creation.component';
|
|
@ -1,35 +0,0 @@
|
|||||||
<cc-page-layout title="Edit {{ type$ | async }}">
|
|
||||||
<div *ngIf="progress$ | async; else content" style="display: flex; justify-content: center">
|
|
||||||
<mat-spinner></mat-spinner>
|
|
||||||
</div>
|
|
||||||
<ng-template #content>
|
|
||||||
<mat-card>
|
|
||||||
<mat-card-content class="content">
|
|
||||||
<cc-thrift-editor
|
|
||||||
[defaultValue]="object$ | async"
|
|
||||||
[extensions]="extensions$ | async"
|
|
||||||
[formControl]="control"
|
|
||||||
[metadata]="metadata$ | async"
|
|
||||||
[type]="type$ | async"
|
|
||||||
class="editor"
|
|
||||||
namespace="domain"
|
|
||||||
></cc-thrift-editor>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
<v-actions>
|
|
||||||
<button mat-button (click)="backToDomain()">
|
|
||||||
<mat-icon aria-label="Login">keyboard_arrow_left</mat-icon>
|
|
||||||
Back to domain
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
[disabled]="control.invalid"
|
|
||||||
color="primary"
|
|
||||||
mat-button
|
|
||||||
(click)="reviewChanges()"
|
|
||||||
>
|
|
||||||
Review changes
|
|
||||||
<mat-icon aria-label="Login">keyboard_arrow_right</mat-icon>
|
|
||||||
</button>
|
|
||||||
</v-actions>
|
|
||||||
</ng-template>
|
|
||||||
</cc-page-layout>
|
|
@ -1,65 +0,0 @@
|
|||||||
import { Component, OnInit, DestroyRef } from '@angular/core';
|
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
||||||
import { FormControl } from '@angular/forms';
|
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
|
||||||
import { from } from 'rxjs';
|
|
||||||
import { first } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { DomainMetadataFormExtensionsService } from '../../../shared/services';
|
|
||||||
import { DomainNavigateService } from '../services/domain-navigate.service';
|
|
||||||
import { DomainObjModificationService } from '../services/domain-obj-modification.service';
|
|
||||||
import { ModifiedDomainObjectService } from '../services/modified-domain-object.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
templateUrl: './domain-obj-modification.component.html',
|
|
||||||
styleUrls: ['../editor-container.scss'],
|
|
||||||
providers: [DomainObjModificationService],
|
|
||||||
})
|
|
||||||
export class DomainObjModificationComponent implements OnInit {
|
|
||||||
control = new FormControl();
|
|
||||||
|
|
||||||
progress$ = this.domainObjModService.progress$;
|
|
||||||
metadata$ = from(import('@vality/domain-proto/metadata.json').then((m) => m.default));
|
|
||||||
object$ = this.domainObjModService.object$;
|
|
||||||
type$ = this.domainObjModService.type$;
|
|
||||||
extensions$ = this.domainMetadataFormExtensionsService.extensions$;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private router: Router,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private domainObjModService: DomainObjModificationService,
|
|
||||||
private modifiedDomainObjectService: ModifiedDomainObjectService,
|
|
||||||
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService,
|
|
||||||
private domainNavigateService: DomainNavigateService,
|
|
||||||
private destroyRef: DestroyRef,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.domainObjModService.object$
|
|
||||||
.pipe(first(), takeUntilDestroyed(this.destroyRef))
|
|
||||||
.subscribe((object) => {
|
|
||||||
if (
|
|
||||||
this.modifiedDomainObjectService.domainObject &&
|
|
||||||
this.route.snapshot.queryParams.ref === this.modifiedDomainObjectService.ref
|
|
||||||
) {
|
|
||||||
this.control.setValue(this.modifiedDomainObjectService.domainObject);
|
|
||||||
} else {
|
|
||||||
this.control.setValue(object);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
reviewChanges() {
|
|
||||||
this.modifiedDomainObjectService.update(
|
|
||||||
this.control.value,
|
|
||||||
this.route.snapshot.queryParams.ref,
|
|
||||||
);
|
|
||||||
void this.router.navigate(['domain', 'review'], {
|
|
||||||
queryParams: { ref: this.route.snapshot.queryParams.ref },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
backToDomain() {
|
|
||||||
this.type$.pipe(first()).subscribe((type) => this.domainNavigateService.toType(type));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { MatCardModule } from '@angular/material/card';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import { ActionsModule } from '@vality/ng-core';
|
|
||||||
|
|
||||||
import { ThriftEditorModule } from '@cc/app/shared/components/thrift-editor';
|
|
||||||
|
|
||||||
import { PageLayoutModule } from '../../../shared';
|
|
||||||
|
|
||||||
import { DomainObjModificationComponent } from './domain-obj-modification.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [DomainObjModificationComponent],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
|
|
||||||
RouterModule,
|
|
||||||
MatProgressSpinnerModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatIconModule,
|
|
||||||
MatDialogModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
ThriftEditorModule,
|
|
||||||
ActionsModule,
|
|
||||||
PageLayoutModule,
|
|
||||||
],
|
|
||||||
exports: [DomainObjModificationComponent],
|
|
||||||
})
|
|
||||||
export class DomainObjModificationModule {}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './domain-obj-modification.module';
|
|
||||||
export * from './domain-obj-modification.component';
|
|
@ -1,31 +0,0 @@
|
|||||||
<cc-page-layout title="Review changes of {{ type$ | async }}">
|
|
||||||
<div *ngIf="progress$ | async; else content" style="display: flex; justify-content: center">
|
|
||||||
<mat-spinner></mat-spinner>
|
|
||||||
</div>
|
|
||||||
<ng-template #content>
|
|
||||||
<mat-card>
|
|
||||||
<mat-card-content class="content">
|
|
||||||
<cc-thrift-viewer
|
|
||||||
[compared]="modifiedObject"
|
|
||||||
[value]="object$ | async"
|
|
||||||
class="editor"
|
|
||||||
kind="diff"
|
|
||||||
></cc-thrift-viewer>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
<v-actions>
|
|
||||||
<button [disabled]="!!(progress$ | async)" mat-button (click)="back()">
|
|
||||||
<mat-icon>keyboard_arrow_left</mat-icon>
|
|
||||||
Back to edit
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
[disabled]="!!(progress$ | async)"
|
|
||||||
color="primary"
|
|
||||||
mat-button
|
|
||||||
(click)="commit()"
|
|
||||||
>
|
|
||||||
Commit
|
|
||||||
</button>
|
|
||||||
</v-actions>
|
|
||||||
</ng-template>
|
|
||||||
</cc-page-layout>
|
|
@ -1,83 +0,0 @@
|
|||||||
import { Component, DestroyRef } from '@angular/core';
|
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
|
||||||
import { switchMap } from 'rxjs';
|
|
||||||
import { first, withLatestFrom } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
|
||||||
import { DomainSecretService } from '@cc/app/shared/services/domain-secret-service';
|
|
||||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
|
||||||
|
|
||||||
import { getUnionKey } from '../../../../utils';
|
|
||||||
import { NotificationService } from '../../../shared/services/notification';
|
|
||||||
import { DomainNavigateService } from '../services/domain-navigate.service';
|
|
||||||
import { DomainObjModificationService } from '../services/domain-obj-modification.service';
|
|
||||||
import { ModifiedDomainObjectService } from '../services/modified-domain-object.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
templateUrl: './domain-obj-review.component.html',
|
|
||||||
styleUrls: ['../editor-container.scss'],
|
|
||||||
providers: [DomainObjModificationService],
|
|
||||||
})
|
|
||||||
export class DomainObjReviewComponent {
|
|
||||||
progress$ = this.domainObjModService.progress$;
|
|
||||||
object$ = this.domainObjModService.object$;
|
|
||||||
type$ = this.domainObjModService.type$;
|
|
||||||
modifiedObject = this.modifiedDomainObjectService.domainObject;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private router: Router,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private domainObjModService: DomainObjModificationService,
|
|
||||||
private modifiedDomainObjectService: ModifiedDomainObjectService,
|
|
||||||
private domainStoreService: DomainStoreService,
|
|
||||||
private notificationService: NotificationService,
|
|
||||||
private notificationErrorService: NotificationErrorService,
|
|
||||||
private domainNavigateService: DomainNavigateService,
|
|
||||||
private domainSecretService: DomainSecretService,
|
|
||||||
private destroyRef: DestroyRef,
|
|
||||||
) {
|
|
||||||
if (!modifiedDomainObjectService.domainObject) {
|
|
||||||
this.back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commit() {
|
|
||||||
this.domainObjModService.fullObject$
|
|
||||||
.pipe(
|
|
||||||
first(),
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
||||||
switchMap((old_object) =>
|
|
||||||
this.domainStoreService.commit({
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
update: {
|
|
||||||
old_object,
|
|
||||||
new_object: this.domainSecretService.restoreDomain(old_object, {
|
|
||||||
[getUnionKey(old_object)]: this.modifiedObject,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
withLatestFrom(this.type$),
|
|
||||||
takeUntilDestroyed(this.destroyRef),
|
|
||||||
)
|
|
||||||
.subscribe({
|
|
||||||
next: ([, type]) => {
|
|
||||||
this.notificationService.success('Successfully changed');
|
|
||||||
void this.domainNavigateService.toType(type);
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
this.notificationErrorService.error(err);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
back() {
|
|
||||||
void this.router.navigate(['domain', 'edit'], {
|
|
||||||
queryParams: { ref: this.route.snapshot.queryParams.ref },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { MatCardModule } from '@angular/material/card';
|
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import { ActionsModule } from '@vality/ng-core';
|
|
||||||
|
|
||||||
import { PageLayoutModule } from '../../../shared';
|
|
||||||
import { ThriftEditorModule } from '../../../shared/components/thrift-editor';
|
|
||||||
import { ThriftViewerModule } from '../../../shared/components/thrift-viewer';
|
|
||||||
|
|
||||||
import { DomainObjReviewComponent } from './domain-obj-review.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [DomainObjReviewComponent],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
|
|
||||||
RouterModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatCheckboxModule,
|
|
||||||
MatIconModule,
|
|
||||||
ThriftEditorModule,
|
|
||||||
MatProgressSpinnerModule,
|
|
||||||
ActionsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
ThriftViewerModule,
|
|
||||||
PageLayoutModule,
|
|
||||||
],
|
|
||||||
exports: [DomainObjReviewComponent],
|
|
||||||
})
|
|
||||||
export class DomainObjReviewModule {}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './domain-obj-review.module';
|
|
||||||
export * from './domain-obj-review.component';
|
|
@ -4,9 +4,6 @@ import { RouterModule } from '@angular/router';
|
|||||||
import { AppAuthGuardService } from '@cc/app/shared/services';
|
import { AppAuthGuardService } from '@cc/app/shared/services';
|
||||||
|
|
||||||
import { DomainInfoComponent } from './domain-info';
|
import { DomainInfoComponent } from './domain-info';
|
||||||
import { DomainObjCreationComponent } from './domain-obj-creation';
|
|
||||||
import { DomainObjModificationComponent } from './domain-obj-modification';
|
|
||||||
import { DomainObjReviewComponent } from './domain-obj-review';
|
|
||||||
import { ROUTING_CONFIG } from './routing-config';
|
import { ROUTING_CONFIG } from './routing-config';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -21,18 +18,6 @@ import { ROUTING_CONFIG } from './routing-config';
|
|||||||
path: '',
|
path: '',
|
||||||
component: DomainInfoComponent,
|
component: DomainInfoComponent,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'create',
|
|
||||||
component: DomainObjCreationComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'edit',
|
|
||||||
component: DomainObjModificationComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'review',
|
|
||||||
component: DomainObjReviewComponent,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
import { DomainInfoModule } from './domain-info';
|
import { DomainInfoModule } from './domain-info';
|
||||||
import { DomainObjModificationModule } from './domain-obj-modification';
|
|
||||||
import { DomainObjReviewModule } from './domain-obj-review';
|
|
||||||
import { DomainRoutingModule } from './domain-routing.module';
|
import { DomainRoutingModule } from './domain-routing.module';
|
||||||
import { MetadataService } from './services/metadata.service';
|
|
||||||
import { ModifiedDomainObjectService } from './services/modified-domain-object.service';
|
import { ModifiedDomainObjectService } from './services/modified-domain-object.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [DomainRoutingModule, DomainInfoModule],
|
||||||
DomainRoutingModule,
|
providers: [ModifiedDomainObjectService],
|
||||||
DomainInfoModule,
|
|
||||||
DomainObjModificationModule,
|
|
||||||
DomainObjReviewModule,
|
|
||||||
],
|
|
||||||
providers: [MetadataService, ModifiedDomainObjectService],
|
|
||||||
})
|
})
|
||||||
export class DomainModule {}
|
export class DomainModule {}
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ThriftAstMetadata } from '@vality/domain-proto';
|
import { ThriftAstMetadata } from '@vality/domain-proto';
|
||||||
import { Reference } from '@vality/domain-proto/domain';
|
import { Reference } from '@vality/domain-proto/domain';
|
||||||
|
import { getImportValue } from '@vality/ng-core';
|
||||||
import { Field } from '@vality/thrift-ts';
|
import { Field } from '@vality/thrift-ts';
|
||||||
import { from, Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { map, shareReplay } from 'rxjs/operators';
|
import { map, shareReplay, withLatestFrom } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable({ providedIn: 'root' })
|
||||||
export class MetadataService {
|
export class MetadataService {
|
||||||
private metadata$: Observable<ThriftAstMetadata[]> = from(
|
private metadata$ = getImportValue<ThriftAstMetadata[]>(
|
||||||
import('@vality/domain-proto/metadata.json').then((m) => m.default),
|
import('@vality/domain-proto/metadata.json'),
|
||||||
).pipe(shareReplay(1)) as Observable<ThriftAstMetadata[]>;
|
).pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||||
|
|
||||||
get metadata() {
|
|
||||||
return this.metadata$;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDomainObjectType(ref: Reference): Observable<string | null> {
|
getDomainObjectType(ref: Reference): Observable<string | null> {
|
||||||
if (!ref) {
|
if (!ref) {
|
||||||
@ -32,12 +29,31 @@ export class MetadataService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDomainFieldByFieldName(fieldName: string): Observable<Field> {
|
getDomainFieldByName(fieldName: string): Observable<Field> {
|
||||||
return this.getDomainFields().pipe(
|
return this.getDomainFields().pipe(
|
||||||
map((fields) => fields.find((f) => f.name === fieldName)),
|
map((fields) => fields.find((f) => f.name === fieldName)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDomainFieldByType(fieldType: string): Observable<Field> {
|
||||||
|
return this.getDomainFields().pipe(
|
||||||
|
map((fields) => fields.find((f) => f.type === fieldType)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDomainObjectDataFieldByName(fieldName: string): Observable<Field> {
|
||||||
|
return this.getDomainFields().pipe(
|
||||||
|
map((fields) => fields.find((f) => f.name === fieldName)),
|
||||||
|
withLatestFrom(this.metadata$),
|
||||||
|
map(
|
||||||
|
([field, metadata]) =>
|
||||||
|
metadata
|
||||||
|
.find(({ name }) => name === 'domain')
|
||||||
|
.ast.struct[String(field.type)]?.find((f) => f.name === 'data'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getDomainFields(): Observable<Field[]> {
|
getDomainFields(): Observable<Field[]> {
|
||||||
return this.metadata$.pipe(
|
return this.metadata$.pipe(
|
||||||
map((m) => m.find(({ name }) => name === 'domain').ast.union.DomainObject),
|
map((m) => m.find(({ name }) => name === 'domain').ast.union.DomainObject),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit, DestroyRef } from '@angular/core';
|
import { Component, OnInit, DestroyRef } from '@angular/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { Validators, FormControl } from '@angular/forms';
|
import { Validators, FormControl } from '@angular/forms';
|
||||||
import { DialogResponseStatus, DialogSuperclass } from '@vality/ng-core';
|
import { DialogResponseStatus, DialogSuperclass, getValue } from '@vality/ng-core';
|
||||||
import {
|
import {
|
||||||
RepairInvoicesRequest,
|
RepairInvoicesRequest,
|
||||||
RepairWithdrawalsRequest,
|
RepairWithdrawalsRequest,
|
||||||
@ -9,11 +9,12 @@ import {
|
|||||||
} from '@vality/repairer-proto/repairer';
|
} from '@vality/repairer-proto/repairer';
|
||||||
import isNil from 'lodash-es/isNil';
|
import isNil from 'lodash-es/isNil';
|
||||||
import { BehaviorSubject, from } from 'rxjs';
|
import { BehaviorSubject, from } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
||||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||||
|
|
||||||
import { progressTo, getFormValueChanges } from '../../../../../utils';
|
import { progressTo } from '../../../../../utils';
|
||||||
import { RepairManagementService } from '../../../../api/repairer';
|
import { RepairManagementService } from '../../../../api/repairer';
|
||||||
import { NotificationService } from '../../../../shared/services/notification';
|
import { NotificationService } from '../../../../shared/services/notification';
|
||||||
|
|
||||||
@ -66,8 +67,11 @@ export class RepairByScenarioDialogComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
getFormValueChanges(this.nsControl)
|
this.nsControl.valueChanges
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
.pipe(
|
||||||
|
map(() => getValue(this.nsControl)),
|
||||||
|
takeUntilDestroyed(this.destroyRef),
|
||||||
|
)
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.form.setValue(
|
this.form.setValue(
|
||||||
this.dialogData.machines.map(({ id }) => ({ id, scenario: {} })),
|
this.dialogData.machines.map(({ id }) => ({ id, scenario: {} })),
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<cc-page-layout title="Terminals">
|
<cc-page-layout title="Terminals">
|
||||||
<cc-page-layout-actions></cc-page-layout-actions>
|
<cc-page-layout-actions>
|
||||||
|
<button color="primary" mat-raised-button (click)="create()">Create</button>
|
||||||
|
</cc-page-layout-actions>
|
||||||
<v-table
|
<v-table
|
||||||
[(sort)]="sort"
|
[(sort)]="sort"
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
@ -9,9 +11,5 @@
|
|||||||
sortOnFront
|
sortOnFront
|
||||||
standaloneFilter
|
standaloneFilter
|
||||||
(update)="update()"
|
(update)="update()"
|
||||||
>
|
></v-table>
|
||||||
<v-table-actions>
|
|
||||||
<button color="primary" mat-raised-button (click)="create()">Create</button>
|
|
||||||
</v-table-actions>
|
|
||||||
</v-table>
|
|
||||||
</cc-page-layout>
|
</cc-page-layout>
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { Component, DestroyRef } from '@angular/core';
|
import { Component, DestroyRef } from '@angular/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { Sort } from '@angular/material/sort';
|
import { Sort } from '@angular/material/sort';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { TerminalObject } from '@vality/domain-proto/domain';
|
import { TerminalObject } from '@vality/domain-proto/domain';
|
||||||
import { Column } from '@vality/ng-core';
|
import { Column, DialogService } from '@vality/ng-core';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { map, take } from 'rxjs/operators';
|
import { map, take } from 'rxjs/operators';
|
||||||
|
|
||||||
@ -11,7 +10,10 @@ import { DomainStoreService } from '../../api/domain-config';
|
|||||||
import { createPredicateColumn } from '../../shared';
|
import { createPredicateColumn } from '../../shared';
|
||||||
import { SidenavInfoService } from '../../shared/components/sidenav-info';
|
import { SidenavInfoService } from '../../shared/components/sidenav-info';
|
||||||
import { TerminalDelegatesCardComponent } from '../../shared/components/terminal-delegates-card/terminal-delegates-card.component';
|
import { TerminalDelegatesCardComponent } from '../../shared/components/terminal-delegates-card/terminal-delegates-card.component';
|
||||||
import { DomainObjectCardComponent } from '../../shared/components/thrift-api-crud';
|
import {
|
||||||
|
DomainObjectCardComponent,
|
||||||
|
CreateDomainObjectDialogComponent,
|
||||||
|
} from '../../shared/components/thrift-api-crud';
|
||||||
|
|
||||||
import { getTerminalShopWalletDelegates } from './utils/get-terminal-shop-wallet-delegates';
|
import { getTerminalShopWalletDelegates } from './utils/get-terminal-shop-wallet-delegates';
|
||||||
|
|
||||||
@ -71,9 +73,9 @@ export class TerminalsComponent {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private domainStoreService: DomainStoreService,
|
private domainStoreService: DomainStoreService,
|
||||||
private router: Router,
|
|
||||||
private sidenavInfoService: SidenavInfoService,
|
private sidenavInfoService: SidenavInfoService,
|
||||||
private destroyRef: DestroyRef,
|
private destroyRef: DestroyRef,
|
||||||
|
private dialogService: DialogService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
@ -81,7 +83,9 @@ export class TerminalsComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
void this.router.navigate(['/domain/create']);
|
this.dialogService.open(CreateDomainObjectDialogComponent, {
|
||||||
|
objectType: 'TerminalObject',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getProvider(terminalObj: TerminalObject) {
|
private getProvider(terminalObj: TerminalObject) {
|
||||||
|
@ -7,12 +7,11 @@ import {
|
|||||||
FormControl,
|
FormControl,
|
||||||
AbstractControl,
|
AbstractControl,
|
||||||
} from '@angular/forms';
|
} from '@angular/forms';
|
||||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
import { FormComponentSuperclass, createControlProviders, getErrorsTree } from '@vality/ng-core';
|
||||||
import { MapType, SetType, ListType } from '@vality/thrift-ts';
|
import { MapType, SetType, ListType } from '@vality/thrift-ts';
|
||||||
import { merge } from 'rxjs';
|
import { merge } from 'rxjs';
|
||||||
|
|
||||||
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form';
|
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form';
|
||||||
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
@ -65,20 +64,22 @@ export class ComplexFormComponent<V, K = never>
|
|||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
const values = this.valueControls.value;
|
const values = this.valueControls.value;
|
||||||
|
if (!this.data.isRequired && !values.length) {
|
||||||
|
this.emitOutgoingValue(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (this.data.type.name) {
|
switch (this.data.type.name) {
|
||||||
case 'list':
|
case 'list':
|
||||||
this.emitOutgoingValue(values.length ? values : null);
|
this.emitOutgoingValue(values);
|
||||||
break;
|
return;
|
||||||
case 'map': {
|
case 'map': {
|
||||||
const keys = this.keyControls.value;
|
const keys = this.keyControls.value;
|
||||||
this.emitOutgoingValue(
|
this.emitOutgoingValue(new Map(values.map((v, idx) => [keys[idx], v])));
|
||||||
keys.length ? new Map(values.map((v, idx) => [keys[idx], v])) : null,
|
return;
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'set':
|
case 'set':
|
||||||
this.emitOutgoingValue(values.length ? new Set(values) : null);
|
this.emitOutgoingValue(new Set(values));
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { createControlProviders, FormControlSuperclass } from '@vality/ng-core';
|
||||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
@ -9,6 +8,6 @@ import { MetadataFormData } from '../../types/metadata-form-data';
|
|||||||
templateUrl: './enum-field.component.html',
|
templateUrl: './enum-field.component.html',
|
||||||
providers: createControlProviders(() => EnumFieldComponent),
|
providers: createControlProviders(() => EnumFieldComponent),
|
||||||
})
|
})
|
||||||
export class EnumFieldComponent<T> extends ValidatedFormControlSuperclass<T> {
|
export class EnumFieldComponent<T> extends FormControlSuperclass<T> {
|
||||||
@Input() data: MetadataFormData<string, 'enum'>;
|
@Input() data: MetadataFormData<string, 'enum'>;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Component, Input, OnChanges, OnInit, DestroyRef } from '@angular/core';
|
import { Component, Input, OnChanges, OnInit, DestroyRef } from '@angular/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { Validator, ValidationErrors, FormControl, Validators } from '@angular/forms';
|
import { Validator, ValidationErrors, FormControl, Validators } from '@angular/forms';
|
||||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
import { FormComponentSuperclass, ComponentChanges, createControlProviders } from '@vality/ng-core';
|
||||||
import { ComponentChanges, createControlProviders } from '@vality/ng-core';
|
|
||||||
import { ThriftType } from '@vality/thrift-ts';
|
import { ThriftType } from '@vality/thrift-ts';
|
||||||
import { defer, switchMap, ReplaySubject, Observable, combineLatest } from 'rxjs';
|
import { defer, switchMap, ReplaySubject, Observable, combineLatest } from 'rxjs';
|
||||||
import { shareReplay, first, map, pluck } from 'rxjs/operators';
|
import { shareReplay, first, map, pluck } from 'rxjs/operators';
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
import { Component, Input, OnChanges, OnInit, SimpleChanges, DestroyRef } from '@angular/core';
|
import { Component, Input, OnChanges, OnInit, DestroyRef } from '@angular/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { ValidationErrors, Validators, FormBuilder, FormGroup } from '@angular/forms';
|
import {
|
||||||
|
ValidationErrors,
|
||||||
|
Validators,
|
||||||
|
FormBuilder,
|
||||||
|
FormGroup,
|
||||||
|
AbstractControl,
|
||||||
|
} from '@angular/forms';
|
||||||
|
import {
|
||||||
|
createControlProviders,
|
||||||
|
ComponentChanges,
|
||||||
|
FormComponentSuperclass,
|
||||||
|
getValueChanges,
|
||||||
|
} from '@vality/ng-core';
|
||||||
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 { combineLatest } from 'rxjs';
|
||||||
import { delay } from 'rxjs/operators';
|
import { map, distinctUntilChanged } from 'rxjs/operators';
|
||||||
|
|
||||||
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils';
|
import { MetadataFormData, isRequiredField } from '../../types/metadata-form-data';
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
|
||||||
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -17,7 +27,7 @@ import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
|||||||
providers: createControlProviders(() => StructFormComponent),
|
providers: createControlProviders(() => StructFormComponent),
|
||||||
})
|
})
|
||||||
export class StructFormComponent<T extends { [N in string]: unknown }>
|
export class StructFormComponent<T extends { [N in string]: unknown }>
|
||||||
extends ValidatedControlSuperclass<T>
|
extends FormComponentSuperclass<T>
|
||||||
implements OnChanges, OnInit
|
implements OnChanges, OnInit
|
||||||
{
|
{
|
||||||
@Input() data: MetadataFormData<string, 'struct'>;
|
@Input() data: MetadataFormData<string, 'struct'>;
|
||||||
@ -42,39 +52,38 @@ export class StructFormComponent<T extends { [N in string]: unknown }>
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
merge(this.control.valueChanges, this.labelControl.valueChanges)
|
combineLatest([getValueChanges(this.control), getValueChanges(this.labelControl)])
|
||||||
.pipe(delay(0), takeUntilDestroyed(this.destroyRef))
|
.pipe(
|
||||||
.subscribe(() => {
|
map(([value, labelValue]) =>
|
||||||
this.emitOutgoingValue(
|
value && labelValue ? (omitBy(value, isNil) as T) : null,
|
||||||
this.control.value && this.labelControl.value
|
),
|
||||||
? (omitBy(this.control.value, isNil) as T)
|
distinctUntilChanged(),
|
||||||
: null,
|
takeUntilDestroyed(this.destroyRef),
|
||||||
);
|
)
|
||||||
|
.subscribe((value) => {
|
||||||
|
this.emitOutgoingValue(value);
|
||||||
});
|
});
|
||||||
return super.ngOnInit();
|
return super.ngOnInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: ComponentChanges<StructFormComponent<T>>) {
|
||||||
const newControlsNames = new Set(this.data.ast.map(({ name }) => name));
|
if (changes.data) {
|
||||||
Object.keys(this.control.controls).forEach((name) => {
|
const newControlsNames = new Set(this.data.ast.map(({ name }) => name));
|
||||||
if (newControlsNames.has(name)) {
|
Object.keys(this.control.controls).forEach((name) => {
|
||||||
newControlsNames.delete(name);
|
|
||||||
} else {
|
|
||||||
this.control.removeControl(name as never);
|
this.control.removeControl(name as never);
|
||||||
}
|
});
|
||||||
});
|
newControlsNames.forEach((name) =>
|
||||||
newControlsNames.forEach((name) =>
|
this.control.addControl(
|
||||||
this.control.addControl(
|
name as never,
|
||||||
name as never,
|
this.fb.control(null, {
|
||||||
this.fb.control(null, {
|
validators: isRequiredField(this.data.ast.find((f) => f.name === name))
|
||||||
validators:
|
|
||||||
this.data.ast.find((f) => f.name === name)?.option === 'required'
|
|
||||||
? [Validators.required]
|
? [Validators.required]
|
||||||
: [],
|
: [],
|
||||||
}) as never,
|
}) as never,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
this.setLabelControl();
|
this.setLabelControl();
|
||||||
|
}
|
||||||
super.ngOnChanges(changes);
|
super.ngOnChanges(changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,8 +92,8 @@ export class StructFormComponent<T extends { [N in string]: unknown }>
|
|||||||
this.setLabelControl(!!(value && Object.keys(value).length));
|
this.setLabelControl(!!(value && Object.keys(value).length));
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
validate(control: AbstractControl): ValidationErrors | null {
|
||||||
return this.labelControl.value ? super.validate() : null;
|
return this.labelControl.value ? super.validate(control) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setLabelControl(value: boolean = false) {
|
private setLabelControl(value: boolean = false) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { createControlProviders, FormControlSuperclass } from '@vality/ng-core';
|
||||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||||
@ -10,7 +9,7 @@ import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
|||||||
templateUrl: './typedef-form.component.html',
|
templateUrl: './typedef-form.component.html',
|
||||||
providers: createControlProviders(() => TypedefFormComponent),
|
providers: createControlProviders(() => TypedefFormComponent),
|
||||||
})
|
})
|
||||||
export class TypedefFormComponent<T> extends ValidatedFormControlSuperclass<T> {
|
export class TypedefFormComponent<T> extends FormControlSuperclass<T> {
|
||||||
@Input() data: MetadataFormData<string, 'typedef'>;
|
@Input() data: MetadataFormData<string, 'typedef'>;
|
||||||
@Input() extensions: MetadataFormExtension[];
|
@Input() extensions: MetadataFormExtension[];
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
[required]="data.isRequired"
|
[required]="data.isRequired"
|
||||||
(ngModelChange)="cleanInternal()"
|
(ngModelChange)="cleanInternal()"
|
||||||
>
|
>
|
||||||
<mat-option *ngFor="let field of data.ast" [value]="field">{{
|
<mat-option *ngFor="let option of options$ | async" [value]="option.value">{{
|
||||||
field.type | fieldLabel: field
|
option.label
|
||||||
}}</mat-option>
|
}}</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
<button
|
<button
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import { Component, Input, OnInit, DestroyRef } from '@angular/core';
|
import { Component, Input, OnInit, DestroyRef, OnChanges } from '@angular/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { ValidationErrors, Validator, FormControl } from '@angular/forms';
|
import { ValidationErrors, Validator, FormControl } from '@angular/forms';
|
||||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
import {
|
||||||
|
FormComponentSuperclass,
|
||||||
|
createControlProviders,
|
||||||
|
getErrorsTree,
|
||||||
|
ComponentChanges,
|
||||||
|
} from '@vality/ng-core';
|
||||||
import { Field } from '@vality/thrift-ts';
|
import { Field } from '@vality/thrift-ts';
|
||||||
import { merge } from 'rxjs';
|
import { merge, ReplaySubject, defer } from 'rxjs';
|
||||||
import { delay, distinctUntilChanged, map } from 'rxjs/operators';
|
import { delay, distinctUntilChanged, map, shareReplay } from 'rxjs/operators';
|
||||||
|
|
||||||
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
|
||||||
|
|
||||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||||
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||||
import { getDefaultValue } from '../../utils/get-default-value';
|
import { getFieldLabel, getDefaultValue } from '../../utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-union-field',
|
selector: 'cc-union-field',
|
||||||
@ -19,7 +22,7 @@ import { getDefaultValue } from '../../utils/get-default-value';
|
|||||||
})
|
})
|
||||||
export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
||||||
extends FormComponentSuperclass<T>
|
extends FormComponentSuperclass<T>
|
||||||
implements OnInit, Validator
|
implements OnInit, Validator, OnChanges
|
||||||
{
|
{
|
||||||
@Input() data: MetadataFormData<string, 'union'>;
|
@Input() data: MetadataFormData<string, 'union'>;
|
||||||
@Input() extensions: MetadataFormExtension[];
|
@Input() extensions: MetadataFormExtension[];
|
||||||
@ -27,6 +30,17 @@ export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
|||||||
fieldControl = new FormControl() as FormControl<Field>;
|
fieldControl = new FormControl() as FormControl<Field>;
|
||||||
internalControl = new FormControl() as FormControl<T[keyof T]>;
|
internalControl = new FormControl() as FormControl<T[keyof T]>;
|
||||||
|
|
||||||
|
protected options$ = defer(() => this.data$).pipe(
|
||||||
|
map((data) =>
|
||||||
|
data.ast
|
||||||
|
.map((field) => ({ label: getFieldLabel(field.type, field), value: field }))
|
||||||
|
.sort((a, b) => a.label.localeCompare(b.label)),
|
||||||
|
),
|
||||||
|
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
private data$ = new ReplaySubject<MetadataFormData<string, 'union'>>(1);
|
||||||
|
|
||||||
constructor(private destroyRef: DestroyRef) {
|
constructor(private destroyRef: DestroyRef) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -50,6 +64,13 @@ export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: ComponentChanges<UnionFieldComponent<T>>) {
|
||||||
|
super.ngOnChanges(changes);
|
||||||
|
if (changes.data) {
|
||||||
|
this.data$.next(this.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
validate(): ValidationErrors | null {
|
||||||
return this.fieldControl.errors || getErrorsTree(this.internalControl);
|
return this.fieldControl.errors || getErrorsTree(this.internalControl);
|
||||||
}
|
}
|
||||||
@ -70,13 +91,11 @@ export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
|||||||
|
|
||||||
cleanInternal(emitEvent = false) {
|
cleanInternal(emitEvent = false) {
|
||||||
this.internalControl.reset(
|
this.internalControl.reset(
|
||||||
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],
|
||||||
) as T[keyof T])
|
|
||||||
: null,
|
|
||||||
{ emitEvent },
|
{ emitEvent },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import { Component, Input, OnChanges } from '@angular/core';
|
||||||
import { Validator } from '@angular/forms';
|
import { Validator } from '@angular/forms';
|
||||||
import { ThriftAstMetadata } from '@vality/domain-proto';
|
import { ThriftAstMetadata } from '@vality/domain-proto';
|
||||||
|
import { createControlProviders, FormControlSuperclass } from '@vality/ng-core';
|
||||||
import { Field, ValueType } from '@vality/thrift-ts';
|
import { Field, ValueType } from '@vality/thrift-ts';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
|
||||||
|
|
||||||
import { MetadataFormData } from './types/metadata-form-data';
|
import { MetadataFormData } from './types/metadata-form-data';
|
||||||
import {
|
import {
|
||||||
MetadataFormExtension,
|
MetadataFormExtension,
|
||||||
@ -19,7 +18,7 @@ import {
|
|||||||
providers: createControlProviders(() => MetadataFormComponent),
|
providers: createControlProviders(() => MetadataFormComponent),
|
||||||
})
|
})
|
||||||
export class MetadataFormComponent<T>
|
export class MetadataFormComponent<T>
|
||||||
extends ValidatedFormControlSuperclass<T>
|
extends FormControlSuperclass<T>
|
||||||
implements OnChanges, Validator
|
implements OnChanges, Validator
|
||||||
{
|
{
|
||||||
@Input() metadata: ThriftAstMetadata[];
|
@Input() metadata: ThriftAstMetadata[];
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { Pipe, PipeTransform } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
import { ValueType, Field } from '@vality/thrift-ts';
|
import { ValueType, Field } from '@vality/thrift-ts';
|
||||||
import startCase from 'lodash-es/startCase';
|
|
||||||
|
|
||||||
import { getValueTypeTitle } from '@cc/app/shared';
|
import { getFieldLabel } from '../utils';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'fieldLabel',
|
name: 'fieldLabel',
|
||||||
})
|
})
|
||||||
export class FieldLabelPipe implements PipeTransform {
|
export class FieldLabelPipe implements PipeTransform {
|
||||||
transform(type: ValueType, field?: Field): string {
|
transform(type: ValueType, field?: Field): string {
|
||||||
return type ? startCase((field ? field.name : getValueTypeTitle(type)).toLowerCase()) : '';
|
return getFieldLabel(type, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,10 @@ export function isTypeWithAliases(
|
|||||||
return Boolean(getByType(data, type, namespace));
|
return Boolean(getByType(data, type, namespace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isRequiredField(field: Field): boolean {
|
||||||
|
return field?.option === 'required'; // optional even if not explicitly stated
|
||||||
|
}
|
||||||
|
|
||||||
export class MetadataFormData<
|
export class MetadataFormData<
|
||||||
T extends ValueType = ValueType,
|
T extends ValueType = ValueType,
|
||||||
S extends StructureType = StructureType,
|
S extends StructureType = StructureType,
|
||||||
@ -86,7 +90,7 @@ export class MetadataFormData<
|
|||||||
}
|
}
|
||||||
|
|
||||||
get isRequired() {
|
get isRequired() {
|
||||||
return this.field?.option === 'required' || this.trueParent?.objectType === 'union';
|
return isRequiredField(this.field) || this.trueParent?.objectType === 'union';
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -5,6 +5,9 @@ import { TypeDefs } from '@vality/thrift-ts/src/thrift-parser';
|
|||||||
import { MetadataFormData, TypeGroup } from '../types/metadata-form-data';
|
import { MetadataFormData, TypeGroup } from '../types/metadata-form-data';
|
||||||
|
|
||||||
export function getDefaultValue(metadata: ThriftAstMetadata[], namespace: string, type: ValueType) {
|
export function getDefaultValue(metadata: ThriftAstMetadata[], namespace: string, type: ValueType) {
|
||||||
|
if (!type) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
let data: MetadataFormData;
|
let data: MetadataFormData;
|
||||||
do {
|
do {
|
||||||
data = new MetadataFormData(metadata, namespace, type);
|
data = new MetadataFormData(metadata, namespace, type);
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import { Field, ValueType } from '@vality/thrift-ts';
|
||||||
|
import startCase from 'lodash-es/startCase';
|
||||||
|
|
||||||
|
import { getValueTypeTitle } from '../../../pipes';
|
||||||
|
|
||||||
|
export function getFieldLabel(type: ValueType, field?: Field) {
|
||||||
|
return type ? startCase((field ? field.name : getValueTypeTitle(type)).toLowerCase()) : '';
|
||||||
|
}
|
2
src/app/shared/components/metadata-form/utils/index.ts
Normal file
2
src/app/shared/components/metadata-form/utils/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './get-field-label';
|
||||||
|
export * from './get-default-value';
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, Input, OnInit, booleanAttribute } from '@angular/core';
|
import { Component, Input, OnInit, booleanAttribute } from '@angular/core';
|
||||||
import { PayoutTool } from '@vality/domain-proto/domain';
|
import { PayoutTool } from '@vality/domain-proto/domain';
|
||||||
import { PartyID, ShopID } from '@vality/domain-proto/payment_processing';
|
import { PartyID, ShopID } from '@vality/domain-proto/payment_processing';
|
||||||
import { createControlProviders, FormControlSuperclass, Option } from '@vality/ng-core';
|
import { FormControlSuperclass, Option, createControlProviders } from '@vality/ng-core';
|
||||||
import { BehaviorSubject, combineLatest, defer, Observable, of, switchMap } from 'rxjs';
|
import { BehaviorSubject, combineLatest, defer, Observable, of, switchMap } from 'rxjs';
|
||||||
import { map, shareReplay } from 'rxjs/operators';
|
import { map, shareReplay } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ export class SidenavInfoService {
|
|||||||
private sidenavInfoComponents?: SidenavInfoComponents,
|
private sidenavInfoComponents?: SidenavInfoComponents,
|
||||||
) {
|
) {
|
||||||
if (!this.sidenavInfoComponents) {
|
if (!this.sidenavInfoComponents) {
|
||||||
this.sidenavInfoComponents = sidenavInfoComponents = {};
|
this.sidenavInfoComponents = sidenavInfoComponents ?? {};
|
||||||
}
|
}
|
||||||
router.events
|
router.events
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<v-dialog
|
||||||
|
*ngIf="!isReview; else reviewTpl"
|
||||||
|
[progress]="!!(progress$ | async)"
|
||||||
|
title="Create domain object"
|
||||||
|
>
|
||||||
|
<cc-domain-thrift-form [formControl]="control" type="DomainObject"></cc-domain-thrift-form>
|
||||||
|
<v-dialog-actions>
|
||||||
|
<button
|
||||||
|
*ngIf="!isReview"
|
||||||
|
[disabled]="control.invalid"
|
||||||
|
color="primary"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="isReview = true"
|
||||||
|
>
|
||||||
|
Review
|
||||||
|
</button>
|
||||||
|
</v-dialog-actions>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<ng-template #reviewTpl>
|
||||||
|
<v-dialog [progress]="!!(progress$ | async)" title="Review domain object">
|
||||||
|
<cc-domain-thrift-viewer
|
||||||
|
[value]="control.value"
|
||||||
|
kind="editor"
|
||||||
|
type="DomainObject"
|
||||||
|
></cc-domain-thrift-viewer>
|
||||||
|
<v-dialog-actions>
|
||||||
|
<button
|
||||||
|
*ngIf="isReview"
|
||||||
|
[disabled]="!!(progress$ | async)"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="isReview = false"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
*ngIf="isReview"
|
||||||
|
[disabled]="!!(progress$ | async)"
|
||||||
|
color="primary"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="create()"
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
</v-dialog-actions>
|
||||||
|
</v-dialog>
|
||||||
|
</ng-template>
|
@ -0,0 +1,109 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Component, DestroyRef, OnInit } from '@angular/core';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { ReactiveFormsModule, FormControl, Validators } from '@angular/forms';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { DomainObject } from '@vality/domain-proto/domain';
|
||||||
|
import {
|
||||||
|
DialogSuperclass,
|
||||||
|
DEFAULT_DIALOG_CONFIG,
|
||||||
|
DialogModule,
|
||||||
|
DEFAULT_DIALOG_CONFIG_FULL_HEIGHT,
|
||||||
|
DialogConfig,
|
||||||
|
progressTo,
|
||||||
|
NotifyLogService,
|
||||||
|
} from '@vality/ng-core';
|
||||||
|
import { BehaviorSubject, switchMap, EMPTY } from 'rxjs';
|
||||||
|
import { first, map, catchError } from 'rxjs/operators';
|
||||||
|
import { ValuesType } from 'utility-types';
|
||||||
|
|
||||||
|
import { getUnionKey } from '../../../../../../utils';
|
||||||
|
import { DomainStoreService } from '../../../../../api/domain-config';
|
||||||
|
import { DomainNavigateService } from '../../../../../sections/domain/services/domain-navigate.service';
|
||||||
|
import { MetadataService } from '../../../../../sections/domain/services/metadata.service';
|
||||||
|
import { DomainThriftFormComponent } from '../domain-thrift-form';
|
||||||
|
import { DomainThriftViewerComponent } from '../domain-thrift-viewer';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cc-create-domain-object-dialog',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
DialogModule,
|
||||||
|
MatButtonModule,
|
||||||
|
DomainThriftFormComponent,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
DomainThriftViewerComponent,
|
||||||
|
],
|
||||||
|
templateUrl: './create-domain-object-dialog.component.html',
|
||||||
|
})
|
||||||
|
export class CreateDomainObjectDialogComponent
|
||||||
|
extends DialogSuperclass<CreateDomainObjectDialogComponent, { objectType?: string } | void>
|
||||||
|
implements OnInit
|
||||||
|
{
|
||||||
|
static defaultDialogConfig: ValuesType<DialogConfig> = {
|
||||||
|
...DEFAULT_DIALOG_CONFIG.large,
|
||||||
|
minHeight: DEFAULT_DIALOG_CONFIG_FULL_HEIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
|
control = new FormControl<DomainObject | null>(null, [Validators.required]);
|
||||||
|
progress$ = new BehaviorSubject(0);
|
||||||
|
isReview = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private domainStoreService: DomainStoreService,
|
||||||
|
private destroyRef: DestroyRef,
|
||||||
|
private log: NotifyLogService,
|
||||||
|
private domainNavigateService: DomainNavigateService,
|
||||||
|
private metadataService: MetadataService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.dialogData) {
|
||||||
|
this.metadataService
|
||||||
|
.getDomainFieldByType(this.dialogData.objectType)
|
||||||
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe((type) => {
|
||||||
|
this.control.setValue({ [type.name]: {} });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create(attempts = 1) {
|
||||||
|
this.domainStoreService
|
||||||
|
.commit({ ops: [{ insert: { object: this.control.value } }] })
|
||||||
|
.pipe(
|
||||||
|
catchError((err) => {
|
||||||
|
if (err?.name === 'ObsoleteCommitVersion' && attempts !== 0) {
|
||||||
|
this.domainStoreService.forceReload();
|
||||||
|
this.create(attempts - 1);
|
||||||
|
this.log.error(err, `Domain config is out of date, one more attempt...`);
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}),
|
||||||
|
switchMap(() => this.getType()),
|
||||||
|
progressTo(this.progress$),
|
||||||
|
takeUntilDestroyed(this.destroyRef),
|
||||||
|
)
|
||||||
|
.subscribe({
|
||||||
|
next: (type) => {
|
||||||
|
this.log.successOperation('create', 'domain object');
|
||||||
|
void this.domainNavigateService.toType(String(type));
|
||||||
|
this.closeWithSuccess();
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.log.errorOperation(err, 'create', 'domain object');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getType() {
|
||||||
|
return this.metadataService.getDomainFieldByName(getUnionKey(this.control.value)).pipe(
|
||||||
|
map((f) => String(f.type)),
|
||||||
|
first(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export * from './create-domain-object-dialog.component';
|
@ -3,8 +3,8 @@ import { Component, DestroyRef, Input, OnChanges } from '@angular/core';
|
|||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { Reference } from '@vality/domain-proto/internal/domain';
|
import { Reference } from '@vality/domain-proto/internal/domain';
|
||||||
import { ComponentChanges } from '@vality/ng-core';
|
import { ComponentChanges, DialogService } from '@vality/ng-core';
|
||||||
import { combineLatest, ReplaySubject } from 'rxjs';
|
import { combineLatest, ReplaySubject, switchMap } from 'rxjs';
|
||||||
import { map, shareReplay, first } from 'rxjs/operators';
|
import { map, shareReplay, first } from 'rxjs/operators';
|
||||||
|
|
||||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||||
@ -13,6 +13,7 @@ import { toJson } from '@cc/utils';
|
|||||||
import { SidenavInfoModule } from '../../../sidenav-info';
|
import { SidenavInfoModule } from '../../../sidenav-info';
|
||||||
import { CardComponent } from '../../../sidenav-info/components/card/card.component';
|
import { CardComponent } from '../../../sidenav-info/components/card/card.component';
|
||||||
import { DomainThriftViewerComponent } from '../domain-thrift-viewer';
|
import { DomainThriftViewerComponent } from '../domain-thrift-viewer';
|
||||||
|
import { EditDomainObjectDialogComponent } from '../edit-domain-object-dialog';
|
||||||
import { DomainObjectService } from '../services';
|
import { DomainObjectService } from '../services';
|
||||||
import { getDomainObjectDetails } from '../utils';
|
import { getDomainObjectDetails } from '../utils';
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ export class DomainObjectCardComponent implements OnChanges {
|
|||||||
private domainObjectService: DomainObjectService,
|
private domainObjectService: DomainObjectService,
|
||||||
private domainStoreService: DomainStoreService,
|
private domainStoreService: DomainStoreService,
|
||||||
private destroyRef: DestroyRef,
|
private destroyRef: DestroyRef,
|
||||||
|
private dialogService: DialogService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnChanges(changes: ComponentChanges<DomainObjectCardComponent>) {
|
ngOnChanges(changes: ComponentChanges<DomainObjectCardComponent>) {
|
||||||
@ -59,7 +61,17 @@ export class DomainObjectCardComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
edit() {
|
edit() {
|
||||||
void this.domainObjectService.edit(this.ref);
|
this.domainObject$
|
||||||
|
.pipe(
|
||||||
|
first(),
|
||||||
|
switchMap((domainObject) =>
|
||||||
|
this.dialogService
|
||||||
|
.open(EditDomainObjectDialogComponent, { domainObject })
|
||||||
|
.afterClosed(),
|
||||||
|
),
|
||||||
|
takeUntilDestroyed(this.destroyRef),
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<cc-thrift-editor
|
<cc-thrift-editor
|
||||||
|
[defaultValue]="defaultValue"
|
||||||
[extensions]="extensions$ | async"
|
[extensions]="extensions$ | async"
|
||||||
[formControl]="control"
|
[formControl]="control"
|
||||||
[metadata]="metadata$ | async"
|
[metadata]="metadata$ | async"
|
||||||
|
@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { ThriftAstMetadata } from '@vality/fistful-proto';
|
import { ThriftAstMetadata } from '@vality/fistful-proto';
|
||||||
import { createControlProviders, getImportValue } from '@vality/ng-core';
|
import { getImportValue, createControlProviders } from '@vality/ng-core';
|
||||||
|
|
||||||
import { DomainMetadataFormExtensionsService } from '../../../../services';
|
import { DomainMetadataFormExtensionsService } from '../../../../services';
|
||||||
import { MetadataFormModule } from '../../../metadata-form';
|
import { MetadataFormModule } from '../../../metadata-form';
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<cc-thrift-viewer
|
<cc-thrift-viewer
|
||||||
|
[compared]="compared"
|
||||||
[extensions]="extensions$ | async"
|
[extensions]="extensions$ | async"
|
||||||
|
[kind]="kind"
|
||||||
[metadata]="metadata$ | async"
|
[metadata]="metadata$ | async"
|
||||||
[progress]="progress"
|
[progress]="progress"
|
||||||
[type]="type"
|
[type]="type"
|
||||||
|
@ -4,7 +4,7 @@ import { ThriftAstMetadata } from '@vality/domain-proto';
|
|||||||
import { getImportValue } from '@vality/ng-core';
|
import { getImportValue } from '@vality/ng-core';
|
||||||
import { ValueType } from '@vality/thrift-ts';
|
import { ValueType } from '@vality/thrift-ts';
|
||||||
|
|
||||||
import { ThriftViewerModule } from '../../../thrift-viewer';
|
import { ThriftViewerModule, ViewerKind } from '../../../thrift-viewer';
|
||||||
|
|
||||||
import { DomainMetadataViewExtensionsService } from './services/domain-metadata-view-extensions';
|
import { DomainMetadataViewExtensionsService } from './services/domain-metadata-view-extensions';
|
||||||
|
|
||||||
@ -15,7 +15,9 @@ import { DomainMetadataViewExtensionsService } from './services/domain-metadata-
|
|||||||
imports: [CommonModule, ThriftViewerModule],
|
imports: [CommonModule, ThriftViewerModule],
|
||||||
})
|
})
|
||||||
export class DomainThriftViewerComponent<T> {
|
export class DomainThriftViewerComponent<T> {
|
||||||
|
@Input() kind: ViewerKind = ViewerKind.Component;
|
||||||
@Input() value: T;
|
@Input() value: T;
|
||||||
|
@Input() compared?: T;
|
||||||
@Input() type: ValueType;
|
@Input() type: ValueType;
|
||||||
@Input({ transform: booleanAttribute }) progress: boolean = false;
|
@Input({ transform: booleanAttribute }) progress: boolean = false;
|
||||||
// @Input() extensions?: MetadataViewExtension[];
|
// @Input() extensions?: MetadataViewExtension[];
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
<ng-container [ngSwitch]="step">
|
||||||
|
<v-dialog
|
||||||
|
*ngSwitchCase="stepEnum.Edit"
|
||||||
|
[progress]="!!(progress$ | async)"
|
||||||
|
title="Edit domain object"
|
||||||
|
>
|
||||||
|
<cc-domain-thrift-form
|
||||||
|
[defaultValue]="(dialogData.domainObject | ccUnionValue)?.data"
|
||||||
|
[formControl]="control"
|
||||||
|
[type]="dataType$ | async"
|
||||||
|
></cc-domain-thrift-form>
|
||||||
|
<v-dialog-actions
|
||||||
|
><ng-container *ngTemplateOutlet="actions"></ng-container
|
||||||
|
></v-dialog-actions>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<v-dialog
|
||||||
|
*ngSwitchCase="stepEnum.Review"
|
||||||
|
[progress]="!!(progress$ | async)"
|
||||||
|
title="Review domain object"
|
||||||
|
>
|
||||||
|
<cc-domain-thrift-viewer
|
||||||
|
[compared]="newObject$ | async"
|
||||||
|
[type]="dataType$ | async"
|
||||||
|
[value]="currentObject ?? dialogData.domainObject"
|
||||||
|
kind="editor"
|
||||||
|
></cc-domain-thrift-viewer>
|
||||||
|
<v-dialog-actions
|
||||||
|
><ng-container *ngTemplateOutlet="actions"></ng-container
|
||||||
|
></v-dialog-actions>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<v-dialog
|
||||||
|
*ngSwitchCase="stepEnum.SourceReview"
|
||||||
|
[progress]="!!(progress$ | async)"
|
||||||
|
title="Changes from the server"
|
||||||
|
>
|
||||||
|
<cc-domain-thrift-viewer
|
||||||
|
*ngIf="currentObject"
|
||||||
|
[compared]="this.currentObject"
|
||||||
|
[type]="dataType$ | async"
|
||||||
|
[value]="dialogData.domainObject"
|
||||||
|
kind="editor"
|
||||||
|
></cc-domain-thrift-viewer>
|
||||||
|
<v-dialog-actions
|
||||||
|
><ng-container *ngTemplateOutlet="actions"></ng-container
|
||||||
|
></v-dialog-actions>
|
||||||
|
</v-dialog>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-template #actions>
|
||||||
|
<button
|
||||||
|
*ngIf="step !== stepEnum.Edit"
|
||||||
|
[disabled]="!!(progress$ | async)"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="step = stepEnum.Edit"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
*ngIf="!!currentObject && step !== stepEnum.SourceReview"
|
||||||
|
[disabled]="!!(progress$ | async)"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="step = stepEnum.SourceReview"
|
||||||
|
>
|
||||||
|
Review changes from the server
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
*ngIf="step !== stepEnum.Review"
|
||||||
|
[disabled]="!allowReview"
|
||||||
|
color="primary"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="step = stepEnum.Review"
|
||||||
|
>
|
||||||
|
Review
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
*ngIf="step === stepEnum.Review"
|
||||||
|
[disabled]="!!(progress$ | async)"
|
||||||
|
color="primary"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="update()"
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
</ng-template>
|
@ -0,0 +1,173 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Component, DestroyRef } from '@angular/core';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { ReactiveFormsModule, FormControl, Validators } from '@angular/forms';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { DomainObject } from '@vality/domain-proto/domain';
|
||||||
|
import {
|
||||||
|
DialogSuperclass,
|
||||||
|
DEFAULT_DIALOG_CONFIG,
|
||||||
|
DialogModule,
|
||||||
|
DEFAULT_DIALOG_CONFIG_FULL_HEIGHT,
|
||||||
|
DialogConfig,
|
||||||
|
NotifyLogService,
|
||||||
|
getValueChanges,
|
||||||
|
progressTo,
|
||||||
|
DialogService,
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
} from '@vality/ng-core';
|
||||||
|
import { BehaviorSubject, switchMap, EMPTY } from 'rxjs';
|
||||||
|
import { first, map, shareReplay, catchError } from 'rxjs/operators';
|
||||||
|
import { ValuesType } from 'utility-types';
|
||||||
|
|
||||||
|
import { getUnionKey, getUnionValue, isEqualThrift } from '../../../../../../utils';
|
||||||
|
import { DomainStoreService } from '../../../../../api/domain-config';
|
||||||
|
import { DomainNavigateService } from '../../../../../sections/domain/services/domain-navigate.service';
|
||||||
|
import { MetadataService } from '../../../../../sections/domain/services/metadata.service';
|
||||||
|
import { ThriftPipesModule } from '../../../../pipes';
|
||||||
|
import { DomainThriftFormComponent } from '../domain-thrift-form';
|
||||||
|
import { DomainThriftViewerComponent } from '../domain-thrift-viewer';
|
||||||
|
|
||||||
|
enum Step {
|
||||||
|
Edit,
|
||||||
|
Review,
|
||||||
|
SourceReview,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cc-edit-domain-object-dialog',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
DialogModule,
|
||||||
|
MatButtonModule,
|
||||||
|
DomainThriftFormComponent,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
DomainThriftViewerComponent,
|
||||||
|
ThriftPipesModule,
|
||||||
|
],
|
||||||
|
templateUrl: './edit-domain-object-dialog.component.html',
|
||||||
|
})
|
||||||
|
export class EditDomainObjectDialogComponent extends DialogSuperclass<
|
||||||
|
EditDomainObjectDialogComponent,
|
||||||
|
{ domainObject: DomainObject }
|
||||||
|
> {
|
||||||
|
static defaultDialogConfig: ValuesType<DialogConfig> = {
|
||||||
|
...DEFAULT_DIALOG_CONFIG.large,
|
||||||
|
minHeight: DEFAULT_DIALOG_CONFIG_FULL_HEIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
|
control = new FormControl<ValuesType<DomainObject>['data']>(
|
||||||
|
getUnionValue(this.dialogData.domainObject).data,
|
||||||
|
[Validators.required],
|
||||||
|
);
|
||||||
|
progress$ = new BehaviorSubject(0);
|
||||||
|
step: Step = Step.Edit;
|
||||||
|
stepEnum = Step;
|
||||||
|
currentObject?: DomainObject;
|
||||||
|
|
||||||
|
type$ = this.metadataService
|
||||||
|
.getDomainFieldByName(getUnionKey(this.dialogData.domainObject))
|
||||||
|
.pipe(
|
||||||
|
map((f) => String(f.type)),
|
||||||
|
first(),
|
||||||
|
);
|
||||||
|
|
||||||
|
dataType$ = this.metadataService
|
||||||
|
.getDomainObjectDataFieldByName(getUnionKey(this.dialogData.domainObject))
|
||||||
|
.pipe(
|
||||||
|
map((f) => String(f.type)),
|
||||||
|
first(),
|
||||||
|
);
|
||||||
|
|
||||||
|
newObject$ = getValueChanges(this.control).pipe(
|
||||||
|
map(() => this.getNewObject()),
|
||||||
|
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
get allowReview() {
|
||||||
|
return (
|
||||||
|
this.control.valid &&
|
||||||
|
!isEqualThrift(this.currentObject ?? this.dialogData.domainObject, this.getNewObject())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private domainStoreService: DomainStoreService,
|
||||||
|
private destroyRef: DestroyRef,
|
||||||
|
private log: NotifyLogService,
|
||||||
|
private domainNavigateService: DomainNavigateService,
|
||||||
|
private metadataService: MetadataService,
|
||||||
|
private dialogService: DialogService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
update(attempts = 1) {
|
||||||
|
this.domainStoreService
|
||||||
|
.getObject({
|
||||||
|
[getUnionKey(this.dialogData.domainObject)]: getUnionValue(
|
||||||
|
this.dialogData.domainObject,
|
||||||
|
).ref,
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
first(),
|
||||||
|
switchMap((currentObject) => {
|
||||||
|
if (!isEqualThrift(currentObject, this.dialogData.domainObject)) {
|
||||||
|
this.dialogService.open(ConfirmDialogComponent, {
|
||||||
|
title: 'The object has been modified',
|
||||||
|
description:
|
||||||
|
'The original object has been modified. View changes in the original object before committing your own.',
|
||||||
|
confirmLabel: 'View',
|
||||||
|
});
|
||||||
|
this.step = Step.SourceReview;
|
||||||
|
this.currentObject = currentObject;
|
||||||
|
return EMPTY;
|
||||||
|
} else if (this.currentObject) {
|
||||||
|
this.currentObject = undefined;
|
||||||
|
}
|
||||||
|
return this.domainStoreService.commit({
|
||||||
|
ops: [
|
||||||
|
{
|
||||||
|
update: {
|
||||||
|
old_object: currentObject,
|
||||||
|
new_object: this.getNewObject(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
if (err?.name === 'ObsoleteCommitVersion' && attempts !== 0) {
|
||||||
|
this.domainStoreService.forceReload();
|
||||||
|
this.update(attempts - 1);
|
||||||
|
this.log.error(err, `Domain config is out of date, one more attempt...`);
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}),
|
||||||
|
switchMap(() => this.type$),
|
||||||
|
progressTo(this.progress$),
|
||||||
|
takeUntilDestroyed(this.destroyRef),
|
||||||
|
)
|
||||||
|
.subscribe({
|
||||||
|
next: (type) => {
|
||||||
|
this.log.successOperation('update', 'domain object');
|
||||||
|
void this.domainNavigateService.toType(type);
|
||||||
|
this.closeWithSuccess();
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.log.errorOperation(err, 'update', 'domain object');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNewObject() {
|
||||||
|
return {
|
||||||
|
[getUnionKey(this.dialogData.domainObject)]: {
|
||||||
|
ref: getUnionValue(this.dialogData.domainObject).ref,
|
||||||
|
data: this.control.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export * from './edit-domain-object-dialog.component';
|
@ -2,5 +2,8 @@ export * from './domain-thrift-viewer';
|
|||||||
export * from './domain-object-field';
|
export * from './domain-object-field';
|
||||||
export * from './domain-thrift-form-dialog';
|
export * from './domain-thrift-form-dialog';
|
||||||
export * from './domain-object-card/domain-object-card.component';
|
export * from './domain-object-card/domain-object-card.component';
|
||||||
|
export * from './domain-thrift-form';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './services';
|
export * from './services';
|
||||||
|
export * from './create-domain-object-dialog';
|
||||||
|
export * from './edit-domain-object-dialog';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { DomainObject } from '@vality/domain-proto/domain';
|
||||||
import { DomainObject, Reference } from '@vality/domain-proto/domain';
|
|
||||||
import {
|
import {
|
||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
DialogResponseStatus,
|
DialogResponseStatus,
|
||||||
@ -16,18 +15,11 @@ import { DomainStoreService } from '../../../../../api/domain-config';
|
|||||||
})
|
})
|
||||||
export class DomainObjectService {
|
export class DomainObjectService {
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private domainStoreService: DomainStoreService,
|
private domainStoreService: DomainStoreService,
|
||||||
private log: NotifyLogService,
|
private log: NotifyLogService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
edit(ref: Reference) {
|
|
||||||
return this.router.navigate(['domain', 'edit'], {
|
|
||||||
queryParams: { ref: JSON.stringify(ref) },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(domainObject: DomainObject) {
|
delete(domainObject: DomainObject) {
|
||||||
return this.dialogService
|
return this.dialogService
|
||||||
.open(ConfirmDialogComponent, { title: 'Delete object' })
|
.open(ConfirmDialogComponent, { title: 'Delete object' })
|
||||||
|
@ -8,13 +8,14 @@ import { map, shareReplay } from 'rxjs/operators';
|
|||||||
import { MetadataFormExtension } from '../../../metadata-form';
|
import { MetadataFormExtension } from '../../../metadata-form';
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export abstract class BaseThriftFormSuperclass
|
export abstract class BaseThriftFormSuperclass<T = unknown>
|
||||||
extends FormControlSuperclass<unknown>
|
extends FormControlSuperclass<T>
|
||||||
implements OnChanges
|
implements OnChanges
|
||||||
{
|
{
|
||||||
@Input() type: ValueType;
|
@Input() type: ValueType;
|
||||||
@Input() namespace?: string;
|
@Input() namespace?: string;
|
||||||
@Input() extensions?: MetadataFormExtension[];
|
@Input() extensions?: MetadataFormExtension[];
|
||||||
|
@Input() defaultValue?: T;
|
||||||
|
|
||||||
protected abstract defaultNamespace: string;
|
protected abstract defaultNamespace: string;
|
||||||
protected abstract metadata$: Observable<ThriftAstMetadata[]>;
|
protected abstract metadata$: Observable<ThriftAstMetadata[]>;
|
||||||
|
@ -1,9 +1,29 @@
|
|||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button color="warn" mat-icon-button (click)="reset()">
|
<button
|
||||||
|
*ngIf="control.invalid"
|
||||||
|
[matTooltip]="control.errors | inlineJson: false"
|
||||||
|
color="warn"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="control.updateValueAndValidity()"
|
||||||
|
>
|
||||||
|
<mat-icon>priority_high</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
*ngIf="control.dirty"
|
||||||
|
color="warn"
|
||||||
|
mat-icon-button
|
||||||
|
matTooltip="Reset"
|
||||||
|
(click)="reset()"
|
||||||
|
>
|
||||||
<mat-icon>restart_alt</mat-icon>
|
<mat-icon>restart_alt</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button color="primary" mat-icon-button (click)="toggleKind()">
|
<button
|
||||||
|
color="primary"
|
||||||
|
mat-icon-button
|
||||||
|
matTooltip="Show {{ kind === 'form' ? 'form' : 'JSON' }} editor"
|
||||||
|
(click)="toggleKind()"
|
||||||
|
>
|
||||||
<mat-icon *ngIf="kind === 'form'">code</mat-icon>
|
<mat-icon *ngIf="kind === 'form'">code</mat-icon>
|
||||||
<mat-icon *ngIf="kind === 'editor'">edit_note</mat-icon>
|
<mat-icon *ngIf="kind === 'editor'">edit_note</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
import { ValidationErrors } from '@angular/forms';
|
import { ValidationErrors, AbstractControl } from '@angular/forms';
|
||||||
import { ThriftAstMetadata } from '@vality/domain-proto';
|
import { ThriftAstMetadata } from '@vality/domain-proto';
|
||||||
import { DialogService, DialogResponseStatus, ConfirmDialogComponent } from '@vality/ng-core';
|
import {
|
||||||
|
DialogService,
|
||||||
|
DialogResponseStatus,
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
createControlProviders,
|
||||||
|
FormControlSuperclass,
|
||||||
|
} from '@vality/ng-core';
|
||||||
import { merge, defer, of, Subject } from 'rxjs';
|
import { merge, defer, of, Subject } from 'rxjs';
|
||||||
import { map, filter, shareReplay } from 'rxjs/operators';
|
import { map, filter, shareReplay } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ValidatedFormControlSuperclass, createControlProviders } from '@cc/utils';
|
|
||||||
import { objectToJSON } from '@cc/utils/thrift-instance';
|
import { objectToJSON } from '@cc/utils/thrift-instance';
|
||||||
|
|
||||||
import { MetadataFormExtension } from '../metadata-form';
|
import { MetadataFormExtension } from '../metadata-form';
|
||||||
@ -21,7 +26,7 @@ export enum EditorKind {
|
|||||||
styleUrls: ['./thrift-editor.component.scss'],
|
styleUrls: ['./thrift-editor.component.scss'],
|
||||||
providers: createControlProviders(() => ThriftEditorComponent),
|
providers: createControlProviders(() => ThriftEditorComponent),
|
||||||
})
|
})
|
||||||
export class ThriftEditorComponent<T> extends ValidatedFormControlSuperclass<T> {
|
export class ThriftEditorComponent<T> extends FormControlSuperclass<T> {
|
||||||
@Input() kind: EditorKind = EditorKind.Form;
|
@Input() kind: EditorKind = EditorKind.Form;
|
||||||
|
|
||||||
@Input() defaultValue?: T;
|
@Input() defaultValue?: T;
|
||||||
@ -49,11 +54,11 @@ export class ThriftEditorComponent<T> extends ValidatedFormControlSuperclass<T>
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
validate(control: AbstractControl): ValidationErrors | null {
|
||||||
if (this.kind === EditorKind.Editor) {
|
if (this.kind === EditorKind.Editor) {
|
||||||
return this.editorError ? { jsonParse: this.editorError } : null;
|
return this.editorError ? { jsonParse: this.editorError } : null;
|
||||||
}
|
}
|
||||||
return super.validate();
|
return super.validate(control);
|
||||||
}
|
}
|
||||||
|
|
||||||
contentChange(str: string) {
|
contentChange(str: string) {
|
||||||
|
@ -4,6 +4,8 @@ import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
import { PipesModule } from '@vality/ng-core';
|
||||||
import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
|
import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
|
||||||
|
|
||||||
import { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
import { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
||||||
@ -22,6 +24,8 @@ import { ThriftEditorComponent } from './thrift-editor.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
PipesModule,
|
||||||
|
MatTooltipModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ThriftEditorModule {}
|
export class ThriftEditorModule {}
|
||||||
|
@ -12,15 +12,13 @@ import {
|
|||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { Validator, ValidationErrors, FormControl } from '@angular/forms';
|
import { Validator, ValidationErrors, FormControl } from '@angular/forms';
|
||||||
import { createMask } from '@ngneat/input-mask';
|
import { createMask } from '@ngneat/input-mask';
|
||||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
import { FormComponentSuperclass, createControlProviders, getValueChanges } from '@vality/ng-core';
|
||||||
import sortBy from 'lodash-es/sortBy';
|
import sortBy from 'lodash-es/sortBy';
|
||||||
import { combineLatest } from 'rxjs';
|
import { combineLatest } from 'rxjs';
|
||||||
import { map, switchMap, first, distinctUntilChanged } from 'rxjs/operators';
|
import { map, switchMap, first, distinctUntilChanged } from 'rxjs/operators';
|
||||||
|
|
||||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||||
|
|
||||||
import { createControlProviders, getFormValueChanges } from '../../utils';
|
|
||||||
|
|
||||||
export interface Cash {
|
export interface Cash {
|
||||||
amount: number;
|
amount: number;
|
||||||
currencyCode: string;
|
currencyCode: string;
|
||||||
@ -42,7 +40,7 @@ export class CashFieldComponent extends FormComponentSuperclass<Cash> implements
|
|||||||
currencyCodeControl = new FormControl<string>(null);
|
currencyCodeControl = new FormControl<string>(null);
|
||||||
|
|
||||||
currencies$ = combineLatest([
|
currencies$ = combineLatest([
|
||||||
getFormValueChanges(this.currencyCodeControl, true),
|
getValueChanges(this.currencyCodeControl),
|
||||||
this.domainStoreService.getObjects('currency'),
|
this.domainStoreService.getObjects('currency'),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
map(([code, currencies]) =>
|
map(([code, currencies]) =>
|
||||||
@ -53,7 +51,7 @@ export class CashFieldComponent extends FormComponentSuperclass<Cash> implements
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
amountMask$ = getFormValueChanges(this.currencyCodeControl, true).pipe(
|
amountMask$ = getValueChanges(this.currencyCodeControl).pipe(
|
||||||
switchMap((code) => this.getCurrencyByCode(code)),
|
switchMap((code) => this.getCurrencyByCode(code)),
|
||||||
map((c) => (this.minor ? 0 : c?.data?.exponent || 2)),
|
map((c) => (this.minor ? 0 : c?.data?.exponent || 2)),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
@ -84,8 +82,8 @@ export class CashFieldComponent extends FormComponentSuperclass<Cash> implements
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
combineLatest([
|
combineLatest([
|
||||||
getFormValueChanges(this.currencyCodeControl, true),
|
getValueChanges(this.currencyCodeControl),
|
||||||
getFormValueChanges(this.amountControl, true),
|
getValueChanges(this.amountControl),
|
||||||
])
|
])
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap(([currencyCode]) => this.getCurrencyByCode(currencyCode)),
|
switchMap(([currencyCode]) => this.getCurrencyByCode(currencyCode)),
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
import { AbstractControl, FormControlState } from '@angular/forms';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { startWith, map } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { getValue } from './get-value';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
export function getFormValueChanges<T>(
|
|
||||||
form: AbstractControl<FormControlState<T> | T>,
|
|
||||||
hasStart = false,
|
|
||||||
): Observable<T> {
|
|
||||||
return form.valueChanges.pipe(
|
|
||||||
...((hasStart ? [startWith(form.value)] : []) as []),
|
|
||||||
map(() => getValue(form)),
|
|
||||||
) as Observable<T>;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import { AbstractControl } from '@angular/forms';
|
|
||||||
|
|
||||||
import { hasControls } from './has-controls';
|
|
||||||
|
|
||||||
export function getValue<T extends AbstractControl>(control: T): T['value'] {
|
|
||||||
if (!hasControls(control)) {
|
|
||||||
return control.value as never;
|
|
||||||
}
|
|
||||||
if (Array.isArray(control.controls)) {
|
|
||||||
const result: T[] = [];
|
|
||||||
for (const v of control.controls) {
|
|
||||||
result.push(getValue(v) as T);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const result: Partial<T> = {};
|
|
||||||
for (const [k, v] of Object.entries(control.controls)) {
|
|
||||||
result[k] = getValue(v) as T;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
|
|
||||||
|
|
||||||
export function hasControls(control: AbstractControl): control is FormGroup | FormArray {
|
|
||||||
return 'controls' in control;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './get-form-value-changes';
|
|
||||||
export * from './validated-control-superclass';
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Provider, Type } from '@angular/core';
|
|
||||||
|
|
||||||
import { provideValidators } from './provide-validators';
|
|
||||||
import { provideValueAccessor } from './provide-value-accessor';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* @param component
|
|
||||||
*/
|
|
||||||
export const createControlProviders = (component: () => Type<unknown>): Provider[] => [
|
|
||||||
provideValueAccessor(component),
|
|
||||||
provideValidators(component),
|
|
||||||
];
|
|
@ -1,6 +0,0 @@
|
|||||||
export * from './validated-control-superclass.directive';
|
|
||||||
export * from './provide-validators';
|
|
||||||
export * from './provide-value-accessor';
|
|
||||||
export * from './create-control-providers';
|
|
||||||
export * from './utils/get-errors-tree';
|
|
||||||
export * from './validated-form-control-superclass.directive';
|
|
@ -1,12 +0,0 @@
|
|||||||
import { Provider, forwardRef, Type } from '@angular/core';
|
|
||||||
import { NG_VALIDATORS } from '@angular/forms';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* @param component
|
|
||||||
*/
|
|
||||||
export const provideValidators = (component: () => Type<unknown>): Provider => ({
|
|
||||||
provide: NG_VALIDATORS,
|
|
||||||
useExisting: forwardRef(component),
|
|
||||||
multi: true,
|
|
||||||
});
|
|
@ -1,12 +0,0 @@
|
|||||||
import { Provider, forwardRef, Type } from '@angular/core';
|
|
||||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* @param component
|
|
||||||
*/
|
|
||||||
export const provideValueAccessor = (component: () => Type<unknown>): Provider => ({
|
|
||||||
provide: NG_VALUE_ACCESSOR,
|
|
||||||
useExisting: forwardRef(component),
|
|
||||||
multi: true,
|
|
||||||
});
|
|
@ -1,29 +0,0 @@
|
|||||||
import { AbstractControl, ValidationErrors } from '@angular/forms';
|
|
||||||
|
|
||||||
import { hasControls } from '../../has-controls';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* 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: AbstractControl) => getErrorsTree(c))
|
|
||||||
.filter(Boolean);
|
|
||||||
} else {
|
|
||||||
errors['formGroupErrors'] = Object.fromEntries(
|
|
||||||
Array.from(Object.entries(control.controls))
|
|
||||||
.map(([k, c]) => [k, getErrorsTree(c)])
|
|
||||||
.filter(([, v]) => !!v),
|
|
||||||
) as ValidationErrors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors;
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
import { Directive, OnInit } from '@angular/core';
|
|
||||||
import { FormGroup, ValidationErrors, Validator } from '@angular/forms';
|
|
||||||
import { WrappedControlSuperclass } from '@s-libs/ng-core';
|
|
||||||
import { EMPTY, Observable } from 'rxjs';
|
|
||||||
|
|
||||||
import { getValue } from '../get-value';
|
|
||||||
|
|
||||||
import { getErrorsTree } from './utils/get-errors-tree';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Directive()
|
|
||||||
export abstract class ValidatedControlSuperclass<OuterType, InnerType = OuterType>
|
|
||||||
extends WrappedControlSuperclass<OuterType, InnerType>
|
|
||||||
implements OnInit, Validator
|
|
||||||
{
|
|
||||||
protected emptyValue: InnerType;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.emptyValue = getValue(this.control);
|
|
||||||
super.ngOnInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
|
||||||
return getErrorsTree(this.control);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setUpOuterToInnerErrors$(
|
|
||||||
_outer$: Observable<ValidationErrors>,
|
|
||||||
): Observable<ValidationErrors> {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setUpInnerToOuterErrors$(
|
|
||||||
_inner$: Observable<ValidationErrors>,
|
|
||||||
): Observable<ValidationErrors> {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected outerToInnerValue(outer: OuterType): InnerType {
|
|
||||||
if ('controls' in this.control) {
|
|
||||||
if (!outer) {
|
|
||||||
return this.emptyValue;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
Object.keys(outer).length < Object.keys((this.control as FormGroup).controls).length
|
|
||||||
) {
|
|
||||||
return Object.assign({}, this.emptyValue, outer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return outer as never;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
import { Directive } from '@angular/core';
|
|
||||||
import { ValidationErrors, FormControl } from '@angular/forms';
|
|
||||||
import { WrappedControlSuperclass } from '@s-libs/ng-core';
|
|
||||||
import { EMPTY, Observable } from 'rxjs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Directive()
|
|
||||||
export class ValidatedFormControlSuperclass<
|
|
||||||
OuterType,
|
|
||||||
InnerType = OuterType,
|
|
||||||
> extends WrappedControlSuperclass<OuterType, InnerType> {
|
|
||||||
// TODO: Validation sometimes doesn't work (is not forwarded higher by nesting) with Angular FormControl
|
|
||||||
control = new FormControl() as FormControl<InnerType>;
|
|
||||||
|
|
||||||
validate(): ValidationErrors | null {
|
|
||||||
return this.control.errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setUpOuterToInnerErrors$(
|
|
||||||
_outer$: Observable<ValidationErrors>,
|
|
||||||
): Observable<ValidationErrors> {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setUpInnerToOuterErrors$(
|
|
||||||
_inner$: Observable<ValidationErrors>,
|
|
||||||
): Observable<ValidationErrors> {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,6 @@ export * from './to-major';
|
|||||||
export * from './thrift-utils';
|
export * from './thrift-utils';
|
||||||
export * from './has-active-fragments';
|
export * from './has-active-fragments';
|
||||||
export * from './poll';
|
export * from './poll';
|
||||||
export * from './forms';
|
|
||||||
export * from './operators';
|
export * from './operators';
|
||||||
export * from './get-enum-keys';
|
export * from './get-enum-keys';
|
||||||
export * from './enumerate';
|
export * from './enumerate';
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from './create-union';
|
export * from './create-union';
|
||||||
|
export * from './is-equal-thrift';
|
||||||
|
5
src/utils/thrift/is-equal-thrift.ts
Normal file
5
src/utils/thrift/is-equal-thrift.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { toJson } from '../thrift-json-converter';
|
||||||
|
|
||||||
|
export function isEqualThrift(a: unknown, b: unknown) {
|
||||||
|
return JSON.stringify(toJson(a)) === JSON.stringify(toJson(b));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user