@unifylib/ui-lib 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +0 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +12 -0
  4. package/src/lib/base-model/SearchStrConfig.ts +12 -0
  5. package/src/lib/base-model/api-response.ts +23 -0
  6. package/src/lib/base-model/audit-log-entry.ts +7 -0
  7. package/src/lib/base-model/button-action-settings.ts +25 -0
  8. package/src/lib/base-model/column-def.model.ts +34 -0
  9. package/src/lib/base-model/do-action-request.ts +11 -0
  10. package/src/lib/base-model/field-action.ts +7 -0
  11. package/src/lib/base-model/field-filter.model.ts +14 -0
  12. package/src/lib/base-model/field-info.ts +98 -0
  13. package/src/lib/base-model/field-predicate.model.ts +7 -0
  14. package/src/lib/base-model/filter-request.ts +27 -0
  15. package/src/lib/base-model/filter.model.ts +49 -0
  16. package/src/lib/base-model/get-items-list.ts +24 -0
  17. package/src/lib/base-model/index.ts +11 -0
  18. package/src/lib/base-model/lookupItem.ts +21 -0
  19. package/src/lib/base-model/null-snackmessage.ts +9 -0
  20. package/src/lib/base-model/page-info.ts +51 -0
  21. package/src/lib/base-model/report-request.model.ts +33 -0
  22. package/src/lib/base-model/response-envelop.model.ts +15 -0
  23. package/src/lib/base-model/snack-message.model.ts +14 -0
  24. package/src/lib/base-model/snackmessage-interface.ts +7 -0
  25. package/src/lib/base-model/table-column.interface.ts +29 -0
  26. package/src/lib/base-model/table-page-user-action.interface.ts +33 -0
  27. package/src/lib/base-model/workflow/workflow-steps.model.ts +9 -0
  28. package/src/lib/base-model/workflow/workflow.model.ts +52 -0
  29. package/src/lib/components/action-confirmation/action-confirmation.component.css +34 -0
  30. package/src/lib/components/action-confirmation/action-confirmation.component.html +18 -0
  31. package/src/lib/components/action-confirmation/action-confirmation.component.spec.ts +23 -0
  32. package/src/lib/components/action-confirmation/action-confirmation.component.ts +58 -0
  33. package/src/lib/components/activity-report-form/activity-report-form.component.html +109 -0
  34. package/src/lib/components/activity-report-form/activity-report-form.component.scss +0 -0
  35. package/src/lib/components/activity-report-form/activity-report-form.component.spec.ts +25 -0
  36. package/src/lib/components/activity-report-form/activity-report-form.component.ts +605 -0
  37. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.css +51 -0
  38. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.html +23 -0
  39. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.spec.ts +23 -0
  40. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.ts +69 -0
  41. package/src/lib/components/audit-log-list/audit-log.component.html +23 -0
  42. package/src/lib/components/audit-log-list/audit-log.component.scss +0 -0
  43. package/src/lib/components/audit-log-list/audit-log.component.spec.ts +25 -0
  44. package/src/lib/components/audit-log-list/audit-log.component.ts +116 -0
  45. package/src/lib/components/auto-complete/auto-complete.component.css +14 -0
  46. package/src/lib/components/auto-complete/auto-complete.component.html +29 -0
  47. package/src/lib/components/auto-complete/auto-complete.component.spec.ts +23 -0
  48. package/src/lib/components/auto-complete/auto-complete.component.ts +330 -0
  49. package/src/lib/components/base-form/base-form.component.html +58 -0
  50. package/src/lib/components/base-form/base-form.component.scss +0 -0
  51. package/src/lib/components/base-form/base-form.component.spec.ts +25 -0
  52. package/src/lib/components/base-form/base-form.component.ts +305 -0
  53. package/src/lib/components/base-form-canvas/base-form-canvas.component.css +22 -0
  54. package/src/lib/components/base-form-canvas/base-form-canvas.component.html +1006 -0
  55. package/src/lib/components/base-form-canvas/base-form-canvas.component.spec.ts +23 -0
  56. package/src/lib/components/base-form-canvas/base-form-canvas.component.ts +573 -0
  57. package/src/lib/components/base-input-dialog/base-input-dialog.component.css +0 -0
  58. package/src/lib/components/base-input-dialog/base-input-dialog.component.html +42 -0
  59. package/src/lib/components/base-input-dialog/base-input-dialog.component.spec.ts +23 -0
  60. package/src/lib/components/base-input-dialog/base-input-dialog.component.ts +78 -0
  61. package/src/lib/components/base-table/base-table.component.html +242 -0
  62. package/src/lib/components/base-table/base-table.component.scss +31 -0
  63. package/src/lib/components/base-table/base-table.component.spec.ts +25 -0
  64. package/src/lib/components/base-table/base-table.component.ts +568 -0
  65. package/src/lib/components/button-actions/button-actions.component.html +28 -0
  66. package/src/lib/components/button-actions/button-actions.component.scss +6 -0
  67. package/src/lib/components/button-actions/button-actions.component.spec.ts +23 -0
  68. package/src/lib/components/button-actions/button-actions.component.ts +72 -0
  69. package/src/lib/components/editable-base-table/editable-base-table.component.html +372 -0
  70. package/src/lib/components/editable-base-table/editable-base-table.component.scss +44 -0
  71. package/src/lib/components/editable-base-table/editable-base-table.component.spec.ts +25 -0
  72. package/src/lib/components/editable-base-table/editable-base-table.component.ts +570 -0
  73. package/src/lib/components/equation-builder/equation-builder.component.css +0 -0
  74. package/src/lib/components/equation-builder/equation-builder.component.html +31 -0
  75. package/src/lib/components/equation-builder/equation-builder.component.spec.ts +23 -0
  76. package/src/lib/components/equation-builder/equation-builder.component.ts +121 -0
  77. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.css +11 -0
  78. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.html +38 -0
  79. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.spec.ts +23 -0
  80. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.ts +317 -0
  81. package/src/lib/components/paginator/paginator.component.css +25 -0
  82. package/src/lib/components/paginator/paginator.component.html +34 -0
  83. package/src/lib/components/paginator/paginator.component.ts +94 -0
  84. package/src/lib/components/rejection-comment/action-comment.component.css +33 -0
  85. package/src/lib/components/rejection-comment/action-comment.component.html +46 -0
  86. package/src/lib/components/rejection-comment/action-comment.component.spec.ts +23 -0
  87. package/src/lib/components/rejection-comment/action-comment.component.ts +86 -0
  88. package/src/lib/components/report-details-dialog/report-details-dialog.component.css +17 -0
  89. package/src/lib/components/report-details-dialog/report-details-dialog.component.html +16 -0
  90. package/src/lib/components/report-details-dialog/report-details-dialog.component.spec.ts +23 -0
  91. package/src/lib/components/report-details-dialog/report-details-dialog.component.ts +113 -0
  92. package/src/lib/components/report-form/report-form.component.html +94 -0
  93. package/src/lib/components/report-form/report-form.component.scss +0 -0
  94. package/src/lib/components/report-form/report-form.component.spec.ts +25 -0
  95. package/src/lib/components/report-form/report-form.component.ts +588 -0
  96. package/src/lib/components/search-bar/search-bar.component.html +62 -0
  97. package/src/lib/components/search-bar/search-bar.component.scss +8 -0
  98. package/src/lib/components/search-bar/search-bar.component.spec.ts +25 -0
  99. package/src/lib/components/search-bar/search-bar.component.ts +70 -0
  100. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.css +54 -0
  101. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.html +22 -0
  102. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.spec.ts +23 -0
  103. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.ts +45 -0
  104. package/src/lib/components/shared-list/shared-list.component.css +0 -0
  105. package/src/lib/components/shared-list/shared-list.component.html +17 -0
  106. package/src/lib/components/shared-list/shared-list.component.spec.ts +23 -0
  107. package/src/lib/components/shared-list/shared-list.component.ts +53 -0
  108. package/src/lib/components/title-bar/title-bar.component.css +0 -0
  109. package/src/lib/components/title-bar/title-bar.component.css.map +1 -0
  110. package/src/lib/components/title-bar/title-bar.component.html +31 -0
  111. package/src/lib/components/title-bar/title-bar.component.scss +23 -0
  112. package/src/lib/components/title-bar/title-bar.component.spec.ts +23 -0
  113. package/src/lib/components/title-bar/title-bar.component.ts +119 -0
  114. package/src/lib/services/backend-service.ts +286 -0
  115. package/src/lib/services/index.ts +3 -0
  116. package/src/lib/services/top-panel.ts +17 -0
  117. package/src/lib/services/trigger-form.service.ts +11 -0
  118. package/src/lib/share-module/shared-module.ts +10 -0
  119. package/src/lib/styles/invoiceq-theme.scss +252 -0
  120. package/src/lib/styles/styles.scss +1723 -0
  121. package/src/lib/utils/base-utils.ts +102 -0
  122. package/src/lib/validators/date-range-validator.ts +31 -0
  123. package/src/lib/validators/index.ts +3 -0
  124. package/src/lib/validators/match-list.validator.ts +10 -0
  125. package/src/lib/validators/multi-email-validator.ts +15 -0
  126. package/src/public-api.ts +21 -0
  127. package/tsconfig.lib.json +15 -0
  128. package/tsconfig.lib.prod.json +11 -0
  129. package/tsconfig.spec.json +15 -0
@@ -0,0 +1,69 @@
1
+ import {Component, HostListener, Inject, OnInit} from '@angular/core';
2
+ import {MAT_DIALOG_DATA, MatDialogContent, MatDialogRef, MatDialogTitle} from "@angular/material/dialog";
3
+ import {FormsModule} from "@angular/forms";
4
+ import {TranslateModule} from "@ngx-translate/core";
5
+ import {MatButton} from "@angular/material/button";
6
+ import {FieldInfo, PageInfo} from "../../base-model";
7
+ import {BaseFormCanvasComponent} from "../base-form-canvas/base-form-canvas.component";
8
+ import {MatDivider} from "@angular/material/divider";
9
+
10
+ @Component({
11
+ selector: 'app-audit-log-details-dialog',
12
+ standalone: true,
13
+ imports: [
14
+ MatDialogTitle,
15
+ MatDialogContent,
16
+ FormsModule,
17
+ TranslateModule,
18
+ MatButton,
19
+ BaseFormCanvasComponent,
20
+ MatDivider
21
+ ],
22
+ templateUrl: './audit-log-details-dialog.component.html',
23
+ styleUrl: './audit-log-details-dialog.component.css'
24
+ })
25
+ export class AuditLogDetailsDialogComponent implements OnInit {
26
+ pageInfo: PageInfo;
27
+ fields: FieldInfo[] = [];
28
+
29
+ actionLabel : string =''
30
+ isTermination : boolean=false;
31
+ comment: string = '';
32
+ external: boolean = false;
33
+ signingRequired: boolean = false;
34
+ tokenReference: string = "";
35
+ warningMsg = false;
36
+ item: any = {};
37
+ constructor(public dialogRef: MatDialogRef<AuditLogDetailsDialogComponent>,
38
+ @Inject(MAT_DIALOG_DATA) public data: any) {
39
+ dialogRef.disableClose = true;
40
+ }
41
+ @HostListener('window:keyup.esc') onKeyUp() {
42
+ this.dialogRef.close();
43
+ }
44
+ ngOnInit(): void {
45
+ this.pageInfo = this.data.pageInfo;
46
+ this.fields = this.data.fields;
47
+
48
+ this.fields = this.data.fields.map((f: any) => ({ ...f }));
49
+
50
+ const showHiddenFields: string[] = this.data.showHiddenFields || [];
51
+ this.fields.forEach(field => {
52
+ if (showHiddenFields.includes(field.property)) {
53
+ field.visible = true;
54
+ }
55
+ });
56
+ this.item = this.data.item;
57
+ this.comment = this.data.comment;
58
+ this.warningMsg = this.data.warningMsg || false;
59
+ }
60
+
61
+ cancel() {
62
+ this.dialogRef.close();
63
+ }
64
+
65
+
66
+ getTitle() {
67
+ return `${this.pageInfo.labelsSection}.${this.pageInfo.id}`;
68
+ }
69
+ }
@@ -0,0 +1,23 @@
1
+ <h4><span style="font-weight: normal; color: #222222" >{{'audit-log.title' | translate}}</span></h4>
2
+ <div class="hrdivider-mini" >
3
+ <hr class="header-hr"/>
4
+ </div>
5
+
6
+ <div fxLayout="row" fxLayout.lt-md="row" fxLayoutGap="5px" fxLayoutAlign="start start" style="width: 100%;"
7
+ *ngFor="let auditLog of auditLogEntries; let i=index">
8
+ <div fxLayout="column" fxFlex="100" fxLayoutAlign="start start">
9
+ <p *ngIf="i===0" style="margin-bottom: 15px; margin-top: 0"></p>
10
+ <p style="margin-bottom: 0; margin-top: 0">
11
+ {{getDescription(auditLog)}}
12
+ <button mat-stroked-button color="secondary" (click)="viewObject(auditLog)">
13
+ {{ 'audit-log.view_details' | translate }}
14
+ </button>
15
+
16
+ </p>
17
+ <p class="invoice-label-text" style="margin: 0;word-wrap: break-word"></p>
18
+ <div class="hrdivider-mini" >
19
+ <hr class="header-hr"/>
20
+ </div>
21
+ </div>
22
+
23
+ </div>
@@ -0,0 +1,25 @@
1
+ import {ComponentFixture, TestBed} from '@angular/core/testing';
2
+
3
+ import {AuditLogComponent} from './audit-log.component';
4
+
5
+ describe('BaseFormComponent', () => {
6
+ let component: AuditLogComponent;
7
+ let fixture: ComponentFixture<AuditLogComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ AuditLogComponent ]
12
+ })
13
+ .compileComponents();
14
+ });
15
+
16
+ beforeEach(() => {
17
+ fixture = TestBed.createComponent(AuditLogComponent);
18
+ component = fixture.componentInstance;
19
+ fixture.detectChanges();
20
+ });
21
+
22
+ it('should create', () => {
23
+ expect(component).toBeTruthy();
24
+ });
25
+ });
@@ -0,0 +1,116 @@
1
+ import {Component, Inject, Input, OnInit} from '@angular/core';
2
+ import {FieldInfo, Filter, FilterRequest, PageInfo, TableColumn} from "../../base-model";
3
+ import {TranslateModule, TranslateService} from "@ngx-translate/core";
4
+ import {BackendService} from "../../services";
5
+ import {DatePipe, NgForOf, NgIf} from "@angular/common";
6
+ import {FlexLayoutModule} from "@angular/flex-layout";
7
+ import {MatButton, MatButtonModule} from "@angular/material/button";
8
+ import {MatIconModule} from "@angular/material/icon";
9
+ import {MatDialog} from "@angular/material/dialog";
10
+ import {ActivatedRoute, Router} from "@angular/router";
11
+ import {AuditLogEntry} from "../../base-model/audit-log-entry";
12
+ import {AuditLogDetailsDialogComponent} from "../audit-log-details-dialog/audit-log-details-dialog.component";
13
+ import {Directionality} from "@angular/cdk/bidi";
14
+
15
+ @Component({
16
+ selector: 'app-audit-log',
17
+ standalone: true,
18
+ imports: [
19
+ FlexLayoutModule,
20
+ NgForOf,
21
+ MatButtonModule,
22
+ TranslateModule,
23
+ NgIf,
24
+ MatIconModule,
25
+ MatButton
26
+ ],
27
+ providers: [DatePipe],
28
+ templateUrl: './audit-log.component.html',
29
+ styleUrl: './audit-log.component.scss'
30
+ })
31
+ export class AuditLogComponent implements OnInit {
32
+ auditLogEntries: AuditLogEntry[] = [];
33
+
34
+ @Input()
35
+ pageInfo!: PageInfo;
36
+
37
+ @Input()
38
+ fields: FieldInfo[];
39
+
40
+ @Input()
41
+ showHiddenFields : string[];
42
+
43
+
44
+ itemId: number;
45
+
46
+ item : any = {};
47
+ isLoaded : boolean = false;
48
+ columnsDefinition: TableColumn<any>[];
49
+
50
+ currentDirection: 'ltr' | 'rtl';
51
+
52
+
53
+ constructor(public dialog: MatDialog,
54
+ private activatedRoute: ActivatedRoute,
55
+ private datePipe: DatePipe,
56
+ private translateService:TranslateService,
57
+ private router:Router,
58
+ private directionality: Directionality,
59
+ @Inject('securityManager') private securityManager: any,
60
+ public backendService: BackendService) {
61
+ }
62
+
63
+ ngOnInit(): void {
64
+ this.currentDirection = this.directionality.value;
65
+ this.directionality.change.subscribe((value) => {
66
+ this.currentDirection = value;
67
+ })
68
+
69
+ this.loadItem();
70
+ }
71
+
72
+
73
+ private loadItem() {
74
+ if (this.activatedRoute.snapshot.queryParams['token']) {
75
+ this.itemId = this.backendService.decrypt(this.activatedRoute.snapshot.queryParams['token']);
76
+ }
77
+ const filterRequest = new FilterRequest;
78
+ if (this.itemId > 0) {
79
+ filterRequest.filters = [];
80
+ filterRequest.sortDirection = "DESC";
81
+ // TODO
82
+ // add pagination support here.
83
+ filterRequest.pageSize = 1000;
84
+ filterRequest.filters.push(new Filter({
85
+ key: 0,
86
+ fieldType: 'Long',
87
+ fieldName: 'id',
88
+ valueObject: this.itemId,
89
+ filterType: 'FILED_FILTER',
90
+ operator: 'EQUALS'
91
+ }));
92
+ }
93
+ this.backendService.getItemAuditLog(filterRequest, this.pageInfo!.apiUri).subscribe(resp => {
94
+ this.auditLogEntries = resp.body;
95
+ });
96
+ }
97
+
98
+
99
+ viewObject(auditLog: AuditLogEntry) {
100
+ const dialogRef = this.dialog.open(AuditLogDetailsDialogComponent, {
101
+ data: {pageInfo: this.pageInfo, fields: this.fields, item:auditLog.subject, comment: auditLog.comment, showHiddenFields:this.showHiddenFields},
102
+ width: '800px',
103
+ height: 'auto',
104
+ direction: this.currentDirection
105
+ });
106
+
107
+ }
108
+
109
+ getDescription(auditLog: AuditLogEntry) {
110
+ return `
111
+ ${auditLog.createdBy || this.translateService.instant('system')}
112
+ ${this.translateService.instant('on')}
113
+ ${this.datePipe.transform(auditLog.createdOn, 'medium')}
114
+ ${this.translateService.instant('audit-log.executed')} ${this.translateService.instant(auditLog.action.toString())}`
115
+ }
116
+ }
@@ -0,0 +1,14 @@
1
+ ::ng-deep .main-auto-complete {
2
+
3
+ .matField {
4
+ margin-bottom: 24px !important;
5
+ .mat-form-field-wrapper {
6
+ padding: 0 !important;
7
+ margin-bottom: 0 !important;
8
+ }
9
+ }
10
+
11
+
12
+ }
13
+
14
+
@@ -0,0 +1,29 @@
1
+ <ng-container *ngIf="this.field" class="main-auto-complete">
2
+ <div class="matField" [formGroup]="form">
3
+ <mat-form-field fxFlex="100" appearance="outline" (click)="this.filterLookupItems('', autocompleteTrigger)">
4
+ <mat-label>{{ field.label! | translate}}</mat-label>
5
+ <input class="flex-auto" type="text"
6
+ [placeholder]="'search_placeholder' | translate"
7
+ [id]="getId()"
8
+ [formControl]="myControl"
9
+ (keydown)="onKeydown($event, autocompleteTrigger)"
10
+ [matAutocomplete]="auto" matInput
11
+ [required]="isRequired"
12
+ #autocompleteTrigger="matAutocompleteTrigger"
13
+ [readonly]="readonly"
14
+ >
15
+ <mat-icon class="arrow_drop_down_autocomplete">arrow_drop_down</mat-icon>
16
+
17
+ <mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption="" [displayWith]="displayFn.bind(this)"
18
+ (optionSelected)="itemSelected($event.option.value)"
19
+ (closed)="closed()">
20
+ <ng-container *ngIf="!field.readonly">
21
+ <mat-option *ngIf="items.length > 1 && lookupItems$" [value]="null">{{ "none" | translate}}</mat-option>
22
+ <mat-option *ngFor="let item of lookupItems$ | async" [value]="item"
23
+ [ngClass]="_allowSelection(item)">
24
+ {{itemNameByLag(item)}}</mat-option>
25
+ </ng-container>
26
+ </mat-autocomplete>
27
+ </mat-form-field>
28
+ </div>
29
+ </ng-container>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { AutoCompleteComponent } from './auto-complete.component';
4
+
5
+ describe('AutoCompleteComponent', () => {
6
+ let component: AutoCompleteComponent;
7
+ let fixture: ComponentFixture<AutoCompleteComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [AutoCompleteComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(AutoCompleteComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,330 @@
1
+ import {
2
+ Component,
3
+ EventEmitter,
4
+ Inject,
5
+ Input,
6
+ OnChanges,
7
+ OnInit,
8
+ Output,
9
+ SimpleChanges,
10
+ ViewChild
11
+ } from '@angular/core';
12
+ import {FieldInfo, Filter, LookupItem} from "../../base-model";
13
+ import {MatAutocomplete, MatAutocompleteTrigger, MatOption} from "@angular/material/autocomplete";
14
+ import {Observable, of} from "rxjs";
15
+ import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
16
+ import {BackendService} from "../../services";
17
+ import {GetItemsList} from "../../base-model/get-items-list";
18
+ import {TranslateModule, TranslateService} from "@ngx-translate/core";
19
+ import {MatFormFieldModule} from "@angular/material/form-field";
20
+ import {MatInputModule} from "@angular/material/input";
21
+ import {AsyncPipe, NgClass, NgForOf, NgIf} from "@angular/common";
22
+ import {MatIcon} from "@angular/material/icon";
23
+ import {FlexLayoutModule} from "@angular/flex-layout";
24
+ import {buildItemsList} from "../../utils/base-utils";
25
+ import {RequireMatch} from "../../validators";
26
+
27
+ @Component({
28
+ selector: 'app-auto-complete',
29
+ standalone: true,
30
+ imports: [
31
+ TranslateModule,
32
+ MatFormFieldModule,
33
+ MatAutocompleteTrigger,
34
+ MatInputModule,
35
+ ReactiveFormsModule,
36
+ NgIf,
37
+ MatAutocomplete,
38
+ AsyncPipe,
39
+ MatOption,
40
+ NgClass,
41
+ MatIcon,
42
+ NgForOf,
43
+ FlexLayoutModule,
44
+
45
+ ],
46
+ templateUrl: './auto-complete.component.html',
47
+ styleUrl: './auto-complete.component.css'
48
+ })
49
+ export class AutoCompleteComponent implements OnInit, OnChanges {
50
+ @ViewChild('autocompleteTrigger') matACTrigger: MatAutocompleteTrigger;
51
+
52
+ lookupItems$: Observable<LookupItem[]> | undefined;
53
+ lookupItems: LookupItem[] = [];
54
+ items: LookupItem[] = [];
55
+
56
+ // @ts-ignore
57
+ // form: FormGroup;
58
+
59
+ @Input()// @ts-ignore
60
+ field: FieldInfo;
61
+
62
+ @Input()// @ts-ignore
63
+ form: FormGroup;
64
+ @Input()// @ts-ignore
65
+ defaultValue: any;
66
+
67
+ @Input()
68
+ readonly:boolean = false;
69
+
70
+ @Input()
71
+ supportingAttributes: any;
72
+
73
+ @Output()
74
+ selectedValue: EventEmitter<LookupItem> = new EventEmitter();
75
+
76
+ @ViewChild(MatAutocompleteTrigger) autocompleteTrigger!: MatAutocompleteTrigger;
77
+
78
+ question = 'Would you like to add ?"';
79
+ cascadedId: number = 0;
80
+ isRequired:boolean = false;
81
+
82
+ private timer: any;
83
+ myControl = new FormControl();
84
+
85
+ constructor(private backendService: BackendService,
86
+ protected translateService: TranslateService,
87
+ @Inject('secretsManager') private secretsManager: any) {
88
+ }
89
+
90
+ ngOnInit(): void {
91
+ this.buildControl();
92
+ this.extractWorkflowGuidedCascading();
93
+ this.getLookupData();
94
+ // this.myControl.valueChanges.subscribe(v => {
95
+ // if (typeof v === 'string') this.filterLookupItems(v, null);
96
+ // });
97
+
98
+ this.form.get(this.field.property).valueChanges.subscribe(x => {
99
+ if (x?.id === -100) {
100
+ this.myControl.reset()
101
+ }
102
+ })
103
+ if (this.field.cascadedBy) {
104
+ this.form.get(this.field.cascadedByProperty)?.valueChanges.subscribe(v => {
105
+ this.cascadedId = this.form.get(this.field.cascadedByProperty).value?.id;
106
+ this.lookupItems = [];
107
+ this.myControl.setValue(undefined);
108
+ this.myControl.patchValue(undefined, {emitEvent: true});
109
+ this.form.get(this.field.property)?.setValue(undefined);
110
+ this.form.get(this.field.property)?.patchValue(undefined, {emitEvent: true});
111
+ this.getLookupData();
112
+ });
113
+ }
114
+
115
+ }
116
+
117
+ private extractWorkflowGuidedCascading() {
118
+ if (this.supportingAttributes && this.field.workflowCascadingField && this.supportingAttributes[this.field.workflowCascadingField]) {
119
+ this.cascadedId = this.supportingAttributes[this.field.workflowCascadingField];
120
+ }
121
+ }
122
+
123
+ private buildControl() {
124
+ this.myControl = new FormControl(this.form?.controls[this.field?.property]);
125
+ this.backendService.fieldAction$.subscribe( e => {
126
+ if (e.property === this.field?.property) {
127
+ this.field.readonly = e.fieldInfo.readonly;
128
+ this.updateAttributes();
129
+ }
130
+ });
131
+ this.updateAttributes();
132
+
133
+ this.myControl.valueChanges.subscribe( v => {
134
+ if (typeof v === 'string') {
135
+ clearTimeout(this.timer);
136
+ this.timer = setTimeout(() => {
137
+ this.filterLookupItems(v, null); }, 700);
138
+ }
139
+ }
140
+ );
141
+ }
142
+
143
+ private updateAttributes() {
144
+ this.myControl.enable();
145
+ if (this.field.readonly) {
146
+ this.myControl.disable();
147
+ this.isRequired = false;
148
+ } else if (this.field.required) {
149
+ this.form?.controls[this.field?.property].setValidators([Validators.required]);
150
+ this.myControl.setValidators([Validators.required]);
151
+ this.isRequired = true;
152
+ }
153
+
154
+ if (!this.field.acceptNewItem) {
155
+ // @ts-ignore
156
+ this.myControl.setValidators(RequireMatch);
157
+ }
158
+
159
+ this.myControl.setValue(this.form?.get(this.field?.property)?.value);
160
+ }
161
+
162
+ ngOnChanges({defaultValue}: SimpleChanges): void {
163
+ this.patchLookupValue(defaultValue?.currentValue);
164
+ }
165
+
166
+ private getLookupData() {
167
+ if (this.field.cascadedBy && !this.cascadedId) {
168
+ } else {
169
+ const listItems = buildItemsList('', this.field.lookupApiPath, this.field.cascadedBy);
170
+ listItems.columns = ['id','code','englishName','arabicName'];
171
+
172
+ this.backendService.getLookupItemsByFilter(listItems, this.cascadedId).subscribe((resp => {
173
+ if (resp.valid) {
174
+ this.lookupItems = resp.body;
175
+ this.lookupItems = [];
176
+ resp.body.forEach((r: LookupItem) => this.lookupItems.push(r));
177
+ if (!this.form?.get('id')?.value) {
178
+ this.patchLookupValue(this.lookupItems?.find(l => l.defaultValue));
179
+ }
180
+ this.patchLookupValue(this.myControl.value);
181
+ }
182
+
183
+ }));
184
+ }
185
+ }
186
+
187
+ itemSelected(value: any) {
188
+ if (value && value.id !== -1) {
189
+ if (value.englishName.indexOf(this.question) === 0) {
190
+ value.englishName = value.englishName.substring(this.question.length).split('"?')[0];
191
+ }
192
+ if (value.arabicName && value.arabicName.indexOf(this.question) === 0) {
193
+ value.arabicName = value.arabicName.substring(this.question.length).split('"?')[0];
194
+ }
195
+ this.form.get(this.field.property)?.setValue(value);
196
+ // @ts-ignore
197
+ this.selectedValue.emit(this.myControl.value);
198
+ }
199
+ setTimeout(() => {
200
+ this.autocompleteTrigger.closePanel();
201
+ });
202
+
203
+ }
204
+
205
+ displayFn(selected: any): string | undefined {
206
+ if (selected?.id < 0) {
207
+ return null;
208
+ }
209
+
210
+ if (Array.isArray(selected))
211
+ selected = this.defaultValue
212
+ return this.translateService.getDefaultLang() === 'en'
213
+ ? selected?.englishName
214
+ : selected?.arabicName;
215
+ }
216
+
217
+
218
+ _allowSelection(option: LookupItem): { [className: string]: boolean } {
219
+ return {
220
+ 'prevent-selection': option.id === -1,
221
+ };
222
+ }
223
+
224
+ itemNameByLag(item: any): string {
225
+ return this.translateService.getDefaultLang() === 'en' ? item.englishName : item.arabicName
226
+
227
+ }
228
+
229
+ filterLookupItems(name: any, trigger: MatAutocompleteTrigger) {
230
+ if (this.myControl.enabled) {
231
+ if (trigger) {
232
+ trigger.openPanel();
233
+ }
234
+ if (name === undefined) {
235
+ name = '';
236
+ }
237
+
238
+ if (name === '' && !this.myControl.value) {
239
+ this.myControl.setValue(undefined);
240
+ this.myControl.updateValueAndValidity();
241
+ }
242
+
243
+ const listItems: GetItemsList = buildItemsList(name, this.field.lookupApiPath, this.field.cascadedBy);
244
+ listItems.filters = this.field.lookupFilterList;
245
+ this.addLookupFilterByAnotherProperties(listItems);
246
+ listItems.columns = ['id','code','englishName','arabicName'];
247
+ this.backendService.getLookupItemsByFilter(listItems);
248
+ if (this.field.cascadedBy) {
249
+ this.cascadedId = this.form.get(this.field.cascadedByProperty).value?.id;
250
+ } else {
251
+ this.extractWorkflowGuidedCascading();
252
+ }
253
+ listItems.columns = ['id','code','englishName','arabicName'];
254
+ this.backendService.getLookupItemsByFilter(listItems, this.cascadedId).subscribe(resp => {
255
+ if (resp.valid) {
256
+ this.items = resp.body.filter((item: { id: any; }) => this.myControl.value?.id !== item.id);
257
+ if (!this.items?.length) {
258
+ this.field.acceptNewItem ?
259
+ this.items?.push(new LookupItem({id: -2, englishName: this.question + name, arabicName: this.question + name})) :
260
+ this.items?.push(new LookupItem({id: -1, englishName: 'No match ...', arabicName: 'غير موجود ... '}));
261
+ }
262
+ } else {
263
+ if (this.items?.length == 0)
264
+ this.field.acceptNewItem && this.backendService.parentForm.get(this.field.cascadedBy).value != null ?
265
+ this.items?.push(new LookupItem({id: -2, englishName: this.question + name, arabicName: this.question + name})) :
266
+ this.items?.push(new LookupItem({id: -1, englishName: 'No match ...', arabicName: 'غير موجود ... '}));
267
+ }
268
+ this.lookupItems$ = of(this.items);
269
+ });
270
+ return;
271
+ }
272
+ }
273
+
274
+ addLookupFilterByAnotherProperties(listItems: GetItemsList) {
275
+ const properties = this.field.lookupFilterList;
276
+ if (!Array.isArray(properties)) return;
277
+
278
+ const newFilters: Filter[] = [];
279
+
280
+ for (const prop of properties) {
281
+ const fieldValue = this.form?.value?.[prop.fieldName];
282
+ const finalValue = typeof fieldValue === 'object' && fieldValue !== null ? fieldValue.code : fieldValue;
283
+ if (!finalValue) continue;
284
+
285
+ const fieldName =typeof fieldValue === 'object' && fieldValue !== null ? prop.fieldName + "." + this.field.flattenBySubAttribute : prop.fieldName;
286
+ const filter = new Filter({
287
+ fieldType: 'FILED_FILTER',
288
+ filterType: undefined,
289
+ operator: prop.operator,
290
+ valueObject: finalValue,
291
+ fieldName: fieldName
292
+ });
293
+
294
+ newFilters.push(filter);
295
+ }
296
+
297
+ if (newFilters.length) {
298
+ listItems.filters = [...(listItems.filters || []), ...newFilters];
299
+ }
300
+ listItems.filters = listItems.filters.filter(f => f.valueObject);
301
+ }
302
+
303
+ private patchLookupValue(defaultValue: any) {
304
+ if (defaultValue) {
305
+
306
+ // this.form?.get(this.field.property)?.patchValue(defaultValue);
307
+ this.myControl.setValue(defaultValue);
308
+ this.myControl.patchValue(defaultValue, {emitEvent: true});
309
+ }
310
+ }
311
+ getId() {
312
+ return this.field.property;
313
+ }
314
+ onKeydown(event: KeyboardEvent, autocompleteTrigger: MatAutocompleteTrigger) {
315
+ if (event.key === 'Enter') {
316
+ this.filterLookupItems('', autocompleteTrigger);
317
+ autocompleteTrigger.openPanel();
318
+ event.preventDefault();
319
+ }
320
+ }
321
+
322
+ closed() {
323
+ if (!this.myControl.value){
324
+ this.form.get(this.field.property)?.setValue(this.myControl.value);
325
+ this.selectedValue.emit(this.myControl.value);
326
+ } else if (typeof this.myControl.value === 'string') {
327
+ this.myControl.setValue(null);
328
+ }
329
+ }
330
+ }