@verisoft/ui-govcz 18.3.1 → 18.5.0
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.
- package/package.json +4 -4
- package/project.json +7 -0
- package/src/lib/components/shared-components/action-button-group/action-button-group.component.ts +1 -1
- package/src/lib/components/shared-components/dynamic-component/dynamic-component-factory.service.ts +75 -23
- package/src/lib/components/shared-components/dynamic-component/dynamic-component.component.ts +5 -4
- package/src/lib/components/shared-components/feature-list/directives/feature-list-column.directive.ts +10 -4
- package/src/lib/components/shared-components/feature-list/feature-list-page.model.ts +2 -1
- package/src/lib/components/shared-components/feature-list/feature-list.component.html +3 -0
- package/src/lib/components/shared-components/feature-list/feature-list.component.scss +1 -1
- package/src/lib/components/shared-components/feature-list/feature-list.component.ts +32 -5
- package/src/lib/components/shared-components/feature-list/index.ts +1 -0
- package/src/lib/components/shared-components/filter/directives/filter-field.directive.ts +19 -8
- package/src/lib/components/shared-components/filter/filter.component.html +1 -0
- package/src/lib/components/shared-components/generic-field/generic-field.component.html +52 -9
- package/src/lib/components/shared-components/generic-field/generic-field.component.ts +16 -1
- package/src/lib/components/shared-components/generic-form/generic-form.component.html +33 -20
- package/src/lib/components/shared-components/generic-form/generic-form.component.ts +10 -1
- package/src/lib/components/shared-components/generic-form/generic-form.model.ts +10 -2
- package/tsconfig.json +3 -1
- package/tsconfig.lib.prod.json +2 -1
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verisoft/ui-govcz",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.5.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/common": "^18.2.8",
|
|
6
6
|
"@angular/core": "^18.2.8",
|
|
7
7
|
"@angular/router": "18.2.8",
|
|
8
8
|
"@gov-design-system-ce/angular": "^1.1.1",
|
|
9
|
-
"@verisoft/ui-core": "18.
|
|
9
|
+
"@verisoft/ui-core": "18.5.0",
|
|
10
10
|
"@gov-design-system-ce/components": "^4.1.3-BETA-10",
|
|
11
11
|
"@angular/forms": "18.2.8",
|
|
12
12
|
"uuid": "^10.0.0",
|
|
13
|
-
"@verisoft/core": "18.
|
|
13
|
+
"@verisoft/core": "18.5.0",
|
|
14
14
|
"zxcvbn": "^4.4.2",
|
|
15
15
|
"rxjs": "~7.8.0",
|
|
16
16
|
"@angular/cdk": "^18.2.14",
|
|
17
17
|
"@ngx-translate/core": "^15.0.0",
|
|
18
|
-
"@verisoft/security-core": "18.
|
|
18
|
+
"@verisoft/security-core": "18.5.0"
|
|
19
19
|
},
|
|
20
20
|
"sideEffects": false
|
|
21
21
|
}
|
package/project.json
CHANGED
|
@@ -44,6 +44,13 @@
|
|
|
44
44
|
"options": {
|
|
45
45
|
"command": "cpx \"src/libs/ui-primeng/src/lib/components/shared-components/**/*.*\" \"src/libs/ui-govcz/src/lib/components/shared-components\" --update"
|
|
46
46
|
}
|
|
47
|
+
},
|
|
48
|
+
"publish": {
|
|
49
|
+
"executor": "@nrwl/js:publish",
|
|
50
|
+
"options": {
|
|
51
|
+
"access": "public",
|
|
52
|
+
"publishDir": "dist/src/libs/ui-govcz"
|
|
53
|
+
}
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
56
|
}
|
package/src/lib/components/shared-components/dynamic-component/dynamic-component-factory.service.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import {
|
|
2
3
|
Injectable,
|
|
3
4
|
ViewContainerRef,
|
|
@@ -6,22 +7,29 @@ import {
|
|
|
6
7
|
Injector,
|
|
7
8
|
ComponentRef,
|
|
8
9
|
ComponentFactory,
|
|
9
|
-
OnInit,
|
|
10
10
|
OnChanges,
|
|
11
11
|
SimpleChanges,
|
|
12
12
|
SimpleChange,
|
|
13
|
+
EventEmitter,
|
|
14
|
+
OnDestroy,
|
|
13
15
|
} from '@angular/core';
|
|
16
|
+
import { ExtendedComponent } from '@verisoft/ui-core';
|
|
17
|
+
import { Subscription } from 'rxjs';
|
|
14
18
|
|
|
15
19
|
@Injectable({
|
|
16
20
|
providedIn: 'root',
|
|
17
21
|
})
|
|
18
|
-
export class DynamicComponentFactoryService {
|
|
19
|
-
constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
|
|
22
|
+
export class DynamicComponentFactoryService implements OnDestroy {
|
|
23
|
+
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
|
|
24
|
+
|
|
25
|
+
ngOnDestroy(): void {
|
|
26
|
+
this.unsubscribeComponentEvents(this);
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
async createDynamicComponent<TComponent>(
|
|
22
30
|
componentType: Type<TComponent>,
|
|
23
31
|
viewContainerRef: ViewContainerRef,
|
|
24
|
-
inputs:
|
|
32
|
+
inputs: ExtendedComponent<TComponent>,
|
|
25
33
|
injector: Injector | undefined = undefined
|
|
26
34
|
) {
|
|
27
35
|
const componentFactory =
|
|
@@ -32,7 +40,6 @@ export class DynamicComponentFactoryService {
|
|
|
32
40
|
undefined,
|
|
33
41
|
injector
|
|
34
42
|
);
|
|
35
|
-
|
|
36
43
|
this.setComponentDataInt(componentFactory, component, inputs);
|
|
37
44
|
this.fireComponentEvents(component.instance, inputs);
|
|
38
45
|
return component;
|
|
@@ -49,27 +56,26 @@ export class DynamicComponentFactoryService {
|
|
|
49
56
|
this.setComponentDataInt(factory, component, inputs);
|
|
50
57
|
}
|
|
51
58
|
|
|
52
|
-
private
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (onChangeComponent.ngOnChanges && inputs) {
|
|
56
|
-
const changeEventArgs = Object.keys(inputs).reduce((changes: SimpleChanges, key: string) => {
|
|
57
|
-
const inputValue = (inputs as { [key: string]: unknown })[key];
|
|
58
|
-
changes[key] = new SimpleChange(undefined, inputValue, true);
|
|
59
|
-
return changes;
|
|
60
|
-
}, {} as SimpleChanges);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
onChangeComponent.ngOnChanges(changeEventArgs);
|
|
64
|
-
}
|
|
59
|
+
private unsubscribeComponentEvents<TComponent>(instance: TComponent) {
|
|
60
|
+
const subscriptionStoreKey = '__outputSubscriptions__';
|
|
61
|
+
const subscriptions = (instance as any)[subscriptionStoreKey] as Map<string, Subscription>;
|
|
65
62
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
63
|
+
if (subscriptions) {
|
|
64
|
+
subscriptions.forEach((sub) => sub.unsubscribe());
|
|
65
|
+
subscriptions.clear();
|
|
70
66
|
}
|
|
71
67
|
}
|
|
72
68
|
|
|
69
|
+
private fireComponentEvents<TComponent>(
|
|
70
|
+
instance: TComponent,
|
|
71
|
+
inputs: ExtendedComponent<TComponent>
|
|
72
|
+
) {
|
|
73
|
+
if (!instance || typeof instance !== 'object') return;
|
|
74
|
+
|
|
75
|
+
this.fireInputComponentEvents(instance, inputs);
|
|
76
|
+
this.fireOutputComponentEvents(instance, inputs);
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
private setComponentDataInt<TComponent>(
|
|
74
80
|
factory: ComponentFactory<TComponent>,
|
|
75
81
|
component: ComponentRef<TComponent>,
|
|
@@ -83,8 +89,54 @@ export class DynamicComponentFactoryService {
|
|
|
83
89
|
.forEach((x) => {
|
|
84
90
|
(<{ [key: string]: unknown }>component.instance)[x] = (<
|
|
85
91
|
{ [key: string]: unknown }
|
|
86
|
-
|
|
92
|
+
>inputs)[x];
|
|
87
93
|
});
|
|
88
94
|
}
|
|
89
95
|
}
|
|
96
|
+
|
|
97
|
+
private fireInputComponentEvents<TComponent>(
|
|
98
|
+
instance: TComponent,
|
|
99
|
+
inputs: ExtendedComponent<TComponent>
|
|
100
|
+
) {
|
|
101
|
+
const onChangeComponent = instance as unknown as OnChanges;
|
|
102
|
+
if (onChangeComponent.ngOnChanges && inputs) {
|
|
103
|
+
const changeEventArgs = Object.keys(inputs).reduce((changes: SimpleChanges, key: string) => {
|
|
104
|
+
const inputValue = (inputs as { [key: string]: unknown })[key];
|
|
105
|
+
changes[key] = new SimpleChange(undefined, inputValue, true);
|
|
106
|
+
return changes;
|
|
107
|
+
}, {} as SimpleChanges);
|
|
108
|
+
|
|
109
|
+
onChangeComponent.ngOnChanges(changeEventArgs);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private fireOutputComponentEvents<TComponent>(
|
|
114
|
+
instance: TComponent & object,
|
|
115
|
+
inputs: ExtendedComponent<TComponent>
|
|
116
|
+
) {
|
|
117
|
+
const outputs = Object.keys(inputs).filter((key) => {
|
|
118
|
+
const emitter = (instance as Record<string, any>)[key];
|
|
119
|
+
return emitter instanceof EventEmitter;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const subscriptionStoreKey = '__outputSubscriptions__';
|
|
123
|
+
if (!(subscriptionStoreKey in instance)) {
|
|
124
|
+
(instance as any)[subscriptionStoreKey] = new Map<string, Subscription>();
|
|
125
|
+
}
|
|
126
|
+
const subscriptions = (instance as any)[subscriptionStoreKey] as Map<string, Subscription>;
|
|
127
|
+
|
|
128
|
+
for (const outputKey of outputs) {
|
|
129
|
+
const eventEmitter = (instance as Record<string, any>)[outputKey] as EventEmitter<any>;
|
|
130
|
+
const callback = inputs[outputKey] as (value: any) => void;
|
|
131
|
+
|
|
132
|
+
if (eventEmitter && typeof callback === 'function') {
|
|
133
|
+
if (subscriptions.has(outputKey)) {
|
|
134
|
+
subscriptions.get(outputKey)!.unsubscribe();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const subscription = eventEmitter.subscribe((value: any) => callback(value));
|
|
138
|
+
subscriptions.set(outputKey, subscription);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
90
142
|
}
|
package/src/lib/components/shared-components/dynamic-component/dynamic-component.component.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
ViewChild,
|
|
12
12
|
ViewContainerRef,
|
|
13
13
|
} from '@angular/core';
|
|
14
|
+
import { ExtendedComponent } from '@verisoft/ui-core';
|
|
14
15
|
import { DynamicComponentFactoryService } from './dynamic-component-factory.service';
|
|
15
16
|
|
|
16
17
|
@Component({
|
|
@@ -22,7 +23,7 @@ import { DynamicComponentFactoryService } from './dynamic-component-factory.serv
|
|
|
22
23
|
export class DynamicComponent<TComponent> implements AfterViewInit, OnChanges {
|
|
23
24
|
@Input() componentType!: Type<TComponent>;
|
|
24
25
|
|
|
25
|
-
@Input() data!:
|
|
26
|
+
@Input() data!: ExtendedComponent<TComponent>;
|
|
26
27
|
|
|
27
28
|
@ViewChild('dynamicContainer', { read: ViewContainerRef, static: true })
|
|
28
29
|
container!: ViewContainerRef;
|
|
@@ -34,15 +35,15 @@ export class DynamicComponent<TComponent> implements AfterViewInit, OnChanges {
|
|
|
34
35
|
private injector = inject(Injector);
|
|
35
36
|
|
|
36
37
|
ngOnChanges(): void {
|
|
37
|
-
this.
|
|
38
|
+
this.createComponent();
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
ngAfterViewInit(): void {
|
|
41
|
-
this.
|
|
42
|
+
this.createComponent();
|
|
42
43
|
this.changeDetectorRef.detectChanges();
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
private
|
|
46
|
+
private createComponent() {
|
|
46
47
|
if (this.container) {
|
|
47
48
|
this.factoryServices.createDynamicComponent(
|
|
48
49
|
this.componentType,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Directive, Input } from '@angular/core';
|
|
2
|
-
import { TableColumnDirective } from '@verisoft/ui-core';
|
|
2
|
+
import { GenericFieldType, GenericFieldTypeType, TableColumnDirective } from '@verisoft/ui-core';
|
|
3
3
|
import { FEATURE_LIST_COLUMN_PROVIDER, FeatureListColumnDefinition, FeatureListColumnProvider } from '../feature-list-page.model';
|
|
4
4
|
|
|
5
5
|
@Directive({
|
|
@@ -14,13 +14,19 @@ import { FEATURE_LIST_COLUMN_PROVIDER, FeatureListColumnDefinition, FeatureListC
|
|
|
14
14
|
},
|
|
15
15
|
],
|
|
16
16
|
})
|
|
17
|
-
export class FeatureListColumnDirective<T>
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
export class FeatureListColumnDirective<T>
|
|
18
|
+
extends TableColumnDirective<T>
|
|
19
|
+
implements FeatureListColumnProvider<T>
|
|
20
|
+
{
|
|
21
|
+
@Input() filter = false;
|
|
22
|
+
|
|
23
|
+
@Input() type: GenericFieldTypeType = GenericFieldType.text;
|
|
20
24
|
|
|
21
25
|
override getDefinition(): FeatureListColumnDefinition<T> {
|
|
22
26
|
const definition = super.getDefinition() as FeatureListColumnDefinition<T>;
|
|
23
27
|
definition.filter = this.filter;
|
|
28
|
+
definition.type = this.type;
|
|
29
|
+
definition.format = this.format;
|
|
24
30
|
return definition;
|
|
25
31
|
}
|
|
26
32
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InjectionToken } from '@angular/core';
|
|
2
2
|
import { Route } from '@angular/router';
|
|
3
|
-
import { ColumnDefinition } from '@verisoft/ui-core';
|
|
3
|
+
import { ColumnDefinition, GenericFieldTypeType } from '@verisoft/ui-core';
|
|
4
4
|
import { FeatureListPageComponent } from './feature-list-page.component';
|
|
5
5
|
|
|
6
6
|
export interface FeatureListPageConfig {
|
|
@@ -30,6 +30,7 @@ export function addFeatureListPage(
|
|
|
30
30
|
|
|
31
31
|
export interface FeatureListColumnDefinition<T> extends ColumnDefinition<T> {
|
|
32
32
|
filter?: boolean;
|
|
33
|
+
type?: GenericFieldTypeType;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export const FEATURE_LIST_COLUMN_PROVIDER = new InjectionToken(
|
|
@@ -48,6 +48,9 @@
|
|
|
48
48
|
[autoBind]="true"
|
|
49
49
|
[datasource]="datasource"
|
|
50
50
|
[columns]="columns"
|
|
51
|
+
[extraFilter]="extraFilter"
|
|
52
|
+
[maximumColumnLength]="maximumColumnLength"
|
|
53
|
+
[disableCustomClicks]="disableCustomClicks"
|
|
51
54
|
(selectionChange)="selectItems($event)"
|
|
52
55
|
>
|
|
53
56
|
</v-table>
|
|
@@ -25,12 +25,13 @@ import {
|
|
|
25
25
|
DialogService,
|
|
26
26
|
downloadFile,
|
|
27
27
|
GenericFieldDefinition,
|
|
28
|
+
MAX_COLUMN_CHAR_COUNT,
|
|
28
29
|
TableDatasourceDirective,
|
|
29
30
|
TableFilterDirective,
|
|
30
31
|
TableSelectionMode,
|
|
31
32
|
TableSelectionModeType,
|
|
32
33
|
} from '@verisoft/ui-core';
|
|
33
|
-
import {
|
|
34
|
+
import { take, switchMap, forkJoin, Observable, of } from 'rxjs';
|
|
34
35
|
import { Icons } from '../../../icons';
|
|
35
36
|
import { TableComponent } from '../../table';
|
|
36
37
|
import {
|
|
@@ -75,7 +76,7 @@ export class FeatureListComponent<T> implements AfterViewInit {
|
|
|
75
76
|
|
|
76
77
|
@Input() autoBind = true;
|
|
77
78
|
|
|
78
|
-
@Input(
|
|
79
|
+
@Input() title!: string;
|
|
79
80
|
|
|
80
81
|
@Input() columns!: FeatureListColumnDefinition<T>[];
|
|
81
82
|
|
|
@@ -119,21 +120,37 @@ export class FeatureListComponent<T> implements AfterViewInit {
|
|
|
119
120
|
|
|
120
121
|
@Input() datasource!: DatasourceType<T>;
|
|
121
122
|
|
|
123
|
+
@Input() extraFilter!: any;
|
|
124
|
+
|
|
125
|
+
@Input() disableCustomClicks = false;
|
|
126
|
+
|
|
127
|
+
@Input() maximumColumnLength = MAX_COLUMN_CHAR_COUNT;
|
|
128
|
+
|
|
122
129
|
@Output() addClick = new EventEmitter();
|
|
123
130
|
|
|
124
131
|
@Output() downloadClick = new EventEmitter();
|
|
125
132
|
|
|
126
133
|
@Output() deleteClick = new EventEmitter<T[]>();
|
|
127
134
|
|
|
135
|
+
@Output() selectionChange = new EventEmitter();
|
|
136
|
+
|
|
137
|
+
@Input() set selectionMode(mode: TableSelectionModeType | undefined) {
|
|
138
|
+
this._selectionMode = mode;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
get selectionMode(): TableSelectionModeType | undefined {
|
|
142
|
+
return this.canDelete
|
|
143
|
+
? TableSelectionMode.single
|
|
144
|
+
: this._selectionMode;
|
|
145
|
+
}
|
|
146
|
+
|
|
128
147
|
icons = Icons;
|
|
129
148
|
|
|
130
149
|
private httpClient = inject(HttpClient);
|
|
131
150
|
|
|
132
151
|
private baseUrl: string = inject(BASE_URL_PATH);
|
|
133
152
|
|
|
134
|
-
|
|
135
|
-
return this.canDelete ? TableSelectionMode.single : undefined;
|
|
136
|
-
}
|
|
153
|
+
private _selectionMode: TableSelectionModeType | undefined;
|
|
137
154
|
|
|
138
155
|
private cdRef = inject(ChangeDetectorRef);
|
|
139
156
|
|
|
@@ -153,10 +170,20 @@ export class FeatureListComponent<T> implements AfterViewInit {
|
|
|
153
170
|
if (this.fieldDeclarations?.length) {
|
|
154
171
|
this.filters = this.fieldDeclarations?.toArray();
|
|
155
172
|
}
|
|
173
|
+
|
|
174
|
+
this.cdRef.detectChanges();
|
|
156
175
|
}
|
|
157
176
|
|
|
158
177
|
selectItems(items: T[]) {
|
|
159
178
|
this.selection = items ?? [];
|
|
179
|
+
|
|
180
|
+
if (this.selectionMode !== undefined) {
|
|
181
|
+
this.selectionChange.emit(
|
|
182
|
+
this.selectionMode === 'multiple'
|
|
183
|
+
? this.selection
|
|
184
|
+
: this.selection[0]
|
|
185
|
+
);
|
|
186
|
+
}
|
|
160
187
|
}
|
|
161
188
|
|
|
162
189
|
startDeleteItems() {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Directive, Input } from '@angular/core';
|
|
2
|
+
import { ValidatorFn } from '@angular/forms';
|
|
3
|
+
import { DatasourceType } from '@verisoft/core';
|
|
2
4
|
import { GenericFieldDefinition, GenericFieldType, GenericFieldTypeType } from '@verisoft/ui-core';
|
|
3
5
|
|
|
4
6
|
@Directive({
|
|
@@ -7,18 +9,27 @@ import { GenericFieldDefinition, GenericFieldType, GenericFieldTypeType } from '
|
|
|
7
9
|
standalone: true,
|
|
8
10
|
})
|
|
9
11
|
export class FilterFieldDirective implements GenericFieldDefinition {
|
|
10
|
-
|
|
11
|
-
@Input({ required: true }) name!: string;
|
|
12
|
+
@Input({ required: true }) name!: string;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
@Input() type: GenericFieldTypeType | undefined = GenericFieldType.text;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
@Input() label: string | undefined;
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
@Input() optionLabel!: string;
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
@Input() optionValue: string | undefined;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
@Input() options: unknown[] | undefined;
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
@Input() value?: unknown;
|
|
25
|
+
|
|
26
|
+
@Input() validator?: ValidatorFn[];
|
|
27
|
+
|
|
28
|
+
@Input() datasource: DatasourceType<any> | undefined;
|
|
29
|
+
|
|
30
|
+
@Input() filterField?: string;
|
|
31
|
+
|
|
32
|
+
@Input() showFilter?: boolean;
|
|
33
|
+
|
|
34
|
+
@Input() localSearch?: boolean;
|
|
24
35
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
[floatLabel]="floatLabel === true"
|
|
5
5
|
[size]="size"
|
|
6
6
|
[formControl]="formControl"
|
|
7
|
-
|
|
8
|
-
} @if (type === fieldTypes.dropdown) {
|
|
7
|
+
/>
|
|
8
|
+
} @else if (type === fieldTypes.dropdown && !datasource) {
|
|
9
9
|
<v-dropdown
|
|
10
10
|
[label]="!floatLabel ? label : ''"
|
|
11
11
|
[floatLabel]="floatLabel ? label : ''"
|
|
@@ -14,14 +14,36 @@
|
|
|
14
14
|
[optionLabel]="optionLabel"
|
|
15
15
|
[optionValue]="optionValue ?? optionLabel"
|
|
16
16
|
[loading]="loading"
|
|
17
|
+
[forceMinWidth]="true"
|
|
17
18
|
[formControl]="formControl"
|
|
19
|
+
[showFilter]="showFilter ?? false"
|
|
20
|
+
[localSearch]="localSearch ?? false"
|
|
18
21
|
(changeEvent)="changed.emit($event)"
|
|
19
22
|
(clearEvent)="cleared.emit($event)"
|
|
20
23
|
(lazyLoadEvent)="lazyLoad.emit($any($event))"
|
|
21
24
|
(showEvent)="showed.emit($event)"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
/>
|
|
26
|
+
} @else if (type === fieldTypes.dropdown && datasource) {
|
|
27
|
+
<v-dropdown
|
|
28
|
+
useDatasource
|
|
29
|
+
[forceMinWidth]="true"
|
|
30
|
+
[datasource]="datasource"
|
|
31
|
+
[optionLabel]="optionLabel"
|
|
32
|
+
[optionValue]="optionValue ?? optionLabel"
|
|
33
|
+
[label]="!floatLabel ? label : ''"
|
|
34
|
+
[floatLabel]="floatLabel ? label : ''"
|
|
35
|
+
[testId]="testId"
|
|
36
|
+
[loading]="loading"
|
|
37
|
+
[formControl]="formControl"
|
|
38
|
+
[showFilter]="showFilter ?? false"
|
|
39
|
+
[filterField]="filterField ?? 'fulltext'"
|
|
40
|
+
[localSearch]="localSearch ?? false"
|
|
41
|
+
(changeEvent)="changed.emit($event)"
|
|
42
|
+
(clearEvent)="cleared.emit($event)"
|
|
43
|
+
(lazyLoadEvent)="lazyLoad.emit($any($event))"
|
|
44
|
+
(showEvent)="showed.emit($event)"
|
|
45
|
+
/>
|
|
46
|
+
} @else if (type === fieldTypes.multiselect && !datasource) {
|
|
25
47
|
<v-multiselect
|
|
26
48
|
[label]="!floatLabel ? label : ''"
|
|
27
49
|
[floatLabel]="floatLabel ? label : ''"
|
|
@@ -35,14 +57,35 @@
|
|
|
35
57
|
(clearEvent)="cleared.emit($event)"
|
|
36
58
|
(lazyLoadEvent)="lazyLoad.emit($any($event))"
|
|
37
59
|
(showEvent)="showed.emit($event)"
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
/>
|
|
61
|
+
} @else if (type === fieldTypes.multiselect && datasource) {
|
|
62
|
+
<v-multiselect
|
|
63
|
+
useDatasource
|
|
64
|
+
[datasource]="datasource"
|
|
65
|
+
[optionLabel]="optionLabel"
|
|
66
|
+
[optionValue]="optionValue ?? optionLabel"
|
|
67
|
+
[label]="!floatLabel ? label : ''"
|
|
68
|
+
[floatLabel]="floatLabel ? label : ''"
|
|
69
|
+
[testId]="testId"
|
|
70
|
+
[loading]="loading"
|
|
71
|
+
[formControl]="formControl"
|
|
72
|
+
(changeEvent)="changed.emit($event)"
|
|
73
|
+
(clearEvent)="cleared.emit($event)"
|
|
74
|
+
(lazyLoadEvent)="lazyLoad.emit($any($event))"
|
|
75
|
+
(showEvent)="showed.emit($event)"
|
|
76
|
+
/>
|
|
40
77
|
} @else if (type === fieldTypes.checkbox) {
|
|
41
78
|
<v-tristatecheckbox
|
|
42
79
|
[label]="label"
|
|
43
80
|
[testId]="testId"
|
|
44
81
|
[formControl]="formControl"
|
|
45
|
-
|
|
82
|
+
/>
|
|
83
|
+
} @else if (type === fieldTypes.simplecheckbox) {
|
|
84
|
+
<v-checkbox
|
|
85
|
+
[label]="label"
|
|
86
|
+
[testId]="testId"
|
|
87
|
+
[formControl]="formControl"
|
|
88
|
+
/>
|
|
46
89
|
} @else if (type === fieldTypes.calendar) {
|
|
47
90
|
<v-calendar
|
|
48
91
|
[label]="!floatLabel ? label : ''"
|
|
@@ -50,5 +93,5 @@
|
|
|
50
93
|
[testId]="testId"
|
|
51
94
|
[formControl]="formControl"
|
|
52
95
|
[icon]="icons.calendar"
|
|
53
|
-
|
|
96
|
+
/>
|
|
54
97
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
1
2
|
import {
|
|
2
3
|
ChangeDetectionStrategy,
|
|
3
4
|
Component,
|
|
@@ -7,11 +8,13 @@ import {
|
|
|
7
8
|
} from '@angular/core';
|
|
8
9
|
import { ReactiveFormsModule } from '@angular/forms';
|
|
9
10
|
import {
|
|
11
|
+
DatasourceType,
|
|
10
12
|
FilterEvent,
|
|
11
13
|
LazyLoadEvent,
|
|
12
14
|
} from '@verisoft/core';
|
|
13
15
|
import {
|
|
14
16
|
BaseFormInputComponent,
|
|
17
|
+
DatasourceDirective,
|
|
15
18
|
FieldSize,
|
|
16
19
|
FieldSizeType,
|
|
17
20
|
GENERIC_FIELD_COMPONENT_TOKEN,
|
|
@@ -21,6 +24,7 @@ import {
|
|
|
21
24
|
} from '@verisoft/ui-core';
|
|
22
25
|
import { Icons } from '../../../icons';
|
|
23
26
|
import { CalendarComponent } from '../../calendar';
|
|
27
|
+
import { CheckboxComponent } from '../../checkbox';
|
|
24
28
|
import { DropdownComponent } from '../../dropdown';
|
|
25
29
|
import { MultiselectComponent } from '../../multiselect';
|
|
26
30
|
import { TextfieldComponent } from '../../textfield';
|
|
@@ -30,13 +34,16 @@ import { TristatecheckboxComponent } from '../../tristatecheckbox';
|
|
|
30
34
|
selector: 'v-generic-field',
|
|
31
35
|
standalone: true,
|
|
32
36
|
imports: [
|
|
37
|
+
CommonModule,
|
|
33
38
|
DropdownComponent,
|
|
34
39
|
CalendarComponent,
|
|
35
40
|
TristatecheckboxComponent,
|
|
36
41
|
MultiselectComponent,
|
|
37
42
|
TextfieldComponent,
|
|
38
43
|
ReactiveFormsModule,
|
|
39
|
-
|
|
44
|
+
CheckboxComponent,
|
|
45
|
+
DatasourceDirective,
|
|
46
|
+
],
|
|
40
47
|
providers: [
|
|
41
48
|
{
|
|
42
49
|
provide: GENERIC_FIELD_COMPONENT_TOKEN,
|
|
@@ -68,6 +75,14 @@ export class GenericFieldComponent<T>
|
|
|
68
75
|
|
|
69
76
|
@Input() filter = true;
|
|
70
77
|
|
|
78
|
+
@Input() datasource?: DatasourceType<T>
|
|
79
|
+
|
|
80
|
+
@Input() filterField?: string;
|
|
81
|
+
|
|
82
|
+
@Input() showFilter?: boolean;
|
|
83
|
+
|
|
84
|
+
@Input() localSearch?: boolean;
|
|
85
|
+
|
|
71
86
|
@Output() changed = new EventEmitter<any>();
|
|
72
87
|
@Output() showed = new EventEmitter<any>();
|
|
73
88
|
@Output() cleared = new EventEmitter<any>();
|
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
@if (formGroupComputed) {
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<div
|
|
3
|
+
class="v-generic-form"
|
|
4
|
+
[ngClass]="showAsRow ? 'd-flex flex-row' : 'row'"
|
|
5
|
+
[formGroup]="formGroupComputed"
|
|
6
|
+
>
|
|
7
|
+
@for(field of fields; track field) { @if (columnClass) {
|
|
8
|
+
<div class="v-generic-form__column {{ columnClass }}">
|
|
9
|
+
<v-generic-field
|
|
10
|
+
[type]="field.type"
|
|
11
|
+
[label]="field.label ?? 'NOT SET' | translate"
|
|
12
|
+
[floatLabel]="field.floatLabel"
|
|
13
|
+
[testId]="field.testId"
|
|
14
|
+
[options]="field.options"
|
|
15
|
+
[optionLabel]="field.optionLabel"
|
|
16
|
+
[optionValue]="field.optionValue ?? field.optionLabel"
|
|
17
|
+
[options]="field.options"
|
|
18
|
+
[size]="field.size"
|
|
19
|
+
[formControlName]="field.name"
|
|
20
|
+
[datasource]="field.datasource"
|
|
21
|
+
[showFilter]="field.showFilter"
|
|
22
|
+
[filterField]="field.filterField"
|
|
23
|
+
[localSearch]="field.localSearch"
|
|
24
|
+
></v-generic-field>
|
|
25
|
+
</div>
|
|
26
|
+
} @else {
|
|
5
27
|
<v-generic-field
|
|
28
|
+
class="me-4"
|
|
6
29
|
[type]="field.type"
|
|
7
|
-
[label]="field.label"
|
|
30
|
+
[label]="field.label ?? 'NOT SET' | translate"
|
|
8
31
|
[floatLabel]="field.floatLabel"
|
|
9
32
|
[testId]="field.testId"
|
|
10
33
|
[options]="field.options"
|
|
@@ -13,21 +36,11 @@
|
|
|
13
36
|
[options]="field.options"
|
|
14
37
|
[size]="field.size"
|
|
15
38
|
[formControlName]="field.name"
|
|
39
|
+
[datasource]="field.datasource"
|
|
40
|
+
[showFilter]="field.showFilter"
|
|
41
|
+
[filterField]="field.filterField"
|
|
42
|
+
[localSearch]="field.localSearch"
|
|
16
43
|
></v-generic-field>
|
|
44
|
+
} }
|
|
17
45
|
</div>
|
|
18
|
-
}
|
|
19
|
-
<v-generic-field
|
|
20
|
-
[type]="field.type"
|
|
21
|
-
[label]="field.label"
|
|
22
|
-
[floatLabel]="field.floatLabel"
|
|
23
|
-
[testId]="field.testId"
|
|
24
|
-
[options]="field.options"
|
|
25
|
-
[optionLabel]="field.optionLabel"
|
|
26
|
-
[optionValue]="field.optionValue ?? field.optionLabel"
|
|
27
|
-
[options]="field.options"
|
|
28
|
-
[size]="field.size"
|
|
29
|
-
[formControlName]="field.name"
|
|
30
|
-
></v-generic-field>
|
|
31
|
-
} }
|
|
32
|
-
</div>
|
|
33
|
-
}
|
|
46
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
1
2
|
import {
|
|
2
3
|
ChangeDetectionStrategy,
|
|
3
4
|
Component,
|
|
@@ -6,6 +7,7 @@ import {
|
|
|
6
7
|
SimpleChanges,
|
|
7
8
|
} from '@angular/core';
|
|
8
9
|
import { ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
|
|
10
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
9
11
|
import { GenericFieldDefinition } from '@verisoft/ui-core';
|
|
10
12
|
import { GenericFieldComponent } from '../generic-field';
|
|
11
13
|
import {
|
|
@@ -16,7 +18,12 @@ import {
|
|
|
16
18
|
@Component({
|
|
17
19
|
selector: 'v-generic-form',
|
|
18
20
|
standalone: true,
|
|
19
|
-
imports: [
|
|
21
|
+
imports: [
|
|
22
|
+
CommonModule,
|
|
23
|
+
GenericFieldComponent,
|
|
24
|
+
ReactiveFormsModule,
|
|
25
|
+
TranslateModule,
|
|
26
|
+
],
|
|
20
27
|
templateUrl: './generic-form.component.html',
|
|
21
28
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
22
29
|
})
|
|
@@ -27,6 +34,8 @@ export class GenericFormComponent implements OnChanges {
|
|
|
27
34
|
|
|
28
35
|
@Input() columns?: number;
|
|
29
36
|
|
|
37
|
+
@Input() showAsRow!: boolean;
|
|
38
|
+
|
|
30
39
|
formGroupComputed!: UntypedFormGroup;
|
|
31
40
|
|
|
32
41
|
columnClass?: string;
|
|
@@ -22,9 +22,17 @@ export function generateFormGroup(
|
|
|
22
22
|
field.name,
|
|
23
23
|
new UntypedFormControl(field.value, field.validator)
|
|
24
24
|
);
|
|
25
|
-
} else {
|
|
25
|
+
} else if (control && control.value !== field.value) {
|
|
26
|
+
control.setValue(field.value);
|
|
26
27
|
control.setValidators(field.validator ?? null);
|
|
27
28
|
}
|
|
29
|
+
else {
|
|
30
|
+
control.setValidators(field.validator ?? null);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (field.readonly && (control || formGroup.get(field.name))) {
|
|
34
|
+
formGroup.get(field.name)?.disable();
|
|
35
|
+
}
|
|
28
36
|
});
|
|
29
37
|
if (!inputGroupChanged) {
|
|
30
38
|
for (const field in formGroup.controls) {
|
|
@@ -55,6 +63,6 @@ export function getColumnClass(value?: number): string | undefined {
|
|
|
55
63
|
case 6:
|
|
56
64
|
return 'col-12 col-md-2';
|
|
57
65
|
}
|
|
58
|
-
|
|
66
|
+
|
|
59
67
|
return 'col-12 col-md-1';
|
|
60
68
|
}
|
package/tsconfig.json
CHANGED