lkt-table 1.1.2 → 1.2.0

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.
@@ -1,31 +1,104 @@
1
1
  <script lang="ts" setup>
2
- import draggable from "vuedraggable";
3
- import {
4
- defaultTableSorter,
5
- getVerticalColSpan,
6
- getDefaultSortColumn,
7
- getColumnByKey
8
- } from "../functions/table-functions";
2
+ import {defaultTableSorter, getColumnByKey, getDefaultSortColumn} from "../functions/table-functions";
9
3
  import LktTableRow from "../components/LktTableRow.vue";
10
- import {computed, onMounted, PropType, ref, useSlots, watch} from "vue";
4
+ import {computed, nextTick, onMounted, ref, useSlots, watch} from "vue";
11
5
  import {LktTableColumn} from "../instances/LktTableColumn";
12
6
  import {LktEvent} from "lkt-events";
13
7
  import LktHiddenRow from "../components/LktHiddenRow.vue";
14
- import {generateRandomString} from "lkt-string-tools";
8
+ import {generateRandomString, replaceAll} from "lkt-string-tools";
15
9
  import {LktObject} from "lkt-ts-interfaces";
16
- const emit = defineEmits(['update:modelValue', 'sort', 'click']);
10
+ import {DataState} from "lkt-data-state";
11
+ import {HTTPResponse} from "lkt-http-client";
12
+ import CreateButton from "../components/CreateButton.vue";
13
+ // import Sortable from 'sortablejs/modular/sortable.complete.esm.js';
14
+ import Sortable from 'sortablejs';
15
+ import TableHeader from "../components/TableHeader.vue";
16
+ import {__} from "lkt-i18n";
17
+
18
+ const emit = defineEmits(['update:modelValue', 'sort', 'click', 'save', 'error', 'before-save']);
17
19
 
18
20
  const slots = useSlots();
19
21
 
20
- const props = defineProps({
21
- modelValue: {type: Array as PropType<LktObject[]>, default: (): any[] => []},
22
- columns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
23
- sorter: {type: Function, default: defaultTableSorter},
24
- sortable: {type: Boolean, default: false},
25
- hideEmptyColumns: {type: Boolean, default: false},
26
- draggableChecker: {type: Function, default: (item: any) => true},
27
- checkValidDrag: {type: Function, default: (evt: any) => true},
28
- draggableItemKey: {type: String, default: 'name'}
22
+ const props = withDefaults(defineProps<{
23
+ modelValue: LktObject[]
24
+ columns: LktTableColumn[]
25
+ sorter?: Function
26
+ draggableChecker?: Function
27
+ checkValidDrag?: Function
28
+ sortable?: boolean
29
+ hideEmptyColumns?: boolean
30
+ draggableItemKey?: string
31
+
32
+
33
+ page?: number
34
+ resource?: string
35
+ noResultsText?: string
36
+ title?: string
37
+ titleTag?: string
38
+ titleIcon?: string
39
+ wrapContentTag?: string
40
+ wrapContentClass?: string
41
+ filters?: LktObject[]
42
+ dataStateConfig?: LktObject
43
+ hiddenSave?: boolean
44
+ editMode?: boolean
45
+ saveDisabled?: boolean
46
+ saveValidator?: Function
47
+ saveConfirm?: string
48
+ confirmData?: LktObject
49
+ saveResource?: string
50
+ saveResourceData?: LktObject
51
+ saveText?: string
52
+ createText?: string
53
+ dropText?: string
54
+ editModeText?: string
55
+ switchEditionEnabled?: boolean
56
+ canCreate?: boolean
57
+ canDrop?: boolean
58
+ dropConfirm?: string
59
+ dropResource?: string
60
+ addNavigation?: boolean
61
+ createEnabledValidator?: Function
62
+ }>(), {
63
+ modelValue: () => [],
64
+ columns: () => [],
65
+ sorter: defaultTableSorter,
66
+ draggableChecker: (item: any) => true,
67
+ checkValidDrag: undefined,
68
+ sortable: false,
69
+ hideEmptyColumns: false,
70
+ draggableItemKey: 'name',
71
+
72
+
73
+ page: 1,
74
+ resource: '',
75
+ noResultsText: 'No results',
76
+ title: '',
77
+ titleTag: 'h2',
78
+ titleIcon: 'h2',
79
+ wrapContentTag: 'div',
80
+ wrapContentClass: '',
81
+ filters: () => [],
82
+ dataStateConfig: () => ({}),
83
+ hiddenSave: false,
84
+ editMode: false,
85
+ saveDisabled: false,
86
+ saveValidator: () => true,
87
+ saveConfirm: '',
88
+ confirmData: () => ({}),
89
+ saveResource: '',
90
+ saveResourceData: () => ({}),
91
+ saveText: 'Save',
92
+ dropText: 'Delete',
93
+ createText: 'Add item',
94
+ editModeText: 'Edit mode',
95
+ switchEditionEnabled: false,
96
+ canCreate: false,
97
+ canDrop: false,
98
+ dropConfirm: '',
99
+ dropResource: '',
100
+ addNavigation: false,
101
+ createEnabledValidator: undefined,
29
102
  });
30
103
 
31
104
  const hiddenColumnsStack: LktObject = {};
@@ -35,16 +108,35 @@ const Sorter = ref(typeof props.sorter === 'function' ? props.sorter : defaultTa
35
108
  SortDirection = ref('asc'),
36
109
  Items = ref(props.modelValue),
37
110
  Hidden = ref(hiddenColumnsStack),
38
- drag = ref(false),
111
+ tableBody = ref(null),
39
112
  Columns = ref(props.columns);
40
113
 
114
+ const Page = ref(props.page),
115
+ loading = ref(true),
116
+ firstLoadReady = ref(false),
117
+ paginator = ref(null),
118
+ sortableObject = ref({}),
119
+ dataState = ref(new DataState({items: Items.value}, props.dataStateConfig)),
120
+ editModeEnabled = ref(props.editMode)
121
+ ;
122
+
123
+ const onResults = (r: any) => {
124
+ //@ts-ignore
125
+ if (Array.isArray(r)) Items.value = r;
126
+ loading.value = false;
127
+ firstLoadReady.value = true;
128
+ dataState.value.store({items: Items.value}).turnStoredIntoOriginal();
129
+ },
130
+ onLoading = () => nextTick(() => loading.value = true),
131
+ doRefresh = () => {
132
+ //@ts-ignore
133
+ paginator.value.doRefresh();
134
+ };
135
+
41
136
 
42
137
  const uniqueId = generateRandomString(12);
43
138
 
44
- const hasData = computed(() => {
45
- return Items.value.length > 0;
46
- }),
47
- emptyColumns = computed(() => {
139
+ const emptyColumns = computed(() => {
48
140
  if (!props.hideEmptyColumns) return [];
49
141
  let r: string[] = [];
50
142
  Columns.value.forEach((column: LktTableColumn) => {
@@ -73,6 +165,9 @@ const hasData = computed(() => {
73
165
  if (props.sortable) ++r;
74
166
  return r;
75
167
  }),
168
+ rowKeyColumns = computed(() => {
169
+ return Columns.value.filter((c: LktTableColumn) => c.isForRowKey);
170
+ }),
76
171
  displayHiddenColumnsIndicator = computed(() => {
77
172
  return hiddenColumns.value.length > 0 && !props.sortable;
78
173
  }),
@@ -84,6 +179,58 @@ const hasData = computed(() => {
84
179
  let r = [];
85
180
  for (let k in slots) if (columnKeys.value.indexOf(k) !== -1) r.push(k);
86
181
  return r;
182
+ }),
183
+ showSaveButton = computed(() => {
184
+ if (props.hiddenSave) return false;
185
+ if (loading.value) return false;
186
+ if (!props.saveResource) return false;
187
+ if (editModeEnabled.value && dataState.value.changed()) return true;
188
+
189
+ return editModeEnabled.value;
190
+ }),
191
+ showEditionButtons = computed(() => {
192
+ if (props.switchEditionEnabled) return true;
193
+ return showSaveButton.value || (editModeEnabled.value && props.canCreate);
194
+ }),
195
+ ableToSave = computed(() => {
196
+ if (props.saveDisabled) return false;
197
+ if (typeof props.saveValidator === 'function' && !props.saveValidator(Items.value)) return false;
198
+ return dataState.value.changed();
199
+ }),
200
+ amountOfItems = computed(() => {
201
+ return Items.value.length;
202
+ }),
203
+ computedSaveResourceData = computed(() => {
204
+ return {
205
+ items: Items.value,
206
+ ...props.saveResourceData
207
+ }
208
+ }),
209
+ computedTitleTag = computed(() => {
210
+ if (props.titleTag === '') return 'h2';
211
+ return props.titleTag;
212
+ }),
213
+ computedWrapContentTag = computed(() => {
214
+ if (props.wrapContentTag === '') return 'div';
215
+ return props.wrapContentTag;
216
+ }),
217
+ computedTitle = computed(() => {
218
+ if (props.title.startsWith('__:')) {
219
+ return __(props.title.substring(3));
220
+ }
221
+ return props.title;
222
+ }),
223
+ computedSaveText = computed(() => {
224
+ if (props.saveText.startsWith('__:')) {
225
+ return __(props.saveText.substring(3));
226
+ }
227
+ return props.saveText;
228
+ }),
229
+ computedEditModeText = computed(() => {
230
+ if (props.editModeText.startsWith('__:')) {
231
+ return __(props.editModeText.substring(3));
232
+ }
233
+ return props.editModeText;
87
234
  });
88
235
 
89
236
 
@@ -127,18 +274,20 @@ const getItemByEvent = (e: any) => {
127
274
  autoLoadSelectColumnsOptions = () => {
128
275
 
129
276
  Columns.value.forEach(col => {
130
- if (col.type === 'select') {
277
+ if (col.type === 'select' && col.autoLoadSelectOptions) {
131
278
 
132
279
  let key = col.autoLoadSelectOptionsKey !== '' ? col.autoLoadSelectOptionsKey : col.key,
133
280
  opts = [];
134
281
 
135
282
  Items.value.forEach(item => {
136
- item[key].forEach (opt => opts.push(opt));
283
+ if (Array.isArray(item[key])) {
284
+ item[key].forEach(opt => opts.push(opt));
285
+ }
137
286
  });
138
287
 
139
288
  let flags = {};
140
289
 
141
- opts = opts.filter(function(opt) {
290
+ opts = opts.filter(function (opt) {
142
291
  if (flags[opt.value]) return false;
143
292
  flags[opt.value] = true;
144
293
  return true;
@@ -147,145 +296,306 @@ const getItemByEvent = (e: any) => {
147
296
  col.setOptions(opts);
148
297
  }
149
298
  })
150
- };
299
+ },
300
+ validDragChecker = (evt: any) => {
301
+ if (typeof props.checkValidDrag === 'function') return props.checkValidDrag(evt);
302
+ return true;
303
+ },
304
+ isDraggable = (element: any) => {
305
+ if (typeof props.draggableChecker === 'function') return props.draggableChecker(element);
306
+ return true;
307
+ },
308
+ onClickAddItem = () => {
309
+ Items.value.push({});
310
+ },
311
+ onButtonLoading = () => {
312
+ loading.value = true;
313
+ },
314
+ onButtonLoaded = () => {
315
+ loading.value = false;
316
+ },
317
+ onSave = ($event: PointerEvent, r: HTTPResponse) => {
318
+ emit('before-save');
319
+ if (props.saveResource) {
320
+ loading.value = false;
321
+ // httpStatus.value = r.httpStatus;
322
+ if (!r.success) {
323
+ emit('error', r.httpStatus);
324
+ return;
325
+ }
326
+ }
327
+ dataState.value.turnStoredIntoOriginal();
328
+
329
+ emit('save', r)
330
+ },
331
+ moveArrayPosition = (arr, oldIndex, newIndex) => {
332
+ if (newIndex >= arr.length) {
333
+ let k = newIndex - arr.length + 1;
334
+ while (k--) arr.push(undefined);
335
+ }
336
+ arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]);
337
+ return arr; // for testing
338
+ },
339
+ onItemUp = (i) => {
340
+ moveArrayPosition(Items.value, i, i - 1);
341
+ },
342
+ onItemDown = (i) => {
343
+ moveArrayPosition(Items.value, i, i + 1);
344
+ },
345
+ onItemDrop = (i) => {
346
+ Items.value.splice(i, 1);
347
+ },
348
+ initSortable = () => {
349
+ let tbody = document.getElementById('lkt-table-body-' + uniqueId);
350
+
351
+ sortableObject.value = new Sortable(tbody, {
352
+ direction: 'vertical',
353
+ handle: '.handle',
354
+ animation: 150,
355
+ onEnd: function (evt: CustomEvent) {
356
+ let oldIndex = evt.oldIndex;
357
+ let newIndex = evt.newIndex;
151
358
 
359
+ let clone = JSON.parse(JSON.stringify(Items.value));
360
+ Items.value.splice(oldIndex, 1, clone[newIndex]);
361
+ Items.value.splice(newIndex, 1, clone[oldIndex]);
362
+ },
363
+ onMove: function (evt, originalEvent) {
364
+ return validDragChecker(evt);
365
+ // return false; — for cancel
366
+ // return -1; — insert before target
367
+ // return 1; — insert after target
368
+ // return true; — keep default insertion point based on the direction
369
+ // return void; — keep default insertion point based on the direction
370
+ },
371
+ });
372
+ },
373
+ getRowKey = (item: LktObject, index: number, isHidden: boolean = false) => {
374
+ let r = [uniqueId, 'row', index];
375
+ if (isHidden) r.push('hidden');
152
376
 
153
- const onEdited = (payload: LktObject, i: any) => {
154
- Items.value[i] = payload;
155
- }
377
+ rowKeyColumns.value.forEach(col => {
378
+ let text = String(item[col.key]).toLowerCase();
379
+ if (text.length > 50) text = text.substring(0, 50);
380
+ text = replaceAll(text, ' ', '-');
381
+ r.push(text);
382
+ });
383
+
384
+ return r.join('-');
385
+ },
386
+ createEnabled = computed(() => {
387
+ if (typeof props.createEnabledValidator === 'function') return props.createEnabledValidator({items: Items.value});
388
+ return true;
389
+ });
156
390
 
157
391
  onMounted(() => {
158
392
  autoLoadSelectColumnsOptions();
159
393
  sort(getColumnByKey(props.columns, SortBy.value));
394
+ dataState.value.store({items: Items.value}).turnStoredIntoOriginal();
395
+ if (props.sortable) {
396
+ nextTick(() => {
397
+ initSortable();
398
+ })
399
+ }
160
400
  })
161
401
 
162
402
  watch(() => props.columns, (v) => Columns.value = v);
163
403
  watch(() => props.modelValue, (v) => Items.value = v);
164
404
  watch(Items, (v: any) => {
165
405
  autoLoadSelectColumnsOptions();
406
+ dataState.value.increment({items: v});
166
407
  emit('update:modelValue', v);
167
- });
408
+ }, {deep: true});
168
409
 
169
- defineExpose({getItemByEvent});
410
+ defineExpose({
411
+ getItemByEvent,
412
+ doRefresh,
413
+ });
170
414
 
171
415
  </script>
172
416
 
173
417
  <template>
174
- <div v-if="hasData" class="lkt-table" :data-sortable="sortable">
175
- <table>
176
- <thead>
177
- <tr>
178
- <th v-if="sortable" data-role="drag-indicator"></th>
179
- <th v-if="displayHiddenColumnsIndicator"></th>
180
- <template v-for="column in visibleColumns">
181
- <th :data-column="column.key"
182
- v-if="emptyColumns.indexOf(column.key) === -1"
183
- v-bind:data-sortable="column.sortable === true"
184
- v-bind:data-sort="column.sortable === true && SortBy === column.key ? SortDirection : ''"
185
- v-bind:colspan="getVerticalColSpan(column, columns.length, Items)"
186
- v-bind:title="column.label"
187
- v-on:click="sort(column)"
418
+ <section class="lkt-table-page" :id="'lkt-table-page-' + uniqueId">
419
+ <header v-if="computedTitle || slots.title">
420
+ <component :is="computedTitleTag" v-if="computedTitle">
421
+ <i v-if="titleIcon" :class="titleIcon"/>
422
+ {{ computedTitle }}
423
+ </component>
424
+ <template v-if="slots.title">
425
+ <slot name="title"/>
426
+ </template>
427
+ </header>
428
+
429
+ <component
430
+ :is="computedWrapContentTag"
431
+ class="lkt-table-page-content-wrapper"
432
+ :class="wrapContentClass"
433
+ >
434
+
435
+ <div class="lkt-table-page-buttons" v-show="showEditionButtons">
436
+
437
+ <lkt-button
438
+ ref="saveButton"
439
+ v-show="showSaveButton"
440
+ palette="success"
441
+ :disabled="!ableToSave"
442
+ :confirm-modal="saveConfirm"
443
+ :confirm-data="confirmData"
444
+ :resource="saveResource"
445
+ :resource-data="computedSaveResourceData"
446
+ v-on:loading="onButtonLoading"
447
+ v-on:loaded="onButtonLoaded"
448
+ v-on:click="onSave">
449
+ <slot v-if="!!slots['button-save']"
450
+ name="button-save"
451
+ :items="Items"
452
+ :edit-mode="editMode"
453
+ :can-update="!saveDisabled"></slot>
454
+ <span v-else>{{ computedSaveText }}</span>
455
+ </lkt-button>
456
+
457
+ <create-button
458
+ v-if="canCreate && editModeEnabled"
459
+ :disabled="!createEnabled"
460
+ :text="createText"
461
+ @click="onClickAddItem"
462
+ />
463
+
464
+ <div class="switch-edition-mode">
465
+ <lkt-field-switch
466
+ v-show="switchEditionEnabled"
467
+ v-model="editModeEnabled"
468
+ :label="computedEditModeText"/>
469
+ </div>
470
+ </div>
471
+
472
+ <div class="lkt-table-page-buttons" v-if="slots.buttons">
473
+ <slot name="buttons"/>
474
+ </div>
475
+
476
+ <div class="lkt-table-page-filters" v-if="firstLoadReady && slots.filters">
477
+ <slot name="filters" :items="Items" :is-loading="loading"/>
478
+ </div>
479
+
480
+ <lkt-loader v-if="loading"/>
481
+
482
+ <div v-show="!loading && Items.length > 0" class="lkt-table" :data-sortable="sortable">
483
+ <table>
484
+ <thead>
485
+ <tr>
486
+ <th v-if="sortable && editModeEnabled" data-role="drag-indicator"/>
487
+ <th v-if="addNavigation && editModeEnabled"/>
488
+ <th v-if="displayHiddenColumnsIndicator"/>
489
+ <template v-for="column in visibleColumns">
490
+ <table-header
491
+ v-if="emptyColumns.indexOf(column.key) === -1"
492
+ :column="column"
493
+ :sort-by="SortBy"
494
+ :sort-direction="SortDirection"
495
+ :amount-of-columns="columns.length"
496
+ :items="Items"
497
+ v-on:click="sort(column)"
498
+ />
499
+ </template>
500
+ <th v-if="canDrop && editModeEnabled"/>
501
+ </tr>
502
+ </thead>
503
+ <tbody
504
+ :ref="(el) => tableBody = el"
505
+ :id="'lkt-table-body-' + uniqueId"
188
506
  >
189
- <div>{{ column.label }}</div>
190
- </th>
191
- </template>
192
- </tr>
193
- </thead>
194
- <draggable v-if="sortable"
195
- v-model="Items"
196
- v-bind:move="checkValidDrag"
197
- v-bind:itemKey="draggableItemKey"
198
- v-on:start="drag=true"
199
- v-on:end="drag=false"
200
- tag="tbody"
201
- class="lkt-sortable-table"
202
- handle="[data-handle-drag]">
203
- <template #item="{element, index}">
204
507
  <lkt-table-row
205
- v-bind:key="uniqueId + '-' + index"
206
- v-bind:i="index"
207
- v-bind:item="element"
208
- v-bind:display-hidden-columns-indicator="displayHiddenColumnsIndicator"
209
- v-bind:is-draggable="draggableChecker ? draggableChecker(element) : true"
210
- v-bind:sortable="sortable"
211
- v-bind:visible-columns="visibleColumns"
212
- v-bind:empty-columns="emptyColumns"
213
- v-bind:hidden-is-visible="isVisible(index)"
508
+ v-for="(item, i) in Items"
509
+ v-model="Items[i]"
510
+ :key="getRowKey(item, i)"
511
+ :i="i"
512
+ :display-hidden-columns-indicator="displayHiddenColumnsIndicator"
513
+ :is-draggable="isDraggable(item)"
514
+ :sortable="sortable"
515
+ :visible-columns="visibleColumns"
516
+ :empty-columns="emptyColumns"
517
+ :add-navigation="addNavigation"
518
+ :hidden-is-visible="isVisible(i)"
519
+ :latest-row="i+1 === amountOfItems"
520
+ :can-drop="canDrop"
521
+ :drop-confirm="dropConfirm"
522
+ :drop-text="dropText"
523
+ :edit-mode-enabled="editModeEnabled"
214
524
  v-on:click="onClick"
215
525
  v-on:show="show"
526
+ v-on:item-up="onItemUp"
527
+ v-on:item-down="onItemDown"
528
+ v-on:item-drop="onItemDrop"
216
529
  >
217
530
  <template
218
531
  v-for="column in colSlots"
219
532
  v-slot:[column]="row">
220
533
  <slot
221
- v-bind:name="column"
222
- v-bind:item="row.item"
223
- v-bind:value="row.value"
224
- v-bind:column="row.column"
225
- ></slot>
534
+ :name="column"
535
+ :item="row.item"
536
+ :value="row.value"
537
+ :column="row.column"
538
+ />
226
539
  </template>
227
540
  </lkt-table-row>
228
- </template>
229
- </draggable>
230
-
231
- <tbody v-else>
232
- <lkt-table-row
233
- v-for="(item, i) in Items"
234
- v-bind:key="uniqueId + '-' + i"
235
- v-bind:i="i"
236
- v-bind:item="item"
237
- v-bind:display-hidden-columns-indicator="displayHiddenColumnsIndicator"
238
- v-bind:is-draggable="draggableChecker ? draggableChecker(item) : true"
239
- v-bind:sortable="sortable"
240
- v-bind:visible-columns="visibleColumns"
241
- v-bind:empty-columns="emptyColumns"
242
- v-bind:hidden-is-visible="isVisible(i)"
243
- v-on:click="onClick"
244
- v-on:show="show"
245
- v-on:edited="onEdited"
246
- >
247
- <template
248
- v-for="column in colSlots"
249
- v-slot:[column]="row">
250
- <slot
251
- v-bind:name="column"
252
- v-bind:item="row.item"
253
- v-bind:value="row.value"
254
- v-bind:column="row.column"
255
- ></slot>
256
- </template>
257
- </lkt-table-row>
258
- <lkt-hidden-row
259
- v-if="hiddenColumns.length > 0"
260
- v-for="(item, i) in Items"
261
- v-bind:key="uniqueId + '-' + i"
262
- v-bind:i="i"
263
- v-bind:item="item"
264
- v-bind:hidden-columns="hiddenColumns"
265
- v-bind:hidden-columns-col-span="hiddenColumnsColSpan"
266
- v-bind:is-draggable="draggableChecker ? draggableChecker(item) : true"
267
- v-bind:sortable="sortable"
268
- v-bind:visible-columns="visibleColumns"
269
- v-bind:empty-columns="emptyColumns"
270
- v-bind:hidden-is-visible="isVisible(i)"
271
- v-on:click="onClick"
272
- v-on:show="show"
273
- >
274
- <template
275
- v-for="column in colSlots"
276
- v-slot:[column]="row">
277
- <slot
278
- v-bind:name="column"
279
- v-bind:item="row.item"
280
- v-bind:value="row.value"
281
- v-bind:column="row.column"
282
- ></slot>
283
- </template>
284
- </lkt-hidden-row>
285
- </tbody>
286
- </table>
287
- </div>
288
- <div v-else-if="!!$slots['no-items']" class="lkt-empty-table">
289
- <slot name="no-items"></slot>
290
- </div>
541
+ <lkt-hidden-row
542
+ v-if="hiddenColumns.length > 0"
543
+ v-model="Items[i]"
544
+ v-for="(item, i) in Items"
545
+ :key="getRowKey(item, i, true)"
546
+ :i="i"
547
+ :hidden-columns="hiddenColumns"
548
+ :hidden-columns-col-span="hiddenColumnsColSpan"
549
+ :is-draggable="isDraggable(item)"
550
+ :sortable="sortable"
551
+ :visible-columns="visibleColumns"
552
+ :empty-columns="emptyColumns"
553
+ :hidden-is-visible="isVisible(i)"
554
+ v-on:click="onClick"
555
+ v-on:show="show"
556
+ >
557
+ <template
558
+ v-for="column in colSlots"
559
+ v-slot:[column]="row">
560
+ <slot
561
+ :name="column"
562
+ :item="row.item"
563
+ :value="row.value"
564
+ :column="row.column"
565
+ />
566
+ </template>
567
+ </lkt-hidden-row>
568
+ </tbody>
569
+ </table>
570
+ </div>
571
+
572
+ <div v-if="!!$slots['no-items']" class="lkt-empty-table">
573
+ <slot name="no-items"/>
574
+ </div>
575
+
576
+
577
+ <div class="lkt-table-page-empty" v-if="!loading && Items.length === 0">
578
+ {{ noResultsText }}
579
+ </div>
580
+
581
+ <div v-if="canCreate && editModeEnabled" class="lkt-table-page-buttons lkt-table-page-buttons-bottom">
582
+ <create-button
583
+ v-if="canCreate && editModeEnabled"
584
+ :disabled="!createEnabled"
585
+ :text="createText"
586
+ @click="onClickAddItem"
587
+ />
588
+ </div>
589
+
590
+ <lkt-paginator
591
+ ref="paginator"
592
+ v-model="Page"
593
+ :resource="resource"
594
+ :filters="filters"
595
+ v-on:results="onResults"
596
+ v-on:loading="onLoading"
597
+ />
598
+
599
+ </component>
600
+ </section>
291
601
  </template>