@zeedhi/teknisa-components-common 1.117.1 → 3.0.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 (177) hide show
  1. package/.package.json +43 -0
  2. package/dist/teknisa-components-common.js +3802 -0
  3. package/dist/teknisa-components-common.min.js +3802 -0
  4. package/dist/types/components/index.d.ts +7 -0
  5. package/{types → dist/types}/components/tek-breadcrumb-header/breadcrumb-header.d.ts +12 -12
  6. package/{types → dist/types}/components/tek-breadcrumb-header/interfaces.d.ts +6 -6
  7. package/dist/types/components/tek-datasource/index.d.ts +3 -0
  8. package/{types → dist/types}/components/tek-datasource/interfaces.d.ts +16 -16
  9. package/{types/components/tek-datasource/memory-datasource.d.ts → dist/types/components/tek-datasource/tek-memory-datasource.d.ts} +93 -100
  10. package/{types/components/tek-datasource/rest-datasource.d.ts → dist/types/components/tek-datasource/tek-rest-datasource.d.ts} +95 -103
  11. package/dist/types/components/tek-grid/columns-searcher.d.ts +5 -0
  12. package/dist/types/components/tek-grid/dynamic-filter-datasource-factory.d.ts +6 -0
  13. package/{types → dist/types}/components/tek-grid/filter-helper.d.ts +7 -7
  14. package/{types → dist/types}/components/tek-grid/grid-filter-button.d.ts +29 -31
  15. package/dist/types/components/tek-grid/grouped-data-manager.d.ts +82 -0
  16. package/dist/types/components/tek-grid/grouped-data-selector.d.ts +7 -0
  17. package/dist/types/components/tek-grid/grouped-view-navigator.d.ts +14 -0
  18. package/dist/types/components/tek-grid/index.d.ts +18 -0
  19. package/dist/types/components/tek-grid/interfaces.d.ts +259 -0
  20. package/dist/types/components/tek-grid/keymap-grouped.d.ts +6 -0
  21. package/{types → dist/types}/components/tek-grid/layout-options.d.ts +39 -31
  22. package/{types/components/tek-grid/grid-column.d.ts → dist/types/components/tek-grid/tek-grid-column.d.ts} +42 -45
  23. package/{types/components/tek-grid/grid-columns-button-controller.d.ts → dist/types/components/tek-grid/tek-grid-columns-button/tek-grid-columns-button-controller.d.ts} +8 -8
  24. package/{types/components/tek-grid/grid-columns-button.d.ts → dist/types/components/tek-grid/tek-grid-columns-button/tek-grid-columns-button.d.ts} +13 -12
  25. package/dist/types/components/tek-grid/tek-grid-controller.d.ts +31 -0
  26. package/dist/types/components/tek-grid/tek-grid-events.d.ts +31 -0
  27. package/{types/utils/grid-base → dist/types/components/tek-grid/tek-grid-toolbar-provider}/export-options/button-option.d.ts +17 -16
  28. package/{types/utils/grid-base → dist/types/components/tek-grid/tek-grid-toolbar-provider}/export-options/index.d.ts +3 -3
  29. package/dist/types/components/tek-grid/tek-grid-toolbar-provider/export-options/interfaces.d.ts +5 -0
  30. package/{types/utils/grid-base → dist/types/components/tek-grid/tek-grid-toolbar-provider}/export-options/multi-option.d.ts +12 -12
  31. package/dist/types/components/tek-grid/tek-grid-toolbar-provider/index.d.ts +2 -0
  32. package/dist/types/components/tek-grid/tek-grid-toolbar-provider/tek-grid-toolbar-provider.d.ts +22 -0
  33. package/dist/types/components/tek-grid/tek-grid.d.ts +216 -0
  34. package/{types → dist/types}/components/tek-user-info/TekUserInfoController.d.ts +22 -21
  35. package/{types → dist/types}/components/tek-user-info/interfaces.d.ts +27 -28
  36. package/{types → dist/types}/components/tek-user-info/tek-user-info-list.d.ts +32 -31
  37. package/{types → dist/types}/components/tek-user-info/tek-user-info.d.ts +37 -38
  38. package/{types → dist/types}/error/delete-rows-error.d.ts +6 -6
  39. package/dist/types/error/tek-grid-delete-rows-error.d.ts +7 -0
  40. package/dist/types/error/teknisa-common-error.d.ts +6 -0
  41. package/dist/types/index.d.ts +2 -0
  42. package/{types → dist/types}/utils/config/config.d.ts +7 -7
  43. package/dist/types/utils/index.d.ts +3 -0
  44. package/dist/types/utils/is-filled-object/is-filled-object.d.ts +2 -0
  45. package/dist/types/utils/is-nil.d.ts +1 -0
  46. package/environments.json +14 -0
  47. package/package.json +26 -18
  48. package/src/components/index.ts +101 -0
  49. package/src/components/tek-breadcrumb-header/breadcrumb-header.ts +29 -0
  50. package/src/components/tek-breadcrumb-header/interfaces.ts +7 -0
  51. package/src/components/tek-datasource/index.ts +3 -0
  52. package/src/components/tek-datasource/interfaces.ts +36 -0
  53. package/src/components/tek-datasource/tek-memory-datasource.ts +314 -0
  54. package/src/components/tek-datasource/tek-rest-datasource.ts +224 -0
  55. package/src/components/tek-grid/columns-searcher.ts +22 -0
  56. package/src/components/tek-grid/dynamic-filter-datasource-factory.ts +20 -0
  57. package/src/components/tek-grid/filter-helper.ts +20 -0
  58. package/src/components/tek-grid/grid-filter-button.ts +419 -0
  59. package/src/components/tek-grid/grouped-data-manager.ts +448 -0
  60. package/src/components/tek-grid/grouped-data-selector.ts +40 -0
  61. package/src/components/tek-grid/grouped-view-navigator.ts +84 -0
  62. package/src/components/tek-grid/index.ts +18 -0
  63. package/src/components/tek-grid/interfaces.ts +329 -0
  64. package/src/components/tek-grid/keymap-grouped.ts +20 -0
  65. package/src/components/tek-grid/layout-options.ts +248 -0
  66. package/src/components/tek-grid/tek-grid-column.ts +193 -0
  67. package/src/components/tek-grid/tek-grid-columns-button/tek-grid-columns-button-controller.ts +28 -0
  68. package/src/components/tek-grid/tek-grid-columns-button/tek-grid-columns-button.ts +38 -0
  69. package/src/components/tek-grid/tek-grid-controller.ts +140 -0
  70. package/src/components/tek-grid/tek-grid-events.ts +105 -0
  71. package/src/components/tek-grid/tek-grid-toolbar-provider/export-options/button-option.ts +26 -0
  72. package/src/components/tek-grid/tek-grid-toolbar-provider/export-options/index.ts +3 -0
  73. package/src/components/tek-grid/tek-grid-toolbar-provider/export-options/interfaces.ts +6 -0
  74. package/src/components/tek-grid/tek-grid-toolbar-provider/export-options/multi-option.ts +85 -0
  75. package/src/components/tek-grid/tek-grid-toolbar-provider/index.ts +2 -0
  76. package/src/components/tek-grid/tek-grid-toolbar-provider/tek-grid-toolbar-provider.ts +365 -0
  77. package/src/components/tek-grid/tek-grid.ts +1118 -0
  78. package/src/components/tek-user-info/TekUserInfoController.ts +87 -0
  79. package/src/components/tek-user-info/interfaces.ts +21 -0
  80. package/src/components/tek-user-info/tek-user-info-list.ts +64 -0
  81. package/src/components/tek-user-info/tek-user-info.ts +337 -0
  82. package/src/error/tek-grid-delete-rows-error.ts +15 -0
  83. package/src/error/teknisa-common-error.ts +8 -0
  84. package/src/index.ts +2 -0
  85. package/src/utils/config/config.ts +8 -0
  86. package/src/utils/index.ts +3 -0
  87. package/src/utils/is-filled-object/is-filled-object.ts +5 -0
  88. package/src/utils/is-nil.ts +3 -0
  89. package/tests/__helpers__/component-event-helper.ts +1 -1
  90. package/tests/__helpers__/get-child-helper.ts +1 -1
  91. package/tests/__helpers__/mock-created-helper.ts +1 -1
  92. package/tests/unit/components/crud/crud-button.spec.ts +1 -1
  93. package/tests/unit/components/tek-datasource/memory-datasource.spec.ts +1 -11
  94. package/tests/unit/components/tek-datasource/rest-datasource.spec.ts +5 -7
  95. package/tests/unit/components/tek-drag-grid/tek-drag-grid.spec.ts +1 -1
  96. package/tests/unit/components/tek-grid/button-option.spec.ts +49 -0
  97. package/tests/unit/components/tek-grid/columns-searcher.spec.ts +112 -0
  98. package/tests/unit/components/tek-grid/dynamic-filter-datasource-factory.spec.ts +90 -0
  99. package/tests/unit/components/tek-grid/filter-helper.spec.ts +34 -130
  100. package/tests/unit/components/tek-grid/grid-filter-button.spec.ts +114 -239
  101. package/tests/unit/components/tek-grid/grouped-data-manager.spec.ts +593 -0
  102. package/tests/unit/components/tek-grid/grouped-data-selector.spec.ts +136 -0
  103. package/tests/unit/components/tek-grid/grouped-view-navigator.spec.ts +244 -0
  104. package/tests/unit/components/tek-grid/keymap-grouped.spec.ts +20 -0
  105. package/tests/unit/components/tek-grid/{layout_options.spec.ts → layout-options.spec.ts} +70 -30
  106. package/tests/unit/components/tek-grid/multi-option.spec.ts +139 -0
  107. package/tests/unit/components/tek-grid/{grid-column.spec.ts → tek-grid-column.spec.ts} +44 -2
  108. package/tests/unit/components/tek-grid/{grid-columns-button.spec.ts → tek-grid-columns-button.spec.ts} +42 -9
  109. package/tests/unit/components/tek-grid/tek-grid-controller.spec.ts +253 -0
  110. package/tests/unit/components/tek-grid/tek-grid-events.spec.ts +186 -0
  111. package/tests/unit/components/tek-grid/tek-grid-toolbar-provider.spec.ts +34 -0
  112. package/tests/unit/components/tek-grid/tek-grid.spec.ts +895 -0
  113. package/tests/unit/components/tek-grid/tek-memory-datasource.spec.ts +482 -0
  114. package/tests/unit/components/tek-grid/tek-rest-datasource.spec.ts +422 -0
  115. package/tests/unit/components/tek-user-info/tek-user-info-list.spec.ts +1 -1
  116. package/tests/unit/components/tek-user-info/tek-user-info.spec.ts +10 -14
  117. package/tests/unit/components/tree-grid/tree-grid.spec.ts +4 -28
  118. package/tests/unit/utils/grid-base/export-options/multi-option.spec.ts +2 -2
  119. package/tests/unit/utils/grid-base/grid-controller.spec.ts +17 -152
  120. package/tsconfig.build.json +7 -0
  121. package/coverage/clover.xml +0 -2007
  122. package/coverage/coverage-final.json +0 -48
  123. package/coverage/lcov-report/base.css +0 -224
  124. package/coverage/lcov-report/block-navigation.js +0 -87
  125. package/coverage/lcov-report/favicon.png +0 -0
  126. package/coverage/lcov-report/index.html +0 -431
  127. package/coverage/lcov-report/prettify.css +0 -1
  128. package/coverage/lcov-report/prettify.js +0 -2
  129. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  130. package/coverage/lcov-report/sorter.js +0 -210
  131. package/coverage/lcov-report/tests/__helpers__/component-event-helper.ts.html +0 -100
  132. package/coverage/lcov-report/tests/__helpers__/flush-promises-helper.ts.html +0 -94
  133. package/coverage/lcov-report/tests/__helpers__/get-child-helper.ts.html +0 -166
  134. package/coverage/lcov-report/tests/__helpers__/index.html +0 -176
  135. package/coverage/lcov-report/tests/__helpers__/index.ts.html +0 -94
  136. package/coverage/lcov-report/tests/__helpers__/mock-created-helper.ts.html +0 -121
  137. package/coverage/lcov.info +0 -3885
  138. package/dist/tek-components-common.esm.js +0 -4833
  139. package/dist/tek-components-common.umd.js +0 -4870
  140. package/tests/unit/components/tek-grid/grid.spec.ts +0 -3377
  141. package/tests/unit/utils/grid-base/delete-rows-error.spec.ts +0 -24
  142. package/types/components/crud/crud-add-button.d.ts +0 -38
  143. package/types/components/crud/crud-button.d.ts +0 -27
  144. package/types/components/crud/crud-cancel-button.d.ts +0 -28
  145. package/types/components/crud/crud-delete-button.d.ts +0 -42
  146. package/types/components/crud/crud-form.d.ts +0 -46
  147. package/types/components/crud/crud-save-button.d.ts +0 -24
  148. package/types/components/crud/interfaces.d.ts +0 -15
  149. package/types/components/index.d.ts +0 -41
  150. package/types/components/tek-card-title/card-title.d.ts +0 -14
  151. package/types/components/tek-card-title/interfaces.d.ts +0 -9
  152. package/types/components/tek-drag-grid/interfaces.d.ts +0 -7
  153. package/types/components/tek-drag-grid/tek-drag-grid.d.ts +0 -36
  154. package/types/components/tek-grid/grid.d.ts +0 -267
  155. package/types/components/tek-grid/interfaces.d.ts +0 -203
  156. package/types/components/tek-image/image.d.ts +0 -55
  157. package/types/components/tek-image/interfaces.d.ts +0 -12
  158. package/types/components/tek-iterable-carousel/interfaces.d.ts +0 -5
  159. package/types/components/tek-iterable-carousel/iterable-carousel.d.ts +0 -13
  160. package/types/components/tek-iterable-component-render/interfaces.d.ts +0 -3
  161. package/types/components/tek-iterable-component-render/iterable-component-render.d.ts +0 -10
  162. package/types/components/tek-loading/interfaces.d.ts +0 -6
  163. package/types/components/tek-loading/loading.d.ts +0 -24
  164. package/types/components/tek-notifications/interfaces.d.ts +0 -22
  165. package/types/components/tek-notifications/notifications.d.ts +0 -35
  166. package/types/components/tek-product-card/interfaces.d.ts +0 -19
  167. package/types/components/tek-product-card/product-card.d.ts +0 -66
  168. package/types/components/tek-tree-grid/interfaces.d.ts +0 -30
  169. package/types/components/tek-tree-grid/tree-grid.d.ts +0 -102
  170. package/types/error/incomplete-groups-error.d.ts +0 -8
  171. package/types/index.d.ts +0 -2
  172. package/types/utils/extract-properties.d.ts +0 -7
  173. package/types/utils/grid-base/export-options/interfaces.d.ts +0 -5
  174. package/types/utils/grid-base/grid-base.d.ts +0 -59
  175. package/types/utils/grid-base/grid-controller.d.ts +0 -27
  176. package/types/utils/index.d.ts +0 -6
  177. package/types/utils/report-filter/report-filter.d.ts +0 -12
@@ -0,0 +1,224 @@
1
+ import { DatasourceFactory, IDatasource, IDictionary, RestDatasource, URL } from '@zeedhi/core';
2
+ import { DynamicFilterOperations, DynamicFilterRelations, IDynamicFilterItem, ITekRestDatasource } from './interfaces';
3
+
4
+ export class TekRestDatasource extends RestDatasource implements ITekRestDatasource {
5
+ /** Dynamic filter data */
6
+ public dynamicFilter!: IDictionary<IDynamicFilterItem[]>;
7
+
8
+ /** Search Join data */
9
+ public searchJoin!: IDictionary<Array<string | number>>;
10
+
11
+ /**
12
+ * Dynamic Filter Operations
13
+ */
14
+ public dynamicFilterOperations = DynamicFilterOperations;
15
+
16
+ /**
17
+ * Dynamic Filter Relations
18
+ */
19
+ public dynamicFilterRelations = DynamicFilterRelations;
20
+
21
+ /**
22
+ * Dynamic Filter applied flag
23
+ */
24
+ protected dynamicFilterApplied = '';
25
+
26
+ /**
27
+ * Create new datasource
28
+ * @param props Datasource properties
29
+ */
30
+ constructor(props: ITekRestDatasource) {
31
+ super({ ...props, lazyLoad: true });
32
+
33
+ if (!this.watchUrl) {
34
+ this.dynamicFilter = this.getInitValue('dynamicFilter', props.dynamicFilter, {});
35
+ this.searchJoin = this.getInitValue('searchJoin', props.searchJoin, {});
36
+ }
37
+ this.lazyLoad = this.getInitValue('lazyLoad', props.lazyLoad, this.lazyLoad);
38
+
39
+ this.createAccessors();
40
+ this.createObjAccessors(this.dynamicFilter, 'dynamicFilter');
41
+ this.createObjAccessors(this.searchJoin, 'searchJoin');
42
+ }
43
+
44
+ protected updateReservedKeys() {
45
+ this.reservedKeys.dynamic_filter = true;
46
+ this.reservedKeys.search_join = true;
47
+ }
48
+
49
+ protected updateInternalProperties(datasource: IDatasource = {}) {
50
+ if (!this.watchUrl) return;
51
+ this.updateReservedKeys();
52
+ super.updateInternalProperties(datasource);
53
+ const queryString = URL.getParsedQueryStringFromUrl();
54
+ this.dynamicFilter = this.getEncodedParam(queryString.dynamic_filter, datasource.dynamicFilter);
55
+ this.searchJoin = this.getEncodedParam(queryString.search_join, datasource.searchJoin);
56
+ }
57
+
58
+ protected getEncodedParam(urlParam: string, datasourceParam: IDictionary<any> = {}): IDictionary<any> {
59
+ return urlParam ? JSON.parse(atob(urlParam)) : datasourceParam;
60
+ }
61
+
62
+ protected getQueryStringValues(): IDictionary<any> {
63
+ const values = super.getQueryStringValues();
64
+ if (this.dynamicFilter && Object.keys(this.dynamicFilter).length) {
65
+ values.dynamic_filter = btoa(JSON.stringify(this.dynamicFilter));
66
+ }
67
+ if (this.searchJoin && Object.keys(this.searchJoin).length) {
68
+ values.search_join = btoa(JSON.stringify(this.searchJoin));
69
+ }
70
+ return values;
71
+ }
72
+
73
+ protected getUrlQueryString() {
74
+ const superQueryString = super.getUrlQueryString();
75
+ const query = URL.getParsedQueryStringFromUrl();
76
+
77
+ let dynamicFilterQuerystring = '';
78
+ if (query.dynamic_filter) {
79
+ dynamicFilterQuerystring = `&${URL.getFormattedQueryString({
80
+ dynamic_filter: query.dynamic_filter,
81
+ })}`;
82
+ }
83
+
84
+ let searchJoinQuerystring = '';
85
+ if (query.search_join) {
86
+ searchJoinQuerystring = `&${URL.getFormattedQueryString({
87
+ search_join: query.search_join,
88
+ })}`;
89
+ }
90
+
91
+ return superQueryString + dynamicFilterQuerystring + searchJoinQuerystring;
92
+ }
93
+
94
+ /**
95
+ * Adds a new dynamic filter position or replace if exists
96
+ * @param column Dynamic Filter column name
97
+ * @param value Dynamic Filter value
98
+ * @returns Promise with data collection
99
+ */
100
+ public addDynamicFilter(column: string, value: any) {
101
+ if (this.isValidDynamicFilterValue(column, value)) {
102
+ this.dynamicFilter[column] = value;
103
+ return this.updateDynamicFilter();
104
+ }
105
+ return this.removeDynamicFilter(column);
106
+ }
107
+
108
+ /**
109
+ * Removes a dynamic filter position
110
+ * @param column Dynamic Filter column name
111
+ * @returns Promise with data collection
112
+ */
113
+ public removeDynamicFilter(column: string) {
114
+ delete this.dynamicFilter[column];
115
+ return this.updateDynamicFilter();
116
+ }
117
+
118
+ /**
119
+ * Sets new dynamic filter value
120
+ * @param filter Dynamic Filter value
121
+ * @returns Promise with data collection
122
+ */
123
+ public setDynamicFilter(filter: IDictionary<any>) {
124
+ this.dynamicFilter = {};
125
+ Object.keys(filter).forEach((column: string) => {
126
+ if (this.isValidDynamicFilterValue(column, filter[column])) {
127
+ this.dynamicFilter[column] = filter[column];
128
+ } else {
129
+ delete this.dynamicFilter[column];
130
+ }
131
+ });
132
+ return this.updateDynamicFilter();
133
+ }
134
+
135
+ /**
136
+ * Clears Dynamic filter value
137
+ * @returns Promise with data collection
138
+ */
139
+ public clearDynamicFilter() {
140
+ this.dynamicFilter = {};
141
+ return this.updateDynamicFilter();
142
+ }
143
+
144
+ /**
145
+ * Resets page and selected rows and tries to update the url
146
+ * @returns Promise with data collection
147
+ */
148
+ public async updateDynamicFilter() {
149
+ this.page = this.firstPage;
150
+ this.selectedRows = [];
151
+ this.visibleSelectedRows = [];
152
+ if (this.watchUrl) {
153
+ if (this.dynamicFilter && Object.keys(this.dynamicFilter).length) {
154
+ URL.updateQueryString({
155
+ dynamic_filter: btoa(JSON.stringify(this.dynamicFilter)),
156
+ });
157
+ } else {
158
+ URL.updateQueryString({
159
+ dynamic_filter: undefined,
160
+ });
161
+ }
162
+ }
163
+ return this.get();
164
+ }
165
+
166
+ /**
167
+ * Checks if a filter value is valid
168
+ * @param value Filter value
169
+ * @returns Is valid filter value
170
+ */
171
+ protected isValidDynamicFilterValue(column: string, value?: IDictionary<any>[]) {
172
+ return (
173
+ !this.reservedKeys[column] &&
174
+ value &&
175
+ value.length > 0 &&
176
+ value.every(
177
+ (filterValue) =>
178
+ this.dynamicFilterOperations[filterValue.operation] &&
179
+ this.dynamicFilterRelations[filterValue.relation] &&
180
+ filterValue.value !== '' &&
181
+ filterValue.value !== null,
182
+ )
183
+ );
184
+ }
185
+
186
+ /**
187
+ * Retrieves request params
188
+ */
189
+ protected getRequestParams(): any {
190
+ const requestParams = super.getRequestParams();
191
+ const isNotEmptyObj = (obj?: IDictionary) => !!(obj && Object.keys(obj).length);
192
+ const isValid =
193
+ this.dynamicFilter &&
194
+ Object.keys(this.dynamicFilter).every((column) => {
195
+ const value = this.dynamicFilter[column];
196
+
197
+ return value && value.length > 0 && this.isValidDynamicFilterValue(column, value);
198
+ });
199
+
200
+ if (isNotEmptyObj(this.dynamicFilter) && isValid) {
201
+ requestParams.dynamic_filter = btoa(JSON.stringify(this.dynamicFilter));
202
+ }
203
+
204
+ if (isNotEmptyObj(this.searchJoin)) {
205
+ requestParams.search_join = btoa(JSON.stringify(this.searchJoin));
206
+ }
207
+ return requestParams;
208
+ }
209
+
210
+ public hasFilter(columnName: string): boolean {
211
+ return this.dynamicFilter[columnName] && this.dynamicFilter[columnName].length > 0;
212
+ }
213
+
214
+ public clone() {
215
+ return {
216
+ ...super.clone(),
217
+ dynamicFilter: this.dynamicFilter,
218
+ searchJoin: this.searchJoin,
219
+ type: 'tek-rest',
220
+ };
221
+ }
222
+ }
223
+
224
+ DatasourceFactory.register('tek-rest', TekRestDatasource);
@@ -0,0 +1,22 @@
1
+ import { IDictionary } from '@zeedhi/core';
2
+ import { IColumnsSearcher, ITekGridColumn } from './interfaces';
3
+
4
+ export class ColumnsSearcher implements IColumnsSearcher {
5
+ async searchColumn(columns: ITekGridColumn[], search: string): Promise<IDictionary<(string | number)[]>> {
6
+ const lookupColumns = columns.filter((column) => !!column.componentProps?.datasource && !column.skipLookupSearch);
7
+ const searchJoin: IDictionary<Array<string | number>> = {};
8
+
9
+ if (search) {
10
+ const promises = lookupColumns.map(async (column) => {
11
+ const searchData = await column.memorySearch(search);
12
+
13
+ const lookupId = column.componentProps!.datasource.uniqueKey;
14
+ searchJoin[column.name] = searchData.map((row: IDictionary) => row[lookupId]);
15
+ });
16
+
17
+ await Promise.all(promises);
18
+ }
19
+
20
+ return searchJoin;
21
+ }
22
+ }
@@ -0,0 +1,20 @@
1
+ import { Datasource, DatasourceFactory, IDictionary } from '@zeedhi/core';
2
+ import { IDynamicFilterDatasourceFactory } from './interfaces';
3
+
4
+ export class DynamicFilterDatasourceFactory implements IDynamicFilterDatasourceFactory {
5
+ factory(options: IDictionary<boolean>): Datasource {
6
+ return DatasourceFactory.factory({
7
+ data: this.getFilterOptionsData(options),
8
+ loadAll: true,
9
+ translate: ['text'],
10
+ });
11
+ }
12
+
13
+ private getFilterOptionsData(options: IDictionary<boolean>): IDictionary<any>[] {
14
+ const optionsKeys = Object.keys(options);
15
+ return optionsKeys.map((item) => ({
16
+ text: `TEKGRID_${item}`,
17
+ value: item,
18
+ }));
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ import { DateHelper } from '@zeedhi/core';
2
+ import { TekGridColumn } from './tek-grid-column';
3
+
4
+ export class TekFilterHelper {
5
+ public static getLabel(name: string) {
6
+ return DateHelper.getLabel(name);
7
+ }
8
+
9
+ public static getValue(name: string, column: TekGridColumn) {
10
+ return DateHelper.getValue(name, column.componentProps.dateFormat);
11
+ }
12
+
13
+ public static register(name: string, label: string, fn: () => Date | [Date, Date]) {
14
+ DateHelper.register(name, label, fn);
15
+ }
16
+
17
+ public static unregister(name: string) {
18
+ DateHelper.unregister(name);
19
+ }
20
+ }
@@ -0,0 +1,419 @@
1
+ import { IDictionary, IEventParam, Metadata } from '@zeedhi/core';
2
+ import {
3
+ Button,
4
+ Form,
5
+ IModal,
6
+ Input,
7
+ Iterable,
8
+ Modal,
9
+ ModalService,
10
+ } from '@zeedhi/common';
11
+ import { ISupportsToolbar, ITekGridColumn, ITekGridFilterButton } from './interfaces';
12
+ import { TekGridColumn } from './tek-grid-column';
13
+ import { TekMemoryDatasource, TekRestDatasource } from '../tek-datasource';
14
+ import { TekFilterHelper } from './filter-helper';
15
+
16
+ /**
17
+ * Base class for TekGrid Filter Button component
18
+ */
19
+ export class TekGridFilterButton extends Button implements ITekGridFilterButton {
20
+ public gridName?: string;
21
+
22
+ public grid: Iterable<TekGridColumn> & ISupportsToolbar;
23
+
24
+ public showCheckboxAll = false;
25
+
26
+ private filterModal?: Modal;
27
+
28
+ protected filterFormInputs: IDictionary<string[]> = {};
29
+
30
+ constructor(props: ITekGridFilterButton) {
31
+ super(props);
32
+ this.gridName = this.getInitValue('gridName', props.gridName, this.gridName);
33
+ this.grid = this.getInitValue('grid', props.grid, undefined);
34
+ this.showCheckboxAll = this.getInitValue('showCheckboxAll', props.showCheckboxAll, this.showCheckboxAll);
35
+ this.createAccessors();
36
+
37
+ if (!this.grid) this.loadGrid();
38
+ }
39
+
40
+ public loadGrid(gridName?: string) {
41
+ if (gridName) this.gridName = gridName;
42
+ if (!this.gridName) return;
43
+
44
+ this.grid = Metadata.getInstances(this.gridName)[0];
45
+ }
46
+
47
+ public click(event?: Event) {
48
+ this.callEvent('click', { component: this, event });
49
+ this.grid.callEvent('filterClick', { component: this.grid, event });
50
+ if (!event?.defaultPrevented) {
51
+ this.createFilterFromColumns.call(this);
52
+ }
53
+ }
54
+
55
+ private loadFilterValues({ component }: IEventParam<Form>) {
56
+ const changedCompNames: string[] = [];
57
+
58
+ const { datasource } = this.grid;
59
+ if (datasource instanceof TekRestDatasource || datasource instanceof TekMemoryDatasource) {
60
+ const { dynamicFilter } = datasource;
61
+
62
+ const newDynamicFilter = { ...this.grid.defaultFilter, ...dynamicFilter };
63
+
64
+ Object.keys(newDynamicFilter).forEach((column) => {
65
+ if (newDynamicFilter[column] && newDynamicFilter[column].length > 0) {
66
+ newDynamicFilter[column].forEach((filterItem: any, index: number) => {
67
+ const relation = filterItem.relation || 'AND';
68
+ const operation = filterItem.operation || 'CONTAINS';
69
+ const compName = `${this.grid!.name}-filter-${relation}-${operation}-${column}-${index}`;
70
+ changedCompNames.push(compName);
71
+ component.value[compName] = filterItem.value;
72
+
73
+ let helperValue = '';
74
+ const columnObj = this.grid!.getColumn(column);
75
+ if (columnObj instanceof TekGridColumn) {
76
+ const { filterProps } = columnObj;
77
+ if (!Array.isArray(filterProps)) {
78
+ helperValue = filterProps.helperValue || '';
79
+ } else {
80
+ filterProps.forEach((prop) => {
81
+ if ((prop.relation || 'AND') === relation && (prop.operation || 'CONTAINS') === operation) {
82
+ helperValue = prop.helperValue || '';
83
+ }
84
+ });
85
+ }
86
+ const inputObj = Metadata.getInstances(compName);
87
+ if (helperValue && inputObj.length && inputObj[0]) {
88
+ (inputObj[0] as Input).hint = TekFilterHelper.getLabel(helperValue);
89
+ }
90
+ }
91
+ });
92
+ }
93
+ });
94
+ } else {
95
+ const { filter } = datasource;
96
+
97
+ const newFilter = { ...this.grid.defaultFilter, ...filter };
98
+
99
+ Object.keys(newFilter).forEach((item) => {
100
+ if (newFilter[item]) {
101
+ const compName = `${this.grid!.name}-filter-AND-CONTAINS-${item}-0`;
102
+ changedCompNames.push(compName);
103
+ component.value[compName] = newFilter[item];
104
+ }
105
+ });
106
+ }
107
+
108
+ Object.keys(component.value).forEach((compName: string) => {
109
+ if (changedCompNames.indexOf(compName) === -1) {
110
+ component.value[compName] = null;
111
+ }
112
+ });
113
+ }
114
+
115
+ public hideFilterModal() {
116
+ this.filterModal!.hide();
117
+ }
118
+
119
+ public destroyFilterModal() {
120
+ if (this.filterModal) this.filterModal!.destroy();
121
+ }
122
+
123
+ private createFilterFromColumns() {
124
+ if (!this.filterModal) {
125
+ const originalProps = {
126
+ height: 'auto',
127
+ maxHeight: '18.75rem',
128
+ persistent: true,
129
+ title: 'FILTER',
130
+ };
131
+ const mergeModalFilterProps = Object.assign(originalProps, this.grid.modalFilterProps);
132
+ const filterModalDef: IModal = {
133
+ name: `${this.grid.name}-filter-modal`,
134
+ persistent: mergeModalFilterProps.persistent,
135
+ grid: mergeModalFilterProps.grid,
136
+ cssClass: mergeModalFilterProps.cssClass,
137
+ cssStyle: mergeModalFilterProps.cssStyle,
138
+ draggable: mergeModalFilterProps.draggable,
139
+ dragHandle: mergeModalFilterProps.dragHandle,
140
+ fullscreen: mergeModalFilterProps.fullscreen,
141
+ light: mergeModalFilterProps.light,
142
+ dark: mergeModalFilterProps.dark,
143
+ escKeydownStop: false,
144
+ children: [
145
+ {
146
+ name: `${this.grid.name}-filter-header-container`,
147
+ component: 'ZdContainer',
148
+ cssClass: 'zd-pa-0 zd-display-flex',
149
+ children: [
150
+ {
151
+ name: `${this.grid.name}-filter-title`,
152
+ component: 'ZdText',
153
+ cssStyle: `color: ${'var(--v-primary-base);'}`,
154
+ text: mergeModalFilterProps.title,
155
+ tag: 'h3',
156
+ },
157
+ {
158
+ name: `${this.grid.name}-filter-spacer`,
159
+ component: 'VSpacer',
160
+ },
161
+ {
162
+ name: `${this.grid.name}-filter-close-button`,
163
+ component: 'ZdModalCloseButton',
164
+ small: true,
165
+ modalName: `${this.grid.name}-filter-modal`,
166
+ },
167
+ ],
168
+ },
169
+ {
170
+ name: `${this.grid.name}-filter-content-container`,
171
+ component: 'ZdContainer',
172
+ scrollView: true,
173
+ cssClass: 'zd-my-2 zd-pa-0 tek-grid-filter-content-container',
174
+ maxHeight: mergeModalFilterProps!.maxHeight,
175
+ height: mergeModalFilterProps!.height,
176
+ children: [
177
+ {
178
+ name: `${this.grid.name}-filter-form`,
179
+ component: 'ZdForm',
180
+ cssClass: 'zd-my-2 zd-pa-0',
181
+ children: this.getFilterModalComponents(),
182
+ events: {
183
+ onMounted: this.loadFilterValues.bind(this),
184
+ },
185
+ },
186
+ ],
187
+ },
188
+ {
189
+ name: `${this.grid.name}-filter-footer-container`,
190
+ component: 'ZdContainer',
191
+ cssClass: 'zd-pa-0',
192
+ children: [
193
+ {
194
+ name: `${this.grid.name}-filter-footer`,
195
+ component: 'ZdFooter',
196
+ color: 'transparent',
197
+ padless: true,
198
+ leftSlot: [
199
+ {
200
+ name: `${this.grid.name}-filter-clearButton`,
201
+ component: 'ZdButton',
202
+ label: 'CLEAR',
203
+ outline: true,
204
+ events: {
205
+ click: this.clearFilter.bind(this),
206
+ },
207
+ },
208
+ ],
209
+ rightSlot: [
210
+ {
211
+ name: `${this.grid.name}-filter-cancelButton`,
212
+ component: 'ZdButton',
213
+ label: 'CANCEL',
214
+ keyMap: {
215
+ esc: {
216
+ event: this.hideFilterModal.bind(this),
217
+ focus: true,
218
+ visible: true,
219
+ input: true,
220
+ stop: true,
221
+ },
222
+ },
223
+ outline: true,
224
+ events: {
225
+ click: this.hideFilterModal.bind(this),
226
+ },
227
+ },
228
+ {
229
+ name: `${this.grid.name}-filter-okButton`,
230
+ component: 'ZdButton',
231
+ label: 'OK',
232
+ events: {
233
+ click: this.applyFilter.bind(this),
234
+ },
235
+ keyMap: {
236
+ 'mod+enter': {
237
+ event: this.applyFilter.bind(this),
238
+ focus: true,
239
+ input: true,
240
+ stop: true,
241
+ visible: true,
242
+ },
243
+ },
244
+ },
245
+ ],
246
+ },
247
+ ],
248
+ },
249
+ ],
250
+ };
251
+
252
+ this.filterModal = ModalService.create(filterModalDef);
253
+ } else {
254
+ this.loadFilterValues({ component: Metadata.getInstance(`${this.grid.name}-filter-form`) });
255
+ }
256
+ this.filterModal.show();
257
+ }
258
+
259
+ public onBeforeDestroy() {
260
+ super.onBeforeDestroy();
261
+ this.destroyFilterModal();
262
+ }
263
+
264
+ private formatFormValue(filterForm: Form) {
265
+ // TODO: add this logic when SelectMultiple is implemented
266
+ // return Object.keys(filterForm.value).reduce((result, item) => {
267
+ // try {
268
+ // const itemInstance = filterForm.getChildInstance<Input>(item);
269
+ // if (!(itemInstance instanceof SelectMultiple) || !itemInstance.checkboxAll) return result;
270
+ // // when selectmultiple with checkboxAll, should either remove it from the filter or
271
+ // // change the value to T, depending on selectAllCompatibilityMode
272
+ // if ((Config as ITekConfig).selectAllCompatibilityMode) {
273
+ // result[item] = 'T';
274
+ // return result;
275
+ // }
276
+
277
+ // delete result[item];
278
+ // return result;
279
+ // } catch (e) {
280
+ // return result;
281
+ // }
282
+ // }, { ...filterForm.value });
283
+
284
+ return filterForm.value;
285
+ }
286
+
287
+ private async applyFilter({ event }: any) {
288
+ const filterForm = Metadata.getInstance<Form>(`${this.grid.name}-filter-form`);
289
+ const isFormValid = await filterForm.validate();
290
+ if (isFormValid.valid) {
291
+ const { datasource } = this.grid;
292
+ const filter: IDictionary = {};
293
+ const formValue = this.formatFormValue(filterForm);
294
+
295
+ if (datasource instanceof TekRestDatasource || datasource instanceof TekMemoryDatasource) {
296
+ Object.keys(formValue).forEach((item) => {
297
+ const itemValue = formValue[item];
298
+
299
+ if (itemValue && !(Array.isArray(itemValue) && !itemValue.length)) {
300
+ const relationAndOperationAndName = item.split(`${this.grid!.name}-filter-`)[1];
301
+ const [relation, operation] = relationAndOperationAndName.split('-');
302
+ let columnName = relationAndOperationAndName.split(`${relation}-${operation}-`)[1];
303
+ columnName = columnName.split('-').slice(0, -1).join('-'); // remove index
304
+
305
+ if (!filter[columnName]) {
306
+ filter[columnName] = [];
307
+ }
308
+
309
+ const value = itemValue;
310
+ filter[columnName].push({
311
+ relation,
312
+ operation,
313
+ value,
314
+ });
315
+ }
316
+ });
317
+
318
+ datasource.dynamicFilter = filter;
319
+ this.setFilter(filter, event, datasource.setDynamicFilter.bind(datasource));
320
+ } else {
321
+ Object.keys(formValue).forEach((item) => {
322
+ let columnName = item.split(`${this.grid!.name}-filter-AND-CONTAINS-`)[1];
323
+ columnName = columnName.split('-').slice(0, -1).join('-'); // remove index
324
+
325
+ if (formValue[item]) {
326
+ filter[columnName] = formValue[item];
327
+ }
328
+ });
329
+
330
+ datasource.filter = filter;
331
+ this.setFilter(filter, event, datasource.setFilter.bind(datasource));
332
+ }
333
+
334
+ this.grid.changeLayout(event);
335
+ }
336
+ }
337
+
338
+ private setFilter(filter: IDictionary, event: Event, filterFn: (filter: IDictionary) => Promise<any>) {
339
+ this.grid.callEvent('beforeApplyFilter', { component: this.grid, event });
340
+ if (event.defaultPrevented) return;
341
+
342
+ filterFn(filter);
343
+ this.hideFilterModal();
344
+ }
345
+
346
+ private clearFilter() {
347
+ const filterForm = Metadata.getInstance<Form>(`${this.grid!.name}-filter-form`);
348
+ Object.keys(filterForm.value).forEach((item) => {
349
+ filterForm.value[item] = null;
350
+ });
351
+ }
352
+
353
+ private sortFilterIndex(col1: ITekGridColumn, col2: ITekGridColumn) {
354
+ const index1 = col1.filterIndex !== undefined ? col1.filterIndex : Number.MAX_SAFE_INTEGER;
355
+ const index2 = col2.filterIndex !== undefined ? col2.filterIndex : Number.MAX_SAFE_INTEGER;
356
+ return index1 - index2;
357
+ }
358
+
359
+ private getFilterModalComponents() {
360
+ const filterColumns: ITekGridColumn[] = [];
361
+ let columnComponentName: any;
362
+ [...this.grid.columns].sort(this.sortFilterIndex).forEach((column) => {
363
+ const filterProps = Array.isArray(column.filterProps) ? column.filterProps : [column.filterProps];
364
+ if (column.filterable && filterProps && filterProps.length > 0) {
365
+ this.filterFormInputs[column.name] = [];
366
+
367
+ filterProps.forEach((filterItem, index: number) => {
368
+ const { datasource } = this.grid;
369
+ if (datasource instanceof TekRestDatasource || datasource instanceof TekMemoryDatasource) {
370
+ const relation = filterItem.relation || 'AND';
371
+ const operation = filterItem.operation || 'CONTAINS';
372
+
373
+ columnComponentName = `${this.grid!.name}-filter-${relation}-${operation}-${column.name}-${index}`;
374
+ } else {
375
+ columnComponentName = `${this.grid!.name}-filter-AND-CONTAINS-${column.name}-${index}`;
376
+ }
377
+
378
+ this.filterFormInputs[column.name].push(columnComponentName);
379
+
380
+ const newColumnComponent = {
381
+ label: column.label,
382
+ ...column.componentProps,
383
+ ...filterItem,
384
+ name: columnComponentName,
385
+ };
386
+
387
+ if (filterItem.helperOptions) {
388
+ if (!newColumnComponent.events) newColumnComponent.events = {};
389
+ newColumnComponent.events.change = this.changeHelperEvent.bind(this, column);
390
+ }
391
+
392
+ if (newColumnComponent.component === 'ZdSelectMultiple') {
393
+ newColumnComponent.showCheckboxAll = newColumnComponent.showCheckboxAll ?? this.showCheckboxAll;
394
+ }
395
+
396
+ filterColumns.push(newColumnComponent);
397
+ });
398
+ }
399
+ });
400
+ return filterColumns;
401
+ }
402
+
403
+ private changeHelperEvent(column: TekGridColumn, { component }: any) {
404
+ const { helperValue } = component;
405
+ const componentName = component.name;
406
+
407
+ if (!Array.isArray(column.filterProps)) {
408
+ column.filterProps.helperValue = helperValue;
409
+ } else {
410
+ column.filterProps.forEach((prop) => {
411
+ const relationAndOperationAndName = componentName.split(`${this.grid!.name}-filter-`)[1];
412
+ const [relation, operation] = relationAndOperationAndName.split('-');
413
+ if ((prop.relation || 'AND') === relation && (prop.operation || 'CONTAINS') === operation) {
414
+ prop.helperValue = helperValue;
415
+ }
416
+ });
417
+ }
418
+ }
419
+ }