@verisoft/ui-primeng 20.0.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.
Files changed (219) hide show
  1. package/.eslintrc.json +43 -0
  2. package/assets/.gitkeep +0 -0
  3. package/jest.config.ts +22 -0
  4. package/ng-package.json +14 -0
  5. package/package.json +6 -18
  6. package/project.json +36 -0
  7. package/src/index.ts +34 -0
  8. package/src/lib/components/breadcrumb/breadcrumb.component.html +11 -0
  9. package/src/lib/components/breadcrumb/breadcrumb.component.scss +18 -0
  10. package/src/lib/components/breadcrumb/breadcrumb.component.spec.ts +21 -0
  11. package/src/lib/components/breadcrumb/breadcrumb.component.stories.ts +36 -0
  12. package/src/lib/components/breadcrumb/breadcrumb.component.ts +27 -0
  13. package/src/lib/components/breadcrumb/breadcrumb.pipe.ts +13 -0
  14. package/src/lib/components/breadcrumb/index.ts +1 -0
  15. package/src/lib/components/button/button-severity.pipe.ts +20 -0
  16. package/src/lib/components/button/button.component.html +20 -0
  17. package/src/lib/components/button/button.component.scss +0 -0
  18. package/src/lib/components/button/button.component.spec.ts +21 -0
  19. package/src/lib/components/button/button.component.ts +49 -0
  20. package/src/lib/components/button/index.ts +1 -0
  21. package/src/lib/components/calendar/calendar.component.html +53 -0
  22. package/src/lib/components/calendar/calendar.component.scss +0 -0
  23. package/src/lib/components/calendar/calendar.component.spec.ts +21 -0
  24. package/src/lib/components/calendar/calendar.component.ts +70 -0
  25. package/src/lib/components/calendar/index.ts +1 -0
  26. package/src/lib/components/checkbox/checkbox.component.html +20 -0
  27. package/src/lib/components/checkbox/checkbox.component.scss +15 -0
  28. package/src/lib/components/checkbox/checkbox.component.spec.ts +21 -0
  29. package/src/lib/components/checkbox/checkbox.component.stories.ts +72 -0
  30. package/src/lib/components/checkbox/checkbox.component.ts +46 -0
  31. package/src/lib/components/checkbox/index.ts +1 -0
  32. package/src/lib/components/confirm-dialog/confirm-dialog.component.html +51 -0
  33. package/src/lib/components/confirm-dialog/confirm-dialog.component.scss +3 -0
  34. package/src/lib/components/confirm-dialog/confirm-dialog.component.spec.ts +21 -0
  35. package/src/lib/components/confirm-dialog/confirm-dialog.component.stories.ts +74 -0
  36. package/src/lib/components/confirm-dialog/confirm-dialog.component.ts +73 -0
  37. package/src/lib/components/confirm-dialog/index.ts +1 -0
  38. package/src/lib/components/dropdown/dropdown.component.html +93 -0
  39. package/src/lib/components/dropdown/dropdown.component.scss +16 -0
  40. package/src/lib/components/dropdown/dropdown.component.spec.ts +21 -0
  41. package/src/lib/components/dropdown/dropdown.component.ts +139 -0
  42. package/src/lib/components/dropdown/index.ts +1 -0
  43. package/src/lib/components/dropdown-button/dropdown-button.component.html +1 -0
  44. package/src/lib/components/dropdown-button/dropdown-button.component.ts +20 -0
  45. package/src/lib/components/dropdown-button/index.ts +1 -0
  46. package/src/lib/components/errors/error.component.html +7 -0
  47. package/src/lib/components/errors/error.component.scss +3 -0
  48. package/src/lib/components/errors/error.component.ts +34 -0
  49. package/src/lib/components/errors/index.ts +1 -0
  50. package/src/lib/components/feature-list/directives/feature-list-column.directive.ts +32 -0
  51. package/src/lib/components/feature-list/directives/feature-list-filter-field.directive.ts +8 -0
  52. package/src/lib/components/feature-list/feature-list-filter.pipe.ts +21 -0
  53. package/src/lib/components/feature-list/feature-list-page.component.ts +32 -0
  54. package/src/lib/components/feature-list/feature-list-page.model.ts +42 -0
  55. package/src/lib/components/feature-list/feature-list.component.html +59 -0
  56. package/src/lib/components/feature-list/feature-list.component.scss +10 -0
  57. package/src/lib/components/feature-list/feature-list.component.ts +341 -0
  58. package/src/lib/components/feature-list/index.ts +5 -0
  59. package/src/lib/components/filter/directives/filter-field.directive.ts +34 -0
  60. package/src/lib/components/filter/filter.component.html +68 -0
  61. package/src/lib/components/filter/filter.component.scss +0 -0
  62. package/src/lib/components/filter/filter.component.spec.ts +21 -0
  63. package/src/lib/components/filter/filter.component.stories.ts +23 -0
  64. package/src/lib/components/filter/filter.component.ts +281 -0
  65. package/src/lib/components/filter/filter.model.ts +18 -0
  66. package/src/lib/components/filter/index.ts +2 -0
  67. package/src/lib/components/form-field/form-field.component.html +42 -0
  68. package/src/lib/components/form-field/form-field.component.scss +0 -0
  69. package/src/lib/components/form-field/form-field.component.spec.ts +21 -0
  70. package/src/lib/components/form-field/form-field.component.stories.ts +69 -0
  71. package/src/lib/components/form-field/form-field.component.ts +37 -0
  72. package/src/lib/components/form-field/index.ts +1 -0
  73. package/src/lib/components/header/header.component.html +84 -0
  74. package/src/lib/components/header/header.component.scss +0 -0
  75. package/src/lib/components/header/header.component.spec.ts +21 -0
  76. package/src/lib/components/header/header.component.stories.ts +24 -0
  77. package/src/lib/components/header/header.component.ts +65 -0
  78. package/src/lib/components/header/index.ts +2 -0
  79. package/src/lib/components/header/services/header-provider.service.ts +15 -0
  80. package/src/lib/components/icon/icon.component.html +2 -0
  81. package/src/lib/components/icon/icon.component.scss +51 -0
  82. package/src/lib/components/icon/icon.component.ts +86 -0
  83. package/src/lib/components/icon/index.ts +2 -0
  84. package/src/lib/components/input-group/index.ts +1 -0
  85. package/src/lib/components/input-group/input-group.component.html +34 -0
  86. package/src/lib/components/input-group/input-group.component.spec.ts +21 -0
  87. package/src/lib/components/input-group/input-group.component.ts +58 -0
  88. package/src/lib/components/loader/index.ts +1 -0
  89. package/src/lib/components/loader/loader.component.html +5 -0
  90. package/src/lib/components/loader/loader.component.scss +0 -0
  91. package/src/lib/components/loader/loader.component.spec.ts +21 -0
  92. package/src/lib/components/loader/loader.component.ts +16 -0
  93. package/src/lib/components/multiselect/index.ts +1 -0
  94. package/src/lib/components/multiselect/multiselect.component.html +67 -0
  95. package/src/lib/components/multiselect/multiselect.component.scss +0 -0
  96. package/src/lib/components/multiselect/multiselect.component.spec.ts +21 -0
  97. package/src/lib/components/multiselect/multiselect.component.ts +120 -0
  98. package/src/lib/components/number-input/index.ts +1 -0
  99. package/src/lib/components/number-input/number-input.component.html +22 -0
  100. package/src/lib/components/number-input/number-input.component.spec.ts +21 -0
  101. package/src/lib/components/number-input/number-input.component.ts +55 -0
  102. package/src/lib/components/page-header/index.ts +1 -0
  103. package/src/lib/components/page-header/page-header.component.html +35 -0
  104. package/src/lib/components/page-header/page-header.component.scss +0 -0
  105. package/src/lib/components/page-header/page-header.component.spec.ts +21 -0
  106. package/src/lib/components/page-header/page-header.component.ts +31 -0
  107. package/src/lib/components/password/index.ts +1 -0
  108. package/src/lib/components/password/password.component.html +24 -0
  109. package/src/lib/components/password/password.component.scss +0 -0
  110. package/src/lib/components/password/password.component.spec.ts +21 -0
  111. package/src/lib/components/password/password.component.ts +56 -0
  112. package/src/lib/components/radiobutton/index.ts +1 -0
  113. package/src/lib/components/radiobutton/radiobutton.component.html +34 -0
  114. package/src/lib/components/radiobutton/radiobutton.component.scss +6 -0
  115. package/src/lib/components/radiobutton/radiobutton.component.spec.ts +21 -0
  116. package/src/lib/components/radiobutton/radiobutton.component.stories.ts +71 -0
  117. package/src/lib/components/radiobutton/radiobutton.component.ts +61 -0
  118. package/src/lib/components/section/index.ts +1 -0
  119. package/src/lib/components/section/section.component.html +25 -0
  120. package/src/lib/components/section/section.component.scss +0 -0
  121. package/src/lib/components/section/section.component.spec.ts +21 -0
  122. package/src/lib/components/section/section.component.ts +31 -0
  123. package/src/lib/components/shared-components/.eslintrc.json +42 -0
  124. package/src/lib/components/shared-components/action-button-group/action-button-group.component.html +25 -0
  125. package/src/lib/components/shared-components/action-button-group/action-button-group.component.scss +0 -0
  126. package/src/lib/components/shared-components/action-button-group/action-button-group.component.spec.ts +21 -0
  127. package/src/lib/components/shared-components/action-button-group/action-button-group.component.ts +111 -0
  128. package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.html +10 -0
  129. package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.scss +0 -0
  130. package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.spec.ts +21 -0
  131. package/src/lib/components/shared-components/action-button-group/components/action-button/action-button.component.ts +69 -0
  132. package/src/lib/components/shared-components/action-button-group/index.ts +2 -0
  133. package/src/lib/components/shared-components/dynamic-component/dynamic-component-factory.service.ts +142 -0
  134. package/src/lib/components/shared-components/dynamic-component/dynamic-component.component.ts +56 -0
  135. package/src/lib/components/shared-components/dynamic-component/index.ts +2 -0
  136. package/src/lib/components/shared-components/generic-field/generic-field.component.html +98 -0
  137. package/src/lib/components/shared-components/generic-field/generic-field.component.spec.ts +21 -0
  138. package/src/lib/components/shared-components/generic-field/generic-field.component.ts +90 -0
  139. package/src/lib/components/shared-components/generic-field/index.ts +1 -0
  140. package/src/lib/components/shared-components/generic-form/generic-form.component.html +46 -0
  141. package/src/lib/components/shared-components/generic-form/generic-form.component.spec.ts +21 -0
  142. package/src/lib/components/shared-components/generic-form/generic-form.component.ts +56 -0
  143. package/src/lib/components/shared-components/generic-form/generic-form.model.spec.ts +82 -0
  144. package/src/lib/components/shared-components/generic-form/generic-form.model.ts +68 -0
  145. package/src/lib/components/shared-components/generic-form/index.ts +2 -0
  146. package/src/lib/components/shared-components/index.ts +4 -0
  147. package/src/lib/components/side-menu/index.ts +2 -0
  148. package/src/lib/components/side-menu/side-menu.component.html +53 -0
  149. package/src/lib/components/side-menu/side-menu.component.scss +0 -0
  150. package/src/lib/components/side-menu/side-menu.component.spec.ts +21 -0
  151. package/src/lib/components/side-menu/side-menu.component.ts +96 -0
  152. package/src/lib/components/side-menu/side-menu.module.ts +66 -0
  153. package/src/lib/components/slider/index.ts +1 -0
  154. package/src/lib/components/slider/slider.component.html +19 -0
  155. package/src/lib/components/slider/slider.component.spec.ts +21 -0
  156. package/src/lib/components/slider/slider.component.ts +56 -0
  157. package/src/lib/components/snackbar/index.ts +2 -0
  158. package/src/lib/components/snackbar/services/snackbar.service.ts +45 -0
  159. package/src/lib/components/snackbar/snackbar.component.html +3 -0
  160. package/src/lib/components/snackbar/snackbar.component.scss +0 -0
  161. package/src/lib/components/snackbar/snackbar.component.spec.ts +21 -0
  162. package/src/lib/components/snackbar/snackbar.component.stories.ts +70 -0
  163. package/src/lib/components/snackbar/snackbar.component.ts +25 -0
  164. package/src/lib/components/stepper/index.ts +1 -0
  165. package/src/lib/components/stepper/stepper.component.html +35 -0
  166. package/src/lib/components/stepper/stepper.component.spec.ts +21 -0
  167. package/src/lib/components/stepper/stepper.component.ts +39 -0
  168. package/src/lib/components/switch/index.ts +1 -0
  169. package/src/lib/components/switch/switch.component.html +18 -0
  170. package/src/lib/components/switch/switch.component.scss +0 -0
  171. package/src/lib/components/switch/switch.component.spec.ts +21 -0
  172. package/src/lib/components/switch/switch.component.stories.ts +65 -0
  173. package/src/lib/components/switch/switch.component.ts +52 -0
  174. package/src/lib/components/tab-view/index.ts +2 -0
  175. package/src/lib/components/tab-view/tab-view-item.component.ts +22 -0
  176. package/src/lib/components/tab-view/tab-view.component.html +41 -0
  177. package/src/lib/components/tab-view/tab-view.component.ts +55 -0
  178. package/src/lib/components/table/index.ts +1 -0
  179. package/src/lib/components/table/table-filter.pipe.ts +59 -0
  180. package/src/lib/components/table/table.component.html +127 -0
  181. package/src/lib/components/table/table.component.scss +11 -0
  182. package/src/lib/components/table/table.component.spec.ts +21 -0
  183. package/src/lib/components/table/table.component.stories.ts +55 -0
  184. package/src/lib/components/table/table.component.ts +288 -0
  185. package/src/lib/components/table/table.models.ts +26 -0
  186. package/src/lib/components/tag/index.ts +2 -0
  187. package/src/lib/components/tag/tag.component.html +12 -0
  188. package/src/lib/components/tag/tag.component.scss +33 -0
  189. package/src/lib/components/tag/tag.component.ts +83 -0
  190. package/src/lib/components/textarea/index.ts +1 -0
  191. package/src/lib/components/textarea/textarea.component.html +40 -0
  192. package/src/lib/components/textarea/textarea.component.scss +5 -0
  193. package/src/lib/components/textarea/textarea.component.spec.ts +21 -0
  194. package/src/lib/components/textarea/textarea.component.stories.ts +98 -0
  195. package/src/lib/components/textarea/textarea.component.ts +62 -0
  196. package/src/lib/components/textfield/index.ts +1 -0
  197. package/src/lib/components/textfield/textfield.component.html +82 -0
  198. package/src/lib/components/textfield/textfield.component.scss +23 -0
  199. package/src/lib/components/textfield/textfield.component.spec.ts +21 -0
  200. package/src/lib/components/textfield/textfield.component.stories.ts +85 -0
  201. package/src/lib/components/textfield/textfield.component.ts +68 -0
  202. package/src/lib/components/tooltip/index.ts +1 -0
  203. package/src/lib/components/tooltip/tooltip.component.html +3 -0
  204. package/src/lib/components/tooltip/tooltip.component.ts +17 -0
  205. package/src/lib/icons.ts +36 -0
  206. package/src/lib/interceptors/http-error-message.interceptor.ts +35 -0
  207. package/src/lib/pages/not-found-page/not-found-page.component.html +26 -0
  208. package/src/lib/pages/not-found-page/not-found-page.component.scss +0 -0
  209. package/src/lib/pages/not-found-page/not-found-page.component.spec.ts +21 -0
  210. package/src/lib/pages/not-found-page/not-found-page.component.ts +16 -0
  211. package/src/tab-view.ts +1 -0
  212. package/src/test-setup.ts +8 -0
  213. package/tsconfig.json +29 -0
  214. package/tsconfig.lib.json +18 -0
  215. package/tsconfig.lib.prod.json +9 -0
  216. package/tsconfig.spec.json +16 -0
  217. package/fesm2022/verisoft-ui-primeng.mjs +0 -2866
  218. package/fesm2022/verisoft-ui-primeng.mjs.map +0 -1
  219. package/index.d.ts +0 -729
@@ -0,0 +1,21 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { FilterComponent } from './filter.component';
3
+
4
+ describe('VerisoftTableFilterComponent', () => {
5
+ let component: FilterComponent<any>;
6
+ let fixture: ComponentFixture<FilterComponent<any>>;
7
+
8
+ beforeEach(async () => {
9
+ await TestBed.configureTestingModule({
10
+ imports: [FilterComponent],
11
+ }).compileComponents();
12
+
13
+ fixture = TestBed.createComponent(FilterComponent);
14
+ component = fixture.componentInstance;
15
+ fixture.detectChanges();
16
+ });
17
+
18
+ it('should create', () => {
19
+ expect(component).toBeTruthy();
20
+ });
21
+ });
@@ -0,0 +1,23 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular';
2
+ import { FilterComponent } from './filter.component';
3
+
4
+ const meta: Meta<FilterComponent<any>> = {
5
+ component: FilterComponent,
6
+ title: 'VerisoftTableFilterComponent',
7
+ };
8
+ export default meta;
9
+ type Story = StoryObj<FilterComponent<any>>;
10
+
11
+ export const Primary: Story = {
12
+ args: {
13
+ filterDefinitions: [],
14
+ debounceTime: 0,
15
+ },
16
+ };
17
+
18
+ export const Heading: Story = {
19
+ args: {
20
+ filterDefinitions: [],
21
+ debounceTime: 0,
22
+ },
23
+ };
@@ -0,0 +1,281 @@
1
+ import { AsyncPipe } from '@angular/common';
2
+ import {
3
+ AfterContentInit,
4
+ ChangeDetectionStrategy,
5
+ ChangeDetectorRef,
6
+ Component,
7
+ ContentChildren,
8
+ forwardRef,
9
+ inject,
10
+ Input,
11
+ OnChanges,
12
+ OnInit,
13
+ QueryList,
14
+ SimpleChanges,
15
+ } from '@angular/core';
16
+ import {
17
+ FormGroup,
18
+ NG_VALUE_ACCESSOR,
19
+ ReactiveFormsModule,
20
+ } from '@angular/forms';
21
+ import { BaseHttpService } from '@verisoft/core';
22
+ import {
23
+ ButtonShortCutDirective,
24
+ DEFAULT_DEBOUNCE_TIME,
25
+ DialogService,
26
+ FieldSize,
27
+ FILTER_COMPONENT_TOKEN,
28
+ FilterCore,
29
+ GenericFieldDefinition,
30
+ isFilterEmpty,
31
+ ScreenSizeService,
32
+ UnsubscribeComponent,
33
+ } from '@verisoft/ui-core';
34
+ import {
35
+ BehaviorSubject,
36
+ combineLatestWith,
37
+ debounceTime,
38
+ distinctUntilChanged,
39
+ map,
40
+ Observable,
41
+ startWith,
42
+ takeUntil,
43
+ } from 'rxjs';
44
+ import { Icons } from '../../icons';
45
+ import { ButtonComponent } from '../button';
46
+ import { generateFormGroup, GenericFormComponent } from '../shared-components/generic-form';
47
+ import { TextfieldComponent } from '../textfield';
48
+ import { FilterFieldDirective } from './directives/filter-field.directive';
49
+ import { getFilledControlCount } from './filter.model';
50
+
51
+ type FilterValueType = { [key: string]: unknown };
52
+
53
+ @Component({
54
+ selector: 'v-filter',
55
+ imports: [
56
+ AsyncPipe,
57
+ ReactiveFormsModule,
58
+ TextfieldComponent,
59
+ GenericFormComponent,
60
+ ButtonComponent,
61
+ ButtonShortCutDirective,
62
+ ],
63
+ providers: [
64
+ {
65
+ provide: NG_VALUE_ACCESSOR,
66
+ useExisting: forwardRef(() => FilterComponent),
67
+ multi: true,
68
+ },
69
+ {
70
+ provide: FILTER_COMPONENT_TOKEN,
71
+ useExisting: FilterComponent,
72
+ },
73
+ ],
74
+ templateUrl: './filter.component.html',
75
+ styleUrl: './filter.component.scss',
76
+ changeDetection: ChangeDetectionStrategy.OnPush
77
+ })
78
+ export class FilterComponent<T extends object>
79
+ extends UnsubscribeComponent
80
+ implements OnChanges, OnInit, AfterContentInit, FilterCore
81
+ {
82
+ @ContentChildren(FilterFieldDirective)
83
+ fieldDeclarations!: QueryList<FilterFieldDirective>;
84
+
85
+ @Input() fields: GenericFieldDefinition[] = [];
86
+
87
+ @Input() filters: GenericFieldDefinition[] = [];
88
+
89
+ @Input() title?: string;
90
+
91
+ @Input() fulltextFieldName = 'searchField';
92
+
93
+ @Input() showFulltext = true;
94
+
95
+ @Input() showFilters = true;
96
+
97
+ @Input() autoBind = true;
98
+
99
+ @Input() debounceTime?: number = DEFAULT_DEBOUNCE_TIME;
100
+
101
+ icons = Icons;
102
+
103
+ fieldDefinitios$?: Observable<GenericFieldDefinition[]>;
104
+
105
+ formGroup$?: Observable<FormGroup>;
106
+
107
+ simpleFormFieldDefinitions$?: Observable<GenericFieldDefinition[]>;
108
+
109
+ private searchField: GenericFieldDefinition = {
110
+ name: this.fulltextFieldName,
111
+ };
112
+
113
+ private onTouch?: () => void;
114
+
115
+ private onChange?: (value: FilterValueType | undefined) => void;
116
+
117
+ private inputFields$ = new BehaviorSubject<
118
+ GenericFieldDefinition[] | undefined
119
+ >([...this.fields ?? [], ...this.filters ?? []]);
120
+
121
+ FieldSize = FieldSize;
122
+
123
+ protected screenSizeService = inject(ScreenSizeService);
124
+ protected changeDetectorRef = inject(ChangeDetectorRef);
125
+ protected dialogService = inject(DialogService);
126
+
127
+ service!: BaseHttpService<T>;
128
+
129
+ formGroup = new FormGroup({});
130
+
131
+ filledFiltersCount$: Observable<string> = this.formGroup.valueChanges.pipe(
132
+ startWith(this.formGroup),
133
+ map(() => getFilledControlCount(this.formGroup).toString())
134
+ );
135
+
136
+ private lastFormFields: GenericFieldDefinition[] = [];
137
+
138
+ ngOnInit(): void {
139
+ this.formGroup.valueChanges
140
+ .pipe(
141
+ takeUntil(this.destroyed$),
142
+ debounceTime(this.debounceTime ?? DEFAULT_DEBOUNCE_TIME),
143
+ map((x) => this.convertFilter(x)),
144
+ distinctUntilChanged()
145
+ )
146
+ .subscribe((value) => this.onChange?.(value));
147
+ }
148
+
149
+ ngOnChanges(changes: SimpleChanges): void {
150
+ if (changes['fields'] || changes['filters']) {
151
+ this.inputFields$.next([...this.fields ?? [], ...this.filters ?? []]);
152
+ }
153
+ }
154
+
155
+ ngAfterContentInit(): void {
156
+ const fieldDeclaratios$: Observable<GenericFieldDefinition[]> =
157
+ this.fieldDeclarations.changes.pipe(
158
+ startWith({}),
159
+ map(() => this.fieldDeclarations.toArray())
160
+ );
161
+
162
+ this.fieldDefinitios$ = this.inputFields$.pipe(
163
+ combineLatestWith(fieldDeclaratios$),
164
+ map(([inputs, views]) => {
165
+ this.searchField.name = this.fulltextFieldName;
166
+ this.lastFormFields = [this.searchField, ...(inputs ?? []), ...views];
167
+ return this.lastFormFields;
168
+ })
169
+ );
170
+
171
+ this.simpleFormFieldDefinitions$ = this.fieldDefinitios$.pipe(
172
+ map((fields) => {
173
+ return fields
174
+ .filter((x) => x.name !== this.fulltextFieldName)
175
+ .map((x) => ({ ...x, floatLabel: true, size: FieldSize.large }));
176
+ })
177
+ );
178
+
179
+ this.formGroup$ = this.fieldDefinitios$.pipe(
180
+ map((fields) =>
181
+ generateFormGroup(fields, this.formGroup, undefined, false)
182
+ )
183
+ );
184
+
185
+ this.changeDetectorRef.detectChanges();
186
+ }
187
+
188
+ protected openFilter() {
189
+ const fields = this.lastFormFields.map((x) => ({
190
+ ...x,
191
+ label:
192
+ x.name === this.fulltextFieldName ? 'Fulltext' : x.label ?? x.name,
193
+ }));
194
+
195
+ const formGroup = generateFormGroup(
196
+ this.lastFormFields,
197
+ undefined,
198
+ undefined,
199
+ false
200
+ );
201
+ formGroup.patchValue(this.formGroup.value);
202
+ this.dialogService.showDialog({
203
+ title: 'Set filters',
204
+ headerIcon: this.icons.filter,
205
+ severity: 'primary',
206
+ componentType: GenericFormComponent,
207
+ data: {
208
+ formGroup,
209
+ fields: fields,
210
+ columns: 1,
211
+ },
212
+ confirmButtonFn: () => this.setFilterValues(formGroup),
213
+ confirmButtonText: 'Apply',
214
+ cancelButtonFn: () => this.clear(),
215
+ cancelButtonText: 'Clear all',
216
+ showCancelButton: true,
217
+ closable: false,
218
+ });
219
+ }
220
+
221
+ protected openSearch() {
222
+ this.dialogService.showDialog({
223
+ headerIcon: 'pi pi-search',
224
+ severity: 'primary',
225
+ innerHTML: '<p>Search</p>',
226
+ confirmButtonFn: () => this.submitValue(),
227
+ confirmButtonText: 'Apply',
228
+ cancelButtonFn: () => this.clear(),
229
+ cancelButtonText: 'Clear all',
230
+ showCancelButton: true,
231
+ closable: false,
232
+ });
233
+ }
234
+
235
+ writeValue(data: FilterValueType): void {
236
+ this.formGroup.patchValue(data);
237
+ }
238
+
239
+ registerOnChange(fn: (value: FilterValueType | undefined) => void): void {
240
+ this.onChange = fn;
241
+ }
242
+
243
+ registerOnTouched(fn: () => void): void {
244
+ this.onTouch = fn;
245
+ }
246
+
247
+ setDisabledState?(isDisabled: boolean): void {
248
+ isDisabled ? this.formGroup.disable() : this.formGroup.enable();
249
+ }
250
+
251
+ submitValue() {
252
+ if (!this.autoBind) {
253
+ this.onChange?.(this.formGroup.value);
254
+ }
255
+ }
256
+
257
+ setFilterValues(dialogFormGroup: FormGroup) {
258
+ this.formGroup.setValue(dialogFormGroup.value);
259
+ this.submitValue();
260
+ }
261
+
262
+ clear() {
263
+ this.formGroup.reset();
264
+ this.submitValue();
265
+ }
266
+
267
+ private convertFilter(
268
+ value: FilterValueType | undefined
269
+ ): FilterValueType | undefined {
270
+ if (value == undefined) {
271
+ return undefined;
272
+ }
273
+
274
+ const isEmpty = isFilterEmpty(value);
275
+ if (isEmpty) {
276
+ return undefined;
277
+ }
278
+
279
+ return value;
280
+ }
281
+ }
@@ -0,0 +1,18 @@
1
+ import { FormGroup } from '@angular/forms';
2
+
3
+ export function getFilledControlCount(formGroup: FormGroup): number {
4
+ let count = 0;
5
+ Object.keys(formGroup.controls).forEach((key) => {
6
+ const control = formGroup.get(key);
7
+ if (control?.value) {
8
+ if (typeof control.value === 'boolean') {
9
+ count++;
10
+ }
11
+ if (typeof control.value === 'string' && control.value.trim() !== '') {
12
+ count++;
13
+ }
14
+ }
15
+ });
16
+
17
+ return count;
18
+ }
@@ -0,0 +1,2 @@
1
+ export * from './filter.component';
2
+ export * from './directives/filter-field.directive';
@@ -0,0 +1,42 @@
1
+ <div class="v-form-field mt-3" [attr.data-testId]="testId">
2
+ <div [ngClass]="{ 'd-block d-md-flex': display === 'flex', 'd-lg-flex': display === 'block' }">
3
+ <div class="col-12 col-md-4 d-flex align-items-center">
4
+ <label
5
+ class="v-formfield-label d-flex align-items-center"
6
+ [ngClass]="{
7
+ 'pb-2': display === 'block',
8
+ 'text-error': (errorProvider.mapError(ngControl?.errors ?? [])) && ngControl?.dirty,
9
+ 'text-warning': (ngControl?.errors | warning) && ngControl?.dirty,
10
+ 'text-default': !ngControl?.invalid && !ngControl?.dirty,
11
+ 'text-secondary': !ngControl?.invalid && ngControl?.dirty
12
+ }"
13
+ >{{ label }}@if (label) {
14
+ <span>:</span>
15
+ }
16
+ @if (required) {
17
+ <span class="text-error ps-1">*</span>
18
+ }
19
+ </label>
20
+ @if (tooltip) {
21
+ <i
22
+ [pTooltip]="tooltip"
23
+ class="ps-2 text-default v-tooltip {{ icons.infoCircle }}"
24
+ ></i>
25
+ }
26
+ </div>
27
+ <div
28
+ class="col-sm-12 col-md-8 col-lg-8"
29
+ >
30
+ <div
31
+ class="v-form-field-content align-items-center w-100"
32
+ [ngClass]="{ 'd-flex': display === 'flex', 'd-block': display === 'block', 'input-warning': ngControl?.errors | warning }"
33
+ >
34
+ <ng-content></ng-content>
35
+ </div>
36
+ </div>
37
+ <div class="align-content-center">
38
+ <ng-container>
39
+ </ng-container>
40
+ </div>
41
+ </div>
42
+ </div>
@@ -0,0 +1,21 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { FormFieldComponent } from './form-field.component';
3
+
4
+ describe('FormFieldComponent', () => {
5
+ let component: FormFieldComponent;
6
+ let fixture: ComponentFixture<FormFieldComponent>;
7
+
8
+ beforeEach(async () => {
9
+ await TestBed.configureTestingModule({
10
+ imports: [FormFieldComponent],
11
+ }).compileComponents();
12
+
13
+ fixture = TestBed.createComponent(FormFieldComponent);
14
+ component = fixture.componentInstance;
15
+ fixture.detectChanges();
16
+ });
17
+
18
+ it('should create', () => {
19
+ expect(component).toBeTruthy();
20
+ });
21
+ });
@@ -0,0 +1,69 @@
1
+ import { NgControl } from '@angular/forms';
2
+ import type { Meta, StoryObj } from '@storybook/angular';
3
+ import { within, expect } from '@storybook/test';
4
+ import { FormFieldComponent } from './form-field.component';
5
+
6
+ const meta: Meta<FormFieldComponent> = {
7
+ component: FormFieldComponent,
8
+ title: 'FormFieldComponent',
9
+ };
10
+ export default meta;
11
+ type Story = StoryObj<FormFieldComponent>;
12
+
13
+ export const Primary: Story = {
14
+ parameters: {
15
+ controls: { expanded: true },
16
+ },
17
+ args: {
18
+ label: 'Label showcase',
19
+ tooltip: 'This is a tooltip lorem ipsum',
20
+ required: false,
21
+ testId: '123',
22
+ display: 'flex',
23
+ ngControl: {} as NgControl,
24
+ },
25
+ argTypes: {
26
+ ngControl: {
27
+ control: false,
28
+ description: 'NgControl which is provided from a form component',
29
+ },
30
+ display: {
31
+ options: ['flex', 'block'],
32
+ control: {
33
+ type: 'radio',
34
+ },
35
+ description:
36
+ 'Defines if the **FormFieldComponent** is in `flex` or `block` display mode',
37
+ },
38
+ required: {
39
+ control: {
40
+ type: 'boolean',
41
+ },
42
+ description: 'Defines if the **FormFieldComponent** is `required`',
43
+ },
44
+ testId: {
45
+ control: {
46
+ type: 'text',
47
+ },
48
+ description: 'Sets the **FormFieldComponent** `test id`',
49
+ },
50
+ label: {
51
+ control: {
52
+ type: 'text',
53
+ },
54
+ description: 'Sets the **FormFieldComponent** `label`',
55
+ },
56
+ tooltip: {
57
+ control: {
58
+ type: 'text',
59
+ },
60
+ description: 'Sets the **FormFieldComponent** `tooltip`',
61
+ },
62
+ },
63
+ play: async ({ canvasElement }: any) => {
64
+ const canvas = within(canvasElement);
65
+ expect(canvas.getByText('Label showcase')).toBeTruthy();
66
+ expect(canvas.queryAllByText('This is a tooltip lorem ipsum')).toBeTruthy();
67
+ expect(canvas.findByTestId('123')).toBeTruthy();
68
+ },
69
+ };
@@ -0,0 +1,37 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, inject, Input, Optional, Self } from '@angular/core';
3
+ import { NgControl, ReactiveFormsModule } from '@angular/forms';
4
+ import { ERROR_PROVIDER_TOKEN } from '@verisoft/core';
5
+ import { BaseFormInputComponent, FormFieldCore, WarningPipe } from '@verisoft/ui-core';
6
+ import { MessageModule } from 'primeng/message';
7
+ import { TooltipModule } from 'primeng/tooltip';
8
+ import { Icons } from '../../icons';
9
+
10
+ @Component({
11
+ selector: 'v-form-field',
12
+ imports: [
13
+ CommonModule,
14
+ WarningPipe,
15
+ ReactiveFormsModule,
16
+ MessageModule,
17
+ TooltipModule,
18
+ ],
19
+ templateUrl: './form-field.component.html',
20
+ styleUrl: './form-field.component.scss'
21
+ })
22
+ export class FormFieldComponent
23
+ extends BaseFormInputComponent
24
+ implements FormFieldCore
25
+ {
26
+ @Input() display: 'flex' | 'block' = 'block';
27
+
28
+ @Input() variant!: 'simple';
29
+
30
+ protected readonly errorProvider = inject(ERROR_PROVIDER_TOKEN)
31
+
32
+ icons = Icons;
33
+
34
+ constructor(@Optional() @Self() ngControl: NgControl) {
35
+ super(ngControl);
36
+ }
37
+ }
@@ -0,0 +1 @@
1
+ export * from './form-field.component';
@@ -0,0 +1,84 @@
1
+ <div
2
+ class="v-header d-flex w-100 text-align-end"
3
+ [ngStyle]="{ position: exampleHeader ? 'relative' : 'fixed' }"
4
+ >
5
+ @if (screenSizeService.isMobileBlock | async) {
6
+ <div class="burger-menu">
7
+ <v-button
8
+ [icon]="menuVisible ? icons.cross : icons.action"
9
+ (click)="toggleMenu()"
10
+ />
11
+ <div class="logo mt-3" [routerLink]="[logoRouterLink]">
12
+ <img [src]="logoUrl" alt=""/>
13
+ </div>
14
+ </div>
15
+ }
16
+ <div class="v-header-title col-auto">
17
+ <p class="text-primary text-nowrap d-none d-md-block ps-3 m-0 w-100">
18
+ {{ title }}
19
+ </p>
20
+ <div class="col-8 col-md-auto ps-3 m-0 w-100">
21
+ <ng-content select="[module]"></ng-content>
22
+ </div>
23
+ </div>
24
+ @if ((screenSizeService.isMobileBlock | async) === false) {
25
+ <div class="w-100 text-start justify-content-start align-content-center">
26
+ <ng-content select="[breadcrumbs]"></ng-content>
27
+ </div>
28
+ <div class="col-auto d-flex align-items-center justify-content-end p-4">
29
+ <div class="d-flex aling-items-center">
30
+ <p-avatar
31
+ image="assets/primeng/images/_global/jara.png"
32
+ styleClass="me-2"
33
+ size="large"
34
+ shape="circle"
35
+ />
36
+ <div class="card align-content-center pe-3">
37
+ <p
38
+ class="text-primary m-0 header-username"
39
+ [innerHTML]="userName"
40
+ ></p>
41
+ <p
42
+ class="text-default m-0 header-userrole"
43
+ [innerHTML]="userRole"
44
+ ></p>
45
+ </div>
46
+ </div>
47
+ <div class="d-flex gap-4 align-items-center">
48
+ <ng-content select="[useractions]"/>
49
+ </div>
50
+ </div>
51
+ }
52
+ @if (screenSizeService.isMobileBlock | async) {
53
+ <div class="user-info-container d-flex align-items-center">
54
+ <div class="d-flex">
55
+ <div class="card pe-3 align-content-center">
56
+ <p-avatar
57
+ image="assets/images/_global/jara.png"
58
+ styleClass="mr-2"
59
+ size="large"
60
+ shape="circle"
61
+ ></p-avatar>
62
+ </div>
63
+ <div class="card align-content-center pe-3 d-flex">
64
+ <div class="user-info">
65
+ <p
66
+ class="text-default m-0 header-username"
67
+ [innerHTML]="userName"
68
+ ></p>
69
+ <p
70
+ class="text-default m-0 header-userrole"
71
+ [innerHTML]="userRole"
72
+ ></p>
73
+ </div>
74
+ <div class="user-actions">
75
+ <ng-content select="[useractions]"></ng-content>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ <div class="d-flex gap-4 align-items-center justify-content-center">
80
+ <ng-content select="[dbcontext]" />
81
+ </div>
82
+ </div>
83
+ }
84
+ </div>
@@ -0,0 +1,21 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { HeaderComponent } from './header.component';
3
+
4
+ describe('HeaderComponent', () => {
5
+ let component: HeaderComponent;
6
+ let fixture: ComponentFixture<HeaderComponent>;
7
+
8
+ beforeEach(async () => {
9
+ await TestBed.configureTestingModule({
10
+ imports: [HeaderComponent],
11
+ }).compileComponents();
12
+
13
+ fixture = TestBed.createComponent(HeaderComponent);
14
+ component = fixture.componentInstance;
15
+ fixture.detectChanges();
16
+ });
17
+
18
+ it('should create', () => {
19
+ expect(component).toBeTruthy();
20
+ });
21
+ });
@@ -0,0 +1,24 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular';
2
+ import { within, expect } from '@storybook/test';
3
+ import { HeaderComponent } from './header.component';
4
+
5
+ const meta: Meta<HeaderComponent> = {
6
+ component: HeaderComponent,
7
+ title: 'HeaderComponent',
8
+ };
9
+ export default meta;
10
+ type Story = StoryObj<HeaderComponent>;
11
+
12
+ export const Primary: Story = {
13
+ args: {
14
+ title: 'verisoft',
15
+ userName: 'Elon Musk',
16
+ userRole: 'Mars Owner',
17
+ },
18
+ play: async ({ canvasElement }: any) => {
19
+ const canvas = within(canvasElement);
20
+ expect(canvas.getByText('verisoft')).toBeTruthy();
21
+ expect(canvas.findByText('Elon Musk')).toBeTruthy();
22
+ expect(canvas.findByText('Mars Owner')).toBeTruthy();
23
+ },
24
+ };