@verisoft/ui-govcz 20.1.0 → 20.1.1
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/src/lib/components/shared-components/action-button-group/action-button-group.component.html +25 -0
- package/src/lib/components/shared-components/action-button-group/action-button-group.component.scss +0 -0
- package/src/lib/components/shared-components/action-button-group/action-button-group.component.spec.ts +21 -0
- package/src/lib/components/shared-components/action-button-group/action-button-group.component.ts +111 -0
- package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.html +10 -0
- package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.scss +0 -0
- package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.spec.ts +21 -0
- package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.ts +69 -0
- package/src/lib/components/shared-components/action-button-group/index.ts +2 -0
- package/src/lib/components/shared-components/dynamic-component/dynamic-component-factory.service.ts +142 -0
- package/src/lib/components/shared-components/dynamic-component/dynamic-component.component.ts +56 -0
- package/src/lib/components/shared-components/dynamic-component/index.ts +2 -0
- package/src/lib/components/shared-components/generic-field/generic-field.component.html +98 -0
- package/src/lib/components/shared-components/generic-field/generic-field.component.spec.ts +21 -0
- package/src/lib/components/shared-components/generic-field/generic-field.component.ts +90 -0
- package/src/lib/components/shared-components/generic-field/index.ts +1 -0
- package/src/lib/components/shared-components/generic-form/generic-form.component.html +46 -0
- package/src/lib/components/shared-components/generic-form/generic-form.component.spec.ts +21 -0
- package/src/lib/components/shared-components/generic-form/generic-form.component.ts +56 -0
- package/src/lib/components/shared-components/generic-form/generic-form.model.spec.ts +82 -0
- package/src/lib/components/shared-components/generic-form/generic-form.model.ts +68 -0
- package/src/lib/components/shared-components/generic-form/index.ts +2 -0
- package/src/lib/components/shared-components/index.ts +4 -0
- package/styles/dist/main.css +13 -0
- package/styles/dist/main.css.map +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
EventEmitter,
|
|
6
|
+
Input,
|
|
7
|
+
Output,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
import { ReactiveFormsModule } from '@angular/forms';
|
|
10
|
+
import {
|
|
11
|
+
DatasourceType,
|
|
12
|
+
FilterEvent,
|
|
13
|
+
LazyLoadEvent,
|
|
14
|
+
} from '@verisoft/core';
|
|
15
|
+
import {
|
|
16
|
+
BaseFormInputComponent,
|
|
17
|
+
DatasourceDirective,
|
|
18
|
+
FieldSize,
|
|
19
|
+
FieldSizeType,
|
|
20
|
+
GENERIC_FIELD_COMPONENT_TOKEN,
|
|
21
|
+
GenericFieldCore,
|
|
22
|
+
GenericFieldType,
|
|
23
|
+
GenericFieldTypeType,
|
|
24
|
+
} from '@verisoft/ui-core';
|
|
25
|
+
import { Icons } from '../../../icons';
|
|
26
|
+
import { CalendarComponent } from '../../calendar';
|
|
27
|
+
import { CheckboxComponent } from '../../checkbox';
|
|
28
|
+
import { DropdownComponent } from '../../dropdown';
|
|
29
|
+
import { MultiselectComponent } from '../../multiselect';
|
|
30
|
+
import { TextfieldComponent } from '../../textfield';
|
|
31
|
+
|
|
32
|
+
@Component({
|
|
33
|
+
selector: 'v-generic-field',
|
|
34
|
+
imports: [
|
|
35
|
+
DropdownComponent,
|
|
36
|
+
CalendarComponent,
|
|
37
|
+
MultiselectComponent,
|
|
38
|
+
TextfieldComponent,
|
|
39
|
+
ReactiveFormsModule,
|
|
40
|
+
CheckboxComponent,
|
|
41
|
+
DatasourceDirective
|
|
42
|
+
],
|
|
43
|
+
providers: [
|
|
44
|
+
{
|
|
45
|
+
provide: GENERIC_FIELD_COMPONENT_TOKEN,
|
|
46
|
+
useExisting: GenericFieldComponent,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
templateUrl: './generic-field.component.html',
|
|
50
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
51
|
+
})
|
|
52
|
+
export class GenericFieldComponent<T>
|
|
53
|
+
extends BaseFormInputComponent
|
|
54
|
+
implements GenericFieldCore<T>
|
|
55
|
+
{
|
|
56
|
+
@Input() type?: GenericFieldTypeType = GenericFieldType.text;
|
|
57
|
+
|
|
58
|
+
@Input() floatLabel?: boolean;
|
|
59
|
+
|
|
60
|
+
@Input() optionLabel: string | undefined;
|
|
61
|
+
|
|
62
|
+
@Input() optionValue: string | undefined;
|
|
63
|
+
|
|
64
|
+
@Input() options: T[] | undefined;
|
|
65
|
+
|
|
66
|
+
@Input() size?: FieldSizeType = FieldSize.medium;
|
|
67
|
+
|
|
68
|
+
@Input() loading = false;
|
|
69
|
+
|
|
70
|
+
@Input() lazy = false;
|
|
71
|
+
|
|
72
|
+
@Input() filter = true;
|
|
73
|
+
|
|
74
|
+
@Input() datasource?: DatasourceType<T>
|
|
75
|
+
|
|
76
|
+
@Input() filterField?: string;
|
|
77
|
+
|
|
78
|
+
@Input() showFilter?: boolean;
|
|
79
|
+
|
|
80
|
+
@Input() localSearch?: boolean;
|
|
81
|
+
|
|
82
|
+
@Output() changed = new EventEmitter<any>();
|
|
83
|
+
@Output() showed = new EventEmitter<any>();
|
|
84
|
+
@Output() cleared = new EventEmitter<any>();
|
|
85
|
+
@Output() lazyLoad = new EventEmitter<LazyLoadEvent>();
|
|
86
|
+
@Output() filtered = new EventEmitter<FilterEvent>();
|
|
87
|
+
|
|
88
|
+
fieldTypes = GenericFieldType;
|
|
89
|
+
icons = Icons;
|
|
90
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './generic-field.component';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
@if (formGroupComputed) {
|
|
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 {
|
|
27
|
+
<v-generic-field
|
|
28
|
+
class="me-4"
|
|
29
|
+
[type]="field.type"
|
|
30
|
+
[label]="field.label ?? 'NOT SET' | translate"
|
|
31
|
+
[floatLabel]="field.floatLabel"
|
|
32
|
+
[testId]="field.testId"
|
|
33
|
+
[options]="field.options"
|
|
34
|
+
[optionLabel]="field.optionLabel"
|
|
35
|
+
[optionValue]="field.optionValue ?? field.optionLabel"
|
|
36
|
+
[options]="field.options"
|
|
37
|
+
[size]="field.size"
|
|
38
|
+
[formControlName]="field.name"
|
|
39
|
+
[datasource]="field.datasource"
|
|
40
|
+
[showFilter]="field.showFilter"
|
|
41
|
+
[filterField]="field.filterField"
|
|
42
|
+
[localSearch]="field.localSearch"
|
|
43
|
+
></v-generic-field>
|
|
44
|
+
} }
|
|
45
|
+
</div>
|
|
46
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { GenericFormComponent } from './generic-form.component';
|
|
3
|
+
|
|
4
|
+
describe('GenericFormComponent', () => {
|
|
5
|
+
let component: GenericFormComponent;
|
|
6
|
+
let fixture: ComponentFixture<GenericFormComponent>;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await TestBed.configureTestingModule({
|
|
10
|
+
imports: [GenericFormComponent],
|
|
11
|
+
}).compileComponents();
|
|
12
|
+
|
|
13
|
+
fixture = TestBed.createComponent(GenericFormComponent);
|
|
14
|
+
component = fixture.componentInstance;
|
|
15
|
+
fixture.detectChanges();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should create', () => {
|
|
19
|
+
expect(component).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
Input,
|
|
6
|
+
OnChanges,
|
|
7
|
+
SimpleChanges,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
import { ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
|
|
10
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
11
|
+
import { GenericFieldDefinition } from '@verisoft/ui-core';
|
|
12
|
+
import { GenericFieldComponent } from '../generic-field';
|
|
13
|
+
import {
|
|
14
|
+
generateFormGroup,
|
|
15
|
+
getColumnClass,
|
|
16
|
+
} from './generic-form.model';
|
|
17
|
+
|
|
18
|
+
@Component({
|
|
19
|
+
selector: 'v-generic-form',
|
|
20
|
+
imports: [
|
|
21
|
+
CommonModule,
|
|
22
|
+
GenericFieldComponent,
|
|
23
|
+
ReactiveFormsModule,
|
|
24
|
+
TranslateModule,
|
|
25
|
+
],
|
|
26
|
+
templateUrl: './generic-form.component.html',
|
|
27
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
28
|
+
})
|
|
29
|
+
export class GenericFormComponent implements OnChanges {
|
|
30
|
+
@Input() formGroup?: UntypedFormGroup;
|
|
31
|
+
|
|
32
|
+
@Input() fields?: GenericFieldDefinition[];
|
|
33
|
+
|
|
34
|
+
@Input() columns?: number;
|
|
35
|
+
|
|
36
|
+
@Input() showAsRow!: boolean;
|
|
37
|
+
|
|
38
|
+
formGroupComputed!: UntypedFormGroup;
|
|
39
|
+
|
|
40
|
+
columnClass?: string;
|
|
41
|
+
|
|
42
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
43
|
+
if (changes['fields'] || changes['formGroup']) {
|
|
44
|
+
this.formGroupComputed = generateFormGroup(
|
|
45
|
+
this.fields,
|
|
46
|
+
this.formGroupComputed,
|
|
47
|
+
this.formGroup,
|
|
48
|
+
!!changes['formGroup']
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (changes['columns']) {
|
|
53
|
+
this.columnClass = getColumnClass(this.columns);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
|
2
|
+
import { generateFormGroup, GenericFieldDefinition } from './generic-form.model';
|
|
3
|
+
|
|
4
|
+
describe('GenericFormModel', () => {
|
|
5
|
+
describe('generateFormGroup', () => {
|
|
6
|
+
const fields = [{ name: 'name' }, { name: 'age' }];
|
|
7
|
+
|
|
8
|
+
const containsField = (formGroup: UntypedFormGroup, field: GenericFieldDefinition) => expect(formGroup.get(field.name)).toBeDefined();
|
|
9
|
+
|
|
10
|
+
test('Should create a new group when no group was provided', () => {
|
|
11
|
+
const formGroup = generateFormGroup([], undefined, undefined, false);
|
|
12
|
+
|
|
13
|
+
expect(formGroup).toBeDefined();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('Should create a new group when no fields are provided', () => {
|
|
17
|
+
const formGroup = generateFormGroup(
|
|
18
|
+
undefined,
|
|
19
|
+
undefined,
|
|
20
|
+
undefined,
|
|
21
|
+
false
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
expect(formGroup).toBeDefined();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('Should create a new group with defined control when fields are provided', () => {
|
|
28
|
+
const formGroup = generateFormGroup(fields, undefined, undefined, false);
|
|
29
|
+
|
|
30
|
+
expect(formGroup).toBeDefined();
|
|
31
|
+
containsField(formGroup, fields[0]);
|
|
32
|
+
containsField(formGroup, fields[1]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('Should used input group and creates control when fields are provided and formgroup does not have a controls', () => {
|
|
36
|
+
const inputGroup = new UntypedFormGroup({});
|
|
37
|
+
|
|
38
|
+
const formGroup = generateFormGroup(fields, undefined, inputGroup, false);
|
|
39
|
+
|
|
40
|
+
expect(formGroup).toBe(inputGroup);
|
|
41
|
+
containsField(formGroup, fields[0]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('Should not remove control from input group when input group is provided and fields does not contain control definition.', () => {
|
|
45
|
+
const inputGroup = new UntypedFormGroup({
|
|
46
|
+
student: new UntypedFormControl(),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const formGroup = generateFormGroup(fields, undefined, inputGroup, false);
|
|
50
|
+
|
|
51
|
+
expect(formGroup.get('student')).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('Should use existing group when input group is provided but have already defined group.', () => {
|
|
55
|
+
const inputGroup = new UntypedFormGroup({
|
|
56
|
+
student: new UntypedFormControl(),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const lastGroup = new UntypedFormGroup({
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const formGroup = generateFormGroup(fields, lastGroup, inputGroup, false);
|
|
63
|
+
|
|
64
|
+
expect(formGroup).toBe(lastGroup);
|
|
65
|
+
containsField(formGroup, fields[0]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('Should use existing a new input group when last form group exists, but input group was changed.', () => {
|
|
69
|
+
const inputGroup = new UntypedFormGroup({
|
|
70
|
+
student: new UntypedFormControl(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const lastGroup = new UntypedFormGroup({
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const formGroup = generateFormGroup(fields, lastGroup, inputGroup, true);
|
|
77
|
+
|
|
78
|
+
expect(formGroup).toBe(inputGroup);
|
|
79
|
+
containsField(formGroup, fields[0]);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
UntypedFormControl,
|
|
3
|
+
UntypedFormGroup,
|
|
4
|
+
} from '@angular/forms';
|
|
5
|
+
import { GenericFieldDefinition } from '@verisoft/ui-core';
|
|
6
|
+
|
|
7
|
+
export function generateFormGroup(
|
|
8
|
+
fields: GenericFieldDefinition[] | undefined,
|
|
9
|
+
lastGroupValue: UntypedFormGroup | undefined,
|
|
10
|
+
inputGroup: UntypedFormGroup | undefined,
|
|
11
|
+
inputGroupChanged = false
|
|
12
|
+
): UntypedFormGroup {
|
|
13
|
+
const formGroup =
|
|
14
|
+
(inputGroupChanged
|
|
15
|
+
? inputGroup ?? lastGroupValue
|
|
16
|
+
: lastGroupValue ?? inputGroup) ?? new UntypedFormGroup({});
|
|
17
|
+
|
|
18
|
+
fields?.forEach((field) => {
|
|
19
|
+
const control = formGroup.get(field.name);
|
|
20
|
+
if (!control) {
|
|
21
|
+
formGroup.addControl(
|
|
22
|
+
field.name,
|
|
23
|
+
new UntypedFormControl(field.value, field.validator)
|
|
24
|
+
);
|
|
25
|
+
} else if (control && control.value !== field.value) {
|
|
26
|
+
control.setValue(field.value);
|
|
27
|
+
control.setValidators(field.validator ?? null);
|
|
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
|
+
}
|
|
36
|
+
});
|
|
37
|
+
if (!inputGroupChanged) {
|
|
38
|
+
for (const field in formGroup.controls) {
|
|
39
|
+
const control = fields?.find((x) => x.name == field);
|
|
40
|
+
if (!control) {
|
|
41
|
+
formGroup.removeControl(field);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return formGroup;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getColumnClass(value?: number): string | undefined {
|
|
50
|
+
if (!value) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
switch (value) {
|
|
55
|
+
case 1:
|
|
56
|
+
return 'col-12';
|
|
57
|
+
case 2:
|
|
58
|
+
return 'col-12 col-md-6';
|
|
59
|
+
case 3:
|
|
60
|
+
return 'col-12 col-md-4';
|
|
61
|
+
case 4:
|
|
62
|
+
return 'col-12 col-md-3';
|
|
63
|
+
case 6:
|
|
64
|
+
return 'col-12 col-md-2';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return 'col-12 col-md-1';
|
|
68
|
+
}
|