@digital-realty/ix-grid 1.4.1-alpha.1 → 1.4.1-alpha.2

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 (65) hide show
  1. package/dist/ix-grid.min.js +5 -5
  2. package/package.json +4 -4
  3. package/rollup.config.mjs +32 -6
  4. package/src/IxGrid.d.ts +148 -0
  5. package/src/IxGrid.js +784 -0
  6. package/src/IxGrid.js.map +1 -0
  7. package/src/IxGridNav.d.ts +2 -0
  8. package/src/IxGridNav.js +8 -0
  9. package/src/IxGridNav.js.map +1 -0
  10. package/src/components/IxGridColumnFilter.d.ts +35 -0
  11. package/src/components/IxGridColumnFilter.js +249 -0
  12. package/src/components/IxGridColumnFilter.js.map +1 -0
  13. package/src/components/IxGridDownloadMenu.d.ts +17 -0
  14. package/src/components/IxGridDownloadMenu.js +98 -0
  15. package/src/components/IxGridDownloadMenu.js.map +1 -0
  16. package/src/components/IxGridNav.d.ts +16 -0
  17. package/src/components/IxGridNav.js +103 -0
  18. package/src/components/IxGridNav.js.map +1 -0
  19. package/src/components/IxGridNoRows.d.ts +10 -0
  20. package/src/components/IxGridNoRows.js +74 -0
  21. package/src/components/IxGridNoRows.js.map +1 -0
  22. package/src/components/IxGridRowFilter.d.ts +55 -0
  23. package/src/components/IxGridRowFilter.js +441 -0
  24. package/src/components/IxGridRowFilter.js.map +1 -0
  25. package/src/components/IxPagination.d.ts +14 -0
  26. package/src/components/IxPagination.js +107 -0
  27. package/src/components/IxPagination.js.map +1 -0
  28. package/src/components/grid-column-filter-styles.d.ts +1 -0
  29. package/src/components/grid-column-filter-styles.js +89 -0
  30. package/src/components/grid-column-filter-styles.js.map +1 -0
  31. package/src/components/grid-row-filter-styles.d.ts +1 -0
  32. package/src/components/grid-row-filter-styles.js +311 -0
  33. package/src/components/grid-row-filter-styles.js.map +1 -0
  34. package/src/components/ix-grid-no-rows.d.ts +1 -0
  35. package/src/components/ix-grid-no-rows.js +2 -0
  36. package/src/components/ix-grid-no-rows.js.map +1 -0
  37. package/src/components/pagination-styles.d.ts +1 -0
  38. package/src/components/pagination-styles.js +84 -0
  39. package/src/components/pagination-styles.js.map +1 -0
  40. package/src/grid-view-styles.d.ts +1 -0
  41. package/src/grid-view-styles.js +283 -0
  42. package/src/grid-view-styles.js.map +1 -0
  43. package/src/index.d.ts +3 -0
  44. package/src/index.js +3 -0
  45. package/src/index.js.map +1 -0
  46. package/src/ix-grid-copy.d.ts +12 -0
  47. package/src/ix-grid-copy.js +12 -0
  48. package/src/ix-grid-copy.js.map +1 -0
  49. package/src/ix-grid-nav.d.ts +1 -0
  50. package/src/ix-grid-nav.js +2 -0
  51. package/src/ix-grid-nav.js.map +1 -0
  52. package/src/ix-grid-no-rows.d.ts +1 -0
  53. package/src/ix-grid-no-rows.js +2 -0
  54. package/src/ix-grid-no-rows.js.map +1 -0
  55. package/src/ix-grid.d.ts +1 -0
  56. package/src/ix-grid.js +2 -0
  57. package/src/ix-grid.js.map +1 -0
  58. package/src/models/IxGridDownloadMenuItemModel.d.ts +7 -0
  59. package/src/models/IxGridDownloadMenuItemModel.js +1 -0
  60. package/src/models/IxGridDownloadMenuItemModel.js.map +1 -0
  61. package/src/test/ix-grid-column-filter.test.js +41 -0
  62. package/src/test/ix-grid-row-filter.test.js +281 -0
  63. package/src/test/ix-grid.test.js +391 -0
  64. package/src/test/ix-pagination.test.js +58 -0
  65. package/web-test-runner.config.mjs +1 -1
package/src/IxGrid.js ADDED
@@ -0,0 +1,784 @@
1
+ import { __decorate } from "tslib";
2
+ /* eslint-disable import/no-duplicates */
3
+ import '@digital-realty/grid';
4
+ import { columnHeaderRenderer } from '@digital-realty/grid/lit.js';
5
+ import '@digital-realty/ix-icon-button/ix-icon-button.js';
6
+ import '@digital-realty/ix-icon/ix-icon.js';
7
+ import '@digital-realty/ix-progress/ix-progress.js';
8
+ import { html, LitElement, nothing, render } from 'lit';
9
+ import { property, query, state } from 'lit/decorators.js';
10
+ import { classMap } from 'lit/directives/class-map.js';
11
+ import { ifDefined } from 'lit/directives/if-defined.js';
12
+ import { formatDate } from 'date-fns';
13
+ import './components/IxGridColumnFilter.js';
14
+ import './components/IxGridDownloadMenu.js';
15
+ import './components/IxGridRowFilter.js';
16
+ import './components/IxPagination.js';
17
+ import { IxGridViewStyles } from './grid-view-styles.js';
18
+ import { copy } from './ix-grid-copy.js';
19
+ export class IxGrid extends LitElement {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.defaultPageSize = 10;
23
+ this.defaultPage = 1;
24
+ this.originalSearchParams = undefined;
25
+ this.columnReorderingAllowed = false;
26
+ this.variantClass = '';
27
+ this.columns = [];
28
+ this.rows = [];
29
+ this.defaultEmptyText = 'No data to display';
30
+ this.sortedColumn = '';
31
+ this.sortDirection = '';
32
+ this.hideHeader = false;
33
+ this.hideFilters = false;
34
+ this.rowLimit = 0;
35
+ this.page = this.defaultPage;
36
+ this.pageSize = this.defaultPageSize;
37
+ this.pageSizes = [5, 10, 25, 100];
38
+ this.recordCount = 0;
39
+ this.localStorageID = undefined;
40
+ this.showDownload = true;
41
+ this.isDownloading = false;
42
+ this.isLoading = false;
43
+ this.downloadMenuItems = [];
44
+ this.addParamsToURL = true;
45
+ this.readParamsFromURL = false;
46
+ this.refreshDataOnColumnVisibilityChange = true;
47
+ this.filterValueChangeDebounceTime = 300;
48
+ this.hideColumnHeaders = false;
49
+ this.preservedQueryParamKeys = [];
50
+ this.filterMaxDate = formatDate(new Date(), 'yyyy-MM-dd');
51
+ this.hashedTableState = '';
52
+ this.hideViewMoreLessButtonIcon = true;
53
+ this.showAddButton = false;
54
+ this.disableAddButton = false;
55
+ this.addButtonLabel = copy.add;
56
+ this.showRemoveAllButton = false;
57
+ this.disableRemoveAllButton = false;
58
+ this.removeAllButtonLabel = copy.removeAll;
59
+ this.filters = [];
60
+ this.isColumnsReordering = false;
61
+ this.isExpanded = false;
62
+ this.displayColumns = [];
63
+ this.defaultFilterKeys = ['sort', 'order', 'page', 'size'];
64
+ this.initialised = false;
65
+ this.handlePopState = () => {
66
+ this.updateSearchParamsFromUri(true);
67
+ this.dispatchChangeEvent();
68
+ };
69
+ this.dispatchChangeEvent = () => {
70
+ const filters = this.filters.reduce((columnFilters, { columnField, value }) => ({
71
+ ...columnFilters,
72
+ [columnField]: value,
73
+ }), {});
74
+ this.dispatchEvent(new CustomEvent('change', {
75
+ detail: {
76
+ columnName: this.sortedColumn,
77
+ sortOrder: this.sortDirection,
78
+ page: this.page,
79
+ pageSize: this.pageSize,
80
+ filters,
81
+ filtersOperators: this.filters.map((f) => ({
82
+ columnField: f.columnField,
83
+ operator: f.operatorValue,
84
+ })),
85
+ },
86
+ bubbles: true,
87
+ composed: true,
88
+ }));
89
+ };
90
+ this.renderColumnHeader = (column, nextColumn, index, length) => {
91
+ const headerClasses = classMap({
92
+ header: true,
93
+ frozen: !!column.frozenToEnd,
94
+ first: index === 0,
95
+ last: index === length - 1,
96
+ border: !(nextColumn === null || nextColumn === void 0 ? void 0 : nextColumn.frozenToEnd),
97
+ });
98
+ return html `
99
+ <div
100
+ @click=${() => column.sortable && this.handleSort(column.name)}
101
+ @keyDown=${() => column.sortable && this.handleSort(column.name)}
102
+ class=${headerClasses}
103
+ >
104
+ <span class="header-label">${column.header}</span>
105
+ ${column.sortable
106
+ ? html `<ix-icon title="Sort" class="header-sort-icon"
107
+ >${this.sortDirection === 'desc' &&
108
+ this.sortedColumn === column.name
109
+ ? `arrow_upward`
110
+ : `arrow_downward`}</ix-icon
111
+ >`
112
+ : nothing}
113
+ </div>
114
+ `;
115
+ };
116
+ this.columnRenderer = (column, root, columnElement, model) => {
117
+ /*
118
+ Due to a quirk of vaadin-grid, in order for the column cells to react to
119
+ changes to bodyRenderer output, we must clear the contents of the cell
120
+ before rendering the new content. Otherwise the new content will be
121
+ appended to the existing content.
122
+ */
123
+ render(nothing, root);
124
+ const templateResult = column.bodyRenderer(model.item, model, columnElement);
125
+ let styledWrapper = templateResult;
126
+ const shouldApplyMaxWidth = !!column.maxWidth;
127
+ const maxWidthSetClass = 'column-max-width-set';
128
+ if (shouldApplyMaxWidth) {
129
+ styledWrapper = html `
130
+ <div class="${maxWidthSetClass}" style="max-width: ${column.maxWidth}">
131
+ ${templateResult}
132
+ </div>
133
+ `;
134
+ }
135
+ render(styledWrapper, root);
136
+ if (shouldApplyMaxWidth) {
137
+ requestAnimationFrame(() => {
138
+ var _a;
139
+ const el = root.querySelector(`.${maxWidthSetClass}`);
140
+ if (el && el.scrollWidth > el.clientWidth) {
141
+ if (!el.querySelector('.custom-tooltip') && ((_a = el.textContent) === null || _a === void 0 ? void 0 : _a.trim())) {
142
+ const tooltip = document.createElement('div');
143
+ tooltip.className = 'custom-tooltip';
144
+ tooltip.style.cssText = `
145
+ background-color: #092241;
146
+ font-size: 0.75rem;
147
+ color: white;
148
+ text-align: left;
149
+ padding: 0.313rem 0.5rem;
150
+ border-radius: 0.188rem;
151
+ max-height: 31.25rem;
152
+ overflow: hidden;
153
+ position: absolute;
154
+ z-index: 1000;
155
+ display: none;
156
+ `;
157
+ tooltip.textContent = el.textContent;
158
+ el.addEventListener('mouseenter', () => {
159
+ tooltip.style.display = 'flex';
160
+ const rect = el.getBoundingClientRect();
161
+ tooltip.style.left = `${rect.left}px`;
162
+ tooltip.style.top = `${rect.bottom + window.scrollY + 4}px`;
163
+ document.body.appendChild(tooltip);
164
+ });
165
+ el.addEventListener('mouseleave', () => {
166
+ tooltip.remove();
167
+ });
168
+ }
169
+ }
170
+ });
171
+ }
172
+ };
173
+ this.renderHeader = () => html `
174
+ <div class="grid-header">
175
+ <slot name="header"><div class="empty"></div></slot>
176
+ ${this.hideFilters
177
+ ? nothing
178
+ : html `<div class="grid-menu">
179
+ <slot name="filters"><div class="empty"></div></slot>
180
+ <ix-grid-column-filter
181
+ .columns=${this.arrangedColumns}
182
+ columnsLocalStorageKey=${ifDefined(this.columnsLocalStorageKey)}
183
+ @columnFilter=${(e) => this.handleOnColumnFilter(e)}
184
+ @reorderColumns=${this.reorderColumnsFromFilter}
185
+ .columnReorderingAllowed=${this.columnReorderingAllowed}
186
+ .refreshDataOnColumnVisibilityChange=${this
187
+ .refreshDataOnColumnVisibilityChange}
188
+ .requestGridUpdate=${() => this.requestUpdate()}
189
+ ></ix-grid-column-filter>
190
+ ${this.showDownload
191
+ ? html `<ix-grid-download-menu
192
+ .items=${this.downloadMenuItems}
193
+ .isDownloading=${this.isDownloading}
194
+ ></ix-grid-download-menu>`
195
+ : nothing}
196
+ <ix-grid-row-filter
197
+ .columns=${this.displayColumns}
198
+ .filterValueChangeDebounceTime=${this
199
+ .filterValueChangeDebounceTime}
200
+ .readParamsFromURL=${this.readParamsFromURL}
201
+ .maxDate=${this.filterMaxDate}
202
+ @rowFilter=${(e) => {
203
+ this.filters = e.detail.filters;
204
+ if (e.detail.resetPage) {
205
+ this.page = this.defaultPage;
206
+ }
207
+ this.updatePage();
208
+ }}
209
+ ></ix-grid-row-filter>
210
+ </div>`}
211
+ </div>
212
+ <div class="touch-edge">
213
+ <slot name="under-header"></slot>
214
+ </div>
215
+ `;
216
+ this.renderRowControls = () => {
217
+ if (this.showAddButton === false &&
218
+ this.showRemoveAllButton === false &&
219
+ this.showViewMoreLessButton === false) {
220
+ return nothing;
221
+ }
222
+ return html ` <div class="row-controls row-limit">
223
+ ${this.renderAddNewButton()} ${this.renderViewMoreLessButton()}
224
+ ${this.renderRemoveAllButton()}
225
+ </div>`;
226
+ };
227
+ this.renderPaginationControls = () => html `
228
+ <div class="row-controls pagination">
229
+ <ix-pagination
230
+ .page=${this.page}
231
+ .pageSize=${this.pageSize}
232
+ .pageSizes=${this.pageSizes}
233
+ .recordCount=${this.recordCount}
234
+ @updatePagination=${(e) => {
235
+ this.page = e.detail.page;
236
+ this.pageSize = e.detail.pageSize;
237
+ this.updatePage();
238
+ }}
239
+ ></ix-pagination>
240
+ </div>
241
+ `;
242
+ }
243
+ get isPersistable() {
244
+ if (this.localStorageID)
245
+ return true;
246
+ return false;
247
+ }
248
+ get columnNames() {
249
+ return this.columns.map((column) => column.name);
250
+ }
251
+ get columnsLocalStorageKey() {
252
+ if (this.hashedTableState === '') {
253
+ const columnsWithoutFunctions = this.columns.map(
254
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
255
+ ({ bodyRenderer, hidden, ...rest }) => rest);
256
+ const serializedColumns = JSON.stringify(columnsWithoutFunctions);
257
+ let hash = 0;
258
+ for (let i = 0; i < serializedColumns.length; i += 1) {
259
+ // Update hash using prime number multiplier (31) for better distribution and ensure it doesn't exceed 32-bit integer
260
+ // eslint-disable-next-line no-bitwise
261
+ hash = (hash * 31 + serializedColumns.charCodeAt(i)) >>> 0;
262
+ }
263
+ // Convert the string to base36 for brevity
264
+ this.hashedTableState = hash.toString(36);
265
+ }
266
+ return `ix-grid-${this.localStorageID}-${this.hashedTableState}-columns`;
267
+ }
268
+ get arrangedColumns() {
269
+ let columnsToDisplay = [];
270
+ columnsToDisplay = this.getColumnsToDisplayFromLocalStorage();
271
+ if (columnsToDisplay.length === 0)
272
+ columnsToDisplay = [...this.columns];
273
+ return columnsToDisplay
274
+ .filter(col => col)
275
+ .map((column) => ({
276
+ ...column,
277
+ width: !column.width ? undefined : column.width,
278
+ }));
279
+ }
280
+ connectedCallback() {
281
+ var _a;
282
+ (_a = super.connectedCallback) === null || _a === void 0 ? void 0 : _a.call(this);
283
+ window.addEventListener('popstate', this.handlePopState);
284
+ }
285
+ disconnectedCallback() {
286
+ var _a;
287
+ window.removeEventListener('popstate', this.handlePopState);
288
+ (_a = super.disconnectedCallback) === null || _a === void 0 ? void 0 : _a.call(this);
289
+ }
290
+ updateSearchParamsFromUri(rebuildFiltersFromUri = false) {
291
+ if (this.readParamsFromURL) {
292
+ const url = new URL(window.location.href);
293
+ const searchParams = new URLSearchParams(url.search);
294
+ const [sortKey, orderKey, pageKey, sizeKey] = this.defaultFilterKeys;
295
+ const sort = searchParams.get(sortKey);
296
+ const order = searchParams.get(orderKey);
297
+ const page = searchParams.get(pageKey);
298
+ const size = searchParams.get(sizeKey);
299
+ if (sort && order) {
300
+ this.sortedColumn = sort;
301
+ this.sortDirection = order;
302
+ }
303
+ if (page) {
304
+ this.page = parseInt(page, 10) || this.defaultPage;
305
+ }
306
+ if (size) {
307
+ this.pageSize = parseInt(size, 10) || this.defaultPageSize;
308
+ }
309
+ if (rebuildFiltersFromUri) {
310
+ this.rebuildFiltersFromUri(searchParams);
311
+ }
312
+ }
313
+ }
314
+ rebuildFiltersFromUri(searchParams) {
315
+ const filters = [];
316
+ for (const [key, value] of searchParams.entries()) {
317
+ const isDefaultKey = this.defaultFilterKeys.includes(key);
318
+ const [columnField, operatorValue] = key.split('_');
319
+ if (!isDefaultKey && columnField && operatorValue) {
320
+ filters.push({
321
+ columnField,
322
+ operatorValue,
323
+ value,
324
+ });
325
+ }
326
+ }
327
+ this.filters = filters;
328
+ }
329
+ update(changedProperties) {
330
+ if (!this.initialised && this.columns.length > 0) {
331
+ this.displayColumns = [...this.columns];
332
+ this.checkLocalStorageUpdate();
333
+ this.initialised = true;
334
+ }
335
+ super.update(changedProperties);
336
+ }
337
+ firstUpdated() {
338
+ this.updateSearchParamsFromUri();
339
+ this.removeOldLocalStorageValues();
340
+ }
341
+ checkLocalStorageUpdate() {
342
+ if (this.isPersistable) {
343
+ const preservedColumns = JSON.parse(localStorage.getItem(this.columnsLocalStorageKey) || '[]');
344
+ if (preservedColumns.length > 0) {
345
+ let updateStorage = false;
346
+ // Scenarios where we should update appData with the latest display columns data
347
+ if (preservedColumns.length !== this.columns.length)
348
+ updateStorage = true;
349
+ const allColumnNamesFound = this.columns.every(column => preservedColumns.some(pc => pc.name === column.name)) &&
350
+ preservedColumns.every(pc => this.columns.some(column => column.name === pc.name));
351
+ if (!allColumnNamesFound)
352
+ updateStorage = true;
353
+ if (updateStorage) {
354
+ this.setColumnsToLocalStorage(this.columns);
355
+ }
356
+ }
357
+ }
358
+ }
359
+ buildQueryFromFilters() {
360
+ const params = new URLSearchParams();
361
+ this.filters.forEach((f) => {
362
+ params.append(`${f.columnField}_${f.operatorValue}`, f.value);
363
+ });
364
+ return Object.fromEntries(params);
365
+ }
366
+ rebuildQueryFromMatchingQuerystringParams() {
367
+ const params = new URLSearchParams();
368
+ if (this.preservedQueryParamKeys.length === 0)
369
+ return {};
370
+ const url = new URL(window.location.href);
371
+ const originalSearchParams = new URLSearchParams(url.search);
372
+ originalSearchParams.forEach((value, key) => {
373
+ if (this.preservedQueryParamKeys.includes(key)) {
374
+ params.append(key, value);
375
+ }
376
+ });
377
+ return Object.fromEntries(params);
378
+ }
379
+ getColumnsToDisplayFromLocalStorage() {
380
+ let columnsToDisplay = [];
381
+ if (this.isPersistable) {
382
+ const preservedColumns = JSON.parse(localStorage.getItem(this.columnsLocalStorageKey) || '[]');
383
+ if (preservedColumns.length > 0) {
384
+ columnsToDisplay =
385
+ this.mapColumnsWithPersistedSettings(preservedColumns);
386
+ }
387
+ }
388
+ return columnsToDisplay;
389
+ }
390
+ mapColumnsWithPersistedSettings(preservedColumns) {
391
+ const preservedMap = new Map(preservedColumns.map(col => [col.name, col]));
392
+ const mappedColumns = this.columns.map(configuredColumn => {
393
+ const preservedColumn = preservedMap.get(configuredColumn.name);
394
+ if (!preservedColumn) {
395
+ return { ...configuredColumn };
396
+ }
397
+ return {
398
+ ...configuredColumn,
399
+ hidden: preservedColumn.hidden,
400
+ frozenToEnd: preservedColumn.frozenToEnd,
401
+ width: preservedColumn.width || undefined,
402
+ };
403
+ });
404
+ mappedColumns.sort((a, b) => {
405
+ const indexA = preservedColumns.findIndex(col => col.name === a.name);
406
+ const indexB = preservedColumns.findIndex(col => col.name === b.name);
407
+ if (indexA === -1 && indexB === -1)
408
+ return 0;
409
+ if (indexA === -1)
410
+ return 1;
411
+ if (indexB === -1)
412
+ return -1;
413
+ return indexA - indexB;
414
+ });
415
+ return mappedColumns;
416
+ }
417
+ removeOldLocalStorageValues() {
418
+ const oldKeys = this.findMatchingLocalStorageKeys(`ix-grid-${this.localStorageID}-`, '-columns', this.hashedTableState);
419
+ for (let i = 0; i <= oldKeys.length; i += 1) {
420
+ localStorage.removeItem(oldKeys[i]);
421
+ }
422
+ }
423
+ findMatchingLocalStorageKeys(prefix, suffix, currentTableStateHash) {
424
+ const matchingKeys = [];
425
+ const currentKey = prefix + currentTableStateHash + suffix;
426
+ for (let i = 0; i < localStorage.length; i += 1) {
427
+ const key = localStorage.key(i);
428
+ if (key &&
429
+ key.startsWith(prefix) &&
430
+ key.endsWith(suffix) &&
431
+ key !== currentKey) {
432
+ matchingKeys.push(key);
433
+ }
434
+ }
435
+ return matchingKeys;
436
+ }
437
+ async updatePage(refreshUrlParams = true) {
438
+ var _a;
439
+ this.dispatchChangeEvent();
440
+ if (this.addParamsToURL && refreshUrlParams) {
441
+ const urlParams = {
442
+ sort: this.sortedColumn,
443
+ order: this.sortDirection,
444
+ page: this.page.toString(),
445
+ size: this.pageSize.toString(),
446
+ ...this.buildQueryFromFilters(),
447
+ ...this.rebuildQueryFromMatchingQuerystringParams(),
448
+ };
449
+ const url = new URL(window.location.href);
450
+ const gridSearchParams = new URLSearchParams(urlParams);
451
+ if (!this.originalSearchParams) {
452
+ this.saveOriginalSearchParams(gridSearchParams);
453
+ }
454
+ const combinedParams = new URLSearchParams([
455
+ ...((_a = this.originalSearchParams) !== null && _a !== void 0 ? _a : []),
456
+ ...gridSearchParams,
457
+ ]);
458
+ url.search = combinedParams.toString();
459
+ window.history.pushState(null, '', url.toString());
460
+ }
461
+ }
462
+ saveOriginalSearchParams(gridSearchParams) {
463
+ const url = new URL(window.location.href);
464
+ const originalSearchParams = new URLSearchParams(url.search);
465
+ this.filters.forEach((f) => {
466
+ originalSearchParams.delete(`${f.columnField}_${f.operatorValue}`);
467
+ });
468
+ gridSearchParams.forEach((value, key) => {
469
+ originalSearchParams.delete(key);
470
+ });
471
+ this.originalSearchParams = originalSearchParams;
472
+ }
473
+ handleSort(column = '') {
474
+ if (this.sortedColumn !== column) {
475
+ this.sortDirection = 'asc';
476
+ }
477
+ else {
478
+ this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
479
+ }
480
+ this.sortedColumn = column;
481
+ this.updatePage();
482
+ }
483
+ setColumnsToLocalStorage(columns) {
484
+ if (this.isPersistable) {
485
+ localStorage.setItem(this.columnsLocalStorageKey, JSON.stringify(columns));
486
+ }
487
+ }
488
+ async reorderColumnsFromTable() {
489
+ var _a, _b;
490
+ const columns = [...this.arrangedColumns];
491
+ const visibleColumns = columns.filter((column) => column.hidden !== true);
492
+ const hiddenColumns = columns.filter((column) => column.hidden === true);
493
+ const frozenColumns = columns.filter((column) => column.frozenToEnd === true);
494
+ const allColumns = [
495
+ ...visibleColumns.filter(column => (column === null || column === void 0 ? void 0 : column.frozenToEnd) !== true),
496
+ ...hiddenColumns.filter(column => (column === null || column === void 0 ? void 0 : column.frozenToEnd) !== true),
497
+ ...frozenColumns,
498
+ ];
499
+ // calulate column order from table header flex order
500
+ const headerNodes = Array.from(((_b = (_a = this.grid) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelectorAll('th')) || []);
501
+ if (headerNodes.length) {
502
+ const columnOrder = headerNodes
503
+ .map((el, id) => ({ id, flexPosition: Number(el.style.order) }))
504
+ .sort((a, b) => a.flexPosition - b.flexPosition)
505
+ .map(el => el.id);
506
+ const columnsCorrectlyOrdered = columnOrder.every((x, i) => i === 0 || x > columnOrder[i - 1]);
507
+ let reorderedColumns = [];
508
+ if (!columnsCorrectlyOrdered) {
509
+ reorderedColumns = columnOrder.map(id => allColumns[id]);
510
+ this.displayColumns = [
511
+ ...reorderedColumns.filter(column => column.hidden !== true && (column === null || column === void 0 ? void 0 : column.frozenToEnd) !== true),
512
+ ...hiddenColumns.filter(column => (column === null || column === void 0 ? void 0 : column.frozenToEnd) !== true),
513
+ ...frozenColumns,
514
+ ];
515
+ this.isColumnsReordering = true;
516
+ await this.updateComplete;
517
+ this.isColumnsReordering = false;
518
+ this.setColumnsToLocalStorage(this.displayColumns);
519
+ }
520
+ }
521
+ }
522
+ async reorderColumnsFromFilter(e) {
523
+ this.displayColumns = [...e.detail.reorderedColumns];
524
+ this.setColumnsToLocalStorage([...this.displayColumns]);
525
+ this.isColumnsReordering = true;
526
+ await this.updateComplete;
527
+ this.isColumnsReordering = false;
528
+ }
529
+ handleOnColumnFilter(e) {
530
+ e.detail.columns.forEach((column, id) => {
531
+ if (!this.displayColumns[id])
532
+ return;
533
+ this.displayColumns[id].hidden = column === null || column === void 0 ? void 0 : column.hidden;
534
+ });
535
+ this.displayColumns = [...this.displayColumns];
536
+ this.updatePage(false);
537
+ }
538
+ cellPartNameGenerator(_column, model) {
539
+ let parts = '';
540
+ if (model.item.disabled) {
541
+ parts += ' ix-disabled-cell';
542
+ }
543
+ return parts;
544
+ }
545
+ renderAddNewButton() {
546
+ if (!this.showAddButton)
547
+ return nothing;
548
+ return html `<ix-button
549
+ name="add-new-button"
550
+ appearance="text"
551
+ has-icon
552
+ ?disabled=${this.disableAddButton}
553
+ @click=${() => this.onAddButtonClick()}
554
+ >
555
+ <ix-icon slot="icon">add</ix-icon>
556
+ <span>${this.addButtonLabel}</span>
557
+ </ix-button>`;
558
+ }
559
+ get showViewMoreLessButton() {
560
+ return this.rowLimit > 0 && this.rows.length > this.rowLimit;
561
+ }
562
+ renderViewMoreLessButton() {
563
+ if (!this.showViewMoreLessButton)
564
+ return nothing;
565
+ return html `
566
+ <ix-button
567
+ appearance="text"
568
+ @click=${() => {
569
+ this.isExpanded = !this.isExpanded;
570
+ }}
571
+ has-icon
572
+ >
573
+ ${this.isExpanded ? copy.viewLess : copy.viewMore}
574
+ ${this.hideViewMoreLessButtonIcon
575
+ ? nothing
576
+ : html `<ix-icon slot="icon"
577
+ >${this.isExpanded ? 'remove' : 'add'}</ix-icon
578
+ >`}
579
+ </ix-button>
580
+ `;
581
+ }
582
+ renderRemoveAllButton() {
583
+ if (!this.showRemoveAllButton)
584
+ return nothing;
585
+ return html `<ix-button
586
+ class="remove-all-button"
587
+ name="remove-all-button"
588
+ appearance="text"
589
+ ?disabled=${this.disableRemoveAllButton}
590
+ @click=${() => this.onRemoveAllButtonClick()}
591
+ >
592
+ <span>${this.removeAllButtonLabel}</span>
593
+ </ix-button>`;
594
+ }
595
+ renderColumns() {
596
+ const arrangedColumnsInstance = [...this.arrangedColumns];
597
+ if (arrangedColumnsInstance.length > 0) {
598
+ return html `${arrangedColumnsInstance.map((column, id) => {
599
+ if (column.hidden === true)
600
+ return nothing;
601
+ return html `<vaadin-grid-column
602
+ ${columnHeaderRenderer(() => this.renderColumnHeader(column, arrangedColumnsInstance[id + 1], id, arrangedColumnsInstance.length), this.sortDirection)}
603
+ .renderer=${(root, columnElement, model) => this.columnRenderer(column, root, columnElement, model)}
604
+ resizable
605
+ width=${ifDefined(column.width)}
606
+ min-width=${ifDefined(column.minWidth)}
607
+ .responsive=${column.responsive}
608
+ ?hidden=${column.hidden}
609
+ ?frozen-to-end=${column.frozenToEnd}
610
+ path=${column.name}
611
+ ?auto-width=${column.autoWidth}
612
+ flex-grow=${ifDefined(column.flexGrow)}
613
+ ></vaadin-grid-column>`;
614
+ })}`;
615
+ }
616
+ return html `<vaadin-grid-column></vaadin-grid-column>`;
617
+ }
618
+ renderLoading() {
619
+ return html ` <div
620
+ class="progress-container"
621
+ style="display: ${this.isLoading ? '' : 'none'}"
622
+ >
623
+ <ix-progress .indeterminate=${true}></ix-progress>
624
+ </div>`;
625
+ }
626
+ renderGrid() {
627
+ if (this.isColumnsReordering) {
628
+ return nothing;
629
+ }
630
+ const columnDisplayed = this.displayColumns.find((column) => column.hidden !== true);
631
+ const displayRows = this.rowLimit > 0 && !this.isExpanded
632
+ ? this.rows.slice(0, this.rowLimit)
633
+ : this.rows;
634
+ return html `<vaadin-grid
635
+ class=${this.hideColumnHeaders ? 'hide-column-headers' : ''}
636
+ .items=${columnDisplayed ? displayRows : []}
637
+ all-rows-visible
638
+ ?column-reordering-allowed=${this.columnReorderingAllowed}
639
+ theme="no-border"
640
+ .cellPartNameGenerator=${this.cellPartNameGenerator}
641
+ @mouseup=${this.reorderColumnsFromTable}
642
+ >
643
+ ${this.renderColumns()}
644
+ <div slot="empty-state"><slot name="no-rows"></slot></div>
645
+ </vaadin-grid>`;
646
+ }
647
+ render() {
648
+ return html `
649
+ <div
650
+ class=${`grid-container ${this.isColumnsReordering ? 'columns-reordering' : ''} ${this.variantClass}`}
651
+ >
652
+ ${this.hideHeader ? nothing : this.renderHeader()}
653
+ ${this.renderLoading()} ${this.renderGrid()} ${this.renderRowControls()}
654
+ ${this.rowLimit > 0 ? nothing : this.renderPaginationControls()}
655
+
656
+ <slot name="footer"></slot>
657
+ </div>
658
+ `;
659
+ }
660
+ }
661
+ IxGrid.styles = [IxGridViewStyles];
662
+ __decorate([
663
+ query('vaadin-grid')
664
+ ], IxGrid.prototype, "grid", void 0);
665
+ __decorate([
666
+ property({ type: Boolean, attribute: 'column-reordering-allowed' })
667
+ ], IxGrid.prototype, "columnReorderingAllowed", void 0);
668
+ __decorate([
669
+ property({ type: String })
670
+ ], IxGrid.prototype, "variantClass", void 0);
671
+ __decorate([
672
+ property({ type: Array })
673
+ ], IxGrid.prototype, "columns", void 0);
674
+ __decorate([
675
+ property({ type: Array })
676
+ ], IxGrid.prototype, "rows", void 0);
677
+ __decorate([
678
+ property({ type: String })
679
+ ], IxGrid.prototype, "defaultEmptyText", void 0);
680
+ __decorate([
681
+ property({ type: String })
682
+ ], IxGrid.prototype, "sortedColumn", void 0);
683
+ __decorate([
684
+ property({ type: String })
685
+ ], IxGrid.prototype, "sortDirection", void 0);
686
+ __decorate([
687
+ property({ type: Boolean })
688
+ ], IxGrid.prototype, "hideHeader", void 0);
689
+ __decorate([
690
+ property({ type: Boolean, attribute: 'hide-filters' })
691
+ ], IxGrid.prototype, "hideFilters", void 0);
692
+ __decorate([
693
+ property({ type: Number })
694
+ ], IxGrid.prototype, "rowLimit", void 0);
695
+ __decorate([
696
+ property({ type: Number })
697
+ ], IxGrid.prototype, "page", void 0);
698
+ __decorate([
699
+ property({ type: Number })
700
+ ], IxGrid.prototype, "pageSize", void 0);
701
+ __decorate([
702
+ property({ type: Array })
703
+ ], IxGrid.prototype, "pageSizes", void 0);
704
+ __decorate([
705
+ property({ type: Number })
706
+ ], IxGrid.prototype, "recordCount", void 0);
707
+ __decorate([
708
+ property({ type: String })
709
+ ], IxGrid.prototype, "localStorageID", void 0);
710
+ __decorate([
711
+ property({ type: Boolean })
712
+ ], IxGrid.prototype, "showDownload", void 0);
713
+ __decorate([
714
+ property({ type: Boolean })
715
+ ], IxGrid.prototype, "isDownloading", void 0);
716
+ __decorate([
717
+ property({ type: Boolean })
718
+ ], IxGrid.prototype, "isLoading", void 0);
719
+ __decorate([
720
+ property({ type: Array })
721
+ ], IxGrid.prototype, "downloadMenuItems", void 0);
722
+ __decorate([
723
+ property({ type: Boolean, attribute: 'add-params-to-url' })
724
+ ], IxGrid.prototype, "addParamsToURL", void 0);
725
+ __decorate([
726
+ property({ type: Boolean })
727
+ ], IxGrid.prototype, "readParamsFromURL", void 0);
728
+ __decorate([
729
+ property({ type: Boolean })
730
+ ], IxGrid.prototype, "refreshDataOnColumnVisibilityChange", void 0);
731
+ __decorate([
732
+ property({ type: Number })
733
+ ], IxGrid.prototype, "filterValueChangeDebounceTime", void 0);
734
+ __decorate([
735
+ property({ type: Boolean })
736
+ ], IxGrid.prototype, "hideColumnHeaders", void 0);
737
+ __decorate([
738
+ property({ type: Array })
739
+ ], IxGrid.prototype, "preservedQueryParamKeys", void 0);
740
+ __decorate([
741
+ property({ type: String })
742
+ ], IxGrid.prototype, "filterMaxDate", void 0);
743
+ __decorate([
744
+ property({ type: String })
745
+ ], IxGrid.prototype, "hashedTableState", void 0);
746
+ __decorate([
747
+ property({ type: Boolean })
748
+ ], IxGrid.prototype, "hideViewMoreLessButtonIcon", void 0);
749
+ __decorate([
750
+ property({ type: Boolean })
751
+ ], IxGrid.prototype, "showAddButton", void 0);
752
+ __decorate([
753
+ property({ type: Boolean })
754
+ ], IxGrid.prototype, "disableAddButton", void 0);
755
+ __decorate([
756
+ property({ type: String })
757
+ ], IxGrid.prototype, "addButtonLabel", void 0);
758
+ __decorate([
759
+ property({ type: Function })
760
+ ], IxGrid.prototype, "onAddButtonClick", void 0);
761
+ __decorate([
762
+ property({ type: Boolean })
763
+ ], IxGrid.prototype, "showRemoveAllButton", void 0);
764
+ __decorate([
765
+ property({ type: Boolean })
766
+ ], IxGrid.prototype, "disableRemoveAllButton", void 0);
767
+ __decorate([
768
+ property({ type: String })
769
+ ], IxGrid.prototype, "removeAllButtonLabel", void 0);
770
+ __decorate([
771
+ property({ type: Function })
772
+ ], IxGrid.prototype, "onRemoveAllButtonClick", void 0);
773
+ __decorate([
774
+ state()
775
+ ], IxGrid.prototype, "filters", void 0);
776
+ __decorate([
777
+ state()
778
+ ], IxGrid.prototype, "isColumnsReordering", void 0);
779
+ __decorate([
780
+ state()
781
+ ], IxGrid.prototype, "isExpanded", void 0);
782
+ __decorate([
783
+ state()
784
+ ], IxGrid.prototype, "displayColumns", void 0);