@kubex/zinc 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/js_build_and_deploy.yaml +1 -1
- package/dist/custom-elements.json +25150 -0
- package/dist/vscode.html-custom-data.json +2874 -0
- package/dist/web-types.json +6611 -0
- package/dist/zn.d.ts +6664 -0
- package/dist/zn.min.css +1 -0
- package/dist/zn.min.js +4740 -0
- package/docs/_includes/default.njk +1 -0
- package/docs/assets/scripts/docs.js +4 -5
- package/docs/assets/scripts/search.js +0 -9
- package/docs/assets/styles/docs.css +3 -3
- package/docs/data/data-table.json +79 -0
- package/docs/data/products-table.json +36 -0
- package/docs/eleventy.config.cjs +3 -0
- package/docs/pages/components/data-select.md +10 -0
- package/docs/pages/components/data-table.md +84 -45
- package/docs/pages/components/dialog.md +1 -1
- package/docs/pages/components/editor.md +1 -3
- package/docs/pages/components/filter-wrapper.md +20 -0
- package/docs/pages/components/icon.md +2 -0
- package/docs/pages/components/item.md +2 -2
- package/docs/pages/components/menu-item.md +12 -3
- package/docs/pages/components/panel.md +17 -0
- package/docs/pages/components/progress-tile.md +17 -1
- package/docs/pages/components/settings-container.md +137 -0
- package/docs/pages/components/textarea.md +1 -1
- package/package.json +3 -1
- package/scss/_root.scss +26 -0
- package/scss/boot.scss +27 -1
- package/scss/mixins/index.scss +30 -1
- package/scss/shared/_base.scss +1 -1
- package/scss/shared/_button.scss +1 -1
- package/scss/shared/layout.scss +7 -0
- package/scss/themes/_dark.scss +5 -5
- package/scss/themes/_light.scss +6 -5
- package/scss/variables/index.scss +9 -0
- package/src/components/alert/alert.component.ts +1 -1
- package/src/components/alert/alert.scss +18 -4
- package/src/components/button/button.component.ts +6 -2
- package/src/components/button/button.scss +16 -1
- package/src/components/button-menu/button-menu.component.ts +23 -15
- package/src/components/button-menu/button-menu.scss +4 -4
- package/src/components/checkbox/checkbox.component.ts +5 -1
- package/src/components/checkbox/checkbox.scss +1 -1
- package/src/components/chip/chip.component.ts +7 -3
- package/src/components/chip/chip.scss +9 -1
- package/src/components/collapsible/collapsible.component.ts +48 -2
- package/src/components/confirm/confirm.component.ts +1 -2
- package/src/components/content-block/content-block.component.ts +25 -1
- package/src/components/content-block/content-block.scss +8 -0
- package/src/components/data-select/data-select.component.ts +1 -1
- package/src/components/data-table/data-table.component.ts +361 -422
- package/src/components/data-table/data-table.scss +6 -1
- package/src/components/datepicker/datepicker.scss +1 -1
- package/src/components/dialog/dialog.component.ts +52 -33
- package/src/components/dialog/dialog.scss +15 -1
- package/src/components/dropdown/dropdown.component.ts +1 -1
- package/src/components/editor/editor.component.ts +196 -158
- package/src/components/editor/editor.scss +25 -5
- package/src/components/editor/modules/ai/index.ts +281 -0
- package/src/components/editor/modules/ai/panel/ai-panel.component.ts +102 -0
- package/src/components/editor/modules/ai/panel/ai-panel.scss +83 -0
- package/src/components/editor/modules/ai/tooltip/ai-tooltip.component.ts +30 -0
- package/src/components/editor/modules/ai/tooltip/ai-tooltip.scss +28 -0
- package/src/components/editor/modules/{attachment-module.ts → attachment/attachment.ts} +7 -7
- package/src/components/editor/modules/context-menu/context-menu-component.ts +115 -0
- package/src/components/editor/modules/context-menu/context-menu.scss +49 -0
- package/src/components/editor/modules/context-menu/context-menu.ts +296 -0
- package/src/components/editor/modules/context-menu/quick-action/index.ts +12 -0
- package/src/components/editor/modules/context-menu/quick-action/quick-action.component.ts +18 -0
- package/src/components/editor/modules/date-picker/date-picker.ts +77 -0
- package/src/components/editor/modules/dialog/dialog.component.ts +115 -0
- package/src/components/editor/modules/dialog/dialog.scss +43 -0
- package/src/components/editor/modules/dialog/dialog.ts +46 -0
- package/src/components/editor/modules/{drag-drop-module.ts → drag-drop/drag-drop.ts} +6 -6
- package/src/components/editor/modules/emoji/emoji.ts +106 -0
- package/src/components/editor/modules/emoji/headless/headless-emoji.component.ts +122 -0
- package/src/components/editor/modules/emoji/headless/headless-emoji.scss +52 -0
- package/src/components/editor/modules/emoji/headless/headless-emoji.ts +223 -0
- package/src/components/editor/modules/{image-resize-module/image-resize-module.ts → image-resize/image-resize.ts} +5 -5
- package/src/components/editor/modules/{time-tracking-module.ts → time-tracking/time-tracking.ts} +5 -5
- package/src/components/editor/modules/toolbar/tool/index.ts +12 -0
- package/src/components/editor/modules/toolbar/tool/tool.component.ts +30 -0
- package/src/components/editor/modules/toolbar/tool/tool.scss +5 -0
- package/src/components/editor/modules/toolbar/toolbar.component.ts +738 -0
- package/src/components/editor/modules/toolbar/toolbar.scss +98 -0
- package/src/components/editor/modules/toolbar/toolbar.ts +328 -0
- package/src/components/expanding-action/expanding-action.component.ts +2 -2
- package/src/components/expanding-action/expanding-action.scss +2 -2
- package/src/components/filter-wrapper/filter-wrapper.component.ts +91 -0
- package/src/components/filter-wrapper/filter-wrapper.scss +11 -0
- package/src/components/filter-wrapper/filter-wrapper.test.ts +10 -0
- package/src/components/filter-wrapper/index.ts +12 -0
- package/src/components/header/header.component.ts +1 -1
- package/src/components/header/header.scss +8 -1
- package/src/components/hover-container/hover-container.scss +39 -36
- package/src/components/icon/icon.component.ts +11 -5
- package/src/components/icon/icon.scss +15 -2
- package/src/components/inline-edit/inline-edit.component.ts +28 -3
- package/src/components/inline-edit/inline-edit.scss +4 -1
- package/src/components/input/input.scss +1 -1
- package/src/components/item/item.component.ts +30 -19
- package/src/components/item/item.scss +56 -14
- package/src/components/linked-select/linked-select.component.ts +5 -1
- package/src/components/menu/menu.component.ts +1 -0
- package/src/components/menu/menu.scss +1 -1
- package/src/components/menu-item/menu-item.component.ts +22 -4
- package/src/components/menu-item/menu-item.scss +54 -7
- package/src/components/navbar/navbar.component.ts +7 -1
- package/src/components/navbar/navbar.scss +26 -16
- package/src/components/option/option.component.ts +4 -1
- package/src/components/option/option.scss +9 -0
- package/src/components/page-nav/page-nav.component.ts +2 -2
- package/src/components/page-nav/page-nav.scss +4 -4
- package/src/components/panel/panel.component.ts +20 -9
- package/src/components/panel/panel.scss +5 -1
- package/src/components/popup/popup.component.ts +16 -2
- package/src/components/progress-tile/progress-tile.component.ts +10 -4
- package/src/components/progress-tile/progress-tile.scss +7 -4
- package/src/components/query-builder/query-builder.component.ts +1 -1
- package/src/components/radio/radio.scss +1 -1
- package/src/components/scroll-container/scroll-container.component.ts +56 -9
- package/src/components/scroll-container/scroll-container.scss +37 -2
- package/src/components/select/select.component.ts +3 -0
- package/src/components/select/select.scss +1 -1
- package/src/components/settings-container/index.ts +12 -0
- package/src/components/settings-container/settings-container.component.ts +226 -0
- package/src/components/settings-container/settings-container.scss +92 -0
- package/src/components/settings-container/settings-container.test.ts +10 -0
- package/src/components/skeleton/skeleton.scss +5 -4
- package/src/components/sp/sp.component.ts +2 -0
- package/src/components/sp/sp.scss +2 -0
- package/src/components/split-button/split-button.component.ts +24 -18
- package/src/components/split-pane/split-pane.component.ts +5 -5
- package/src/components/stat/stat.component.ts +5 -1
- package/src/components/stat/stat.scss +24 -1
- package/src/components/style/style.component.ts +18 -0
- package/src/components/tabs/tabs.component.ts +12 -1
- package/src/components/textarea/textarea.component.ts +3 -1
- package/src/components/textarea/textarea.scss +21 -2
- package/src/components/vertical-stepper/vertical-stepper.scss +1 -1
- package/src/internal/form.ts +3 -1
- package/src/internal/slot.ts +29 -3
- package/src/utilities/on.ts +7 -8
- package/src/utilities/query.ts +5 -1
- package/src/wc.scss +7 -0
- package/src/zinc.ts +5 -0
- package/src/components/editor/modules/dialog-module/dialog-module.component.ts +0 -289
- package/src/components/editor/modules/dialog-module/dialog-module.scss +0 -115
- package/src/components/editor/modules/dialog-module/dialog-module.ts +0 -99
- package/src/components/editor/modules/events/zn-show-canned-response-dialog.ts +0 -15
- package/src/components/editor/modules/menu-module/menu-module.component.ts +0 -149
- package/src/components/editor/modules/menu-module/menu-module.scss +0 -17
- package/src/components/editor/modules/menu-module/menu-module.ts +0 -203
|
@@ -19,20 +19,46 @@ import ZnHoverContainer from "../hover-container";
|
|
|
19
19
|
import ZnMenu from "../menu";
|
|
20
20
|
import ZnMenuItem from "../menu-item";
|
|
21
21
|
import ZnSkeleton from "../skeleton";
|
|
22
|
+
|
|
23
|
+
import type ZnDataSelect from "../data-select";
|
|
24
|
+
import type ZnInput from "../input";
|
|
25
|
+
import type ZnQueryBuilder from "../query-builder";
|
|
22
26
|
import type ZnSelect from "../select";
|
|
23
27
|
|
|
24
28
|
import styles from './data-table.scss';
|
|
25
29
|
|
|
26
30
|
const DEFAULT_PAGE = 1;
|
|
27
31
|
const DEFAULT_PER_PAGE = 10;
|
|
28
|
-
const DEFAULT_TOTAL_PAGES = 10;
|
|
29
32
|
|
|
30
|
-
interface
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
interface Cell {
|
|
34
|
+
text: string;
|
|
35
|
+
column: string;
|
|
36
|
+
color?: string;
|
|
37
|
+
style?: string;
|
|
38
|
+
iconSrc?: string;
|
|
39
|
+
iconColor?: string;
|
|
40
|
+
hoverContent?: string;
|
|
41
|
+
hoverPlacement?: string;
|
|
42
|
+
chipColor?: string;
|
|
43
|
+
gaid?: string;
|
|
44
|
+
sortValue?: string;
|
|
45
|
+
uri?: string;
|
|
46
|
+
target?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface Row {
|
|
50
|
+
id: string;
|
|
51
|
+
uri?: string;
|
|
52
|
+
target?: string;
|
|
53
|
+
actions?: ActionConfig[];
|
|
54
|
+
cells: Cell[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface Response {
|
|
58
|
+
rows: Row[];
|
|
59
|
+
perPage: number;
|
|
33
60
|
total: number;
|
|
34
|
-
|
|
35
|
-
data: any[];
|
|
61
|
+
page: number;
|
|
36
62
|
}
|
|
37
63
|
|
|
38
64
|
export enum ActionSlots {
|
|
@@ -40,101 +66,48 @@ export enum ActionSlots {
|
|
|
40
66
|
modify = 'modify-action',
|
|
41
67
|
create = 'create-action',
|
|
42
68
|
filter = 'filter',
|
|
69
|
+
filter_top = 'filter-top',
|
|
43
70
|
sort = 'sort',
|
|
71
|
+
inputs = 'inputs'
|
|
44
72
|
}
|
|
45
73
|
|
|
46
|
-
interface
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface RenderDataValue {
|
|
51
|
-
value: string | number;
|
|
52
|
-
type: string;
|
|
53
|
-
tag: string;
|
|
54
|
-
url: string;
|
|
55
|
-
target: string;
|
|
56
|
-
gaid?: string;
|
|
57
|
-
html?: string;
|
|
58
|
-
color?: string;
|
|
59
|
-
caption: CaptionConfig;
|
|
60
|
-
buttons: ButtonConfig[];
|
|
61
|
-
menu: MenuConfig[];
|
|
62
|
-
icon: IconConfig;
|
|
63
|
-
hover: HoverContainerConfig;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
interface CaptionConfig {
|
|
67
|
-
title: string;
|
|
68
|
-
summary: string;
|
|
74
|
+
interface ActionConfig {
|
|
75
|
+
text: string;
|
|
69
76
|
uri: string;
|
|
70
77
|
target: string;
|
|
71
78
|
gaid: string;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
interface IconConfig {
|
|
76
|
-
src: string;
|
|
77
|
-
size: number;
|
|
78
|
-
color: string;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
interface HoverContainerConfig {
|
|
82
|
-
label: string;
|
|
83
|
-
content: string;
|
|
84
|
-
anchor: string;
|
|
85
|
-
placement:
|
|
86
|
-
| 'top'
|
|
87
|
-
| 'top-start'
|
|
88
|
-
| 'top-end'
|
|
89
|
-
| 'bottom'
|
|
90
|
-
| 'bottom-start'
|
|
91
|
-
| 'bottom-end'
|
|
92
|
-
| 'right'
|
|
93
|
-
| 'right-start'
|
|
94
|
-
| 'right-end'
|
|
95
|
-
| 'left'
|
|
96
|
-
| 'left-start'
|
|
97
|
-
| 'left-end';
|
|
98
|
-
icon: IconConfig;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
interface ButtonConfig {
|
|
102
|
-
id: string;
|
|
103
|
-
href: string;
|
|
104
|
-
gaid: string;
|
|
105
|
-
uri: string;
|
|
106
|
-
size: string;
|
|
107
|
-
color: string;
|
|
79
|
+
confirmType: string;
|
|
80
|
+
confirmTitle: string;
|
|
81
|
+
confirmContent: string;
|
|
108
82
|
icon: string;
|
|
109
|
-
|
|
110
|
-
tooltip: string;
|
|
111
|
-
target: string;
|
|
112
|
-
label: string;
|
|
113
|
-
outline: boolean;
|
|
114
|
-
confirm: ConfirmConfig;
|
|
83
|
+
type: string;
|
|
115
84
|
}
|
|
116
85
|
|
|
117
|
-
interface
|
|
118
|
-
|
|
119
|
-
href: string;
|
|
120
|
-
gaid: string;
|
|
121
|
-
target: string;
|
|
86
|
+
interface HeaderConfig {
|
|
87
|
+
key: string;
|
|
122
88
|
label: string;
|
|
89
|
+
required?: boolean;
|
|
90
|
+
default?: boolean;
|
|
91
|
+
sortable?: boolean;
|
|
92
|
+
filterable?: boolean;
|
|
123
93
|
}
|
|
124
94
|
|
|
125
|
-
interface
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
action: string;
|
|
95
|
+
interface DataRequest {
|
|
96
|
+
page: number;
|
|
97
|
+
perPage: number;
|
|
98
|
+
sortColumn: string;
|
|
99
|
+
sortDirection: string;
|
|
100
|
+
filter: string;
|
|
132
101
|
}
|
|
133
102
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
103
|
+
type AllowedInputElement =
|
|
104
|
+
HTMLInputElement
|
|
105
|
+
| HTMLSelectElement
|
|
106
|
+
| HTMLTextAreaElement
|
|
107
|
+
| ZnInput
|
|
108
|
+
| ZnSelect
|
|
109
|
+
| ZnDataSelect
|
|
110
|
+
| ZnQueryBuilder
|
|
138
111
|
|
|
139
112
|
/**
|
|
140
113
|
* @summary Short summary of the component's intended use.
|
|
@@ -180,14 +153,11 @@ export default class ZnDataTable extends ZincElement {
|
|
|
180
153
|
@property({attribute: 'data-uri'}) dataUri: string;
|
|
181
154
|
@property({attribute: 'data', type: Object, reflect: true}) data: any;
|
|
182
155
|
@property({attribute: 'sort-column'}) sortColumn: string;
|
|
183
|
-
@property({attribute: 'sort-direction'}) sortDirection: string;
|
|
156
|
+
@property({attribute: 'sort-direction'}) sortDirection: string = "asc";
|
|
184
157
|
@property({attribute: 'filter'}) filter: string = '';
|
|
185
|
-
|
|
186
158
|
@property({attribute: 'wide-column'}) wideColumn: string;
|
|
187
159
|
@property({attribute: 'key'}) key: string = 'id';
|
|
188
|
-
|
|
189
|
-
@property({attribute: 'headers', type: Object})
|
|
190
|
-
headers: Record<string, string | HeaderConfig> = {};
|
|
160
|
+
@property({attribute: 'headers', type: Object}) headers: Record<string, HeaderConfig> = {};
|
|
191
161
|
|
|
192
162
|
// Hide header text keeping the content - e.g. Action buttons without a header
|
|
193
163
|
@property({attribute: 'hide-headers', type: Object}) hiddenHeaders = '{}';
|
|
@@ -208,10 +178,19 @@ export default class ZnDataTable extends ZincElement {
|
|
|
208
178
|
|
|
209
179
|
@property() caption: string;
|
|
210
180
|
|
|
181
|
+
@property({attribute: "empty-state-caption"}) emptyStateCaption: string;
|
|
182
|
+
|
|
183
|
+
@property({attribute: "empty-state-icon"}) emptyStateIcon: string = "data_alert";
|
|
184
|
+
|
|
211
185
|
// Hide the checkbox column
|
|
212
186
|
@property({attribute: 'hide-checkboxes', type: Boolean}) hideCheckboxes: boolean;
|
|
187
|
+
|
|
213
188
|
@property() filters: [] = [];
|
|
214
189
|
|
|
190
|
+
@property() method: 'GET' | 'POST' = 'POST';
|
|
191
|
+
|
|
192
|
+
@property({attribute: "no-initial-load", type: Boolean}) noInitialLoad: boolean = false;
|
|
193
|
+
|
|
215
194
|
// Data Table Properties
|
|
216
195
|
private _initialLoad = true;
|
|
217
196
|
private _lastTableContent: TemplateResult = html``;
|
|
@@ -223,7 +202,6 @@ export default class ZnDataTable extends ZincElement {
|
|
|
223
202
|
private totalPages: number;
|
|
224
203
|
|
|
225
204
|
private _rows: any[] = [];
|
|
226
|
-
private _filteredRows: any[] = [];
|
|
227
205
|
|
|
228
206
|
private numberOfRowsSelected: number = 0;
|
|
229
207
|
private selectedRows: any[] = [];
|
|
@@ -237,94 +215,123 @@ export default class ZnDataTable extends ZincElement {
|
|
|
237
215
|
ActionSlots.modify.valueOf(),
|
|
238
216
|
ActionSlots.create.valueOf(),
|
|
239
217
|
ActionSlots.filter.valueOf(),
|
|
240
|
-
ActionSlots.sort.valueOf()
|
|
218
|
+
ActionSlots.sort.valueOf(),
|
|
219
|
+
ActionSlots.inputs.valueOf()
|
|
241
220
|
);
|
|
242
221
|
|
|
243
222
|
private _dataTask = new Task(this, {
|
|
244
|
-
task: async ([dataUri], {signal}) => {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const params = new URLSearchParams();
|
|
248
|
-
params.append('page', this.page.toString());
|
|
249
|
-
params.append('per_page', this.itemsPerPage.toString());
|
|
250
|
-
if (this.sortColumn) {
|
|
251
|
-
params.append('sort_column', this.sortColumn);
|
|
252
|
-
}
|
|
253
|
-
if (this.sortDirection) {
|
|
254
|
-
params.append('sort_direction', this.sortDirection);
|
|
223
|
+
task: async ([dataUri, requestParams], {signal}) => {
|
|
224
|
+
if (dataUri === undefined || this.noInitialLoad && this._initialLoad) {
|
|
225
|
+
return {rows: [], page: 1, perPage: this.itemsPerPage, total: 0};
|
|
255
226
|
}
|
|
256
|
-
if (this.filter) {
|
|
257
|
-
params.append('filter', this.filter);
|
|
258
|
-
}
|
|
259
|
-
url += '?' + params.toString();
|
|
260
|
-
|
|
261
|
-
if (!this.dataUri) {
|
|
262
|
-
return new Promise<TableData>((resolve) => {
|
|
263
|
-
if (!this.data) throw new Error('No data provided, please provide data or dataUri');
|
|
264
|
-
let localData = Array.isArray(this.data?.data) ? this.data.data as RowData[] : [];
|
|
265
|
-
|
|
266
|
-
if (this.sortColumn) {
|
|
267
|
-
localData = localData.sort((a, b) => {
|
|
268
|
-
const aValue = a?.[this.sortColumn];
|
|
269
|
-
const bValue = b?.[this.sortColumn];
|
|
270
|
-
return this.sortData(aValue, bValue);
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
227
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
228
|
+
const requestData: DataRequest = {
|
|
229
|
+
page: this.page,
|
|
230
|
+
perPage: this.itemsPerPage,
|
|
231
|
+
sortColumn: this.sortColumn,
|
|
232
|
+
sortDirection: this.sortDirection,
|
|
233
|
+
filter: this.filter,
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// get all inputs that are in the inputs slot and add them to the
|
|
237
|
+
const inputs = this.hasSlotController.getSlots(ActionSlots.inputs.valueOf());
|
|
238
|
+
const params: Record<string, any> = {};
|
|
239
|
+
if (inputs) {
|
|
240
|
+
inputs.forEach((input) => {
|
|
241
|
+
const allowedInputs = ['zn-input', 'zn-select', 'zn-query-builder', 'zn-multiselect', 'zn-params-select', 'input', 'select', 'textarea'];
|
|
242
|
+
if (allowedInputs.includes(input.tagName.toLowerCase())) {
|
|
243
|
+
const value = (input as AllowedInputElement).value as string || input.getAttribute('value');
|
|
244
|
+
const name = (input as AllowedInputElement).name || input.getAttribute('name');
|
|
245
|
+
if (name) {
|
|
246
|
+
params[name] = value;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
288
249
|
});
|
|
250
|
+
Object.assign(requestData, params);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
// Add any extra request params
|
|
255
|
+
if (requestParams && typeof requestParams === 'object') {
|
|
256
|
+
Object.assign(requestData, requestParams);
|
|
289
257
|
}
|
|
290
258
|
|
|
291
259
|
// This is also used for Rubix, so it may not work for your application.
|
|
292
|
-
const response = await fetch(
|
|
260
|
+
const response = await fetch(dataUri, {
|
|
261
|
+
method: this.method,
|
|
262
|
+
headers: {
|
|
263
|
+
'x-kx-fetch-style': 'zn-data-table',
|
|
264
|
+
},
|
|
293
265
|
signal,
|
|
294
266
|
credentials: 'same-origin',
|
|
267
|
+
body: this.method === 'POST' ? JSON.stringify(requestData) : undefined
|
|
295
268
|
});
|
|
296
269
|
|
|
297
270
|
if (!response.ok) throw new Error(response.statusText);
|
|
298
271
|
return response.json();
|
|
299
272
|
},
|
|
300
|
-
args: () => [this.dataUri]
|
|
273
|
+
args: () => [this.dataUri, this.requestParams]
|
|
301
274
|
});
|
|
302
275
|
|
|
276
|
+
private rowHasActions: boolean = false;
|
|
277
|
+
|
|
278
|
+
requestParams: Record<string, any> = {};
|
|
279
|
+
|
|
280
|
+
builtinRequestParams: Record<string, any> = {};
|
|
281
|
+
|
|
282
|
+
refresh() {
|
|
283
|
+
// Allow manual refresh to trigger the first data load when no-initial-load is set
|
|
284
|
+
this._initialLoad = false;
|
|
285
|
+
this._dataTask.run().then(r => r);
|
|
286
|
+
}
|
|
287
|
+
|
|
303
288
|
render() {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
289
|
+
// If no-initial-load is set, do not invoke the Task on the first render
|
|
290
|
+
let tableBody: TemplateResult;
|
|
291
|
+
if (this.noInitialLoad && this._initialLoad) {
|
|
292
|
+
tableBody = html`
|
|
293
|
+
<slot name="empty-state"></slot>`;
|
|
294
|
+
} else {
|
|
295
|
+
tableBody = this._dataTask.render({
|
|
296
|
+
pending: () => {
|
|
297
|
+
if (this._initialLoad) {
|
|
298
|
+
return html`
|
|
299
|
+
<div>${this.loadingTable()}</div>`;
|
|
300
|
+
}
|
|
301
|
+
return html`
|
|
302
|
+
<div class="reduced-opacity">${this._lastTableContent}</div>`;
|
|
303
|
+
},
|
|
304
|
+
complete: (data) => {
|
|
305
|
+
this._initialLoad = false;
|
|
306
|
+
this._lastTableContent = html`
|
|
307
|
+
<div>${this.renderTable(data as Response)}</div>`;
|
|
308
|
+
return this._lastTableContent;
|
|
309
|
+
},
|
|
310
|
+
error: (error) => {
|
|
311
|
+
if (error instanceof Error) {
|
|
312
|
+
if (error.name === "SyntaxError") {
|
|
313
|
+
console.debug(error.message)
|
|
314
|
+
return html`
|
|
315
|
+
<zn-sp>
|
|
316
|
+
<zn-alert level="error">Unable to load data</zn-alert>
|
|
317
|
+
</zn-sp>`;
|
|
318
|
+
} else if (error.message === "Not Found") {
|
|
319
|
+
return this.emptyState();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
307
322
|
return html`
|
|
308
|
-
<div>${
|
|
323
|
+
<div>${error}</div>`
|
|
309
324
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
},
|
|
313
|
-
complete: (data) => {
|
|
314
|
-
this._initialLoad = false;
|
|
315
|
-
this._lastTableContent = html`
|
|
316
|
-
<div>${this.renderTable(data as TableData)}</div>`;
|
|
317
|
-
return this._lastTableContent;
|
|
318
|
-
},
|
|
319
|
-
error: (error) => html`
|
|
320
|
-
<div>${error}</div>`
|
|
321
|
-
}) as TemplateResult;
|
|
325
|
+
}) as TemplateResult;
|
|
326
|
+
}
|
|
322
327
|
|
|
323
328
|
const hasActions = this.hasSlotController.test(ActionSlots.delete.valueOf())
|
|
324
329
|
|| this.hasSlotController.test(ActionSlots.modify.valueOf())
|
|
325
330
|
|| this.hasSlotController.test(ActionSlots.create.valueOf())
|
|
326
331
|
|| this.hasSlotController.test(ActionSlots.sort.valueOf())
|
|
327
|
-
|| this.hasSlotController.test(ActionSlots.filter.valueOf())
|
|
332
|
+
|| this.hasSlotController.test(ActionSlots.filter.valueOf())
|
|
333
|
+
|| this.hasSlotController.test(ActionSlots.filter_top.valueOf())
|
|
334
|
+
|| this.hasSlotController.test(ActionSlots.inputs.valueOf());
|
|
328
335
|
|
|
329
336
|
// Headers do not need to be re-rendered with new data
|
|
330
337
|
return html`
|
|
@@ -362,28 +369,50 @@ export default class ZnDataTable extends ZincElement {
|
|
|
362
369
|
}
|
|
363
370
|
}
|
|
364
371
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
372
|
+
emptyState() {
|
|
373
|
+
return html`
|
|
374
|
+
<div class="table--empty">
|
|
375
|
+
<zn-empty-state
|
|
376
|
+
caption="${this.emptyStateCaption ? this.emptyStateCaption : (this.caption ? "No " + this.caption.toLowerCase() + " found" : "No data found")}"
|
|
377
|
+
icon="${this.emptyStateIcon}">
|
|
378
|
+
</zn-empty-state>
|
|
379
|
+
</div>`;
|
|
380
|
+
}
|
|
369
381
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
</div>`;
|
|
382
|
+
renderTable(data: Response) {
|
|
383
|
+
this.itemsPerPage = Math.max(1, data.perPage ?? DEFAULT_PER_PAGE);
|
|
384
|
+
this.page = Math.max(1, data.page ?? DEFAULT_PAGE);
|
|
385
|
+
this.totalPages = Math.ceil(Math.max(1, data.total) / this.itemsPerPage);
|
|
386
|
+
|
|
387
|
+
if (!data?.rows || data.rows.length === 0) {
|
|
388
|
+
return this.emptyState();
|
|
378
389
|
}
|
|
379
390
|
|
|
380
|
-
const
|
|
381
|
-
|
|
391
|
+
const filteredHeaders = Object.values(this.headers).filter((header) => {
|
|
392
|
+
return !Object.values(this.hiddenColumns).includes(header.key);
|
|
393
|
+
});
|
|
382
394
|
|
|
383
|
-
this.
|
|
384
|
-
this._rows = this.getRows(keys, data);
|
|
395
|
+
this._rows = this.getRows(data);
|
|
385
396
|
|
|
386
397
|
const hasSelectedRows = this.selectedRows.length > 0;
|
|
398
|
+
this.rowHasActions = this._rows.some((row: Row) => row.actions && row.actions.length > 0);
|
|
399
|
+
|
|
400
|
+
// To make sure the cells are in the same order as the headers, we need to map them cell.col to heading.key
|
|
401
|
+
this._rows.forEach((row: Row) => {
|
|
402
|
+
const orderedCells: Cell[] = [];
|
|
403
|
+
// const unorderedCells = row.cells.filter((c: Cell) => !filteredHeaders.some((h: HeaderConfig) => h.key === c.column));
|
|
404
|
+
|
|
405
|
+
filteredHeaders.forEach((header: HeaderConfig) => {
|
|
406
|
+
const cell = row.cells.find((c: Cell) => c.column === header.key);
|
|
407
|
+
if (cell) {
|
|
408
|
+
orderedCells.push(cell);
|
|
409
|
+
} else {
|
|
410
|
+
orderedCells.push({text: '', column: header.key});
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
row.cells = orderedCells;//.concat(unorderedCells);
|
|
415
|
+
});
|
|
387
416
|
|
|
388
417
|
return html`
|
|
389
418
|
<div style="overflow-x: auto">
|
|
@@ -399,17 +428,20 @@ export default class ZnDataTable extends ZincElement {
|
|
|
399
428
|
<th>
|
|
400
429
|
<div><input type="checkbox" @change="${this.selectAll}"></div>
|
|
401
430
|
</th>`}
|
|
402
|
-
${
|
|
431
|
+
${filteredHeaders.map((header: HeaderConfig) => this.renderCellHeader(header))}
|
|
432
|
+
${this.rowHasActions ? html`
|
|
433
|
+
<th></th>` : html``}
|
|
403
434
|
</tr>
|
|
404
435
|
</thead>
|
|
405
436
|
<tbody>
|
|
406
|
-
${this.
|
|
437
|
+
${this._rows.map((row: Row) => html`
|
|
407
438
|
<tr>
|
|
408
439
|
${this.hideCheckboxes ? html`` : html`
|
|
409
440
|
<td class="${classMap({'hidden': !hasSelectedRows})}">
|
|
410
441
|
<div><input type="checkbox" @change="${this.selectRow}"></div>
|
|
411
442
|
</td>`}
|
|
412
|
-
${row.map((value:
|
|
443
|
+
${row.cells.map((value: Cell, index: number) => this.renderCellBody(index, value))}
|
|
444
|
+
${this.rowHasActions ? this.renderActions(row) : null}
|
|
413
445
|
</tr>`)}
|
|
414
446
|
</tbody>
|
|
415
447
|
</table>
|
|
@@ -421,6 +453,8 @@ export default class ZnDataTable extends ZincElement {
|
|
|
421
453
|
|
|
422
454
|
getTableHeader() {
|
|
423
455
|
return html`
|
|
456
|
+
<slot name="${ActionSlots.filter_top.valueOf()}"></slot>
|
|
457
|
+
<slot name="${ActionSlots.inputs.valueOf()}" style="display: none"></slot>
|
|
424
458
|
<div class="table__header">
|
|
425
459
|
<div class="table__header__actions">
|
|
426
460
|
${this.getActions()}
|
|
@@ -460,7 +494,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
460
494
|
}
|
|
461
495
|
|
|
462
496
|
getPagination() {
|
|
463
|
-
if (this.hidePagination || (this.totalPages <= 1 && this._rows.length <=
|
|
497
|
+
if (this.hidePagination || (this.totalPages <= 1 && this._rows.length <= this.itemsPerPage)) return null;
|
|
464
498
|
|
|
465
499
|
const optionsRowsPerPage = [10, 20, 30, 40, 50];
|
|
466
500
|
optionsRowsPerPage.filter((option) => option <= this._rows.length);
|
|
@@ -597,22 +631,6 @@ export default class ZnDataTable extends ZincElement {
|
|
|
597
631
|
this.requestUpdate();
|
|
598
632
|
}
|
|
599
633
|
|
|
600
|
-
|
|
601
|
-
private updateActionKeys(slotName: string) {
|
|
602
|
-
if (this.hasSlotController.test(slotName)) {
|
|
603
|
-
// we need to look into the slot controller for the keys input
|
|
604
|
-
const slots = this.hasSlotController.getSlots(slotName);
|
|
605
|
-
if (slots) {
|
|
606
|
-
slots.forEach((slot) => {
|
|
607
|
-
const input = slot.querySelector('input[name="keys"]');
|
|
608
|
-
if (input && input instanceof HTMLInputElement) {
|
|
609
|
-
input.value = this.getSelectedKeys().join(',');
|
|
610
|
-
}
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
634
|
selectRow(e: PointerEvent) {
|
|
617
635
|
if (!(e.target && (e.target instanceof Element))) {
|
|
618
636
|
return;
|
|
@@ -670,181 +688,61 @@ export default class ZnDataTable extends ZincElement {
|
|
|
670
688
|
};
|
|
671
689
|
}
|
|
672
690
|
|
|
673
|
-
|
|
691
|
+
renderCell(data: Cell) {
|
|
674
692
|
if (data && typeof data === 'object') {
|
|
675
|
-
let content: TemplateResult = html`${data
|
|
676
|
-
|
|
677
|
-
if (data['html']) {
|
|
678
|
-
return html`${unsafeHTML(data['html'])}`;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
if (data['type'] === 'timestamp') {
|
|
682
|
-
const timestamp = typeof data['value'] === 'string' ? parseInt(data['value']) : data['value'];
|
|
683
|
-
content = html`${new Intl.DateTimeFormat('en-GB', {
|
|
684
|
-
dateStyle: 'medium',
|
|
685
|
-
timeStyle: 'short',
|
|
686
|
-
hourCycle: 'h12',
|
|
687
|
-
timeZone: 'UTC'
|
|
688
|
-
}).format(new Date(timestamp < 10000000000 ? timestamp * 1000 : timestamp))}`;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (data['tag'] === 'zn-chip') {
|
|
692
|
-
const type = data['type'];
|
|
693
|
-
content = html`
|
|
694
|
-
<zn-chip type="${type}">${content}</zn-chip>`;
|
|
695
|
-
}
|
|
693
|
+
let content: TemplateResult = html`${data.text}`;
|
|
696
694
|
|
|
697
|
-
if (data
|
|
695
|
+
if (data.style || data.color) {
|
|
698
696
|
content = html`
|
|
699
|
-
<
|
|
697
|
+
<zn-style ${ifDefined(data.style || nothing)}
|
|
698
|
+
color="${ifDefined(data.color || nothing)}">${content}
|
|
699
|
+
</zn-style>`;
|
|
700
700
|
}
|
|
701
701
|
|
|
702
|
-
if (data
|
|
702
|
+
if (data.uri) {
|
|
703
703
|
content = html`
|
|
704
|
-
<a href="${data
|
|
705
|
-
data-target="${ifDefined(data
|
|
706
|
-
gaid="${ifDefined(data
|
|
704
|
+
<a href="${data.uri}"
|
|
705
|
+
data-target="${ifDefined(data.target || nothing)}"
|
|
706
|
+
gaid="${ifDefined(data.gaid || nothing)}">${content}</a>`;
|
|
707
707
|
}
|
|
708
708
|
|
|
709
|
-
if (data
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
if (data['caption'].icon) {
|
|
714
|
-
const icon = data['caption'].icon;
|
|
715
|
-
const src = icon['src'] ?? icon;
|
|
716
|
-
const size = icon['size'] ?? 16;
|
|
717
|
-
const color = icon['color'] ?? '';
|
|
718
|
-
|
|
719
|
-
captionIcon = html`
|
|
720
|
-
<zn-icon src="${src}" size="${size}" color="${color}"></zn-icon>`;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
if (data['caption'].uri) {
|
|
724
|
-
title = html` <a data-target="${ifDefined(data['caption'].target || nothing)}"
|
|
725
|
-
href="${data['caption'].uri}"
|
|
726
|
-
gaid="${ifDefined(data['caption'].gaid)}"
|
|
727
|
-
class="title">
|
|
728
|
-
${data['caption'].title}
|
|
729
|
-
</a>`
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
content = html`
|
|
733
|
-
<div class="${classMap({
|
|
734
|
-
'caption': true,
|
|
735
|
-
'caption--icon': data['caption'].icon !== undefined,
|
|
736
|
-
})}">
|
|
737
|
-
${captionIcon}
|
|
738
|
-
<div>
|
|
739
|
-
${title}
|
|
740
|
-
<span class="summary">${data['caption'].summary}</span>
|
|
741
|
-
</div>
|
|
742
|
-
</div>`;
|
|
709
|
+
if (data.chipColor) {
|
|
710
|
+
return html`
|
|
711
|
+
<zn-chip type="${data.chipColor}">${content}</zn-chip>`;
|
|
743
712
|
}
|
|
744
713
|
|
|
745
|
-
if (data
|
|
746
|
-
const placement = data
|
|
714
|
+
if (data.hoverContent) {
|
|
715
|
+
const placement = data.hoverPlacement ?? 'top';
|
|
747
716
|
|
|
748
|
-
if (data
|
|
749
|
-
const
|
|
750
|
-
const
|
|
751
|
-
const size = icon['size'] ?? 16;
|
|
752
|
-
const color = icon['color'] ?? '';
|
|
717
|
+
if (data.iconSrc) {
|
|
718
|
+
const src = data.iconSrc;
|
|
719
|
+
const color = data.iconColor ?? '';
|
|
753
720
|
|
|
754
721
|
return html`
|
|
755
|
-
${
|
|
722
|
+
${content}
|
|
756
723
|
<zn-hover-container placement="${placement}"
|
|
757
724
|
flip>
|
|
758
|
-
<zn-icon src="${src}"
|
|
725
|
+
<zn-icon src="${src}" color="${color}"></zn-icon>
|
|
759
726
|
<div slot="content">
|
|
760
|
-
${unsafeHTML(data
|
|
727
|
+
${unsafeHTML(data.hoverContent)}
|
|
761
728
|
</div>
|
|
762
729
|
</zn-hover-container>`;
|
|
763
730
|
}
|
|
764
731
|
|
|
765
732
|
return html`
|
|
766
|
-
${data['hover'].label}
|
|
767
733
|
<zn-hover-container placement="${placement}"
|
|
768
734
|
flip>
|
|
769
|
-
<div slot="anchor">${
|
|
770
|
-
${unsafeHTML(data
|
|
735
|
+
<div slot="anchor">${content}</div>
|
|
736
|
+
${unsafeHTML(data.hoverContent)}
|
|
771
737
|
</zn-hover-container>`;
|
|
772
738
|
}
|
|
773
739
|
|
|
774
|
-
if (data
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
<zn-button slot="trigger" icon="more_horiz" icon-size="24" color="transparent" size="content"></zn-button>
|
|
778
|
-
<zn-menu>
|
|
779
|
-
${data['menu'].map((item: MenuConfig) => {
|
|
780
|
-
return html`
|
|
781
|
-
<zn-menu-item id="${item.id}"
|
|
782
|
-
href="${item.href}"
|
|
783
|
-
gaid="${item.gaid}"
|
|
784
|
-
data-target="${ifDefined(item.target)}">
|
|
785
|
-
${item.label}
|
|
786
|
-
</zn-menu-item>`;
|
|
787
|
-
})}
|
|
788
|
-
</zn-menu>
|
|
789
|
-
</zn-dropdown>`
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
if (data['buttons']) {
|
|
793
|
-
content = html`
|
|
794
|
-
${Object.values(data['buttons']).map((button) => {
|
|
795
|
-
if (button.confirm) {
|
|
796
|
-
return html`
|
|
797
|
-
<div>
|
|
798
|
-
<zn-button
|
|
799
|
-
id="${button.id}"
|
|
800
|
-
size="${button.size}"
|
|
801
|
-
color="${button.color}"
|
|
802
|
-
icon="${button.icon}"
|
|
803
|
-
icon-size="${button.iconSize}"
|
|
804
|
-
tooltip="${button.tooltip}"
|
|
805
|
-
outline="${ifDefined(button.outline)}">
|
|
806
|
-
${button.label || nothing}
|
|
807
|
-
</zn-button>
|
|
808
|
-
<zn-confirm
|
|
809
|
-
fid="${button.confirm.fid}"
|
|
810
|
-
trigger="${button.confirm.trigger}"
|
|
811
|
-
type="${button.confirm.type}"
|
|
812
|
-
caption="${button.confirm.caption}"
|
|
813
|
-
content="${button.confirm.content}"
|
|
814
|
-
action="${button.confirm.action}"></zn-confirm>
|
|
815
|
-
</div>`;
|
|
816
|
-
}
|
|
817
|
-
return html`
|
|
818
|
-
<zn-button
|
|
819
|
-
id="${button.id}"
|
|
820
|
-
href="${button.href}"
|
|
821
|
-
gaid="${button.gaid}"
|
|
822
|
-
size="${button.size}"
|
|
823
|
-
color="${button.color}"
|
|
824
|
-
icon="${button.icon}"
|
|
825
|
-
icon-size="${button.iconSize}"
|
|
826
|
-
tooltip="${button.tooltip}"
|
|
827
|
-
data-uri="${button.uri}"
|
|
828
|
-
data-target="${['modal', 'slide'].includes(button.target) ? button.target : nothing}"
|
|
829
|
-
target="${!['modal', 'slide'].includes(button.target) ? button.target : nothing}"
|
|
830
|
-
outline="${ifDefined(button.outline)}">
|
|
831
|
-
${button.label || nothing}
|
|
832
|
-
</zn-button>`;
|
|
833
|
-
})}`;
|
|
834
|
-
}
|
|
740
|
+
if (data.iconSrc) {
|
|
741
|
+
const src = data.iconSrc;
|
|
742
|
+
const color = data.iconColor ?? '';
|
|
835
743
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const size = data['icon']?.['size'] ?? 16;
|
|
839
|
-
const color = data['icon']?.['color'] ?? '';
|
|
840
|
-
|
|
841
|
-
content = html`
|
|
842
|
-
<zn-icon src="${icon}" size="${size}" color="${color}"></zn-icon> ${content}`;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
if (data['color']) {
|
|
846
|
-
content = html`
|
|
847
|
-
<zn-style color="${data['color']}">${content}</zn-style>`;
|
|
744
|
+
return html`
|
|
745
|
+
<zn-icon src="${src}" color="${color}"></zn-icon> ${content}`;
|
|
848
746
|
}
|
|
849
747
|
|
|
850
748
|
return content;
|
|
@@ -853,6 +751,21 @@ export default class ZnDataTable extends ZincElement {
|
|
|
853
751
|
return data;
|
|
854
752
|
}
|
|
855
753
|
|
|
754
|
+
private updateActionKeys(slotName: string) {
|
|
755
|
+
if (this.hasSlotController.test(slotName)) {
|
|
756
|
+
// we need to look into the slot controller for the keys input
|
|
757
|
+
const slots = this.hasSlotController.getSlots(slotName);
|
|
758
|
+
if (slots) {
|
|
759
|
+
slots.forEach((slot) => {
|
|
760
|
+
const input = slot.querySelector('input[name="keys"]');
|
|
761
|
+
if (input && input instanceof HTMLInputElement) {
|
|
762
|
+
input.value = this.getSelectedKeys().join(',');
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
856
769
|
private getTableSortIcon(key: any) {
|
|
857
770
|
if (this.sortColumn !== key) {
|
|
858
771
|
return html`
|
|
@@ -874,68 +787,33 @@ export default class ZnDataTable extends ZincElement {
|
|
|
874
787
|
</div>`;
|
|
875
788
|
}
|
|
876
789
|
|
|
877
|
-
private renderCellHeader(
|
|
878
|
-
const sortable = !Object.values(this.unsortableHeaders).includes(key) && !Object.values(this.hiddenHeaders).includes(key) && !this.unsortable;
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
const header: string | HeaderConfig = this.headers[key];
|
|
882
|
-
|
|
883
|
-
if (this.hasHeaderPosition(header)) {
|
|
884
|
-
return html`
|
|
885
|
-
<th
|
|
886
|
-
class="${classMap({
|
|
887
|
-
'table__head': true,
|
|
888
|
-
'table__head--wide': key === this.wideColumn,
|
|
889
|
-
'table__head--last': key === headerKeys[headerKeys.length - 1],
|
|
890
|
-
'table__head--hidden': Object.values(this.hiddenHeaders).includes(key),
|
|
891
|
-
[`table__head--${header.position}`]: true
|
|
892
|
-
})}"
|
|
893
|
-
@click="${sortable ? this.updateSort(key) : undefined}">
|
|
894
|
-
<div>
|
|
895
|
-
${header.title}
|
|
896
|
-
${sortable ? this.getTableSortIcon(key) : nothing}
|
|
897
|
-
</div>
|
|
898
|
-
</th>
|
|
899
|
-
`;
|
|
900
|
-
}
|
|
790
|
+
private renderCellHeader(header: HeaderConfig) {
|
|
791
|
+
const sortable = !Object.values(this.unsortableHeaders).includes(header.key) && !Object.values(this.hiddenHeaders).includes(header.key) && !this.unsortable;
|
|
792
|
+
const lastHeader = Object.keys(this.headers).filter((key) => !Object.values(this.hiddenColumns).includes(key)).slice(-1)[0];
|
|
793
|
+
const lastHeaderKey = lastHeader ? this.headers[lastHeader].key : '';
|
|
901
794
|
|
|
902
795
|
return html`
|
|
903
796
|
<th
|
|
904
797
|
class="${classMap({
|
|
905
798
|
'table__head': true,
|
|
906
|
-
'table__head--wide': key === this.wideColumn,
|
|
907
|
-
'table__head--last': key ===
|
|
908
|
-
'table__head--hidden': Object.values(this.hiddenHeaders).includes(key),
|
|
799
|
+
'table__head--wide': header.key === this.wideColumn,
|
|
800
|
+
'table__head--last': header.key === lastHeaderKey,
|
|
801
|
+
'table__head--hidden': Object.values(this.hiddenHeaders).includes(header.key),
|
|
909
802
|
})}"
|
|
910
|
-
@click="${sortable ? this.updateSort(key) : undefined}">
|
|
803
|
+
@click="${sortable ? this.updateSort(header.key) : undefined}">
|
|
911
804
|
<div>
|
|
912
|
-
${header}
|
|
913
|
-
${sortable ? this.getTableSortIcon(key) : nothing}
|
|
805
|
+
${header.label}
|
|
806
|
+
${sortable ? this.getTableSortIcon(header.key) : nothing}
|
|
914
807
|
</div>
|
|
915
808
|
</th>
|
|
916
809
|
`;
|
|
917
810
|
}
|
|
918
811
|
|
|
919
|
-
private renderCellBody(index: number, value:
|
|
812
|
+
private renderCellBody(index: number, value: Cell) {
|
|
920
813
|
const headerKeys: string[] = Object.keys(this.headers).filter(
|
|
921
814
|
(key) => !Object.values(this.hiddenColumns).includes(key)
|
|
922
815
|
);
|
|
923
816
|
const headerKey: string = headerKeys[index];
|
|
924
|
-
const header = this.headers[headerKey];
|
|
925
|
-
|
|
926
|
-
if (this.hasHeaderPosition(header)) {
|
|
927
|
-
return html`
|
|
928
|
-
<td
|
|
929
|
-
@click="${this.selectRow}"
|
|
930
|
-
class="${classMap({
|
|
931
|
-
'table__cell': true,
|
|
932
|
-
'table__cell--wide': headerKey === this.wideColumn,
|
|
933
|
-
'table__cell--last': headerKey === headerKeys[headerKeys.length - 1],
|
|
934
|
-
[`table__cell--${header.position}`]: true
|
|
935
|
-
})}">
|
|
936
|
-
<div>${this.renderData(value)}</div>
|
|
937
|
-
</td>`;
|
|
938
|
-
}
|
|
939
817
|
|
|
940
818
|
return html`
|
|
941
819
|
<td
|
|
@@ -945,32 +823,49 @@ export default class ZnDataTable extends ZincElement {
|
|
|
945
823
|
'table__cell--wide': headerKey === this.wideColumn,
|
|
946
824
|
'table__cell--last': headerKey === headerKeys[headerKeys.length - 1],
|
|
947
825
|
})}">
|
|
948
|
-
<div>${this.
|
|
826
|
+
<div>${this.renderCell(value)}</div>
|
|
949
827
|
</td>`;
|
|
950
828
|
}
|
|
951
829
|
|
|
952
|
-
private
|
|
953
|
-
|
|
954
|
-
}
|
|
830
|
+
private getRows(data: Response): Row[] {
|
|
831
|
+
const sourceRows = data.rows;
|
|
955
832
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
});
|
|
833
|
+
if (this.sortColumn) {
|
|
834
|
+
const headerKeys = Object.keys(this.headers);
|
|
835
|
+
const sortIndex = headerKeys.indexOf(this.sortColumn);
|
|
960
836
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
837
|
+
sourceRows.sort((rowA: Row, rowB: Row) => {
|
|
838
|
+
const getCellForSort = (row: Row): Cell => {
|
|
839
|
+
const byHeading = row.cells.find((cell: Cell) => cell.column === this.sortColumn);
|
|
840
|
+
if (byHeading !== undefined) return byHeading as unknown as Cell;
|
|
841
|
+
return row.cells[sortIndex];
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
const aVal = getCellForSort(rowA);
|
|
845
|
+
const bVal = getCellForSort(rowB);
|
|
846
|
+
return this.sortData(aVal, bVal);
|
|
965
847
|
});
|
|
966
848
|
}
|
|
967
849
|
|
|
968
|
-
return
|
|
850
|
+
return sourceRows;
|
|
969
851
|
}
|
|
970
852
|
|
|
971
|
-
private getSelectedKeys() {
|
|
853
|
+
private getSelectedKeys(): (string)[] {
|
|
972
854
|
const headerKeys = Object.keys(this.headers);
|
|
973
|
-
|
|
855
|
+
const keyIndex = headerKeys.indexOf(this.key);
|
|
856
|
+
|
|
857
|
+
return this.selectedRows
|
|
858
|
+
.map((row: Row) => {
|
|
859
|
+
if (this.key === 'id' || keyIndex === -1) {
|
|
860
|
+
return row.id;
|
|
861
|
+
}
|
|
862
|
+
const cell = row.cells?.[keyIndex] as Cell;
|
|
863
|
+
if (cell.sortValue) {
|
|
864
|
+
return cell.sortValue;
|
|
865
|
+
}
|
|
866
|
+
return cell.text as string;
|
|
867
|
+
})
|
|
868
|
+
.filter((v): v is string => v !== undefined && v !== null);
|
|
974
869
|
}
|
|
975
870
|
|
|
976
871
|
private updateKeys() {
|
|
@@ -986,36 +881,27 @@ export default class ZnDataTable extends ZincElement {
|
|
|
986
881
|
this.updateActionKeys('delete-action');
|
|
987
882
|
}
|
|
988
883
|
|
|
989
|
-
private
|
|
990
|
-
|
|
991
|
-
|
|
884
|
+
private extractComparable(cell: Cell): string {
|
|
885
|
+
const sortValue = cell.sortValue;
|
|
886
|
+
if (sortValue) {
|
|
887
|
+
return sortValue;
|
|
992
888
|
}
|
|
993
889
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
} else if (typeof a === 'object' && a && 'value' in a) {
|
|
997
|
-
a = a.value as string | number;
|
|
998
|
-
}
|
|
890
|
+
return cell.text;
|
|
891
|
+
}
|
|
999
892
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
b = b.value as string | number;
|
|
1004
|
-
}
|
|
893
|
+
private sortData(a: Cell, b: Cell) {
|
|
894
|
+
const aCompare = this.extractComparable(a);
|
|
895
|
+
const bCompare = this.extractComparable(b);
|
|
1005
896
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
if (typeof b === 'string') {
|
|
1011
|
-
b = b.toLowerCase();
|
|
1012
|
-
}
|
|
897
|
+
const aNormal = aCompare.toLowerCase();
|
|
898
|
+
const bNormal = bCompare.toLowerCase();
|
|
1013
899
|
|
|
1014
900
|
if (this.sortDirection === 'asc') {
|
|
1015
|
-
return
|
|
901
|
+
return aNormal > bNormal ? 1 : aNormal < bNormal ? -1 : 0;
|
|
1016
902
|
}
|
|
1017
903
|
|
|
1018
|
-
return
|
|
904
|
+
return aNormal < bNormal ? 1 : aNormal > bNormal ? -1 : 0;
|
|
1019
905
|
}
|
|
1020
906
|
|
|
1021
907
|
private loadingTable() {
|
|
@@ -1090,4 +976,57 @@ export default class ZnDataTable extends ZincElement {
|
|
|
1090
976
|
</table>
|
|
1091
977
|
</div>`;
|
|
1092
978
|
}
|
|
979
|
+
|
|
980
|
+
private renderActions(row: Row) {
|
|
981
|
+
if ((row.actions === null || row.actions === undefined) && this.rowHasActions) {
|
|
982
|
+
// return an empty cell to keep the table structure
|
|
983
|
+
return html`
|
|
984
|
+
<td></td>`;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
if (!row.actions || row.actions.length === 0) {
|
|
988
|
+
return html``;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
return html`
|
|
992
|
+
<td class="table__cell table__cell--actions">
|
|
993
|
+
<zn-dropdown placement="bottom-end">
|
|
994
|
+
<zn-button slot="trigger"
|
|
995
|
+
icon="more_vert"
|
|
996
|
+
size="small"
|
|
997
|
+
color="transparent"
|
|
998
|
+
icon-size="24"
|
|
999
|
+
aria-label="Row actions">
|
|
1000
|
+
</zn-button>
|
|
1001
|
+
<zn-menu>
|
|
1002
|
+
${row.actions?.map((action: ActionConfig) => {
|
|
1003
|
+
if (action.confirmContent) {
|
|
1004
|
+
const triggerId = 'confirm-action-' + Math.random().toString(36).substring(2, 15);
|
|
1005
|
+
return html`
|
|
1006
|
+
<zn-confirm trigger="${triggerId}"
|
|
1007
|
+
type="${ifDefined(action.confirmType)}"
|
|
1008
|
+
caption="${action.confirmTitle}"
|
|
1009
|
+
content="${action.confirmContent}"
|
|
1010
|
+
action="${action.uri}"></zn-confirm>
|
|
1011
|
+
<zn-menu-item id="${triggerId}">
|
|
1012
|
+
${(action.icon) ? html`
|
|
1013
|
+
<zn-icon src="${action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
|
|
1014
|
+
${action.text}
|
|
1015
|
+
</zn-menu-item>`;
|
|
1016
|
+
} else {
|
|
1017
|
+
return html`
|
|
1018
|
+
<zn-menu-item value="${action.text}"
|
|
1019
|
+
href="${action.uri}"
|
|
1020
|
+
gaid="${ifDefined(action.gaid || nothing)}"
|
|
1021
|
+
data-target="${ifDefined(action.target || nothing)}">
|
|
1022
|
+
${(action.icon) ? html`
|
|
1023
|
+
<zn-icon src="${action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
|
|
1024
|
+
${action.text}
|
|
1025
|
+
</zn-menu-item>`;
|
|
1026
|
+
}
|
|
1027
|
+
})}
|
|
1028
|
+
</zn-menu>
|
|
1029
|
+
</zn-dropdown>
|
|
1030
|
+
</td>`;
|
|
1031
|
+
}
|
|
1093
1032
|
}
|