verben-authentication-ui 1.0.37 → 1.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 (159) hide show
  1. package/README.md +23 -1
  2. package/esm2022/src/lib/base/core/base-data-page.facade.mjs +215 -0
  3. package/esm2022/src/lib/base/core/base-data-page.service.mjs +103 -0
  4. package/esm2022/src/lib/base/core/base-data-page.state.mjs +203 -0
  5. package/esm2022/src/lib/base/handlers/filter-handler.service.mjs +53 -0
  6. package/esm2022/src/lib/base/handlers/search-handler.service.mjs +31 -0
  7. package/esm2022/src/lib/base/handlers/sort-handler.service.mjs +49 -0
  8. package/esm2022/src/lib/base/models/api-payload.mjs +4 -0
  9. package/esm2022/src/lib/base/models/page-config.interface.mjs +2 -0
  10. package/esm2022/src/lib/base/public-api.mjs +14 -6
  11. package/esm2022/src/lib/base/utils/column-helpers.mjs +45 -0
  12. package/esm2022/src/lib/components/button/button.component.mjs +3 -3
  13. package/esm2022/src/lib/components/forgot-password/forgot-password.component.mjs +2 -2
  14. package/esm2022/src/lib/components/mail/mail.component.mjs +3 -3
  15. package/esm2022/src/lib/components/mail-validation/mail-validation.component.mjs +5 -5
  16. package/esm2022/src/lib/components/o-auth/o-auth.component.mjs +3 -3
  17. package/esm2022/src/lib/components/otp-input/otp-input.component.mjs +2 -2
  18. package/esm2022/src/lib/components/reset-password/reset-password.component.mjs +2 -2
  19. package/esm2022/src/lib/components/role-control/base-table-style.mjs +6 -6
  20. package/esm2022/src/lib/components/role-control/role-control.component.mjs +3 -3
  21. package/esm2022/src/lib/components/sign-in/sign-in.component.mjs +4 -4
  22. package/esm2022/src/lib/components/sign-up/sign-up.component.mjs +6 -6
  23. package/esm2022/src/lib/components/sso/base-table-style.mjs +6 -6
  24. package/esm2022/src/lib/components/sso/sso-form/sso-form.component.mjs +3 -3
  25. package/esm2022/src/lib/components/sso/sso.component.mjs +3 -3
  26. package/esm2022/src/lib/components/two-factor-auth-otp/two-factor-auth-otp.component.mjs +4 -4
  27. package/esm2022/src/lib/components/two-factor-auth-setup/two-factor-auth-setup.component.mjs +5 -5
  28. package/esm2022/src/lib/components/user-management/public-api.mjs +2 -1
  29. package/esm2022/src/lib/components/user-management/user-management-card/user-management-card.component.mjs +23 -0
  30. package/esm2022/src/lib/components/user-management/user-management-form/user-management-form.component.mjs +53 -91
  31. package/esm2022/src/lib/components/user-management/user-management-table/user-management-table.component.mjs +68 -0
  32. package/esm2022/src/lib/components/user-management/user-management.component.mjs +98 -509
  33. package/esm2022/src/lib/components/user-management/user-management.module.mjs +11 -80
  34. package/esm2022/src/lib/components/user-management/user-status-badge/user-status-badge.component.mjs +8 -6
  35. package/esm2022/src/lib/components/user-management/user.config.mjs +94 -0
  36. package/esm2022/src/lib/components/user-management/user.facade.mjs +118 -0
  37. package/esm2022/src/lib/components/user-management/user.service.mjs +60 -0
  38. package/esm2022/src/lib/components/user-management/user.state.mjs +33 -0
  39. package/esm2022/src/lib/components/user-request/user-request.component.mjs +8 -8
  40. package/esm2022/src/lib/components/user-request-approval/public-api.mjs +2 -2
  41. package/esm2022/src/lib/components/user-request-approval/user-access-request-status-badge/user-access-request-status-badge.component.mjs +8 -6
  42. package/esm2022/src/lib/components/user-request-approval/user-access-request.config.mjs +79 -0
  43. package/esm2022/src/lib/components/user-request-approval/user-access-request.facade.mjs +123 -0
  44. package/esm2022/src/lib/components/user-request-approval/user-access-request.service.mjs +74 -0
  45. package/esm2022/src/lib/components/user-request-approval/user-access-request.state.mjs +26 -0
  46. package/esm2022/src/lib/components/user-request-approval/user-request-approval-card/user-request-approval-card.component.mjs +23 -0
  47. package/esm2022/src/lib/components/user-request-approval/user-request-approval-form/user-request-approval-form.component.mjs +124 -0
  48. package/esm2022/src/lib/components/user-request-approval/user-request-approval-table/user-request-approval-table.component.mjs +44 -0
  49. package/esm2022/src/lib/components/user-request-approval/user-request-approval.component.mjs +101 -273
  50. package/esm2022/src/lib/components/user-request-approval/user-request-approval.module.mjs +10 -74
  51. package/fesm2022/verben-authentication-ui-src-lib-base.mjs +596 -214
  52. package/fesm2022/verben-authentication-ui-src-lib-base.mjs.map +1 -1
  53. package/fesm2022/verben-authentication-ui-src-lib-components-button.mjs +2 -2
  54. package/fesm2022/verben-authentication-ui-src-lib-components-button.mjs.map +1 -1
  55. package/fesm2022/verben-authentication-ui-src-lib-components-forgot-password.mjs +2 -2
  56. package/fesm2022/verben-authentication-ui-src-lib-components-forgot-password.mjs.map +1 -1
  57. package/fesm2022/verben-authentication-ui-src-lib-components-mail-validation.mjs +4 -4
  58. package/fesm2022/verben-authentication-ui-src-lib-components-mail-validation.mjs.map +1 -1
  59. package/fesm2022/verben-authentication-ui-src-lib-components-mail.mjs +2 -2
  60. package/fesm2022/verben-authentication-ui-src-lib-components-mail.mjs.map +1 -1
  61. package/fesm2022/verben-authentication-ui-src-lib-components-o-auth.mjs +2 -2
  62. package/fesm2022/verben-authentication-ui-src-lib-components-o-auth.mjs.map +1 -1
  63. package/fesm2022/verben-authentication-ui-src-lib-components-otp-input.mjs +2 -2
  64. package/fesm2022/verben-authentication-ui-src-lib-components-otp-input.mjs.map +1 -1
  65. package/fesm2022/verben-authentication-ui-src-lib-components-reset-password.mjs +2 -2
  66. package/fesm2022/verben-authentication-ui-src-lib-components-reset-password.mjs.map +1 -1
  67. package/fesm2022/verben-authentication-ui-src-lib-components-role-control.mjs +7 -7
  68. package/fesm2022/verben-authentication-ui-src-lib-components-role-control.mjs.map +1 -1
  69. package/fesm2022/verben-authentication-ui-src-lib-components-sign-in.mjs +3 -3
  70. package/fesm2022/verben-authentication-ui-src-lib-components-sign-in.mjs.map +1 -1
  71. package/fesm2022/verben-authentication-ui-src-lib-components-sign-up.mjs +5 -5
  72. package/fesm2022/verben-authentication-ui-src-lib-components-sign-up.mjs.map +1 -1
  73. package/fesm2022/verben-authentication-ui-src-lib-components-sso.mjs +9 -9
  74. package/fesm2022/verben-authentication-ui-src-lib-components-sso.mjs.map +1 -1
  75. package/fesm2022/verben-authentication-ui-src-lib-components-two-factor-auth-otp.mjs +3 -3
  76. package/fesm2022/verben-authentication-ui-src-lib-components-two-factor-auth-otp.mjs.map +1 -1
  77. package/fesm2022/verben-authentication-ui-src-lib-components-two-factor-auth-setup.mjs +4 -4
  78. package/fesm2022/verben-authentication-ui-src-lib-components-two-factor-auth-setup.mjs.map +1 -1
  79. package/fesm2022/verben-authentication-ui-src-lib-components-user-management.mjs +468 -831
  80. package/fesm2022/verben-authentication-ui-src-lib-components-user-management.mjs.map +1 -1
  81. package/fesm2022/verben-authentication-ui-src-lib-components-user-request-approval.mjs +509 -952
  82. package/fesm2022/verben-authentication-ui-src-lib-components-user-request-approval.mjs.map +1 -1
  83. package/fesm2022/verben-authentication-ui-src-lib-components-user-request.mjs +7 -7
  84. package/fesm2022/verben-authentication-ui-src-lib-components-user-request.mjs.map +1 -1
  85. package/package.json +36 -42
  86. package/src/lib/base/README.md +99 -0
  87. package/src/lib/base/core/base-data-page.facade.d.ts +65 -0
  88. package/src/lib/base/core/base-data-page.service.d.ts +43 -0
  89. package/src/lib/base/core/base-data-page.state.d.ts +68 -0
  90. package/src/lib/base/handlers/filter-handler.service.d.ts +13 -0
  91. package/src/lib/base/handlers/search-handler.service.d.ts +20 -0
  92. package/src/lib/base/handlers/sort-handler.service.d.ts +13 -0
  93. package/src/lib/base/models/api-payload.d.ts +2 -0
  94. package/src/lib/base/models/page-config.interface.d.ts +21 -0
  95. package/src/lib/base/public-api.d.ts +9 -5
  96. package/src/lib/base/utils/column-helpers.d.ts +16 -0
  97. package/src/lib/components/user-management/public-api.d.ts +1 -0
  98. package/src/lib/components/user-management/user-management-card/user-management-card.component.d.ts +11 -0
  99. package/src/lib/components/user-management/user-management-form/user-management-form.component.d.ts +12 -14
  100. package/src/lib/components/user-management/user-management-table/user-management-table.component.d.ts +30 -0
  101. package/src/lib/components/user-management/user-management.component.d.ts +28 -124
  102. package/src/lib/components/user-management/user-management.module.d.ts +8 -8
  103. package/src/lib/components/user-management/user-status-badge/user-status-badge.component.d.ts +1 -1
  104. package/src/lib/components/user-management/user.config.d.ts +13 -0
  105. package/src/lib/components/user-management/user.facade.d.ts +42 -0
  106. package/src/lib/components/user-management/user.service.d.ts +26 -0
  107. package/src/lib/components/user-management/user.state.d.ts +19 -0
  108. package/src/lib/components/user-request-approval/public-api.d.ts +1 -1
  109. package/src/lib/components/user-request-approval/user-access-request-status-badge/user-access-request-status-badge.component.d.ts +1 -1
  110. package/src/lib/components/user-request-approval/user-access-request.config.d.ts +13 -0
  111. package/src/lib/components/user-request-approval/user-access-request.facade.d.ts +36 -0
  112. package/src/lib/components/user-request-approval/user-access-request.service.d.ts +30 -0
  113. package/src/lib/components/user-request-approval/user-access-request.state.d.ts +16 -0
  114. package/src/lib/components/user-request-approval/user-request-approval-card/user-request-approval-card.component.d.ts +11 -0
  115. package/src/lib/components/user-request-approval/user-request-approval-form/user-request-approval-form.component.d.ts +47 -0
  116. package/src/lib/components/user-request-approval/user-request-approval-table/user-request-approval-table.component.d.ts +20 -0
  117. package/src/lib/components/user-request-approval/user-request-approval.component.d.ts +29 -68
  118. package/src/lib/components/user-request-approval/user-request-approval.module.d.ts +7 -6
  119. package/esm2022/src/lib/base/base-data.component.mjs +0 -80
  120. package/esm2022/src/lib/base/base-data.facade.mjs +0 -130
  121. package/esm2022/src/lib/base/base-data.service.mjs +0 -21
  122. package/esm2022/src/lib/base/base-data.state.mjs +0 -74
  123. package/esm2022/src/lib/base/models.mjs +0 -2
  124. package/esm2022/src/lib/components/user-management/base-table-style.mjs +0 -53
  125. package/esm2022/src/lib/components/user-management/services/user-management.service.mjs +0 -110
  126. package/esm2022/src/lib/components/user-management/user-management.columns.mjs +0 -53
  127. package/esm2022/src/lib/components/user-request-approval/access-request.columns.mjs +0 -29
  128. package/esm2022/src/lib/components/user-request-approval/base-table-style.mjs +0 -53
  129. package/esm2022/src/lib/components/user-request-approval/facades/user-access-request.facade.mjs +0 -260
  130. package/esm2022/src/lib/components/user-request-approval/helper.mjs +0 -56
  131. package/esm2022/src/lib/components/user-request-approval/services/user-access-request.service.mjs +0 -92
  132. package/esm2022/src/lib/components/user-request-approval/states/user-access-request.state.mjs +0 -92
  133. package/esm2022/src/lib/components/user-request-approval/user-request-form/user-request-form.component.mjs +0 -105
  134. package/esm2022/src/lib/components/user-request-process/index.mjs +0 -2
  135. package/esm2022/src/lib/components/user-request-process/public-api.mjs +0 -3
  136. package/esm2022/src/lib/components/user-request-process/user-request-process.component.mjs +0 -11
  137. package/esm2022/src/lib/components/user-request-process/user-request-process.module.mjs +0 -18
  138. package/esm2022/src/lib/components/user-request-process/verben-authentication-ui-src-lib-components-user-request-process.mjs +0 -5
  139. package/fesm2022/verben-authentication-ui-src-lib-components-user-request-process.mjs +0 -34
  140. package/fesm2022/verben-authentication-ui-src-lib-components-user-request-process.mjs.map +0 -1
  141. package/src/lib/base/base-data.component.d.ts +0 -32
  142. package/src/lib/base/base-data.facade.d.ts +0 -27
  143. package/src/lib/base/base-data.service.d.ts +0 -14
  144. package/src/lib/base/base-data.state.d.ts +0 -28
  145. package/src/lib/base/models.d.ts +0 -11
  146. package/src/lib/components/user-management/base-table-style.d.ts +0 -1
  147. package/src/lib/components/user-management/services/user-management.service.d.ts +0 -44
  148. package/src/lib/components/user-management/user-management.columns.d.ts +0 -3
  149. package/src/lib/components/user-request-approval/access-request.columns.d.ts +0 -3
  150. package/src/lib/components/user-request-approval/base-table-style.d.ts +0 -1
  151. package/src/lib/components/user-request-approval/facades/user-access-request.facade.d.ts +0 -39
  152. package/src/lib/components/user-request-approval/helper.d.ts +0 -7
  153. package/src/lib/components/user-request-approval/services/user-access-request.service.d.ts +0 -64
  154. package/src/lib/components/user-request-approval/states/user-access-request.state.d.ts +0 -35
  155. package/src/lib/components/user-request-approval/user-request-form/user-request-form.component.d.ts +0 -34
  156. package/src/lib/components/user-request-process/index.d.ts +0 -1
  157. package/src/lib/components/user-request-process/public-api.d.ts +0 -2
  158. package/src/lib/components/user-request-process/user-request-process.component.d.ts +0 -5
  159. package/src/lib/components/user-request-process/user-request-process.module.d.ts +0 -7
@@ -1,43 +1,163 @@
1
+ import { SearchPropertyValueType, SortDirection, SearchOperator, SearchPropertySign, ErrorResponse } from 'verben-authentication-ui/src/lib/models';
2
+ export { SearchOperator, SearchPropertySign, SearchPropertyValueType, SortDirection } from 'verben-authentication-ui/src/lib/models';
1
3
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, Component, Input, Output } from '@angular/core';
3
- import { BehaviorSubject, Subject, debounceTime, distinctUntilChanged, takeUntil } from 'rxjs';
4
- import { takeUntil as takeUntil$1 } from 'rxjs/operators';
4
+ import { signal, Injectable } from '@angular/core';
5
+ import { BehaviorSubject, lastValueFrom, Subject, debounce, timer, distinctUntilChanged, takeUntil } from 'rxjs';
6
+ import * as i1 from 'verben-authentication-ui/src/lib/services';
7
+ import { SortDirection as SortDirection$1 } from 'verben-ng-ui';
5
8
 
6
- class BaseDataState {
9
+ // Re-export the shared API payload models so base-page consumers can import
10
+ // them from a single place without reaching into the models entry point.
11
+
12
+ /**
13
+ * Extract property name from column definition.
14
+ * Only columns with accessorKey can be used for filter/sort.
15
+ */
16
+ function getPropertyName(column) {
17
+ if (!column.accessorKey) {
18
+ throw new Error(`Column '${column.id}' must have accessorKey for filter/sort operations`);
19
+ }
20
+ return String(column.accessorKey);
21
+ }
22
+ /**
23
+ * Infer API property type from column definition.
24
+ * Uses basic heuristics based on the accessor key name.
25
+ */
26
+ function inferPropertyType(column) {
27
+ if (!column.accessorKey) {
28
+ return SearchPropertyValueType.String;
29
+ }
30
+ const propertyName = String(column.accessorKey).toLowerCase();
31
+ // Date detection. Includes the common audit fields (CreatedAt, UpdatedAt,
32
+ // ModifiedAt, DeletedAt) whose names contain neither "date" nor "time".
33
+ if (propertyName.includes('date') ||
34
+ propertyName.includes('time') ||
35
+ /^(created|updated|modified|deleted)/.test(propertyName)) {
36
+ return SearchPropertyValueType.Date;
37
+ }
38
+ if (propertyName.startsWith('is') || propertyName.startsWith('has')) {
39
+ return SearchPropertyValueType.Bool;
40
+ }
41
+ if (propertyName.includes('count') ||
42
+ propertyName.includes('amount') ||
43
+ propertyName.includes('price') ||
44
+ propertyName.includes('total')) {
45
+ return SearchPropertyValueType.Decimal;
46
+ }
47
+ return SearchPropertyValueType.String;
48
+ }
49
+ /**
50
+ * Find a column by its id.
51
+ */
52
+ function findColumn(columns, columnId) {
53
+ return columns.find((col) => col.id === columnId);
54
+ }
55
+
56
+ /**
57
+ * Abstract state management for base data pages.
58
+ * Tracks items, loading state, query params, filters, sorts, search, and
59
+ * visible columns. Card data is held in signals for cheap change detection.
60
+ */
61
+ class BaseDataPageState {
7
62
  updating$ = new BehaviorSubject(false);
8
63
  items$ = new BehaviorSubject([]);
9
- searchTerm$ = new BehaviorSubject('');
64
+ totalCount$ = new BehaviorSubject(0);
10
65
  queryParams$ = new BehaviorSubject({
11
66
  skip: 0,
12
67
  limit: 20,
13
- sortOrder: 'asc',
68
+ sortOrder: SortDirection.Asc,
14
69
  });
15
- columns$ = new BehaviorSubject([]);
70
+ searchTerm$ = new BehaviorSubject('');
71
+ filters$ = new BehaviorSubject([]);
72
+ sorts$ = new BehaviorSubject([]);
73
+ visibleColumns$ = new BehaviorSubject([]);
74
+ cardData = signal([]);
75
+ currentCardData = signal(null);
76
+ cardDataMapper;
77
+ /**
78
+ * Stable identity for a record. The auth models key on uppercase `Id`/`Code`
79
+ * and only sometimes carry a lowercase `id`, so match across all three rather
80
+ * than assuming one is populated.
81
+ */
82
+ getItemKey(item) {
83
+ return item.Id || item.id || item.Code;
84
+ }
85
+ updateCardDataFromItems(items) {
86
+ if (this.cardDataMapper) {
87
+ this.cardData.set(items.map((item) => this.cardDataMapper(item)));
88
+ }
89
+ }
90
+ // ===== Loading State =====
16
91
  isUpdating$() {
17
92
  return this.updating$.asObservable();
18
93
  }
19
94
  setUpdating(isUpdating) {
20
95
  this.updating$.next(isUpdating);
21
96
  }
97
+ // ===== Items =====
22
98
  getItems$() {
23
99
  return this.items$.asObservable();
24
100
  }
101
+ getItemsValue() {
102
+ return this.items$.getValue();
103
+ }
25
104
  setItems(items) {
26
105
  this.items$.next(items);
106
+ this.updateCardDataFromItems(items);
27
107
  }
28
108
  appendItems(newItems) {
29
- const currentItems = this.items$.getValue();
30
- this.items$.next([...currentItems, ...newItems]);
109
+ const allItems = [...this.items$.getValue(), ...newItems];
110
+ this.items$.next(allItems);
111
+ this.updateCardDataFromItems(allItems);
31
112
  }
32
- getSearchTerm$() {
33
- return this.searchTerm$.asObservable();
113
+ addItem(item) {
114
+ const allItems = [item, ...this.items$.getValue()];
115
+ this.items$.next(allItems);
116
+ this.updateCardDataFromItems(allItems);
34
117
  }
35
- getSearchTermValue() {
36
- return this.searchTerm$.getValue();
118
+ updateItem(updatedItem) {
119
+ const items = this.items$.getValue();
120
+ const key = this.getItemKey(updatedItem);
121
+ const index = items.findIndex((item) => this.getItemKey(item) === key);
122
+ if (index !== -1) {
123
+ items[index] = updatedItem;
124
+ const allItems = [...items];
125
+ this.items$.next(allItems);
126
+ this.updateCardDataFromItems(allItems);
127
+ }
37
128
  }
38
- setSearchTerm(term) {
39
- this.searchTerm$.next(term);
129
+ /** Update the item when its key already exists, otherwise prepend it. */
130
+ upsertItem(item) {
131
+ const key = this.getItemKey(item);
132
+ const exists = this.items$
133
+ .getValue()
134
+ .some((existing) => this.getItemKey(existing) === key);
135
+ if (exists) {
136
+ this.updateItem(item);
137
+ }
138
+ else {
139
+ this.addItem(item);
140
+ }
141
+ }
142
+ removeItem(itemKey) {
143
+ const filteredItems = this.items$
144
+ .getValue()
145
+ .filter((item) => this.getItemKey(item) !== itemKey);
146
+ this.items$.next(filteredItems);
147
+ this.updateCardDataFromItems(filteredItems);
148
+ }
149
+ clearItems() {
150
+ this.items$.next([]);
151
+ this.updateCardDataFromItems([]);
152
+ }
153
+ // ===== Total Count =====
154
+ getTotalCount$() {
155
+ return this.totalCount$.asObservable();
40
156
  }
157
+ setTotalCount(count) {
158
+ this.totalCount$.next(count);
159
+ }
160
+ // ===== Query Parameters =====
41
161
  getQueryParams$() {
42
162
  return this.queryParams$.asObservable();
43
163
  }
@@ -48,258 +168,520 @@ class BaseDataState {
48
168
  this.queryParams$.next({ ...this.queryParams$.getValue(), ...params });
49
169
  }
50
170
  resetPagination() {
171
+ this.queryParams$.next({ ...this.queryParams$.getValue(), skip: 0 });
172
+ }
173
+ incrementPagination() {
51
174
  const currentParams = this.queryParams$.getValue();
52
- this.queryParams$.next({ ...currentParams, skip: 0 });
175
+ this.queryParams$.next({
176
+ ...currentParams,
177
+ skip: currentParams.skip + currentParams.limit,
178
+ });
53
179
  }
54
- getColumns$() {
55
- return this.columns$.asObservable();
180
+ // ===== Search =====
181
+ getSearchTerm$() {
182
+ return this.searchTerm$.asObservable();
56
183
  }
57
- setColumns(columns) {
58
- this.columns$.next(columns);
184
+ getSearchTermValue() {
185
+ return this.searchTerm$.getValue();
59
186
  }
60
- // CRUD Operations
61
- addItem(item) {
62
- const currentItems = this.items$.getValue();
63
- this.items$.next([...currentItems, item]);
187
+ setSearchTerm(term) {
188
+ this.searchTerm$.next(term);
64
189
  }
65
- updateItem(updatedItem) {
66
- const items = this.items$.getValue();
67
- const index = items.findIndex((item) => item.Id === updatedItem.Id);
68
- if (index !== -1) {
69
- items[index] = updatedItem;
70
- this.items$.next([...items]);
71
- }
190
+ // ===== Filters =====
191
+ getFilters$() {
192
+ return this.filters$.asObservable();
72
193
  }
73
- removeItem(itemId) {
74
- const currentItems = this.items$.getValue();
75
- this.items$.next(currentItems.filter((item) => item.Id !== itemId));
194
+ getFiltersValue() {
195
+ return this.filters$.getValue();
76
196
  }
77
- }
78
-
79
- class BaseDataService {
80
- http;
81
- baseUrl;
82
- constructor(http, baseUrl) {
83
- this.http = http;
84
- this.baseUrl = baseUrl;
197
+ setFilters(filters) {
198
+ this.filters$.next(filters);
85
199
  }
86
- getItems(skip, limit, sortParam, sortOrder) {
87
- return this.http.get(`${this.baseUrl}/${this.getEndpoint()}/${skip}/${limit}/${String(sortParam)}/${sortOrder}`);
200
+ clearFilters() {
201
+ this.filters$.next([]);
88
202
  }
89
- getItemsBySearchTerm(searchTerm, skip, limit, sortParam, sortOrder) {
90
- return this.http.get(`${this.baseUrl}/${this.getEndpoint()}/search/${searchTerm}/${skip}/${limit}/${String(sortParam)}/${sortOrder}`);
203
+ // ===== Sorts =====
204
+ getSorts$() {
205
+ return this.sorts$.asObservable();
91
206
  }
92
- saveItems(items) {
93
- return this.http.post(`${this.baseUrl}/${this.getEndpoint()}`, items);
207
+ getSortsValue() {
208
+ return this.sorts$.getValue();
94
209
  }
95
- deleteItems(itemIds) {
96
- return this.http.delete(`${this.baseUrl}/${this.getEndpoint()}?ids=${itemIds.join(',')}`);
210
+ setSorts(sorts) {
211
+ this.sorts$.next(sorts);
97
212
  }
98
- }
99
-
100
- class BaseDataFacade {
101
- state;
102
- service;
103
- searchSubject = new Subject();
104
- destroy$ = new Subject();
105
- constructor(state, service) {
106
- this.state = state;
107
- this.service = service;
108
- this.setupSearchHandler();
213
+ clearSorts() {
214
+ this.sorts$.next([]);
109
215
  }
110
- setupSearchHandler() {
111
- this.searchSubject
112
- .pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.destroy$))
113
- .subscribe((searchTerm) => {
114
- this.handleSearch(searchTerm);
115
- });
216
+ // ===== Visible Columns =====
217
+ getVisibleColumns$() {
218
+ return this.visibleColumns$.asObservable();
116
219
  }
117
- destroy() {
118
- this.destroy$.next();
119
- this.destroy$.complete();
220
+ getVisibleColumnsValue() {
221
+ return this.visibleColumns$.getValue();
120
222
  }
121
- // State Observables
122
- isUpdating$() {
123
- return this.state.isUpdating$();
223
+ setVisibleColumns(columns) {
224
+ this.visibleColumns$.next(columns);
124
225
  }
125
- getItems$() {
126
- return this.state.getItems$();
226
+ // ===== Card Data =====
227
+ setCardDataMapper(mapper) {
228
+ this.cardDataMapper = mapper;
127
229
  }
128
- getSearchTerm$() {
129
- return this.state.getSearchTerm$();
230
+ getCardData() {
231
+ return this.cardData;
130
232
  }
131
- getQueryParams$() {
132
- return this.state.getQueryParams$();
233
+ setCardData(data) {
234
+ this.cardData.set(data);
133
235
  }
134
- // Actions
135
- search(term) {
136
- this.searchSubject.next(term);
236
+ getCurrentCardData() {
237
+ return this.currentCardData;
137
238
  }
138
- async handleSearch(searchTerm) {
139
- this.state.setSearchTerm(searchTerm);
140
- this.state.resetPagination();
141
- await this.loadItems();
239
+ setCurrentCardData(data) {
240
+ this.currentCardData.set(data);
142
241
  }
143
- async loadItems() {
144
- try {
145
- this.state.setUpdating(true);
146
- const params = this.state.getQueryParamsValue();
147
- const searchTerm = this.state.getSearchTermValue();
148
- const response = searchTerm
149
- ? await this.service
150
- .getItemsBySearchTerm(searchTerm, params.skip, params.limit, params.sortParam, params.sortOrder)
151
- .toPromise()
152
- : await this.service
153
- .getItems(params.skip, params.limit, params.sortParam, params.sortOrder)
154
- .toPromise();
155
- if (response?.Result) {
156
- this.state.setItems(response?.Result);
157
- }
158
- }
159
- catch (error) {
160
- console.error('Failed to load items:', error);
161
- throw error;
162
- }
163
- finally {
164
- this.state.setUpdating(false);
165
- }
242
+ // ===== Reset All =====
243
+ reset() {
244
+ this.clearItems();
245
+ this.setSearchTerm('');
246
+ this.clearFilters();
247
+ this.clearSorts();
248
+ this.setVisibleColumns([]);
249
+ this.cardData.set([]);
250
+ this.currentCardData.set(null);
251
+ this.resetPagination();
252
+ this.setTotalCount(0);
166
253
  }
167
- async loadMore() {
168
- try {
169
- this.state.setUpdating(true);
170
- const currentParams = this.state.getQueryParamsValue();
171
- const newSkip = currentParams.skip + currentParams.limit;
172
- this.state.updateQueryParams({ skip: newSkip });
173
- const response = await this.service
174
- .getItems(newSkip, currentParams.limit, currentParams.sortParam, currentParams.sortOrder)
175
- .toPromise();
176
- if (response?.Result) {
177
- this.state.appendItems(response.Result);
254
+ }
255
+
256
+ /**
257
+ * Converts FilterCondition[] emitted by lib-data-filter into the
258
+ * SearchPropertyValue[] payload the search API expects.
259
+ */
260
+ class FilterHandlerService {
261
+ buildFilterPayload(filters, columns) {
262
+ return filters
263
+ .map((filter) => {
264
+ const column = findColumn(columns, filter.columnId);
265
+ if (!column) {
266
+ console.warn(`Column not found for filter: ${filter.columnId}`);
267
+ return null;
178
268
  }
179
- }
180
- catch (error) {
181
- console.error('Failed to load more items:', error);
182
- throw error;
183
- }
184
- finally {
185
- this.state.setUpdating(false);
186
- }
187
- }
188
- async saveItem(item) {
189
- try {
190
- this.state.setUpdating(true);
191
- const response = await this.service.saveItems([item]).toPromise();
192
- if (response?.[0]) {
193
- this.state.updateItem(response[0]);
269
+ const propertyName = getPropertyName(column);
270
+ const propertyType = inferPropertyType(column);
271
+ const sign = this.mapOperatorToSign(filter.operator);
272
+ return {
273
+ PropertyName: propertyName,
274
+ EntityValue: String(filter.value),
275
+ Type: propertyType,
276
+ Operator: SearchOperator.And,
277
+ Sign: sign,
278
+ };
279
+ })
280
+ .filter(Boolean);
281
+ }
282
+ mapOperatorToSign(operator) {
283
+ const operatorMap = {
284
+ startsWith: SearchPropertySign.LIKE,
285
+ endsWith: SearchPropertySign.LIKE,
286
+ contains: SearchPropertySign.LIKE,
287
+ equals: SearchPropertySign.EQ,
288
+ equal: SearchPropertySign.EQ,
289
+ greaterThan: SearchPropertySign.GT,
290
+ lessThan: SearchPropertySign.LT,
291
+ on: SearchPropertySign.EQ,
292
+ before: SearchPropertySign.LT,
293
+ after: SearchPropertySign.GT,
294
+ };
295
+ return operatorMap[operator] || SearchPropertySign.EQ;
296
+ }
297
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilterHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
298
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilterHandlerService, providedIn: 'root' });
299
+ }
300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilterHandlerService, decorators: [{
301
+ type: Injectable,
302
+ args: [{ providedIn: 'root' }]
303
+ }] });
304
+
305
+ /**
306
+ * Converts SortCondition[] emitted by lib-data-sort into the
307
+ * SearchPropertyValue[] payload the search API expects.
308
+ */
309
+ class SortHandlerService {
310
+ buildSortPayload(sorts, columns) {
311
+ return sorts
312
+ .map((sort) => {
313
+ const column = findColumn(columns, sort.columnId);
314
+ if (!column) {
315
+ console.warn(`Column not found for sort: ${sort.columnId}`);
316
+ return null;
194
317
  }
318
+ const propertyName = getPropertyName(column);
319
+ const propertyType = inferPropertyType(column);
320
+ return {
321
+ PropertyName: propertyName,
322
+ EntityValue: '',
323
+ Type: propertyType,
324
+ Operator: SearchOperator.And,
325
+ Sign: SearchPropertySign.EQ,
326
+ Sort: this.mapSortDirection(sort.direction),
327
+ };
328
+ })
329
+ .filter(Boolean);
330
+ }
331
+ mapSortDirection(direction) {
332
+ switch (direction) {
333
+ case SortDirection$1.Asc:
334
+ return SortDirection.Asc;
335
+ case SortDirection$1.Desc:
336
+ return SortDirection.Desc;
337
+ default:
338
+ return SortDirection.None;
195
339
  }
196
- catch (error) {
197
- console.error('Failed to save item:', error);
198
- throw error;
340
+ }
341
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SortHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
342
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SortHandlerService, providedIn: 'root' });
343
+ }
344
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SortHandlerService, decorators: [{
345
+ type: Injectable,
346
+ args: [{ providedIn: 'root' }]
347
+ }] });
348
+
349
+ /**
350
+ * Abstract base service for data pages.
351
+ * Handles list/search/save/delete with filter and sort support.
352
+ *
353
+ * The concrete URLs are built by the protected `*Url` seams below so that
354
+ * services whose API does not follow the default `Get{Endpoint}/{skip}/{limit}`
355
+ * conventions (e.g. plural names or a trailing sort suffix) can override just
356
+ * the URL without reimplementing the request-selection logic in `getData()`.
357
+ * When `baseUrl` is omitted, HttpWebRequestService falls back to the
358
+ * AuthenticationAPI base.
359
+ */
360
+ class BaseDataPageService {
361
+ server;
362
+ filterHandler;
363
+ sortHandler;
364
+ baseUrl;
365
+ constructor(server, filterHandler, sortHandler, baseUrl) {
366
+ this.server = server;
367
+ this.filterHandler = filterHandler;
368
+ this.sortHandler = sortHandler;
369
+ this.baseUrl = baseUrl;
370
+ }
371
+ // ===== URL seams (override in child services when the API deviates) =====
372
+ listUrl(skip, limit) {
373
+ return `Get${this.getEndpoint()}/${skip}/${limit}`;
374
+ }
375
+ searchTermUrl(term, skip, limit) {
376
+ return `Get${this.getEndpoint()}WithParam/${term}/${skip}/${limit}`;
377
+ }
378
+ filterSearchUrl(skip, limit) {
379
+ return `Search${this.getEndpoint()}/${skip}/${limit}`;
380
+ }
381
+ saveUrl() {
382
+ return `Save${this.getEndpoint()}`;
383
+ }
384
+ deleteUrl(itemIds) {
385
+ return `${this.getEndpoint()}/${itemIds.join(',')}`;
386
+ }
387
+ // ===== Payload =====
388
+ buildPayload(filters, sorts, columns) {
389
+ const filterPayload = this.filterHandler.buildFilterPayload(filters, columns);
390
+ const sortPayload = this.sortHandler.buildSortPayload(sorts, columns);
391
+ return [...filterPayload, ...sortPayload];
392
+ }
393
+ // ===== Reads =====
394
+ /**
395
+ * Fetch data, automatically choosing the endpoint based on parameters:
396
+ * search-only -> GET WithParam, filters/sorts -> POST Search, otherwise plain GET.
397
+ */
398
+ async getData(skip, limit, filters, sorts, searchTerm, columns) {
399
+ const hasFilters = !!filters && filters.length > 0;
400
+ const hasSorts = !!sorts && sorts.length > 0;
401
+ if (searchTerm && !hasFilters && !hasSorts) {
402
+ return this.server.get(this.searchTermUrl(searchTerm, skip, limit), this.baseUrl);
199
403
  }
200
- finally {
201
- this.state.setUpdating(false);
404
+ if (hasFilters || hasSorts) {
405
+ if (!columns) {
406
+ throw new Error('Columns required for filter/sort operations');
407
+ }
408
+ const payload = this.buildPayload(filters || [], sorts || [], columns);
409
+ return this.server.post(this.filterSearchUrl(skip, limit), payload, this.baseUrl);
202
410
  }
411
+ return this.server.get(this.listUrl(skip, limit), this.baseUrl);
412
+ }
413
+ // ===== Writes =====
414
+ async saveItems(items) {
415
+ return this.server.post(this.saveUrl(), items, this.baseUrl);
203
416
  }
204
- async deleteItem(itemId) {
417
+ async deleteItems(itemIds) {
418
+ // HttpWebRequestService.delete returns a raw observable that rejects on HTTP
419
+ // error (unlike get/post, which resolve an ErrorResponse), so normalize here
420
+ // to keep the facade's error-handling contract uniform.
205
421
  try {
206
- this.state.setUpdating(true);
207
- await this.service.deleteItems([itemId]).toPromise();
208
- this.state.removeItem(itemId);
422
+ const result = await lastValueFrom(this.server.delete(this.deleteUrl(itemIds), this.baseUrl));
423
+ return result ?? false;
209
424
  }
210
- catch (error) {
211
- console.error('Failed to delete item:', error);
212
- throw error;
425
+ catch (err) {
426
+ const msg = err?.error?.ErrorMsg || err?.ErrorMsg || err?.message || 'Delete failed';
427
+ return new ErrorResponse(msg);
213
428
  }
214
- finally {
215
- this.state.setUpdating(false);
429
+ }
430
+ // ===== Export =====
431
+ async exportData(filters, sorts, searchTerm, columns) {
432
+ const result = await this.getData(0, 999999, filters, sorts, searchTerm, columns);
433
+ if (result instanceof ErrorResponse) {
434
+ return result;
216
435
  }
436
+ return result.Result || [];
217
437
  }
218
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataFacade, deps: [{ token: BaseDataState }, { token: BaseDataService }], target: i0.ɵɵFactoryTarget.Injectable });
219
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataFacade });
438
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataPageService, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
439
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataPageService });
220
440
  }
221
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataFacade, decorators: [{
441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataPageService, decorators: [{
222
442
  type: Injectable
223
- }], ctorParameters: () => [{ type: BaseDataState }, { type: BaseDataService }] });
443
+ }], ctorParameters: () => [{ type: i1.HttpWebRequestService }, { type: FilterHandlerService }, { type: SortHandlerService }, { type: undefined }] });
224
444
 
225
- class BaseDataComponent {
226
- facade;
227
- columns;
228
- selectionChange = new EventEmitter();
229
- exportData = new EventEmitter();
230
- destroy$ = new Subject();
231
- isLoading = false;
232
- items = [];
233
- selectedItems = [];
234
- isGridView = true;
235
- constructor(facade) {
236
- this.facade = facade;
445
+ /**
446
+ * Debounces search terms. Emits the term after the user stops typing.
447
+ * Provided per page so each page owns its own debounce stream.
448
+ *
449
+ * `search$` is a stable observable whose debounce interval is read live from
450
+ * `debounceMs`, so `setDebounceTime()` can be called after subscribers have
451
+ * attached (e.g. from a runtime `@Input`) and still take effect.
452
+ */
453
+ class SearchHandlerService {
454
+ searchSubject = new Subject();
455
+ debounceMs = 500;
456
+ search$ = this.searchSubject.asObservable().pipe(debounce(() => timer(this.debounceMs)), distinctUntilChanged());
457
+ search(term) {
458
+ this.searchSubject.next(term);
237
459
  }
238
- ngOnInit() {
239
- this.setupSubscriptions();
240
- this.loadInitialData();
460
+ setDebounceTime(ms) {
461
+ this.debounceMs = ms;
241
462
  }
242
463
  ngOnDestroy() {
243
- this.destroy$.next();
244
- this.destroy$.complete();
464
+ this.searchSubject.complete();
245
465
  }
246
- setupSubscriptions() {
247
- this.facade
248
- .isUpdating$()
249
- .pipe(takeUntil$1(this.destroy$))
250
- .subscribe((loading) => (this.isLoading = loading));
251
- this.facade
252
- .getItems$()
253
- .pipe(takeUntil$1(this.destroy$))
254
- .subscribe((items) => (this.items = items));
255
- }
256
- async loadInitialData() {
257
- try {
258
- await this.facade.loadItems();
259
- }
260
- catch (error) {
261
- // Handle error appropriately
262
- console.error('Failed to load initial data:', error);
466
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
467
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchHandlerService });
468
+ }
469
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchHandlerService, decorators: [{
470
+ type: Injectable
471
+ }] });
472
+
473
+ /**
474
+ * Abstract facade for base data pages.
475
+ * Orchestrates state, service, and search handler, and surfaces the host app's
476
+ * busy indicator / toasts through UtilService.
477
+ */
478
+ class BaseDataPageFacade {
479
+ state;
480
+ service;
481
+ searchHandler;
482
+ utilService;
483
+ config;
484
+ destroy$ = new Subject();
485
+ cardSelectionCleared = new Subject();
486
+ constructor(state, service, searchHandler, utilService, config) {
487
+ this.state = state;
488
+ this.service = service;
489
+ this.searchHandler = searchHandler;
490
+ this.utilService = utilService;
491
+ this.config = config;
492
+ this.initializeSearchHandler();
493
+ this.state.setVisibleColumns(this.config.columns);
494
+ if (this.config.cardDataMapper) {
495
+ this.state.setCardDataMapper(this.config.cardDataMapper);
263
496
  }
497
+ // Drive the host busy indicator from the shared loading flag.
498
+ this.state
499
+ .isUpdating$()
500
+ .pipe(takeUntil(this.destroy$))
501
+ .subscribe((loading) => this.utilService.sendBI(loading));
264
502
  }
265
- onSearch(event) {
266
- this.facade.search(event.value);
503
+ // ===== Configuration =====
504
+ getConfig() {
505
+ return this.config;
267
506
  }
268
- async onLoadMore() {
269
- try {
270
- await this.facade.loadMore();
507
+ getColumns() {
508
+ return this.config.columns;
509
+ }
510
+ // ===== Observables =====
511
+ get items$() {
512
+ return this.state.getItems$();
513
+ }
514
+ get isLoading$() {
515
+ return this.state.isUpdating$();
516
+ }
517
+ get totalCount$() {
518
+ return this.state.getTotalCount$();
519
+ }
520
+ get filters$() {
521
+ return this.state.getFilters$();
522
+ }
523
+ get sorts$() {
524
+ return this.state.getSorts$();
525
+ }
526
+ get searchTerm$() {
527
+ return this.state.getSearchTerm$();
528
+ }
529
+ get visibleColumns$() {
530
+ return this.state.getVisibleColumns$();
531
+ }
532
+ get cardData() {
533
+ return this.state.getCardData();
534
+ }
535
+ get currentCardData() {
536
+ return this.state.getCurrentCardData();
537
+ }
538
+ /**
539
+ * Emits when a refetch invalidates the current card selection.
540
+ * Card views listen to this to clear their own selection state.
541
+ */
542
+ get cardSelectionCleared$() {
543
+ return this.cardSelectionCleared.asObservable();
544
+ }
545
+ // ===== Data Loading =====
546
+ async loadData() {
547
+ this.clearCardSelection();
548
+ this.state.setUpdating(true);
549
+ this.state.clearItems();
550
+ this.state.resetPagination();
551
+ const params = this.state.getQueryParamsValue();
552
+ const filters = this.state.getFiltersValue();
553
+ const sorts = this.state.getSortsValue();
554
+ const searchTerm = this.state.getSearchTermValue();
555
+ const result = await this.service.getData(params.skip, params.limit, filters, sorts, searchTerm, this.config.columns);
556
+ this.state.setUpdating(false);
557
+ if (result instanceof ErrorResponse) {
558
+ this.utilService.showError(result.ErrorMsg);
559
+ return;
271
560
  }
272
- catch (error) {
273
- console.error('Failed to load more:', error);
561
+ this.state.setItems(result.Result || []);
562
+ this.state.setTotalCount(result.Total || 0);
563
+ }
564
+ addItem(item) {
565
+ this.state.addItem(item);
566
+ }
567
+ async loadMore() {
568
+ this.state.setUpdating(true);
569
+ this.state.incrementPagination();
570
+ const params = this.state.getQueryParamsValue();
571
+ const filters = this.state.getFiltersValue();
572
+ const sorts = this.state.getSortsValue();
573
+ const searchTerm = this.state.getSearchTermValue();
574
+ const result = await this.service.getData(params.skip, params.limit, filters, sorts, searchTerm, this.config.columns);
575
+ this.state.setUpdating(false);
576
+ if (result instanceof ErrorResponse) {
577
+ this.utilService.showError(result.ErrorMsg);
578
+ return;
274
579
  }
580
+ this.state.appendItems(result.Result || []);
581
+ }
582
+ async refresh() {
583
+ await this.loadData();
584
+ }
585
+ // ===== Search =====
586
+ onSearch(term) {
587
+ this.searchHandler.search(term);
275
588
  }
276
- onViewChange(isGridView) {
277
- this.isGridView = isGridView;
589
+ initializeSearchHandler() {
590
+ if (this.config.searchDebounceTime) {
591
+ this.searchHandler.setDebounceTime(this.config.searchDebounceTime);
592
+ }
593
+ this.searchHandler.search$.pipe(takeUntil(this.destroy$)).subscribe((term) => {
594
+ this.state.setSearchTerm(term);
595
+ this.loadData();
596
+ });
278
597
  }
279
- onSelectionChange(selected) {
280
- this.selectedItems = selected;
281
- this.selectionChange.emit(selected);
598
+ // ===== Filters / Sorts =====
599
+ async applyFilters(filters) {
600
+ this.state.setFilters(filters);
601
+ await this.loadData();
602
+ }
603
+ async clearFilters() {
604
+ this.state.clearFilters();
605
+ await this.loadData();
606
+ }
607
+ async applySorts(sorts) {
608
+ this.state.setSorts(sorts);
609
+ await this.loadData();
610
+ }
611
+ async clearSorts() {
612
+ this.state.clearSorts();
613
+ await this.loadData();
614
+ }
615
+ // ===== Visible Columns =====
616
+ updateVisibleColumns(columns) {
617
+ this.state.setVisibleColumns(columns);
618
+ }
619
+ // ===== Card Data =====
620
+ selectCard(cardData) {
621
+ this.state.setCurrentCardData(cardData);
622
+ }
623
+ /**
624
+ * Drop the current card selection because the data it referred to is being
625
+ * replaced. Called by loadData(); deliberately not by loadMore(), which only
626
+ * appends and leaves an existing selection valid.
627
+ */
628
+ clearCardSelection() {
629
+ this.state.setCurrentCardData(null);
630
+ this.cardSelectionCleared.next();
631
+ }
632
+ // ===== CRUD =====
633
+ async saveItems(items) {
634
+ this.state.setUpdating(true);
635
+ const result = await this.service.saveItems(items);
636
+ this.state.setUpdating(false);
637
+ if (result instanceof ErrorResponse) {
638
+ this.utilService.showError(result.ErrorMsg);
639
+ return false;
640
+ }
641
+ this.utilService.showSuccess('Record(s) saved successfully');
642
+ result.forEach((savedItem) => this.state.upsertItem(savedItem));
643
+ return true;
644
+ }
645
+ async deleteItems(itemIds) {
646
+ this.state.setUpdating(true);
647
+ const result = await this.service.deleteItems(itemIds);
648
+ this.state.setUpdating(false);
649
+ if (result instanceof ErrorResponse) {
650
+ this.utilService.showError(result.ErrorMsg);
651
+ return false;
652
+ }
653
+ itemIds.forEach((id) => this.state.removeItem(id));
654
+ return true;
655
+ }
656
+ // ===== Export =====
657
+ async exportData() {
658
+ const filters = this.state.getFiltersValue();
659
+ const sorts = this.state.getSortsValue();
660
+ const searchTerm = this.state.getSearchTermValue();
661
+ const result = await this.service.exportData(filters, sorts, searchTerm, this.config.columns);
662
+ if (result instanceof ErrorResponse) {
663
+ return [];
664
+ }
665
+ return result;
282
666
  }
283
- onExport(data) {
284
- this.exportData.emit(data);
667
+ // ===== Cleanup =====
668
+ ngOnDestroy() {
669
+ this.destroy$.next();
670
+ this.destroy$.complete();
671
+ this.cardSelectionCleared.complete();
285
672
  }
286
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataComponent, deps: [{ token: BaseDataFacade }], target: i0.ɵɵFactoryTarget.Component });
287
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BaseDataComponent, selector: "ng-component", inputs: { columns: "columns" }, outputs: { selectionChange: "selectionChange", exportData: "exportData" }, ngImport: i0, template: '', isInline: true });
673
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataPageFacade, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
674
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataPageFacade });
288
675
  }
289
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataComponent, decorators: [{
290
- type: Component,
291
- args: [{ template: '' }]
292
- }], ctorParameters: () => [{ type: BaseDataFacade }], propDecorators: { columns: [{
293
- type: Input
294
- }], selectionChange: [{
295
- type: Output
296
- }], exportData: [{
297
- type: Output
298
- }] } });
676
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseDataPageFacade, decorators: [{
677
+ type: Injectable
678
+ }], ctorParameters: () => [{ type: BaseDataPageState }, { type: BaseDataPageService }, { type: SearchHandlerService }, { type: i1.UtilService }, { type: undefined }] });
679
+
680
+ // Models and interfaces
299
681
 
300
682
  /**
301
683
  * Generated bundle index. Do not edit.
302
684
  */
303
685
 
304
- export { BaseDataComponent, BaseDataFacade, BaseDataService, BaseDataState };
686
+ export { BaseDataPageFacade, BaseDataPageService, BaseDataPageState, FilterHandlerService, SearchHandlerService, SortHandlerService, findColumn, getPropertyName, inferPropertyType };
305
687
  //# sourceMappingURL=verben-authentication-ui-src-lib-base.mjs.map