@kubex/zinc 1.0.4 → 1.0.6
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/dist/custom-elements.json +1278 -191
- package/dist/vscode.html-custom-data.json +93 -16
- package/dist/web-types.json +235 -25
- package/dist/zn.d.ts +1313 -941
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +2049 -931
- 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/bulk-actions/bulk-actions.component.ts +152 -84
- package/src/components/bulk-actions/bulk-actions.scss +2 -0
- 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/chart/chart.component.ts +14 -12
- 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/cols/cols.component.ts +7 -3
- package/src/components/cols/cols.scss +22 -14
- package/src/components/confirm/confirm.component.ts +1 -2
- package/src/components/content-block/content-block.component.ts +104 -14
- 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 +394 -430
- 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 +52 -6
- package/src/components/inline-edit/inline-edit.scss +15 -2
- package/src/components/input/input.scss +1 -1
- package/src/components/item/item.component.ts +30 -19
- package/src/components/item/item.scss +57 -23
- 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 +99 -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 +25 -1
- 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
|
+
import ZnStyle from "../style";
|
|
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.
|
|
@@ -175,19 +148,17 @@ export default class ZnDataTable extends ZincElement {
|
|
|
175
148
|
'zn-button-group': ZnButtonGroup,
|
|
176
149
|
'zn-confirm': ZnConfirm,
|
|
177
150
|
'zn-skeleton': ZnSkeleton,
|
|
151
|
+
'zn-style': ZnStyle,
|
|
178
152
|
};
|
|
179
153
|
|
|
180
154
|
@property({attribute: 'data-uri'}) dataUri: string;
|
|
181
155
|
@property({attribute: 'data', type: Object, reflect: true}) data: any;
|
|
182
156
|
@property({attribute: 'sort-column'}) sortColumn: string;
|
|
183
|
-
@property({attribute: 'sort-direction'}) sortDirection: string;
|
|
157
|
+
@property({attribute: 'sort-direction'}) sortDirection: string = "asc";
|
|
184
158
|
@property({attribute: 'filter'}) filter: string = '';
|
|
185
|
-
|
|
186
159
|
@property({attribute: 'wide-column'}) wideColumn: string;
|
|
187
160
|
@property({attribute: 'key'}) key: string = 'id';
|
|
188
|
-
|
|
189
|
-
@property({attribute: 'headers', type: Object})
|
|
190
|
-
headers: Record<string, string | HeaderConfig> = {};
|
|
161
|
+
@property({attribute: 'headers', type: Object}) headers: Record<string, HeaderConfig> = {};
|
|
191
162
|
|
|
192
163
|
// Hide header text keeping the content - e.g. Action buttons without a header
|
|
193
164
|
@property({attribute: 'hide-headers', type: Object}) hiddenHeaders = '{}';
|
|
@@ -208,10 +179,19 @@ export default class ZnDataTable extends ZincElement {
|
|
|
208
179
|
|
|
209
180
|
@property() caption: string;
|
|
210
181
|
|
|
182
|
+
@property({attribute: "empty-state-caption"}) emptyStateCaption: string;
|
|
183
|
+
|
|
184
|
+
@property({attribute: "empty-state-icon"}) emptyStateIcon: string = "data_alert";
|
|
185
|
+
|
|
211
186
|
// Hide the checkbox column
|
|
212
187
|
@property({attribute: 'hide-checkboxes', type: Boolean}) hideCheckboxes: boolean;
|
|
188
|
+
|
|
213
189
|
@property() filters: [] = [];
|
|
214
190
|
|
|
191
|
+
@property() method: 'GET' | 'POST' = 'POST';
|
|
192
|
+
|
|
193
|
+
@property({attribute: "no-initial-load", type: Boolean}) noInitialLoad: boolean = false;
|
|
194
|
+
|
|
215
195
|
// Data Table Properties
|
|
216
196
|
private _initialLoad = true;
|
|
217
197
|
private _lastTableContent: TemplateResult = html``;
|
|
@@ -223,7 +203,6 @@ export default class ZnDataTable extends ZincElement {
|
|
|
223
203
|
private totalPages: number;
|
|
224
204
|
|
|
225
205
|
private _rows: any[] = [];
|
|
226
|
-
private _filteredRows: any[] = [];
|
|
227
206
|
|
|
228
207
|
private numberOfRowsSelected: number = 0;
|
|
229
208
|
private selectedRows: any[] = [];
|
|
@@ -237,98 +216,130 @@ export default class ZnDataTable extends ZincElement {
|
|
|
237
216
|
ActionSlots.modify.valueOf(),
|
|
238
217
|
ActionSlots.create.valueOf(),
|
|
239
218
|
ActionSlots.filter.valueOf(),
|
|
240
|
-
ActionSlots.sort.valueOf()
|
|
219
|
+
ActionSlots.sort.valueOf(),
|
|
220
|
+
ActionSlots.inputs.valueOf()
|
|
241
221
|
);
|
|
242
222
|
|
|
243
223
|
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);
|
|
255
|
-
}
|
|
256
|
-
if (this.filter) {
|
|
257
|
-
params.append('filter', this.filter);
|
|
224
|
+
task: async ([dataUri, requestParams], {signal}) => {
|
|
225
|
+
if (dataUri === undefined || this.noInitialLoad && this._initialLoad) {
|
|
226
|
+
return {rows: [], page: 1, perPage: this.itemsPerPage, total: 0};
|
|
258
227
|
}
|
|
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
228
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
229
|
+
const requestData: DataRequest = {
|
|
230
|
+
page: this.page,
|
|
231
|
+
perPage: this.itemsPerPage,
|
|
232
|
+
sortColumn: this.sortColumn,
|
|
233
|
+
sortDirection: this.sortDirection,
|
|
234
|
+
filter: this.filter,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// get all inputs that are in the inputs slot and add them to the
|
|
238
|
+
const inputs = this.hasSlotController.getSlots(ActionSlots.inputs.valueOf());
|
|
239
|
+
const params: Record<string, any> = {};
|
|
240
|
+
if (inputs) {
|
|
241
|
+
inputs.forEach((input) => {
|
|
242
|
+
const allowedInputs = ['zn-input', 'zn-select', 'zn-query-builder', 'zn-multiselect', 'zn-params-select', 'input', 'select', 'textarea'];
|
|
243
|
+
if (allowedInputs.includes(input.tagName.toLowerCase())) {
|
|
244
|
+
const value = (input as AllowedInputElement).value as string || input.getAttribute('value');
|
|
245
|
+
const name = (input as AllowedInputElement).name || input.getAttribute('name');
|
|
246
|
+
if (name) {
|
|
247
|
+
params[name] = value;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
288
250
|
});
|
|
251
|
+
Object.assign(requestData, params);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
// Add any extra request params
|
|
256
|
+
if (requestParams && typeof requestParams === 'object') {
|
|
257
|
+
Object.assign(requestData, requestParams);
|
|
289
258
|
}
|
|
290
259
|
|
|
291
260
|
// This is also used for Rubix, so it may not work for your application.
|
|
292
|
-
const response = await fetch(
|
|
261
|
+
const response = await fetch(dataUri, {
|
|
262
|
+
method: this.method,
|
|
263
|
+
headers: {
|
|
264
|
+
'x-kx-fetch-style': 'zn-data-table',
|
|
265
|
+
},
|
|
293
266
|
signal,
|
|
294
267
|
credentials: 'same-origin',
|
|
268
|
+
body: this.method === 'POST' ? JSON.stringify(requestData) : undefined
|
|
295
269
|
});
|
|
296
270
|
|
|
297
271
|
if (!response.ok) throw new Error(response.statusText);
|
|
298
272
|
return response.json();
|
|
299
273
|
},
|
|
300
|
-
args: () => [this.dataUri]
|
|
274
|
+
args: () => [this.dataUri, this.requestParams]
|
|
301
275
|
});
|
|
302
276
|
|
|
277
|
+
private rowHasActions: boolean = false;
|
|
278
|
+
|
|
279
|
+
requestParams: Record<string, any> = {};
|
|
280
|
+
|
|
281
|
+
builtinRequestParams: Record<string, any> = {};
|
|
282
|
+
|
|
283
|
+
refresh() {
|
|
284
|
+
// Allow manual refresh to trigger the first data load when no-initial-load is set
|
|
285
|
+
this._initialLoad = false;
|
|
286
|
+
this._dataTask.run().then(r => r);
|
|
287
|
+
}
|
|
288
|
+
|
|
303
289
|
render() {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
290
|
+
// If no-initial-load is set, do not invoke the Task on the first render
|
|
291
|
+
let tableBody: TemplateResult;
|
|
292
|
+
if (this.noInitialLoad && this._initialLoad) {
|
|
293
|
+
tableBody = html`
|
|
294
|
+
<slot name="empty-state"></slot>`;
|
|
295
|
+
} else {
|
|
296
|
+
tableBody = this._dataTask.render({
|
|
297
|
+
pending: () => {
|
|
298
|
+
if (this._initialLoad) {
|
|
299
|
+
return html`
|
|
300
|
+
<div>${this.loadingTable()}</div>`;
|
|
301
|
+
}
|
|
307
302
|
return html`
|
|
308
|
-
<div>${this.
|
|
303
|
+
<div class="reduced-opacity">${this._lastTableContent}</div>`;
|
|
304
|
+
},
|
|
305
|
+
complete: (data) => {
|
|
306
|
+
this._initialLoad = false;
|
|
307
|
+
this._lastTableContent = html`
|
|
308
|
+
<div>${this.renderTable(data as Response)}</div>`;
|
|
309
|
+
return this._lastTableContent;
|
|
310
|
+
},
|
|
311
|
+
error: (error) => {
|
|
312
|
+
if (error instanceof Error) {
|
|
313
|
+
if (error.name === "SyntaxError") {
|
|
314
|
+
console.debug(error.message)
|
|
315
|
+
return html`
|
|
316
|
+
<zn-sp>
|
|
317
|
+
<zn-alert level="error">Unable to load data</zn-alert>
|
|
318
|
+
</zn-sp>`;
|
|
319
|
+
} else if (error.message === "Not Found") {
|
|
320
|
+
return this.emptyState();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return html`
|
|
324
|
+
<div>${error}</div>`
|
|
309
325
|
}
|
|
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;
|
|
326
|
+
}) as TemplateResult;
|
|
327
|
+
}
|
|
322
328
|
|
|
323
329
|
const hasActions = this.hasSlotController.test(ActionSlots.delete.valueOf())
|
|
324
330
|
|| this.hasSlotController.test(ActionSlots.modify.valueOf())
|
|
325
331
|
|| this.hasSlotController.test(ActionSlots.create.valueOf())
|
|
326
332
|
|| this.hasSlotController.test(ActionSlots.sort.valueOf())
|
|
327
|
-
|| this.hasSlotController.test(ActionSlots.filter.valueOf())
|
|
333
|
+
|| this.hasSlotController.test(ActionSlots.filter.valueOf())
|
|
334
|
+
|| this.hasSlotController.test(ActionSlots.filter_top.valueOf());
|
|
335
|
+
|
|
336
|
+
const hasInputs = this.hasSlotController.test(ActionSlots.inputs.valueOf());
|
|
328
337
|
|
|
329
338
|
// Headers do not need to be re-rendered with new data
|
|
330
339
|
return html`
|
|
331
340
|
<div class="table-container" ${ref((el) => (this.tableContainer = el))}>
|
|
341
|
+
${hasInputs ? html`
|
|
342
|
+
<slot name="${ActionSlots.inputs.valueOf()}" style="display: none"></slot>` : null}
|
|
332
343
|
${hasActions ? this.getTableHeader() : html``}
|
|
333
344
|
${tableBody}
|
|
334
345
|
</div>
|
|
@@ -362,28 +373,50 @@ export default class ZnDataTable extends ZincElement {
|
|
|
362
373
|
}
|
|
363
374
|
}
|
|
364
375
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
376
|
+
emptyState() {
|
|
377
|
+
return html`
|
|
378
|
+
<div class="table--empty">
|
|
379
|
+
<zn-empty-state
|
|
380
|
+
caption="${this.emptyStateCaption ? this.emptyStateCaption : (this.caption ? "No " + this.caption.toLowerCase() + " found" : "No data found")}"
|
|
381
|
+
icon="${this.emptyStateIcon}">
|
|
382
|
+
</zn-empty-state>
|
|
383
|
+
</div>`;
|
|
384
|
+
}
|
|
369
385
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
</div>`;
|
|
386
|
+
renderTable(data: Response) {
|
|
387
|
+
this.itemsPerPage = Math.max(1, data.perPage ?? DEFAULT_PER_PAGE);
|
|
388
|
+
this.page = Math.max(1, data.page ?? DEFAULT_PAGE);
|
|
389
|
+
this.totalPages = Math.ceil(Math.max(1, data.total) / this.itemsPerPage);
|
|
390
|
+
|
|
391
|
+
if (!data?.rows || data.rows.length === 0) {
|
|
392
|
+
return this.emptyState();
|
|
378
393
|
}
|
|
379
394
|
|
|
380
|
-
const
|
|
381
|
-
|
|
395
|
+
const filteredHeaders = Object.values(this.headers).filter((header) => {
|
|
396
|
+
return !Object.values(this.hiddenColumns).includes(header.key);
|
|
397
|
+
});
|
|
382
398
|
|
|
383
|
-
this.
|
|
384
|
-
this._rows = this.getRows(keys, data);
|
|
399
|
+
this._rows = this.getRows(data);
|
|
385
400
|
|
|
386
401
|
const hasSelectedRows = this.selectedRows.length > 0;
|
|
402
|
+
this.rowHasActions = this._rows.some((row: Row) => row.actions && row.actions.length > 0);
|
|
403
|
+
|
|
404
|
+
// To make sure the cells are in the same order as the headers, we need to map them cell.col to heading.key
|
|
405
|
+
this._rows.forEach((row: Row) => {
|
|
406
|
+
const orderedCells: Cell[] = [];
|
|
407
|
+
// const unorderedCells = row.cells.filter((c: Cell) => !filteredHeaders.some((h: HeaderConfig) => h.key === c.column));
|
|
408
|
+
|
|
409
|
+
filteredHeaders.forEach((header: HeaderConfig) => {
|
|
410
|
+
const cell = row.cells.find((c: Cell) => c.column === header.key);
|
|
411
|
+
if (cell) {
|
|
412
|
+
orderedCells.push(cell);
|
|
413
|
+
} else {
|
|
414
|
+
orderedCells.push({text: '', column: header.key});
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
row.cells = orderedCells;//.concat(unorderedCells);
|
|
419
|
+
});
|
|
387
420
|
|
|
388
421
|
return html`
|
|
389
422
|
<div style="overflow-x: auto">
|
|
@@ -391,7 +424,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
391
424
|
'table': true,
|
|
392
425
|
'table--standalone': this.standalone,
|
|
393
426
|
'with-hover': !this.unsortable,
|
|
394
|
-
'table-
|
|
427
|
+
'table--with-checkboxes': !this.hideCheckboxes,
|
|
395
428
|
})}">
|
|
396
429
|
<thead>
|
|
397
430
|
<tr>
|
|
@@ -399,17 +432,20 @@ export default class ZnDataTable extends ZincElement {
|
|
|
399
432
|
<th>
|
|
400
433
|
<div><input type="checkbox" @change="${this.selectAll}"></div>
|
|
401
434
|
</th>`}
|
|
402
|
-
${
|
|
435
|
+
${filteredHeaders.map((header: HeaderConfig) => this.renderCellHeader(header))}
|
|
436
|
+
${this.rowHasActions ? html`
|
|
437
|
+
<th></th>` : html``}
|
|
403
438
|
</tr>
|
|
404
439
|
</thead>
|
|
405
440
|
<tbody>
|
|
406
|
-
${this.
|
|
441
|
+
${this._rows.map((row: Row) => html`
|
|
407
442
|
<tr>
|
|
408
443
|
${this.hideCheckboxes ? html`` : html`
|
|
409
444
|
<td class="${classMap({'hidden': !hasSelectedRows})}">
|
|
410
445
|
<div><input type="checkbox" @change="${this.selectRow}"></div>
|
|
411
446
|
</td>`}
|
|
412
|
-
${row.map((value:
|
|
447
|
+
${row.cells.map((value: Cell, index: number) => this.renderCellBody(index, value))}
|
|
448
|
+
${this.rowHasActions ? this.renderActions(row) : null}
|
|
413
449
|
</tr>`)}
|
|
414
450
|
</tbody>
|
|
415
451
|
</table>
|
|
@@ -421,6 +457,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
421
457
|
|
|
422
458
|
getTableHeader() {
|
|
423
459
|
return html`
|
|
460
|
+
<slot name="${ActionSlots.filter_top.valueOf()}"></slot>
|
|
424
461
|
<div class="table__header">
|
|
425
462
|
<div class="table__header__actions">
|
|
426
463
|
${this.getActions()}
|
|
@@ -460,7 +497,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
460
497
|
}
|
|
461
498
|
|
|
462
499
|
getPagination() {
|
|
463
|
-
if (this.hidePagination || (this.totalPages <= 1 && this._rows.length <=
|
|
500
|
+
if (this.hidePagination || (this.totalPages <= 1 && this._rows.length <= this.itemsPerPage)) return null;
|
|
464
501
|
|
|
465
502
|
const optionsRowsPerPage = [10, 20, 30, 40, 50];
|
|
466
503
|
optionsRowsPerPage.filter((option) => option <= this._rows.length);
|
|
@@ -597,45 +634,33 @@ export default class ZnDataTable extends ZincElement {
|
|
|
597
634
|
this.requestUpdate();
|
|
598
635
|
}
|
|
599
636
|
|
|
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
|
-
selectRow(e: PointerEvent) {
|
|
637
|
+
selectRow(e: Event) {
|
|
617
638
|
if (!(e.target && (e.target instanceof Element))) {
|
|
618
639
|
return;
|
|
619
640
|
}
|
|
620
641
|
|
|
621
|
-
|
|
642
|
+
const target: Element | null = e.target;
|
|
622
643
|
// if is a button or a link continue
|
|
623
|
-
if (target
|
|
624
|
-
return
|
|
644
|
+
if (target?.tagName === 'ZN-BUTTON' || target?.tagName === 'A' || target?.tagName === 'BUTTON') {
|
|
645
|
+
return;
|
|
625
646
|
}
|
|
626
647
|
|
|
627
|
-
//
|
|
628
|
-
|
|
629
|
-
|
|
648
|
+
// Find the parent row
|
|
649
|
+
let parent: Element | null = target.closest ? target.closest('tr') : target.parentElement;
|
|
650
|
+
while (parent && parent.tagName !== 'TR') {
|
|
651
|
+
parent = parent.parentElement;
|
|
630
652
|
}
|
|
631
653
|
|
|
632
|
-
if (
|
|
654
|
+
if (parent === null) {
|
|
633
655
|
return;
|
|
634
656
|
}
|
|
635
657
|
|
|
636
|
-
const checkbox =
|
|
658
|
+
const checkbox: HTMLInputElement | null = parent.querySelector('input[type="checkbox"]');
|
|
637
659
|
if (checkbox) {
|
|
638
|
-
|
|
660
|
+
const isCheckboxTarget = target instanceof HTMLInputElement && target.type === 'checkbox';
|
|
661
|
+
if (!isCheckboxTarget) {
|
|
662
|
+
checkbox.checked = !checkbox.checked;
|
|
663
|
+
}
|
|
639
664
|
}
|
|
640
665
|
|
|
641
666
|
this.selectedRows = this._rows.filter((_, index) => {
|
|
@@ -670,181 +695,79 @@ export default class ZnDataTable extends ZincElement {
|
|
|
670
695
|
};
|
|
671
696
|
}
|
|
672
697
|
|
|
673
|
-
|
|
698
|
+
renderCell(data: Cell) {
|
|
674
699
|
if (data && typeof data === 'object') {
|
|
675
|
-
let content: TemplateResult = html`${data
|
|
700
|
+
let content: TemplateResult | ZincElement = html`${data.text}`;
|
|
676
701
|
|
|
677
|
-
if (data
|
|
678
|
-
|
|
679
|
-
|
|
702
|
+
if (data.style || data.color) {
|
|
703
|
+
const styleStr = typeof data.style === 'string' ? data.style : '';
|
|
704
|
+
const tokens = new Set(styleStr.split(',').filter(Boolean));
|
|
680
705
|
|
|
681
|
-
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
dateStyle: 'medium',
|
|
685
|
-
timeStyle: 'short',
|
|
686
|
-
hourCycle: 'h12',
|
|
687
|
-
timeZone: 'UTC'
|
|
688
|
-
}).format(new Date(timestamp < 10000000000 ? timestamp * 1000 : timestamp))}`;
|
|
689
|
-
}
|
|
706
|
+
const isMono = tokens.has('mono') || tokens.has('code');
|
|
707
|
+
const isBorder = tokens.has('border');
|
|
708
|
+
const isCenter = tokens.has('center');
|
|
690
709
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
710
|
+
if (tokens.has('bold') || tokens.has('strong')) {
|
|
711
|
+
content = html`<strong>${content}</strong>`;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (tokens.has('italic')) {
|
|
715
|
+
content = html`<em>${content}</em>`;
|
|
716
|
+
}
|
|
696
717
|
|
|
697
|
-
if (data['tag'] === 'code') {
|
|
698
718
|
content = html`
|
|
699
|
-
<
|
|
719
|
+
<zn-style
|
|
720
|
+
font="${isMono ? 'mono' : nothing}"
|
|
721
|
+
border="${isBorder || nothing}"
|
|
722
|
+
center="${isCenter || nothing}"
|
|
723
|
+
color="${ifDefined(data.color)}">${content}
|
|
724
|
+
</zn-style>`;
|
|
700
725
|
}
|
|
701
726
|
|
|
702
|
-
if (data
|
|
727
|
+
if (data.uri) {
|
|
703
728
|
content = html`
|
|
704
|
-
<a href="${data
|
|
705
|
-
data-target="${ifDefined(data
|
|
706
|
-
gaid="${ifDefined(data
|
|
729
|
+
<a href="${data.uri}"
|
|
730
|
+
data-target="${ifDefined(data.target || nothing)}"
|
|
731
|
+
gaid="${ifDefined(data.gaid || nothing)}">${content}</a>`;
|
|
707
732
|
}
|
|
708
733
|
|
|
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>`;
|
|
734
|
+
if (data.chipColor) {
|
|
735
|
+
return html`
|
|
736
|
+
<zn-chip type="${data.chipColor}">${content}</zn-chip>`;
|
|
743
737
|
}
|
|
744
738
|
|
|
745
|
-
if (data
|
|
746
|
-
const placement = data
|
|
739
|
+
if (data.hoverContent) {
|
|
740
|
+
const placement = data.hoverPlacement ?? 'top';
|
|
747
741
|
|
|
748
|
-
if (data
|
|
749
|
-
const
|
|
750
|
-
const
|
|
751
|
-
const size = icon['size'] ?? 16;
|
|
752
|
-
const color = icon['color'] ?? '';
|
|
742
|
+
if (data.iconSrc) {
|
|
743
|
+
const src = data.iconSrc;
|
|
744
|
+
const color = data.iconColor ?? '';
|
|
753
745
|
|
|
754
746
|
return html`
|
|
755
|
-
${
|
|
747
|
+
${content}
|
|
756
748
|
<zn-hover-container placement="${placement}"
|
|
757
749
|
flip>
|
|
758
|
-
<zn-icon src="${src}"
|
|
750
|
+
<zn-icon src="${src}" color="${color}"></zn-icon>
|
|
759
751
|
<div slot="content">
|
|
760
|
-
${unsafeHTML(data
|
|
752
|
+
${unsafeHTML(data.hoverContent)}
|
|
761
753
|
</div>
|
|
762
754
|
</zn-hover-container>`;
|
|
763
755
|
}
|
|
764
756
|
|
|
765
757
|
return html`
|
|
766
|
-
${data['hover'].label}
|
|
767
758
|
<zn-hover-container placement="${placement}"
|
|
768
759
|
flip>
|
|
769
|
-
<div slot="anchor">${
|
|
770
|
-
${unsafeHTML(data
|
|
760
|
+
<div slot="anchor">${content}</div>
|
|
761
|
+
${unsafeHTML(data.hoverContent)}
|
|
771
762
|
</zn-hover-container>`;
|
|
772
763
|
}
|
|
773
764
|
|
|
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
|
-
}
|
|
835
|
-
|
|
836
|
-
if (data['icon']) {
|
|
837
|
-
const icon = data['icon']?.['src'] ?? data['icon'];
|
|
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
|
-
}
|
|
765
|
+
if (data.iconSrc) {
|
|
766
|
+
const src = data.iconSrc;
|
|
767
|
+
const color = data.iconColor ?? '';
|
|
844
768
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
<zn-style color="${data['color']}">${content}</zn-style>`;
|
|
769
|
+
return html`
|
|
770
|
+
<zn-icon src="${src}" color="${color}"></zn-icon> ${content}`;
|
|
848
771
|
}
|
|
849
772
|
|
|
850
773
|
return content;
|
|
@@ -853,6 +776,21 @@ export default class ZnDataTable extends ZincElement {
|
|
|
853
776
|
return data;
|
|
854
777
|
}
|
|
855
778
|
|
|
779
|
+
private updateActionKeys(slotName: string) {
|
|
780
|
+
if (this.hasSlotController.test(slotName)) {
|
|
781
|
+
// we need to look into the slot controller for the keys input
|
|
782
|
+
const slots = this.hasSlotController.getSlots(slotName);
|
|
783
|
+
if (slots) {
|
|
784
|
+
slots.forEach((slot) => {
|
|
785
|
+
const input = slot.querySelector('input[name="keys"]');
|
|
786
|
+
if (input && input instanceof HTMLInputElement) {
|
|
787
|
+
input.value = this.getSelectedKeys().join(',');
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
856
794
|
private getTableSortIcon(key: any) {
|
|
857
795
|
if (this.sortColumn !== key) {
|
|
858
796
|
return html`
|
|
@@ -874,68 +812,33 @@ export default class ZnDataTable extends ZincElement {
|
|
|
874
812
|
</div>`;
|
|
875
813
|
}
|
|
876
814
|
|
|
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
|
-
}
|
|
815
|
+
private renderCellHeader(header: HeaderConfig) {
|
|
816
|
+
const sortable = !Object.values(this.unsortableHeaders).includes(header.key) && !Object.values(this.hiddenHeaders).includes(header.key) && !this.unsortable;
|
|
817
|
+
const lastHeader = Object.keys(this.headers).filter((key) => !Object.values(this.hiddenColumns).includes(key)).slice(-1)[0];
|
|
818
|
+
const lastHeaderKey = lastHeader ? this.headers[lastHeader].key : '';
|
|
901
819
|
|
|
902
820
|
return html`
|
|
903
821
|
<th
|
|
904
822
|
class="${classMap({
|
|
905
823
|
'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),
|
|
824
|
+
'table__head--wide': header.key === this.wideColumn,
|
|
825
|
+
'table__head--last': header.key === lastHeaderKey,
|
|
826
|
+
'table__head--hidden': Object.values(this.hiddenHeaders).includes(header.key),
|
|
909
827
|
})}"
|
|
910
|
-
@click="${sortable ? this.updateSort(key) : undefined}">
|
|
828
|
+
@click="${sortable ? this.updateSort(header.key) : undefined}">
|
|
911
829
|
<div>
|
|
912
|
-
${header}
|
|
913
|
-
${sortable ? this.getTableSortIcon(key) : nothing}
|
|
830
|
+
${header.label}
|
|
831
|
+
${sortable ? this.getTableSortIcon(header.key) : nothing}
|
|
914
832
|
</div>
|
|
915
833
|
</th>
|
|
916
834
|
`;
|
|
917
835
|
}
|
|
918
836
|
|
|
919
|
-
private renderCellBody(index: number, value:
|
|
837
|
+
private renderCellBody(index: number, value: Cell) {
|
|
920
838
|
const headerKeys: string[] = Object.keys(this.headers).filter(
|
|
921
839
|
(key) => !Object.values(this.hiddenColumns).includes(key)
|
|
922
840
|
);
|
|
923
841
|
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
842
|
|
|
940
843
|
return html`
|
|
941
844
|
<td
|
|
@@ -945,32 +848,49 @@ export default class ZnDataTable extends ZincElement {
|
|
|
945
848
|
'table__cell--wide': headerKey === this.wideColumn,
|
|
946
849
|
'table__cell--last': headerKey === headerKeys[headerKeys.length - 1],
|
|
947
850
|
})}">
|
|
948
|
-
<div>${this.
|
|
851
|
+
<div>${this.renderCell(value)}</div>
|
|
949
852
|
</td>`;
|
|
950
853
|
}
|
|
951
854
|
|
|
952
|
-
private
|
|
953
|
-
|
|
954
|
-
}
|
|
855
|
+
private getRows(data: Response): Row[] {
|
|
856
|
+
const sourceRows = data.rows;
|
|
955
857
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
});
|
|
858
|
+
if (this.sortColumn) {
|
|
859
|
+
const headerKeys = Object.keys(this.headers);
|
|
860
|
+
const sortIndex = headerKeys.indexOf(this.sortColumn);
|
|
960
861
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
862
|
+
sourceRows.sort((rowA: Row, rowB: Row) => {
|
|
863
|
+
const getCellForSort = (row: Row): Cell => {
|
|
864
|
+
const byHeading = row.cells.find((cell: Cell) => cell.column === this.sortColumn);
|
|
865
|
+
if (byHeading !== undefined) return byHeading as unknown as Cell;
|
|
866
|
+
return row.cells[sortIndex];
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
const aVal = getCellForSort(rowA);
|
|
870
|
+
const bVal = getCellForSort(rowB);
|
|
871
|
+
return this.sortData(aVal, bVal);
|
|
965
872
|
});
|
|
966
873
|
}
|
|
967
874
|
|
|
968
|
-
return
|
|
875
|
+
return sourceRows;
|
|
969
876
|
}
|
|
970
877
|
|
|
971
|
-
private getSelectedKeys() {
|
|
878
|
+
private getSelectedKeys(): (string)[] {
|
|
972
879
|
const headerKeys = Object.keys(this.headers);
|
|
973
|
-
|
|
880
|
+
const keyIndex = headerKeys.indexOf(this.key);
|
|
881
|
+
|
|
882
|
+
return this.selectedRows
|
|
883
|
+
.map((row: Row) => {
|
|
884
|
+
if (this.key === 'id' || keyIndex === -1) {
|
|
885
|
+
return row.id;
|
|
886
|
+
}
|
|
887
|
+
const cell = row.cells?.[keyIndex] as Cell;
|
|
888
|
+
if (cell.sortValue) {
|
|
889
|
+
return cell.sortValue;
|
|
890
|
+
}
|
|
891
|
+
return cell.text as string;
|
|
892
|
+
})
|
|
893
|
+
.filter((v): v is string => v !== undefined && v !== null);
|
|
974
894
|
}
|
|
975
895
|
|
|
976
896
|
private updateKeys() {
|
|
@@ -986,36 +906,27 @@ export default class ZnDataTable extends ZincElement {
|
|
|
986
906
|
this.updateActionKeys('delete-action');
|
|
987
907
|
}
|
|
988
908
|
|
|
989
|
-
private
|
|
990
|
-
|
|
991
|
-
|
|
909
|
+
private extractComparable(cell: Cell): string {
|
|
910
|
+
const sortValue = cell.sortValue;
|
|
911
|
+
if (sortValue) {
|
|
912
|
+
return sortValue;
|
|
992
913
|
}
|
|
993
914
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
} else if (typeof a === 'object' && a && 'value' in a) {
|
|
997
|
-
a = a.value as string | number;
|
|
998
|
-
}
|
|
915
|
+
return cell.text;
|
|
916
|
+
}
|
|
999
917
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
b = b.value as string | number;
|
|
1004
|
-
}
|
|
918
|
+
private sortData(a: Cell, b: Cell) {
|
|
919
|
+
const aCompare = this.extractComparable(a);
|
|
920
|
+
const bCompare = this.extractComparable(b);
|
|
1005
921
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
if (typeof b === 'string') {
|
|
1011
|
-
b = b.toLowerCase();
|
|
1012
|
-
}
|
|
922
|
+
const aNormal = aCompare.toLowerCase();
|
|
923
|
+
const bNormal = bCompare.toLowerCase();
|
|
1013
924
|
|
|
1014
925
|
if (this.sortDirection === 'asc') {
|
|
1015
|
-
return
|
|
926
|
+
return aNormal > bNormal ? 1 : aNormal < bNormal ? -1 : 0;
|
|
1016
927
|
}
|
|
1017
928
|
|
|
1018
|
-
return
|
|
929
|
+
return aNormal < bNormal ? 1 : aNormal > bNormal ? -1 : 0;
|
|
1019
930
|
}
|
|
1020
931
|
|
|
1021
932
|
private loadingTable() {
|
|
@@ -1090,4 +1001,57 @@ export default class ZnDataTable extends ZincElement {
|
|
|
1090
1001
|
</table>
|
|
1091
1002
|
</div>`;
|
|
1092
1003
|
}
|
|
1004
|
+
|
|
1005
|
+
private renderActions(row: Row) {
|
|
1006
|
+
if ((row.actions === null || row.actions === undefined) && this.rowHasActions) {
|
|
1007
|
+
// return an empty cell to keep the table structure
|
|
1008
|
+
return html`
|
|
1009
|
+
<td></td>`;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (!row.actions || row.actions.length === 0) {
|
|
1013
|
+
return html``;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
return html`
|
|
1017
|
+
<td class="table__cell table__cell--actions">
|
|
1018
|
+
<zn-dropdown placement="bottom-end">
|
|
1019
|
+
<zn-button slot="trigger"
|
|
1020
|
+
icon="more_vert"
|
|
1021
|
+
size="small"
|
|
1022
|
+
color="transparent"
|
|
1023
|
+
icon-size="24"
|
|
1024
|
+
aria-label="Row actions">
|
|
1025
|
+
</zn-button>
|
|
1026
|
+
<zn-menu>
|
|
1027
|
+
${row.actions?.map((action: ActionConfig) => {
|
|
1028
|
+
if (action.confirmContent) {
|
|
1029
|
+
const triggerId = 'confirm-action-' + Math.random().toString(36).substring(2, 15);
|
|
1030
|
+
return html`
|
|
1031
|
+
<zn-confirm trigger="${triggerId}"
|
|
1032
|
+
type="${ifDefined(action.confirmType)}"
|
|
1033
|
+
caption="${action.confirmTitle}"
|
|
1034
|
+
content="${action.confirmContent}"
|
|
1035
|
+
action="${action.uri}"></zn-confirm>
|
|
1036
|
+
<zn-menu-item id="${triggerId}">
|
|
1037
|
+
${(action.icon) ? html`
|
|
1038
|
+
<zn-icon src="${action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
|
|
1039
|
+
${action.text}
|
|
1040
|
+
</zn-menu-item>`;
|
|
1041
|
+
} else {
|
|
1042
|
+
return html`
|
|
1043
|
+
<zn-menu-item value="${action.text}"
|
|
1044
|
+
href="${action.uri}"
|
|
1045
|
+
gaid="${ifDefined(action.gaid || nothing)}"
|
|
1046
|
+
data-target="${ifDefined(action.target || nothing)}">
|
|
1047
|
+
${(action.icon) ? html`
|
|
1048
|
+
<zn-icon src="${action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
|
|
1049
|
+
${action.text}
|
|
1050
|
+
</zn-menu-item>`;
|
|
1051
|
+
}
|
|
1052
|
+
})}
|
|
1053
|
+
</zn-menu>
|
|
1054
|
+
</zn-dropdown>
|
|
1055
|
+
</td>`;
|
|
1056
|
+
}
|
|
1093
1057
|
}
|