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/router": "17.0.8",
|
||||
"@ngneat/input-mask": "6.0.0",
|
||||
"@s-libs/ng-core": "17.0.0",
|
||||
"@vality/deanonimus-proto": "2.0.1-2a02d87.0",
|
||||
"@vality/domain-proto": "2.0.1-23211ff.0",
|
||||
"@vality/fistful-proto": "2.0.1-3b9a0a7.0",
|
||||
"@vality/machinegun-proto": "1.0.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/repairer-proto": "2.0.2-07b73e9.0",
|
||||
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
||||
@ -6523,9 +6522,9 @@
|
||||
"integrity": "sha512-kAiKSTvof+jFuNkQKyAsc2s+Br2NXPWAyKuD0f7mQIk9HrP8uHsKJya5KxdOdng97JYe0MSUlx7seQxWmCgYfA=="
|
||||
},
|
||||
"node_modules/@vality/ng-core": {
|
||||
"version": "17.1.1-pr-57-1a4e713.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.1.1-pr-57-1a4e713.0.tgz",
|
||||
"integrity": "sha512-Jar5VUIp5OISoCc0rhmcsk9EkVjzItlT2N/sMCFIKIKD51XDxn6NvYXOOwOiNAyu1LAd71mGPT8GvdWazR12cA==",
|
||||
"version": "17.1.1-pr-57-8ca06c2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.1.1-pr-57-8ca06c2.0.tgz",
|
||||
"integrity": "sha512-io0j/knhIGgqmi8HxfuTZMGycVSO8qE9EYq5KN7lP7ectNeDrpvZdKcsJUg2kfTtWWaG9p8DSR5CHbe36tDxYA==",
|
||||
"dependencies": {
|
||||
"@angular/material-date-fns-adapter": "^17.0.0",
|
||||
"@ng-matero/extensions": "^17.0.0",
|
||||
|
@ -28,13 +28,12 @@
|
||||
"@angular/platform-server": "17.0.8",
|
||||
"@angular/router": "17.0.8",
|
||||
"@ngneat/input-mask": "6.0.0",
|
||||
"@s-libs/ng-core": "17.0.0",
|
||||
"@vality/deanonimus-proto": "2.0.1-2a02d87.0",
|
||||
"@vality/domain-proto": "2.0.1-23211ff.0",
|
||||
"@vality/fistful-proto": "2.0.1-3b9a0a7.0",
|
||||
"@vality/machinegun-proto": "1.0.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/repairer-proto": "2.0.2-07b73e9.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 { NotifyLogService } from '@vality/ng-core';
|
||||
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 { inProgressFrom, progressTo, getUnionKey } from '../../../../utils';
|
||||
import { DomainSecretService } from '../../../shared/services';
|
||||
import { handleError } from '../../../shared/services/notification-error';
|
||||
import { RepositoryService } from '../index';
|
||||
import { RepositoryService } from '../repository.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
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(
|
||||
() => this.progress$,
|
||||
defer(() => this.snapshot$),
|
||||
|
@ -2,12 +2,11 @@ import { Component, Input, OnChanges } from '@angular/core';
|
||||
import { Validator } from '@angular/forms';
|
||||
import { Claim } from '@vality/domain-proto/claim_management';
|
||||
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 { map } from 'rxjs/operators';
|
||||
|
||||
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';
|
||||
|
||||
@ -17,7 +16,7 @@ import { createPartyClaimMetadataFormExtensions } from './utils/create-party-cla
|
||||
providers: createControlProviders(() => ModificationFormComponent),
|
||||
})
|
||||
export class ModificationFormComponent
|
||||
extends ValidatedFormControlSuperclass<unknown>
|
||||
extends FormControlSuperclass<unknown>
|
||||
implements Validator, OnChanges
|
||||
{
|
||||
@Input() party: Party;
|
||||
|
@ -3,14 +3,11 @@
|
||||
title="Domain config"
|
||||
>
|
||||
<cc-page-layout-actions>
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
routerLink="/domain/create"
|
||||
style="white-space: nowrap"
|
||||
>
|
||||
Create object
|
||||
<button color="primary" mat-raised-button style="white-space: nowrap" (click)="create()">
|
||||
Create
|
||||
</button>
|
||||
</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>
|
||||
|
@ -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 { CreateDomainObjectDialogComponent } from '../../../shared/components/thrift-api-crud';
|
||||
|
||||
@Component({
|
||||
templateUrl: './domain-info.component.html',
|
||||
styleUrls: ['./domain-info.component.scss'],
|
||||
@ -9,6 +15,26 @@ import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||
export class DomainInfoComponent {
|
||||
version$ = this.domainStoreService.version$;
|
||||
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 { 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 { MatButtonModule } from '@angular/material/button';
|
||||
import { Sort } from '@angular/material/sort';
|
||||
@ -11,6 +12,8 @@ import {
|
||||
SelectFieldModule,
|
||||
TableModule,
|
||||
ActionsModule,
|
||||
DialogService,
|
||||
getValueChanges,
|
||||
} from '@vality/ng-core';
|
||||
import sortBy from 'lodash-es/sortBy';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
@ -25,6 +28,7 @@ import {
|
||||
DomainThriftViewerComponent,
|
||||
DomainObjectCardComponent,
|
||||
DomainObjectService,
|
||||
EditDomainObjectDialogComponent,
|
||||
} from '../../../../shared/components/thrift-api-crud';
|
||||
import { MetadataService } from '../../services/metadata.service';
|
||||
|
||||
@ -49,6 +53,8 @@ interface DomainObjectData {
|
||||
],
|
||||
})
|
||||
export class DomainObjectsTableComponent implements OnInit {
|
||||
@Output() selectedChange = new EventEmitter<string[]>();
|
||||
|
||||
typesControl = new FormControl<string[]>(
|
||||
(this.qp.params.types as (keyof DomainObject)[]) || [],
|
||||
);
|
||||
@ -105,7 +111,11 @@ export class DomainObjectsTableComponent implements OnInit {
|
||||
{
|
||||
label: 'Edit',
|
||||
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 sidenavInfoService: SidenavInfoService,
|
||||
private domainObjectService: DomainObjectService,
|
||||
private destroyRef: DestroyRef,
|
||||
private dialogService: DialogService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.typesControl.valueChanges.subscribe((types) => {
|
||||
void this.qp.patch({ types });
|
||||
});
|
||||
this.typesControl.valueChanges
|
||||
.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() {
|
||||
|
@ -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 { 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';
|
||||
|
||||
@NgModule({
|
||||
@ -21,18 +18,6 @@ import { ROUTING_CONFIG } from './routing-config';
|
||||
path: '',
|
||||
component: DomainInfoComponent,
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: DomainObjCreationComponent,
|
||||
},
|
||||
{
|
||||
path: 'edit',
|
||||
component: DomainObjModificationComponent,
|
||||
},
|
||||
{
|
||||
path: 'review',
|
||||
component: DomainObjReviewComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
|
@ -1,19 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { DomainInfoModule } from './domain-info';
|
||||
import { DomainObjModificationModule } from './domain-obj-modification';
|
||||
import { DomainObjReviewModule } from './domain-obj-review';
|
||||
import { DomainRoutingModule } from './domain-routing.module';
|
||||
import { MetadataService } from './services/metadata.service';
|
||||
import { ModifiedDomainObjectService } from './services/modified-domain-object.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DomainRoutingModule,
|
||||
DomainInfoModule,
|
||||
DomainObjModificationModule,
|
||||
DomainObjReviewModule,
|
||||
],
|
||||
providers: [MetadataService, ModifiedDomainObjectService],
|
||||
imports: [DomainRoutingModule, DomainInfoModule],
|
||||
providers: [ModifiedDomainObjectService],
|
||||
})
|
||||
export class DomainModule {}
|
||||
|
@ -1,19 +1,16 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ThriftAstMetadata } from '@vality/domain-proto';
|
||||
import { Reference } from '@vality/domain-proto/domain';
|
||||
import { getImportValue } from '@vality/ng-core';
|
||||
import { Field } from '@vality/thrift-ts';
|
||||
import { from, Observable, of } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map, shareReplay, withLatestFrom } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class MetadataService {
|
||||
private metadata$: Observable<ThriftAstMetadata[]> = from(
|
||||
import('@vality/domain-proto/metadata.json').then((m) => m.default),
|
||||
).pipe(shareReplay(1)) as Observable<ThriftAstMetadata[]>;
|
||||
|
||||
get metadata() {
|
||||
return this.metadata$;
|
||||
}
|
||||
private metadata$ = getImportValue<ThriftAstMetadata[]>(
|
||||
import('@vality/domain-proto/metadata.json'),
|
||||
).pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||
|
||||
getDomainObjectType(ref: Reference): Observable<string | null> {
|
||||
if (!ref) {
|
||||
@ -32,12 +29,31 @@ export class MetadataService {
|
||||
);
|
||||
}
|
||||
|
||||
getDomainFieldByFieldName(fieldName: string): Observable<Field> {
|
||||
getDomainFieldByName(fieldName: string): Observable<Field> {
|
||||
return this.getDomainFields().pipe(
|
||||
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[]> {
|
||||
return this.metadata$.pipe(
|
||||
map((m) => m.find(({ name }) => name === 'domain').ast.union.DomainObject),
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, OnInit, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Validators, FormControl } from '@angular/forms';
|
||||
import { DialogResponseStatus, DialogSuperclass } from '@vality/ng-core';
|
||||
import { DialogResponseStatus, DialogSuperclass, getValue } from '@vality/ng-core';
|
||||
import {
|
||||
RepairInvoicesRequest,
|
||||
RepairWithdrawalsRequest,
|
||||
@ -9,11 +9,12 @@ import {
|
||||
} from '@vality/repairer-proto/repairer';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import { BehaviorSubject, from } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||
|
||||
import { progressTo, getFormValueChanges } from '../../../../../utils';
|
||||
import { progressTo } from '../../../../../utils';
|
||||
import { RepairManagementService } from '../../../../api/repairer';
|
||||
import { NotificationService } from '../../../../shared/services/notification';
|
||||
|
||||
@ -66,8 +67,11 @@ export class RepairByScenarioDialogComponent
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
getFormValueChanges(this.nsControl)
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
this.nsControl.valueChanges
|
||||
.pipe(
|
||||
map(() => getValue(this.nsControl)),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.form.setValue(
|
||||
this.dialogData.machines.map(({ id }) => ({ id, scenario: {} })),
|
||||
|
@ -1,5 +1,7 @@
|
||||
<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
|
||||
[(sort)]="sort"
|
||||
[columns]="columns"
|
||||
@ -9,9 +11,5 @@
|
||||
sortOnFront
|
||||
standaloneFilter
|
||||
(update)="update()"
|
||||
>
|
||||
<v-table-actions>
|
||||
<button color="primary" mat-raised-button (click)="create()">Create</button>
|
||||
</v-table-actions>
|
||||
</v-table>
|
||||
></v-table>
|
||||
</cc-page-layout>
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Sort } from '@angular/material/sort';
|
||||
import { Router } from '@angular/router';
|
||||
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 { map, take } from 'rxjs/operators';
|
||||
|
||||
@ -11,7 +10,10 @@ import { DomainStoreService } from '../../api/domain-config';
|
||||
import { createPredicateColumn } from '../../shared';
|
||||
import { SidenavInfoService } from '../../shared/components/sidenav-info';
|
||||
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';
|
||||
|
||||
@ -71,9 +73,9 @@ export class TerminalsComponent {
|
||||
|
||||
constructor(
|
||||
private domainStoreService: DomainStoreService,
|
||||
private router: Router,
|
||||
private sidenavInfoService: SidenavInfoService,
|
||||
private destroyRef: DestroyRef,
|
||||
private dialogService: DialogService,
|
||||
) {}
|
||||
|
||||
update() {
|
||||
@ -81,7 +83,9 @@ export class TerminalsComponent {
|
||||
}
|
||||
|
||||
create() {
|
||||
void this.router.navigate(['/domain/create']);
|
||||
this.dialogService.open(CreateDomainObjectDialogComponent, {
|
||||
objectType: 'TerminalObject',
|
||||
});
|
||||
}
|
||||
|
||||
private getProvider(terminalObj: TerminalObject) {
|
||||
|
@ -7,12 +7,11 @@ import {
|
||||
FormControl,
|
||||
AbstractControl,
|
||||
} 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 { merge } from 'rxjs';
|
||||
|
||||
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form';
|
||||
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
||||
|
||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||
|
||||
@ -65,20 +64,22 @@ export class ComplexFormComponent<V, K = never>
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => {
|
||||
const values = this.valueControls.value;
|
||||
if (!this.data.isRequired && !values.length) {
|
||||
this.emitOutgoingValue(null);
|
||||
return;
|
||||
}
|
||||
switch (this.data.type.name) {
|
||||
case 'list':
|
||||
this.emitOutgoingValue(values.length ? values : null);
|
||||
break;
|
||||
this.emitOutgoingValue(values);
|
||||
return;
|
||||
case 'map': {
|
||||
const keys = this.keyControls.value;
|
||||
this.emitOutgoingValue(
|
||||
keys.length ? new Map(values.map((v, idx) => [keys[idx], v])) : null,
|
||||
);
|
||||
break;
|
||||
this.emitOutgoingValue(new Map(values.map((v, idx) => [keys[idx], v])));
|
||||
return;
|
||||
}
|
||||
case 'set':
|
||||
this.emitOutgoingValue(values.length ? new Set(values) : null);
|
||||
break;
|
||||
this.emitOutgoingValue(new Set(values));
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||
import { createControlProviders, FormControlSuperclass } from '@vality/ng-core';
|
||||
|
||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||
|
||||
@ -9,6 +8,6 @@ import { MetadataFormData } from '../../types/metadata-form-data';
|
||||
templateUrl: './enum-field.component.html',
|
||||
providers: createControlProviders(() => EnumFieldComponent),
|
||||
})
|
||||
export class EnumFieldComponent<T> extends ValidatedFormControlSuperclass<T> {
|
||||
export class EnumFieldComponent<T> extends FormControlSuperclass<T> {
|
||||
@Input() data: MetadataFormData<string, 'enum'>;
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { Component, Input, OnChanges, OnInit, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Validator, ValidationErrors, FormControl, Validators } from '@angular/forms';
|
||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
||||
import { ComponentChanges, createControlProviders } from '@vality/ng-core';
|
||||
import { FormComponentSuperclass, ComponentChanges, createControlProviders } from '@vality/ng-core';
|
||||
import { ThriftType } from '@vality/thrift-ts';
|
||||
import { defer, switchMap, ReplaySubject, Observable, combineLatest } from 'rxjs';
|
||||
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 { 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 omitBy from 'lodash-es/omitBy';
|
||||
import { merge } from 'rxjs';
|
||||
import { delay } from 'rxjs/operators';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map, distinctUntilChanged } from 'rxjs/operators';
|
||||
|
||||
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils';
|
||||
|
||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||
import { MetadataFormData, isRequiredField } from '../../types/metadata-form-data';
|
||||
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||
|
||||
@Component({
|
||||
@ -17,7 +27,7 @@ import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||
providers: createControlProviders(() => StructFormComponent),
|
||||
})
|
||||
export class StructFormComponent<T extends { [N in string]: unknown }>
|
||||
extends ValidatedControlSuperclass<T>
|
||||
extends FormComponentSuperclass<T>
|
||||
implements OnChanges, OnInit
|
||||
{
|
||||
@Input() data: MetadataFormData<string, 'struct'>;
|
||||
@ -42,39 +52,38 @@ export class StructFormComponent<T extends { [N in string]: unknown }>
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
merge(this.control.valueChanges, this.labelControl.valueChanges)
|
||||
.pipe(delay(0), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => {
|
||||
this.emitOutgoingValue(
|
||||
this.control.value && this.labelControl.value
|
||||
? (omitBy(this.control.value, isNil) as T)
|
||||
: null,
|
||||
);
|
||||
combineLatest([getValueChanges(this.control), getValueChanges(this.labelControl)])
|
||||
.pipe(
|
||||
map(([value, labelValue]) =>
|
||||
value && labelValue ? (omitBy(value, isNil) as T) : null,
|
||||
),
|
||||
distinctUntilChanged(),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe((value) => {
|
||||
this.emitOutgoingValue(value);
|
||||
});
|
||||
return super.ngOnInit();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
const newControlsNames = new Set(this.data.ast.map(({ name }) => name));
|
||||
Object.keys(this.control.controls).forEach((name) => {
|
||||
if (newControlsNames.has(name)) {
|
||||
newControlsNames.delete(name);
|
||||
} else {
|
||||
ngOnChanges(changes: ComponentChanges<StructFormComponent<T>>) {
|
||||
if (changes.data) {
|
||||
const newControlsNames = new Set(this.data.ast.map(({ name }) => name));
|
||||
Object.keys(this.control.controls).forEach((name) => {
|
||||
this.control.removeControl(name as never);
|
||||
}
|
||||
});
|
||||
newControlsNames.forEach((name) =>
|
||||
this.control.addControl(
|
||||
name as never,
|
||||
this.fb.control(null, {
|
||||
validators:
|
||||
this.data.ast.find((f) => f.name === name)?.option === 'required'
|
||||
});
|
||||
newControlsNames.forEach((name) =>
|
||||
this.control.addControl(
|
||||
name as never,
|
||||
this.fb.control(null, {
|
||||
validators: isRequiredField(this.data.ast.find((f) => f.name === name))
|
||||
? [Validators.required]
|
||||
: [],
|
||||
}) as never,
|
||||
),
|
||||
);
|
||||
this.setLabelControl();
|
||||
}) as never,
|
||||
),
|
||||
);
|
||||
this.setLabelControl();
|
||||
}
|
||||
super.ngOnChanges(changes);
|
||||
}
|
||||
|
||||
@ -83,8 +92,8 @@ export class StructFormComponent<T extends { [N in string]: unknown }>
|
||||
this.setLabelControl(!!(value && Object.keys(value).length));
|
||||
}
|
||||
|
||||
validate(): ValidationErrors | null {
|
||||
return this.labelControl.value ? super.validate() : null;
|
||||
validate(control: AbstractControl): ValidationErrors | null {
|
||||
return this.labelControl.value ? super.validate(control) : null;
|
||||
}
|
||||
|
||||
private setLabelControl(value: boolean = false) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||
import { createControlProviders, FormControlSuperclass } from '@vality/ng-core';
|
||||
|
||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||
@ -10,7 +9,7 @@ import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||
templateUrl: './typedef-form.component.html',
|
||||
providers: createControlProviders(() => TypedefFormComponent),
|
||||
})
|
||||
export class TypedefFormComponent<T> extends ValidatedFormControlSuperclass<T> {
|
||||
export class TypedefFormComponent<T> extends FormControlSuperclass<T> {
|
||||
@Input() data: MetadataFormData<string, 'typedef'>;
|
||||
@Input() extensions: MetadataFormExtension[];
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
[required]="data.isRequired"
|
||||
(ngModelChange)="cleanInternal()"
|
||||
>
|
||||
<mat-option *ngFor="let field of data.ast" [value]="field">{{
|
||||
field.type | fieldLabel: field
|
||||
<mat-option *ngFor="let option of options$ | async" [value]="option.value">{{
|
||||
option.label
|
||||
}}</mat-option>
|
||||
</mat-select>
|
||||
<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 { 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 { merge } from 'rxjs';
|
||||
import { delay, distinctUntilChanged, map } from 'rxjs/operators';
|
||||
|
||||
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
||||
import { merge, ReplaySubject, defer } from 'rxjs';
|
||||
import { delay, distinctUntilChanged, map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { MetadataFormData } from '../../types/metadata-form-data';
|
||||
import { MetadataFormExtension } from '../../types/metadata-form-extension';
|
||||
import { getDefaultValue } from '../../utils/get-default-value';
|
||||
import { getFieldLabel, getDefaultValue } from '../../utils';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-union-field',
|
||||
@ -19,7 +22,7 @@ import { getDefaultValue } from '../../utils/get-default-value';
|
||||
})
|
||||
export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
||||
extends FormComponentSuperclass<T>
|
||||
implements OnInit, Validator
|
||||
implements OnInit, Validator, OnChanges
|
||||
{
|
||||
@Input() data: MetadataFormData<string, 'union'>;
|
||||
@Input() extensions: MetadataFormExtension[];
|
||||
@ -27,6 +30,17 @@ export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
||||
fieldControl = new FormControl() as FormControl<Field>;
|
||||
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) {
|
||||
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 {
|
||||
return this.fieldControl.errors || getErrorsTree(this.internalControl);
|
||||
}
|
||||
@ -70,13 +91,11 @@ export class UnionFieldComponent<T extends { [N in string]: unknown }>
|
||||
|
||||
cleanInternal(emitEvent = false) {
|
||||
this.internalControl.reset(
|
||||
this.fieldControl.value
|
||||
? (getDefaultValue(
|
||||
this.data.metadata,
|
||||
this.data.namespace,
|
||||
this.fieldControl.value.type,
|
||||
) as T[keyof T])
|
||||
: null,
|
||||
getDefaultValue(
|
||||
this.data.metadata,
|
||||
this.data.namespace,
|
||||
this.fieldControl.value?.type,
|
||||
) as T[keyof T],
|
||||
{ emitEvent },
|
||||
);
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Component, Input, OnChanges } from '@angular/core';
|
||||
import { Validator } from '@angular/forms';
|
||||
import { ThriftAstMetadata } from '@vality/domain-proto';
|
||||
import { createControlProviders, FormControlSuperclass } from '@vality/ng-core';
|
||||
import { Field, ValueType } from '@vality/thrift-ts';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
|
||||
|
||||
import { MetadataFormData } from './types/metadata-form-data';
|
||||
import {
|
||||
MetadataFormExtension,
|
||||
@ -19,7 +18,7 @@ import {
|
||||
providers: createControlProviders(() => MetadataFormComponent),
|
||||
})
|
||||
export class MetadataFormComponent<T>
|
||||
extends ValidatedFormControlSuperclass<T>
|
||||
extends FormControlSuperclass<T>
|
||||
implements OnChanges, Validator
|
||||
{
|
||||
@Input() metadata: ThriftAstMetadata[];
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { ValueType, Field } from '@vality/thrift-ts';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
|
||||
import { getValueTypeTitle } from '@cc/app/shared';
|
||||
import { getFieldLabel } from '../utils';
|
||||
|
||||
@Pipe({
|
||||
name: 'fieldLabel',
|
||||
})
|
||||
export class FieldLabelPipe implements PipeTransform {
|
||||
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));
|
||||
}
|
||||
|
||||
export function isRequiredField(field: Field): boolean {
|
||||
return field?.option === 'required'; // optional even if not explicitly stated
|
||||
}
|
||||
|
||||
export class MetadataFormData<
|
||||
T extends ValueType = ValueType,
|
||||
S extends StructureType = StructureType,
|
||||
@ -86,7 +90,7 @@ export class MetadataFormData<
|
||||
}
|
||||
|
||||
get isRequired() {
|
||||
return this.field?.option === 'required' || this.trueParent?.objectType === 'union';
|
||||
return isRequiredField(this.field) || this.trueParent?.objectType === 'union';
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
@ -5,6 +5,9 @@ import { TypeDefs } from '@vality/thrift-ts/src/thrift-parser';
|
||||
import { MetadataFormData, TypeGroup } from '../types/metadata-form-data';
|
||||
|
||||
export function getDefaultValue(metadata: ThriftAstMetadata[], namespace: string, type: ValueType) {
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
let data: MetadataFormData;
|
||||
do {
|
||||
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 { PayoutTool } from '@vality/domain-proto/domain';
|
||||
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 { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
|
@ -31,7 +31,7 @@ export class SidenavInfoService {
|
||||
private sidenavInfoComponents?: SidenavInfoComponents,
|
||||
) {
|
||||
if (!this.sidenavInfoComponents) {
|
||||
this.sidenavInfoComponents = sidenavInfoComponents = {};
|
||||
this.sidenavInfoComponents = sidenavInfoComponents ?? {};
|
||||
}
|
||||
router.events
|
||||
.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 { MatButtonModule } from '@angular/material/button';
|
||||
import { Reference } from '@vality/domain-proto/internal/domain';
|
||||
import { ComponentChanges } from '@vality/ng-core';
|
||||
import { combineLatest, ReplaySubject } from 'rxjs';
|
||||
import { ComponentChanges, DialogService } from '@vality/ng-core';
|
||||
import { combineLatest, ReplaySubject, switchMap } from 'rxjs';
|
||||
import { map, shareReplay, first } from 'rxjs/operators';
|
||||
|
||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||
@ -13,6 +13,7 @@ import { toJson } from '@cc/utils';
|
||||
import { SidenavInfoModule } from '../../../sidenav-info';
|
||||
import { CardComponent } from '../../../sidenav-info/components/card/card.component';
|
||||
import { DomainThriftViewerComponent } from '../domain-thrift-viewer';
|
||||
import { EditDomainObjectDialogComponent } from '../edit-domain-object-dialog';
|
||||
import { DomainObjectService } from '../services';
|
||||
import { getDomainObjectDetails } from '../utils';
|
||||
|
||||
@ -50,6 +51,7 @@ export class DomainObjectCardComponent implements OnChanges {
|
||||
private domainObjectService: DomainObjectService,
|
||||
private domainStoreService: DomainStoreService,
|
||||
private destroyRef: DestroyRef,
|
||||
private dialogService: DialogService,
|
||||
) {}
|
||||
|
||||
ngOnChanges(changes: ComponentChanges<DomainObjectCardComponent>) {
|
||||
@ -59,7 +61,17 @@ export class DomainObjectCardComponent implements OnChanges {
|
||||
}
|
||||
|
||||
edit() {
|
||||
void this.domainObjectService.edit(this.ref);
|
||||
this.domainObject$
|
||||
.pipe(
|
||||
first(),
|
||||
switchMap((domainObject) =>
|
||||
this.dialogService
|
||||
.open(EditDomainObjectDialogComponent, { domainObject })
|
||||
.afterClosed(),
|
||||
),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
delete() {
|
||||
|
@ -1,4 +1,5 @@
|
||||
<cc-thrift-editor
|
||||
[defaultValue]="defaultValue"
|
||||
[extensions]="extensions$ | async"
|
||||
[formControl]="control"
|
||||
[metadata]="metadata$ | async"
|
||||
|
@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
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 { MetadataFormModule } from '../../../metadata-form';
|
||||
|
@ -1,5 +1,7 @@
|
||||
<cc-thrift-viewer
|
||||
[compared]="compared"
|
||||
[extensions]="extensions$ | async"
|
||||
[kind]="kind"
|
||||
[metadata]="metadata$ | async"
|
||||
[progress]="progress"
|
||||
[type]="type"
|
||||
|
@ -4,7 +4,7 @@ import { ThriftAstMetadata } from '@vality/domain-proto';
|
||||
import { getImportValue } from '@vality/ng-core';
|
||||
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';
|
||||
|
||||
@ -15,7 +15,9 @@ import { DomainMetadataViewExtensionsService } from './services/domain-metadata-
|
||||
imports: [CommonModule, ThriftViewerModule],
|
||||
})
|
||||
export class DomainThriftViewerComponent<T> {
|
||||
@Input() kind: ViewerKind = ViewerKind.Component;
|
||||
@Input() value: T;
|
||||
@Input() compared?: T;
|
||||
@Input() type: ValueType;
|
||||
@Input({ transform: booleanAttribute }) progress: boolean = false;
|
||||
// @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-thrift-form-dialog';
|
||||
export * from './domain-object-card/domain-object-card.component';
|
||||
export * from './domain-thrift-form';
|
||||
export * from './utils';
|
||||
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 { Router } from '@angular/router';
|
||||
import { DomainObject, Reference } from '@vality/domain-proto/domain';
|
||||
import { DomainObject } from '@vality/domain-proto/domain';
|
||||
import {
|
||||
ConfirmDialogComponent,
|
||||
DialogResponseStatus,
|
||||
@ -16,18 +15,11 @@ import { DomainStoreService } from '../../../../../api/domain-config';
|
||||
})
|
||||
export class DomainObjectService {
|
||||
constructor(
|
||||
private router: Router,
|
||||
private dialogService: DialogService,
|
||||
private domainStoreService: DomainStoreService,
|
||||
private log: NotifyLogService,
|
||||
) {}
|
||||
|
||||
edit(ref: Reference) {
|
||||
return this.router.navigate(['domain', 'edit'], {
|
||||
queryParams: { ref: JSON.stringify(ref) },
|
||||
});
|
||||
}
|
||||
|
||||
delete(domainObject: DomainObject) {
|
||||
return this.dialogService
|
||||
.open(ConfirmDialogComponent, { title: 'Delete object' })
|
||||
|
@ -8,13 +8,14 @@ import { map, shareReplay } from 'rxjs/operators';
|
||||
import { MetadataFormExtension } from '../../../metadata-form';
|
||||
|
||||
@Directive()
|
||||
export abstract class BaseThriftFormSuperclass
|
||||
extends FormControlSuperclass<unknown>
|
||||
export abstract class BaseThriftFormSuperclass<T = unknown>
|
||||
extends FormControlSuperclass<T>
|
||||
implements OnChanges
|
||||
{
|
||||
@Input() type: ValueType;
|
||||
@Input() namespace?: string;
|
||||
@Input() extensions?: MetadataFormExtension[];
|
||||
@Input() defaultValue?: T;
|
||||
|
||||
protected abstract defaultNamespace: string;
|
||||
protected abstract metadata$: Observable<ThriftAstMetadata[]>;
|
||||
|
@ -1,9 +1,29 @@
|
||||
<div class="wrapper">
|
||||
<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>
|
||||
</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 === 'editor'">edit_note</mat-icon>
|
||||
</button>
|
||||
|
@ -1,11 +1,16 @@
|
||||
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 { 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 { map, filter, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { ValidatedFormControlSuperclass, createControlProviders } from '@cc/utils';
|
||||
import { objectToJSON } from '@cc/utils/thrift-instance';
|
||||
|
||||
import { MetadataFormExtension } from '../metadata-form';
|
||||
@ -21,7 +26,7 @@ export enum EditorKind {
|
||||
styleUrls: ['./thrift-editor.component.scss'],
|
||||
providers: createControlProviders(() => ThriftEditorComponent),
|
||||
})
|
||||
export class ThriftEditorComponent<T> extends ValidatedFormControlSuperclass<T> {
|
||||
export class ThriftEditorComponent<T> extends FormControlSuperclass<T> {
|
||||
@Input() kind: EditorKind = EditorKind.Form;
|
||||
|
||||
@Input() defaultValue?: T;
|
||||
@ -49,11 +54,11 @@ export class ThriftEditorComponent<T> extends ValidatedFormControlSuperclass<T>
|
||||
super();
|
||||
}
|
||||
|
||||
validate(): ValidationErrors | null {
|
||||
validate(control: AbstractControl): ValidationErrors | null {
|
||||
if (this.kind === EditorKind.Editor) {
|
||||
return this.editorError ? { jsonParse: this.editorError } : null;
|
||||
}
|
||||
return super.validate();
|
||||
return super.validate(control);
|
||||
}
|
||||
|
||||
contentChange(str: string) {
|
||||
|
@ -4,6 +4,8 @@ import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
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 { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
||||
@ -22,6 +24,8 @@ import { ThriftEditorComponent } from './thrift-editor.component';
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
FormsModule,
|
||||
PipesModule,
|
||||
MatTooltipModule,
|
||||
],
|
||||
})
|
||||
export class ThriftEditorModule {}
|
||||
|
@ -12,15 +12,13 @@ import {
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Validator, ValidationErrors, FormControl } from '@angular/forms';
|
||||
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 { combineLatest } from 'rxjs';
|
||||
import { map, switchMap, first, distinctUntilChanged } from 'rxjs/operators';
|
||||
|
||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||
|
||||
import { createControlProviders, getFormValueChanges } from '../../utils';
|
||||
|
||||
export interface Cash {
|
||||
amount: number;
|
||||
currencyCode: string;
|
||||
@ -42,7 +40,7 @@ export class CashFieldComponent extends FormComponentSuperclass<Cash> implements
|
||||
currencyCodeControl = new FormControl<string>(null);
|
||||
|
||||
currencies$ = combineLatest([
|
||||
getFormValueChanges(this.currencyCodeControl, true),
|
||||
getValueChanges(this.currencyCodeControl),
|
||||
this.domainStoreService.getObjects('currency'),
|
||||
]).pipe(
|
||||
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)),
|
||||
map((c) => (this.minor ? 0 : c?.data?.exponent || 2)),
|
||||
distinctUntilChanged(),
|
||||
@ -84,8 +82,8 @@ export class CashFieldComponent extends FormComponentSuperclass<Cash> implements
|
||||
|
||||
ngOnInit() {
|
||||
combineLatest([
|
||||
getFormValueChanges(this.currencyCodeControl, true),
|
||||
getFormValueChanges(this.amountControl, true),
|
||||
getValueChanges(this.currencyCodeControl),
|
||||
getValueChanges(this.amountControl),
|
||||
])
|
||||
.pipe(
|
||||
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 './has-active-fragments';
|
||||
export * from './poll';
|
||||
export * from './forms';
|
||||
export * from './operators';
|
||||
export * from './get-enum-keys';
|
||||
export * from './enumerate';
|
||||
|
@ -1 +1,2 @@
|
||||
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