bfg-common 1.3.93 → 1.3.94

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,1569 +1,1587 @@
1
- <template>
2
- <div class="relative" style="display: flex">
3
- <div
4
- :id="outerWrapper"
5
- :class="[
6
- 'datagrid-outer-wrapper',
7
- {
8
- 'datagrid-outer-wrapper-opened-info': isShowHiddenInfo,
9
- },
10
- ]"
11
- >
12
- <div class="datagrid-inner-wrapper">
13
- <div
14
- v-if="props.isMainFilter"
15
- class="main-filter-content flex-justify-end"
16
- >
17
- <atoms-the-icon class="filter-icon" name="filter" />
18
- <input
19
- v-model.trim="mainFilter"
20
- :id="`${props.testId}-main-filter-input`"
21
- :placeholder="props.mainFilterPlaceholder"
22
- type="text"
23
- @input="emits('main-filter', mainFilter)"
24
- />
25
- </div>
26
- <div
27
- :class="[
28
- 'datagrid',
29
- {
30
- 'datagrid-opened-info': isShowHiddenInfo,
31
- },
32
- ]"
33
- >
34
- <div :id="tableWrapperId" class="datagrid-table-wrapper">
35
- <div class="datagrid-table">
36
- <div class="datagrid-header">
37
- <div class="datagrid-row">
38
- <div class="datagrid-row-master datagrid-row-flex">
39
- <div
40
- v-if="props.type || $slots.toggleBlock"
41
- class="datagrid-row-sticky"
42
- >
43
- <div
44
- v-if="props.type"
45
- :id="expandableCaret"
46
- class="datagrid-column datagrid-expandable-caret datagrid-fixed-column flex-align-center flex-justify-center"
47
- >
48
- <template v-if="props.type === 'checkbox'">
49
- <div
50
- class="clr-checkbox-wrapper flex-align-center flex-justify-center w-100"
51
- >
52
- <input
53
- :id="`${props.testId}-${inputId}-all`"
54
- v-model="selectedAll"
55
- type="checkbox"
56
- class="checkbox-btn"
57
- :value="-1"
58
- @change="changeAll"
59
- />
60
- <label
61
- :for="`${props.testId}-${inputId}-all`"
62
- class="clr-control-label"
63
- />
64
- </div>
65
- <div class="datagrid-column-separator"></div>
66
- </template>
67
- </div>
68
- <div
69
- v-if="$slots.toggleBlock"
70
- class="datagrid-toggle-block datagrid-column datagrid-fixed-width"
71
- >
72
- <div class="datagrid-column-flex">
73
- <div class="datagrid-column-separator">
74
- <span class="clr-sr-only" />
75
- <div class="datagrid-column-resize-tracker" />
76
- </div>
77
- </div>
78
- </div>
79
- </div>
80
- <div class="datagrid-row-scrollable">
81
- <div
82
- v-for="(item, key) in headItemsPresent"
83
- :key="key"
84
- :style="{
85
- width: columnsWidth[key][0],
86
- minWidth: columnsWidth[key][1],
87
- }"
88
- class="datagrid-column datagrid-fixed-width"
89
- >
90
- <div class="datagrid-column-flex">
91
- <button
92
- :id="`${props.testId}-sort-column-${key}`"
93
- :class="[
94
- 'datagrid-column-title',
95
- {
96
- 'default text-decoration-none':
97
- !item.sortColumn,
98
- },
99
- ]"
100
- @click="sortTable(item.sortColumn)"
101
- >
102
- <slot :key="key" name="th" :item="item">
103
- <span
104
- :title="item.text"
105
- :style="{
106
- width:
107
- columnsWidth[key][0]?.slice(0, -2) -
108
- (item.hasFilter ? 65 : 40) +
109
- 'px',
110
- }"
111
- class="title-column"
112
- >
113
- {{ item.text }}
114
- </span>
115
- </slot>
116
- <span
117
- v-if="item.sortColumn"
118
- class="sort-arrow-wrap"
119
- >
120
- <atoms-the-icon
121
- v-show="sortInfo[0] === item.sortColumn"
122
- :class="['sort-arrow', { down: sortInfo[1] }]"
123
- name="sort-arrow"
124
- />
125
- </span>
126
- </button>
127
- <button
128
- v-if="item.hasFilter"
129
- :id="`${props.testId}-filter-icon-${key}`"
130
- class="datagrid-filter-toggle clr-anchor clr-smart-open-close"
131
- @click="filterShow[key] = !filterShow[key]"
132
- >
133
- <atoms-the-icon
134
- v-if="filterTerm[key]"
135
- class="filter-icon"
136
- name="filter-solid"
137
- style="fill: #0079b8"
138
- />
139
- <atoms-the-icon
140
- v-else
141
- class="filter-icon"
142
- name="filter"
143
- />
144
- </button>
145
- <atoms-popup-simple-popup
146
- v-model="filterShow[key]"
147
- :test-id="`${props.testId}-filter`"
148
- top="100%"
149
- :left="key === 0 ? '0' : ''"
150
- :right="key !== 0 ? '0' : ''"
151
- >
152
- <input
153
- :id="`${props.testId}-filter-input-${key}`"
154
- v-model="filterTerm[key]"
155
- type="text"
156
- @input="filtering"
157
- />
158
- </atoms-popup-simple-popup>
159
- <div
160
- v-show="
161
- !isShowHiddenInfo ||
162
- (isShowHiddenInfo && key === 0)
163
- "
164
- :class="[
165
- 'datagrid-column-separator',
166
- {
167
- 'double-arrow-separator':
168
- key === 0 && props.withInfo,
169
- },
170
- ]"
171
- @mousedown="setGrab(key, $event)"
172
- >
173
- <button
174
- :id="`${props.testId}-resize-tracker-${key}`"
175
- class="datagrid-column-handle drag-handle draggable"
176
- />
177
- <span class="clr-sr-only" />
178
- <div class="datagrid-column-resize-tracker" />
179
- </div>
180
- </div>
181
- </div>
182
- </div>
183
- </div>
184
- </div>
185
- </div>
186
-
187
- <template v-if="bodyItemsPresent.length">
188
- <div
189
- v-for="(item, key) in bodyItemsPresent"
190
- :key="item.id"
191
- :class="[
192
- 'datagrid-body-row datagrid-row animation',
193
- {
194
- 'datagrid-selected active':
195
- !props.withInfo && checkIsSelectedRow(item[0].id),
196
- 'datagrid-selected-info':
197
- props.withInfo &&
198
- isShowHiddenInfo &&
199
- checkIsSelectedRow(item[0].id),
200
- },
201
- ]"
202
- :[props.rowAttributeIdName]="item[0].dataId"
203
- >
204
- <div>
205
- <div
206
- class="datagrid-row-master datagrid-row-flex"
207
- @click.stop="selectRowById(item[0])"
208
- >
209
- <div
210
- v-if="props.type || $slots.toggleBlock"
211
- class="datagrid-row-sticky"
212
- @click.stop
213
- >
214
- <div
215
- :id="expandableCaret"
216
- :class="[
217
- 'datagrid-expandable-caret flex-justify-center datagrid-cell',
218
- {
219
- 'datagrid-fixed-column': !props.withInfo,
220
- 'datagrid-fixed-column-without-separator':
221
- props.withInfo,
222
- },
223
- ]"
224
- >
225
- <!--TODO refactoring (duplicate)-->
226
- <div
227
- v-if="$slots.toggleBlock && !props.type"
228
- class="datagrid-cell datagrid-fixed-width"
229
- >
230
- <div class="flex-align-center">
231
- <button
232
- :id="`${props.testId}-toggle-icon-${key}`"
233
- class="datagrid-expandable-caret-button reset-btn"
234
- @click="toggle(key)"
235
- >
236
- <atoms-the-icon
237
- :class="[
238
- 'datagrid-expandable-caret-icon',
239
- { toggle: toggedItems[key] },
240
- ]"
241
- name="angle"
242
- />
243
- </button>
244
- </div>
245
- </div>
246
- <slot
247
- v-if="props.type"
248
- :key="key"
249
- name="type"
250
- :item="item"
251
- >
252
- <div
253
- :class="
254
- item[0]?.disabled && 'clr-form-control-disabled'
255
- "
256
- >
257
- <div
258
- :class="`clr-${props.type}-wrapper flex-justify-center flex-align-center`"
259
- >
260
- <input
261
- :id="`${props.testId}-${inputId}-${item[0].id}`"
262
- :key="item[0].id"
263
- v-model="selectedRowLocal"
264
- :type="props.type"
265
- :class="`${props.type}-btn`"
266
- :value="item[0].id"
267
- :disabled="item[0]?.disabled || false"
268
- name="selected-store"
269
- @change="
270
- changeSelectedRow($event, item[0].id)
271
- "
272
- />
273
- <label
274
- :for="`${props.testId}-${inputId}-${item[0].id}`"
275
- class="clr-control-label"
276
- />
277
- </div>
278
- </div>
279
- </slot>
280
- </div>
281
- <!--TODO refactoring (duplicate)-->
282
- <div
283
- v-if="$slots.toggleBlock && props.type"
284
- class="datagrid-cell datagrid-fixed-width"
285
- >
286
- <div class="flex-align-center">
287
- <button
288
- :id="`${props.testId}-toggle-icon-${key}`"
289
- class="datagrid-expandable-caret-button reset-btn"
290
- @click="toggle(key)"
291
- >
292
- <atoms-the-icon
293
- :class="[
294
- 'datagrid-expandable-caret-icon',
295
- { toggle: toggedItems[key] },
296
- ]"
297
- name="angle"
298
- />
299
- </button>
300
- </div>
301
- </div>
302
- </div>
303
- <div class="datagrid-row-scrollable">
304
- <div class="datagrid-scrolling-cells">
305
- <div
306
- v-for="(item2, key2) in item"
307
- v-show="
308
- !isShowHiddenInfo ||
309
- item2.key === 'col1' ||
310
- item2.key === 'icon'
311
- "
312
- :key="key2"
313
- :style="{
314
- width: columnsWidth[key2][0],
315
- minWidth: columnsWidth[key2][1],
316
- }"
317
- :class="[
318
- 'datagrid-cell datagrid-fixed-width',
319
- {
320
- 'hidden-text-triangle':
321
- isShowHiddenInfo &&
322
- item2.data?.name === 'hidden-text-triangle',
323
- },
324
- ]"
325
- >
326
- <div
327
- :class="[
328
- 'flex-align-center h-100',
329
- {
330
- 'double-arrow-width':
331
- item2.data?.name === 'doubleArrows',
332
- },
333
- ]"
334
- >
335
- <div
336
- v-if="item2.data?.name === 'doubleArrows'"
337
- :id="`show-info-${item[0].data.id}`"
338
- :class="[
339
- 'double-arrow-wrap',
340
- {
341
- 'arrow-selected':
342
- isShowHiddenInfo &&
343
- item2.id === selectedRow,
344
- },
345
- ]"
346
- @click.prevent.stop="
347
- doubleArrowClick(item2, item)
348
- "
349
- >
350
- <atoms-the-icon
351
- v-if="item2.data?.name === 'doubleArrows'"
352
- name="doubleArrows"
353
- :class="[
354
- 'double-arrow',
355
- {
356
- 'arrow-selected':
357
- isShowHiddenInfo &&
358
- item2.id === selectedRow,
359
- },
360
- ]"
361
- />
362
- </div>
363
- <span
364
- v-if="item2.text && item2.data?.iconClassName"
365
- class="vertical-divider"
366
- />
367
- <slot :name="item2.key" :item="item2">
368
- <span class="text-ellipsis" :title="item2.text"
369
- >{{ item2.text }}
370
- </span>
371
- </slot>
372
- </div>
373
- </div>
374
- </div>
375
- <div
376
- v-show="toggedItems[key]"
377
- class="datagrid-row-flex datagrid-row-detail datagrid-container"
378
- >
379
- <slot name="toggleBlock" :item="item" />
380
- </div>
381
- </div>
382
- </div>
383
- </div>
384
- </div>
385
- </template>
386
- <template v-else>
387
- <div class="datagrid-placeholder-container">
388
- <div class="datagrid-placeholder datagrid-empty">
389
- <div class="datagrid-placeholder-image"></div>
390
-
391
- <span>No items found</span>
392
- </div>
393
- </div>
394
- </template>
395
- </div>
396
- </div>
397
- </div>
398
-
399
- <div
400
- v-if="!hideFooter"
401
- :class="[
402
- 'datagrid-footer',
403
- {
404
- 'datagrid-footer-opened-info': isShowHiddenInfo,
405
- },
406
- ]"
407
- >
408
- <div
409
- v-if="props.type === 'checkbox' && props.selectedRow?.length"
410
- class="clr-form-control-disabled"
411
- >
412
- <div class="clr-checkbox-wrapper">
413
- <input
414
- :id="`${props.testId}-check-all`"
415
- type="checkbox"
416
- checked
417
- />
418
- <label class="clr-control-label">
419
- {{ props.selectedRow?.length }}
420
- </label>
421
- </div>
422
- </div>
423
- <div class="datagrid-footer-description flex-align-center">
424
- <atoms-table-data-grid-column-switch
425
- v-if="columnKeysLocal"
426
- v-model:column-keys="columnKeysLocal"
427
- :test-id="`${props.testId}-footer-description`"
428
- class="switch-icon"
429
- />
430
-
431
- <div v-if="$slots.action" class="datagrid-footer__action">
432
- <slot name="action" />
433
- </div>
434
- </div>
435
-
436
- <atoms-table-data-grid-pagination
437
- test-id="props.testId"
438
- :page-size="props.pageSize"
439
- :page="props.page"
440
- :options="mergeOptions"
441
- :total-items="props.totalItems"
442
- :total-pages="props.totalPages"
443
- :hide-pagination="props.hidePagination"
444
- :hide-page-size="props.hidePageSize"
445
- :show-page-info="props.showPageInfo"
446
- :page-items-count="props.bodyItems.length"
447
- :is-show-hidden-info="isShowHiddenInfo"
448
- @change-page-size="changePageSize"
449
- @change-page="changePage"
450
- />
451
- </div>
452
-
453
- <atoms-loader v-show="props.loading" class="datagrid-spinner" />
454
- </div>
455
- </div>
456
- <div
457
- v-if="isShowInfo"
458
- id="hidden-features"
459
- :class="[
460
- 'hidden-features',
461
- {
462
- 'show-hidden-info': isShowHiddenInfo,
463
- },
464
- ]"
465
- >
466
- <div class="header">
467
- <slot name="hiddenInfoHeader" :item="showedInfoCol" />
468
- <button
469
- :id="`${props.testId}-hidden-info-toggle-icon-${showedInfoRow?.key}-${showedInfoRow?.data.name}`"
470
- class="signpost-action close"
471
- @click="isShowHiddenInfo = false"
472
- >
473
- <atoms-the-icon class="close-icon" name="close" />
474
- </button>
475
- </div>
476
- <slot name="hiddenInfoBody" />
477
- </div>
478
- </div>
479
- </template>
480
-
481
- <script setup lang="ts">
482
- import { UI_I_HTMLSelectElement } from '~/lib/models/interfaces'
483
- import { itemsPerPage } from '~/components/atoms/table/dataGrid/lib/config/itemsPerPage'
484
- import {
485
- UI_I_HeadItem,
486
- UI_I_BodyItem,
487
- UI_I_ColumnKey,
488
- } from '~/components/atoms/table/dataGrid/lib/models/interfaces'
489
- import { UI_I_OptionItem } from '~/components/atoms/lib/models/interfaces'
490
- import {
491
- UI_T_ColumnKeys,
492
- UI_T_DataGridType,
493
- UI_T_SelectedRow,
494
- } from '~/components/atoms/table/dataGrid/lib/models/types'
495
-
496
- const props = withDefaults(
497
- defineProps<{
498
- headItems: UI_I_HeadItem[]
499
- bodyItems: UI_I_BodyItem[][]
500
- pageSize: number
501
- page: number
502
- totalItems: number
503
- totalPages: number
504
- loading?: boolean
505
- columnKeys?: UI_I_ColumnKey[]
506
- selectedRow?: UI_T_SelectedRow
507
- type?: UI_T_DataGridType
508
- itemsPerPage?: UI_I_OptionItem[]
509
- offSelectByRow?: boolean
510
- hidePageSize?: boolean
511
- showPageInfo?: boolean
512
- serverOff?: boolean
513
- fillWidth?: boolean
514
- hideFooter?: boolean
515
- hidePagination?: boolean
516
- testId?: string
517
- withInfo?: boolean
518
- rowAttributeIdName?: string
519
- isMainFilter?: boolean
520
- mainFilterPlaceholder?: string
521
- }>(),
522
- {
523
- columnKeys: undefined,
524
- selectedRow: undefined,
525
- type: undefined,
526
- itemsPerPage: undefined,
527
- fillWidth: true,
528
- testId: 'ui-data-grid',
529
- withInfo: false,
530
- rowAttributeIdName: 'data-id',
531
- }
532
- )
533
-
534
- const emits = defineEmits<{
535
- (event: 'update:column-keys', value: UI_T_ColumnKeys): void
536
- (event: 'update:selected-row', value: UI_T_SelectedRow): void
537
- (event: 'update:page-size', value: number): void
538
- (event: 'update:page', value: number): void
539
- (event: 'main-filter', value: string): void
540
- (event: 'filtering', value: string[][]): void
541
- (event: 'sorting', value: [string, boolean]): void
542
- (event: 'change', value: any): void
543
- (event: 'row-detail', value: number): void
544
- }>()
545
-
546
- const mainFilter = ref<string>('')
547
-
548
- const mergeOptions = computed<UI_I_OptionItem[]>(
549
- () => props.itemsPerPage || itemsPerPage
550
- )
551
-
552
- const inputId = ref<string>(`radio-input-${useUniqueId()}`)
553
-
554
- const columnKeysLocal = computed<UI_T_ColumnKeys>({
555
- get() {
556
- return props.columnKeys
557
- },
558
- set(newValue) {
559
- emits('update:column-keys', newValue)
560
- },
561
- })
562
-
563
- const selectedAll = ref<boolean>(false)
564
- const changeAll = (e: UI_I_HTMLSelectElement): void => {
565
- const newSelectedRow: (number | string)[] = []
566
- if (e.target.checked) {
567
- bodyItemsPresent.value.forEach((row) => {
568
- if (row[0]?.disabled) return
569
-
570
- newSelectedRow.push(row[0].id)
571
- })
572
- }
573
-
574
- emits('update:selected-row', newSelectedRow)
575
- }
576
-
577
- const selectedRowLocal = ref<UI_T_SelectedRow>([])
578
- const isShowHiddenInfo = ref<boolean>(false)
579
- const tableWrapperId = `table-wrapper-${useUniqueId()}`
580
- let memoryWidth = '0'
581
-
582
- const showedInfoRow = ref<UI_I_BodyItem | null>(null)
583
- const showedInfoCol = ref<UI_I_BodyItem[] | null>(null)
584
-
585
- const isShowInfo = computed(
586
- () =>
587
- showedInfoRow.value &&
588
- showedInfoRow.value.id === props.selectedRow &&
589
- !showedInfoRow.value.data?.text &&
590
- isShowHiddenInfo.value
591
- )
592
-
593
- const setShowedInfoData = (
594
- item: UI_I_BodyItem | null,
595
- items: UI_I_BodyItem[] | null,
596
- reset: boolean = false
597
- ): void => {
598
- showedInfoRow.value = item
599
- showedInfoCol.value = items
600
-
601
- reset && (isShowHiddenInfo.value = false)
602
- item && selectRowById(item)
603
- reset && (isShowHiddenInfo.value = true)
604
- }
605
-
606
- const doubleArrowClick = (
607
- item: UI_I_BodyItem,
608
- items: UI_I_BodyItem[]
609
- ): void => {
610
- if (!isShowHiddenInfo.value) {
611
- setShowedInfoData(item, items)
612
- } else {
613
- if (showedInfoRow.value?.id !== item.id) {
614
- setShowedInfoData(item, items, true)
615
-
616
- return
617
- } else {
618
- setShowedInfoData(null, null)
619
- }
620
- }
621
-
622
- isShowHiddenInfo.value = !isShowHiddenInfo.value
623
- }
624
-
625
- watch(
626
- () => props.selectedRow,
627
- (newValue) => {
628
- if (newValue === undefined) return
629
-
630
- if (Array.isArray(newValue) && !newValue.length) selectedAll.value = false
631
-
632
- selectedRowLocal.value = newValue
633
- },
634
- { immediate: true }
635
- )
636
- const selectRowById = (item: UI_I_BodyItem): void => {
637
- const { id, disabled } = item
638
-
639
- if (props.offSelectByRow || isShowHiddenInfo.value || disabled) return
640
-
641
- if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
642
- const has = selectedRowLocal.value.includes(id)
643
- if (has) {
644
- selectedRowLocal.value = selectedRowLocal.value.filter(
645
- (rowId: string | number) => rowId !== id
646
- )
647
- } else {
648
- selectedRowLocal.value.push(id)
649
- }
650
-
651
- emits('change', selectedRowLocal.value)
652
- emits('update:selected-row', selectedRowLocal.value)
653
-
654
- changeSelectedAll(!has)
655
- return
656
- }
657
-
658
- emits('change', id)
659
- emits('update:selected-row', id)
660
- }
661
- const changeSelectedRow = (
662
- e: UI_I_HTMLSelectElement,
663
- id: number | string
664
- ): void => {
665
- if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
666
- const newSelectedRow = [...selectedRowLocal.value]
667
- emits('change', newSelectedRow)
668
- emits('update:selected-row', newSelectedRow)
669
-
670
- changeSelectedAll(e.target.checked)
671
- return
672
- }
673
-
674
- emits('change', id)
675
- emits('update:selected-row', id)
676
- }
677
- const changeSelectedAll = (checked: boolean): void => {
678
- if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
679
- const newSelectedRow = [...selectedRowLocal.value]
680
-
681
- if (!checked) {
682
- selectedAll.value = false
683
- } else if (newSelectedRow.length === bodyItemsPresent.value.length) {
684
- selectedAll.value = true
685
- }
686
- }
687
- }
688
-
689
- const checkIsSelectedRow = (id: number | string): boolean => {
690
- if (props.type === 'checkbox' && Array.isArray(props.selectedRow)) {
691
- return props.selectedRow.includes(id)
692
- }
693
- return props.selectedRow === id
694
- }
695
-
696
- // Sorting
697
- const sortInfo = ref<[string, boolean]>(['', true])
698
- const sortedColumnIndex = computed<number>(() => {
699
- let index = -1
700
- headItemsPresent.value.forEach((item, key) => {
701
- if (item.sortColumn === sortInfo.value[0]) index = key
702
- })
703
-
704
- return index
705
- })
706
- const sortTable = (sortName: string): void => {
707
- if (!sortName) return
708
-
709
- emits('update:selected-row', selectedRowLocal.value)
710
-
711
- if (sortInfo.value[0] === sortName) {
712
- sortInfo.value[1] = !sortInfo.value[1]
713
-
714
- emits('sorting', sortInfo.value)
715
- return
716
- }
717
- sortInfo.value[0] = sortName
718
- sortInfo.value[1] = true
719
-
720
- emits('sorting', sortInfo.value)
721
- }
722
-
723
- // Filtering
724
- const filterShow = ref<boolean[]>([])
725
- const filterTerm = ref<string[]>([])
726
- const filtering = (): void => {
727
- const filter: string[][] = []
728
- headItemsPresent.value.forEach((item, key) => {
729
- if (filterTerm.value[key]) filter.push([item.key, filterTerm.value[key]])
730
- })
731
-
732
- emits('filtering', filter)
733
- }
734
-
735
- // Pagination
736
- const changePageSize = (value: number): void => {
737
- emits('update:page-size', value)
738
- }
739
- const changePage = (value: number): void => {
740
- emits('update:page', value)
741
- }
742
-
743
- const headItemsPresent = computed<UI_I_HeadItem[]>(() => {
744
- if (!columnKeysLocal.value) {
745
- return props.headItems
746
- }
747
-
748
- return props.headItems.filter((item, key) => {
749
- return columnKeysLocal.value?.find(
750
- (item2, key2) => item2.key === item.key && key === key2
751
- )?.show
752
- })
753
- })
754
-
755
- const bodyItemsPresent = computed<UI_I_BodyItem[][]>(() => {
756
- let items: UI_I_BodyItem[][] = props.bodyItems
757
-
758
- // Filtering by column
759
- if (columnKeysLocal.value) {
760
- items = items.map((arr) => {
761
- arr = arr.filter((item, key) => {
762
- return columnKeysLocal.value?.find(
763
- (item2, key2) => item2.key === item.key && key === key2
764
- )?.show
765
- })
766
- return arr
767
- })
768
- }
769
-
770
- if (props.serverOff) {
771
- // Sorting
772
- if (sortInfo.value[0] !== '') {
773
- items = useDeepCopy(items).sort(
774
- (a: UI_I_BodyItem[], b: UI_I_BodyItem[]) => {
775
- const first = a[sortedColumnIndex.value].text.toString().toLowerCase()
776
- const second = b[sortedColumnIndex.value].text
777
- .toString()
778
- .toLowerCase()
779
-
780
- if (sortInfo.value[1]) {
781
- return first > second ? 1 : first < second ? -1 : 0
782
- } else {
783
- return first < second ? 1 : first > second ? -1 : 0
784
- }
785
- }
786
- )
787
- }
788
- // Filtering
789
- const hasFilter = headItemsPresent.value.some(
790
- (_, key) => filterTerm.value[key]
791
- )
792
- if (hasFilter) {
793
- items = items.filter((row) => {
794
- // 0 - начальное значение
795
- // 1 - найден элемент
796
- // -1 - ненайден элемент
797
- let hasItem = 0
798
- headItemsPresent.value.forEach((item, key) => {
799
- if (!filterTerm.value[key]) return
800
- const term = filterTerm.value[key].toLowerCase()
801
-
802
- row.forEach((col) => {
803
- if (
804
- col.key === item.key &&
805
- typeof col.text === 'string' &&
806
- hasItem != -1
807
- ) {
808
- hasItem = col.text.toLowerCase().includes(term) ? 1 : -1
809
- }
810
- })
811
- })
812
-
813
- return hasItem === 1
814
- })
815
- }
816
- }
817
-
818
- return items
819
- })
820
-
821
- const toggedItems = ref<boolean[]>([])
822
-
823
- const toggle = (key: number): void => {
824
- toggedItems.value[key] = !toggedItems.value[key]
825
- if (!toggedItems.value[key]) return
826
- emits('row-detail', key)
827
- }
828
-
829
- const outerWrapper = `datagrid-outer-wrapper${useUniqueId()}`
830
- const expandableCaret = `datagrid-expandable-caret${useUniqueId()}`
831
-
832
- // Resize
833
- let helper = false
834
- let setColumnWidth = (): void => {
835
- if (!helper) {
836
- columnsWidth.value = []
837
- headItemsPresent.value.forEach((item) => {
838
- columnsWidth.value.push([
839
- item.width, // width
840
- item.width, // min-width
841
- ])
842
- })
843
-
844
- helper = true
845
- setTimeout(() => setColumnWidth(), 0)
846
- return
847
- }
848
- // Не продолжаем, чтобы ширина калонок была так как заданно в headItemsPresent
849
- if (!props.fillWidth) return
850
-
851
- const dataGridWidth = document.getElementById(outerWrapper)?.clientWidth || 0
852
- const leftColumnWidth =
853
- document.getElementById(expandableCaret)?.clientWidth || 0
854
- const bordersWidth = 2
855
- const columnWidth =
856
- (dataGridWidth - leftColumnWidth - bordersWidth) /
857
- headItemsPresent.value.length
858
-
859
- headItemsPresent.value.forEach((item) => {
860
- columnsWidth.value.push([
861
- `${columnWidth}px`, // width
862
- item.width, // min-width
863
- ])
864
- })
865
- }
866
- setColumnWidth = useThrottle(setColumnWidth)
867
-
868
- const columnsWidth = ref<[string, string][]>([])
869
- watch(
870
- bodyItemsPresent,
871
- (newValue: UI_I_BodyItem[][]) => {
872
- newValue.forEach(() => {
873
- toggedItems.value.push(false)
874
- })
875
- setColumnWidth()
876
- },
877
- {
878
- immediate: true,
879
- deep: true,
880
- }
881
- )
882
-
883
- watch(
884
- headItemsPresent,
885
- (newValue: UI_I_HeadItem[]) => {
886
- filterShow.value = newValue.map(() => false)
887
- filterTerm.value = newValue.map(() => '')
888
- },
889
- {
890
- immediate: true,
891
- deep: true,
892
- }
893
- )
894
-
895
- const grabColumn = ref<number>(-1)
896
- const grabStartX = ref<number>(0)
897
- const setGrab = (key: number, e: MouseEvent): void => {
898
- if (props.withInfo && key === 0) return
899
-
900
- if (!isShowHiddenInfo.value) {
901
- grabColumn.value = key
902
- const currentWidth = parseInt(columnsWidth.value[grabColumn.value][0])
903
- grabStartX.value = e.clientX - currentWidth
904
- }
905
- }
906
-
907
- const isDrag = ref<boolean>(false)
908
-
909
- const mouseup = (): void => {
910
- if (grabColumn.value === -1) {
911
- return
912
- }
913
-
914
- grabColumn.value = -1
915
- isDrag.value = false
916
- }
917
-
918
- let resizeObserve: ResizeObserver
919
- let mousemove = (e: MouseEvent): void => {
920
- if (grabColumn.value === -1) return
921
-
922
- e.preventDefault()
923
- isDrag.value = true
924
- resizeObserve.disconnect()
925
-
926
- const minWidth = parseInt(columnsWidth.value[grabColumn.value][1])
927
- const changeX = Math.max(e.clientX - grabStartX.value, minWidth)
928
-
929
- columnsWidth.value[grabColumn.value] = [`${changeX}px`, `${minWidth}px`]
930
- }
931
- mousemove = useThrottle(mousemove)
932
-
933
- const setResizeObserve = (): void => {
934
- const el = document.getElementById(outerWrapper)
935
-
936
- if (!el) {
937
- setTimeout(setResizeObserve, 0)
938
- return
939
- }
940
-
941
- resizeObserve = new ResizeObserver(setColumnWidth)
942
- resizeObserve.observe(el)
943
- }
944
-
945
- let resizeObserveWithInfo: ResizeObserver
946
-
947
- const setColumnWidthWithInfo = (ent: ResizeObserverEntry[]): void => {
948
- if (isShowHiddenInfo.value) {
949
- memoryWidth = columnsWidth.value[1][0]
950
- columnsWidth.value[1][0] = `${ent[0].contentBoxSize[0].inlineSize - 86}px`
951
- } else {
952
- columnsWidth.value[1][0] = memoryWidth
953
- }
954
- }
955
-
956
- const setResizeObserveWithInfo = (): void => {
957
- const el = document.querySelector('.datagrid')
958
-
959
- if (!el) {
960
- setTimeout(setResizeObserveWithInfo, 0)
961
- return
962
- }
963
-
964
- resizeObserveWithInfo = new ResizeObserver(setColumnWidthWithInfo)
965
- resizeObserveWithInfo.observe(el)
966
- }
967
-
968
- onMounted(() => {
969
- window.addEventListener('mousemove', mousemove)
970
- window.addEventListener('mouseup', mouseup)
971
-
972
- if (props.withInfo) {
973
- setResizeObserveWithInfo()
974
- }
975
-
976
- setResizeObserve()
977
- })
978
- onUnmounted(() => {
979
- window.removeEventListener('mouseup', mouseup)
980
- window.removeEventListener('mousemove', mousemove)
981
- })
982
- </script>
983
-
984
- <style scoped lang="scss">
985
- @import '~/assets/scss/common/mixins';
986
- .datagrid-outer-wrapper {
987
- @include flex($dir: row);
988
- padding-top: 12px;
989
- flex-grow: 1;
990
- overflow: auto;
991
-
992
- &.datagrid-outer-wrapper-opened-info {
993
- width: 35%;
994
- min-width: 195px;
995
- }
996
-
997
- & * {
998
- box-sizing: border-box;
999
- }
1000
-
1001
- & svg {
1002
- fill: var(--table-color);
1003
- }
1004
-
1005
- .datagrid-inner-wrapper {
1006
- @include flex($dir: column);
1007
- flex-grow: 1;
1008
- overflow: auto;
1009
-
1010
- .main-filter-content {
1011
- align-items: center;
1012
-
1013
- .filter-icon {
1014
- width: 16px;
1015
- height: 16px;
1016
- margin-right: 10px;
1017
- }
1018
- }
1019
- .datagrid {
1020
- overflow: auto;
1021
- flex: 1 1 auto;
1022
- border-radius: 0.125rem 0.125rem 0 0;
1023
- background-color: var(--block-view-bg-color);
1024
- border-color: var(--global-border-color);
1025
-
1026
- &.datagrid-opened-info {
1027
- border-radius: 0.125rem 0 0 0;
1028
- overflow-x: hidden;
1029
- }
1030
-
1031
- .datagrid-table-wrapper {
1032
- min-width: max-content;
1033
- display: flex;
1034
- flex: 1 1 auto;
1035
- min-height: 100%;
1036
-
1037
- .datagrid-table {
1038
- @include flex($dir: column);
1039
- flex: 1 1 auto;
1040
- align-content: flex-start;
1041
- position: relative;
1042
-
1043
- .datagrid-header {
1044
- position: sticky;
1045
- top: 0;
1046
- z-index: 501;
1047
- width: auto;
1048
-
1049
- .datagrid-row-scrollable {
1050
- flex-direction: row;
1051
-
1052
- .datagrid-column-separator {
1053
- user-select: none;
1054
-
1055
- &::after {
1056
- cursor: col-resize;
1057
- }
1058
- &.double-arrow-separator .datagrid-column-handle {
1059
- cursor: unset;
1060
- }
1061
- &.double-arrow-separator::after {
1062
- cursor: unset;
1063
- }
1064
- }
1065
- }
1066
-
1067
- .datagrid-row {
1068
- color: var(--table-color);
1069
- background-color: var(--block-view-bg-color);
1070
-
1071
- &.datagrid-selected {
1072
- background-color: var(--row-selected-bg-color);
1073
- border-bottom: 1px solid var(--global-border-color);
1074
-
1075
- & :deep(*) {
1076
- color: var(--table-active-color);
1077
- }
1078
- }
1079
-
1080
- .datagrid-column {
1081
- background-color: var(--block-view-bg-color);
1082
- border-bottom: 1px solid var(--global-border-color);
1083
- padding: 6px 12px 5px;
1084
- position: relative;
1085
- //flex: 1 1 auto;
1086
-
1087
- &:last-child {
1088
- flex: 1 1 auto;
1089
- }
1090
-
1091
- &.datagrid-toggle-block {
1092
- width: 38px;
1093
- min-width: 38px;
1094
-
1095
- .datagrid-column-separator {
1096
- cursor: default;
1097
-
1098
- &::after {
1099
- cursor: default;
1100
- }
1101
- }
1102
- }
1103
- }
1104
-
1105
- .datagrid-column-title {
1106
- align-self: auto;
1107
- color: var(--table-color);
1108
- background-color: var(--block-view-bg-color);
1109
- border-bottom-color: var(--global-border-color);
1110
- font-size: 11px;
1111
- @include flex($align: center);
1112
- display: flex;
1113
- flex-direction: row;
1114
- justify-content: flex-start;
1115
- align-items: center;
1116
- //line-height: 24px;
1117
- line-height: normal;
1118
-
1119
- .title-column {
1120
- font-weight: bold;
1121
- font-size: 11px;
1122
- overflow: hidden;
1123
- text-wrap: none;
1124
- text-overflow: ellipsis;
1125
- }
1126
-
1127
- .sort-arrow-wrap {
1128
- margin-left: auto;
1129
- height: 14px;
1130
- width: 14px;
1131
- min-height: 14px;
1132
- min-width: 14px;
1133
- vertical-align: middle;
1134
-
1135
- .sort-arrow {
1136
- &.down {
1137
- transform: rotate(180deg);
1138
- }
1139
- }
1140
- }
1141
- .title-icon {
1142
- width: 24px;
1143
- height: 24px;
1144
- }
1145
- }
1146
-
1147
- .datagrid-filter-toggle {
1148
- background: unset;
1149
- margin-top: -4px;
1150
- align-self: center;
1151
-
1152
- .filter-icon {
1153
- width: 16px;
1154
- height: 16px;
1155
- }
1156
- }
1157
- }
1158
- }
1159
-
1160
- .datagrid-placeholder-container {
1161
- .datagrid-placeholder.datagrid-empty {
1162
- background: var(--block-view-bg-color);
1163
- }
1164
- span {
1165
- font-size: 16px;
1166
- color: var(--global-font-color4);
1167
- }
1168
- }
1169
-
1170
- .datagrid-row {
1171
- width: 100%;
1172
- min-width: max-content;
1173
- border-top: none;
1174
- color: var(--table-color);
1175
- background-color: var(--block-view-bg-color);
1176
- border-bottom: 1px solid var(--global-border-color);
1177
-
1178
- &.datagrid-selected {
1179
- & :deep(*) {
1180
- color: var(--table-active-color);
1181
- }
1182
-
1183
- .datagrid-cell {
1184
- background-color: var(--row-selected-bg-color);
1185
- border-bottom: 1px solid var(--global-border-color);
1186
- position: relative;
1187
- line-height: 1rem;
1188
- }
1189
-
1190
- .datagrid-row-detail {
1191
- background-color: var(--row-selected-bg-color);
1192
- border-bottom: 1px solid var(--global-border-color);
1193
- }
1194
- }
1195
-
1196
- .datagrid-cell {
1197
- min-width: 38px;
1198
- min-height: 28px;
1199
- padding: 2px 12px 3px 12px;
1200
- position: relative;
1201
-
1202
- &:has(.double-arrow-wrap) {
1203
- padding-left: 4px;
1204
- }
1205
-
1206
- &:has(.double-arrow-wrap)::after {
1207
- content: '';
1208
- width: 0.5px;
1209
- height: calc(100% - 6px);
1210
- position: absolute;
1211
- right: 2px;
1212
- top: 3px;
1213
- background-color: var(--global-border-color);
1214
- }
1215
-
1216
- &:last-child {
1217
- flex: 1 1 auto;
1218
- }
1219
-
1220
- button {
1221
- height: 0.9rem;
1222
- width: 0.9rem;
1223
-
1224
- .arrow-icon {
1225
- width: 16px;
1226
- height: 16px;
1227
- transform: rotate(90deg);
1228
- }
1229
- }
1230
-
1231
- .datagrid-cell-icon {
1232
- display: inline-block;
1233
- width: 16px;
1234
- height: 16px;
1235
- }
1236
-
1237
- .datagrid-expandable-caret-button {
1238
- cursor: pointer;
1239
- width: 100%;
1240
-
1241
- .datagrid-expandable-caret-icon {
1242
- width: 16px;
1243
- height: 16px;
1244
- transform: rotate(90deg);
1245
- fill: var(--table-caret-color);
1246
-
1247
- &.toggle {
1248
- transform: rotate(180deg);
1249
- }
1250
- }
1251
- }
1252
- }
1253
-
1254
- &.datagrid-selected-info {
1255
- width: 100%;
1256
- min-width: max-content;
1257
- border-top: none;
1258
- color: var(--table-color);
1259
- background-color: var(--block-view-bg-color);
1260
-
1261
- .datagrid-cell {
1262
- position: relative;
1263
-
1264
- &.hidden-text-triangle::after {
1265
- content: '';
1266
- position: absolute;
1267
- transform: rotate(225deg);
1268
- border-bottom: 15px solid transparent;
1269
- border-right: 15px solid var(--global-bg-color);
1270
- bottom: 26%;
1271
- right: -16px;
1272
- z-index: 1000;
1273
- }
1274
-
1275
- &.hidden-text-triangle::before {
1276
- content: '';
1277
- transform: rotate(-135deg);
1278
- position: absolute;
1279
- border-bottom: 16px solid transparent;
1280
- border-right: 16px solid var(--global-border-color);
1281
- bottom: 23%;
1282
- right: -17px;
1283
- z-index: 999;
1284
- }
1285
- }
1286
- }
1287
- }
1288
-
1289
- .datagrid-row-sticky {
1290
- @include flex($w: nowrap);
1291
- position: sticky;
1292
- left: 0;
1293
- z-index: 500;
1294
- background-color: var(--block-view-bg-color);
1295
-
1296
- .datagrid-column {
1297
- color: var(--table-color);
1298
- background-color: var(--block-view-bg-color);
1299
- border-bottom-color: var(--global-border-color);
1300
- text-align: left;
1301
- display: flex;
1302
- flex: 1 1 auto;
1303
- vertical-align: top;
1304
- border: none;
1305
-
1306
- &.datagrid-expandable-caret {
1307
- .datagrid-column-separator {
1308
- display: block;
1309
-
1310
- &::after {
1311
- top: 0;
1312
- height: 18px;
1313
- }
1314
- }
1315
-
1316
- .radio-btn {
1317
- width: 16px;
1318
- height: 16px;
1319
- }
1320
- }
1321
-
1322
- .datagrid-column-separator {
1323
- position: relative;
1324
- //left: 0.6rem;
1325
- flex: 0 0 auto;
1326
- width: 0.05rem;
1327
- order: 100;
1328
- margin-left: auto;
1329
- height: 100%;
1330
- }
1331
- }
1332
-
1333
- .datagrid-fixed-column-without-separator {
1334
- background-color: var(--block-view-bg-color);
1335
-
1336
- &::after {
1337
- background-color: transparent;
1338
- }
1339
- }
1340
-
1341
- .datagrid-fixed-column {
1342
- background-color: var(--block-view-bg-color);
1343
-
1344
- &::after {
1345
- content: '';
1346
- width: 0.05rem;
1347
- height: calc(100% - 0.5rem);
1348
- position: absolute;
1349
- right: 0;
1350
- top: 0.25rem;
1351
- background-color: var(--global-border-color);
1352
- }
1353
-
1354
- .clr-form-control-disabled {
1355
- .clr-checkbox-wrapper {
1356
- label {
1357
- cursor: not-allowed;
1358
- }
1359
- }
1360
- }
1361
- }
1362
- }
1363
-
1364
- .datagrid-row-scrollable {
1365
- @include flex($ff: row nowrap);
1366
- flex: 1 1 auto;
1367
-
1368
- .datagrid-scrolling-cells {
1369
- @include flex($ff: row nowrap);
1370
- flex: 1 1 auto;
1371
- }
1372
- }
1373
- .datagrid-body-row {
1374
- .datagrid-row-scrollable {
1375
- @include flex($ff: column nowrap);
1376
-
1377
- .datagrid-row-detail {
1378
- flex: 1;
1379
- }
1380
- }
1381
-
1382
- &:not(.datagrid-selected):hover {
1383
- border-bottom: 1px solid var(--table-hover-row-border-color);
1384
- background-color: var(--table-hover-row-background-color);
1385
- color: var(--table-hover-row-color);
1386
-
1387
- .datagrid-fixed-column {
1388
- background-color: var(--table-hover-row-background-color);
1389
- }
1390
- .datagrid-cell {
1391
- background-color: var(--table-hover-row-background-color);
1392
- }
1393
- }
1394
- }
1395
- }
1396
- }
1397
- }
1398
-
1399
- .datagrid-footer {
1400
- flex: 0 0 auto;
1401
- @include flex($ff: row nowrap, $just: space-between, $align: stretch);
1402
- font-size: 0.55rem;
1403
- background-color: var(--block-view-bg-color);
1404
- border: 0.05rem solid var(--global-border-color);
1405
- border-top: none;
1406
- border-radius: 0 0 0.15rem 0.15rem;
1407
- padding: 0 0.6rem;
1408
- height: 28px;
1409
-
1410
- &.datagrid-footer-opened-info {
1411
- border-radius: 0 0 0 0.15rem;
1412
- flex-direction: row-reverse;
1413
- }
1414
-
1415
- .clr-form-control-disabled {
1416
- opacity: 1;
1417
-
1418
- .clr-checkbox-wrapper {
1419
- label {
1420
- color: #8c8c8c;
1421
- margin-right: 9px;
1422
- padding-left: 22px;
1423
- &:before {
1424
- position: absolute;
1425
- top: 4px;
1426
- left: 0;
1427
- content: '';
1428
- display: inline-block;
1429
- height: 16px;
1430
- width: 16px;
1431
- border: none;
1432
- border-radius: 3px;
1433
- background-color: var(--table-checkbox-color);
1434
- }
1435
-
1436
- &:after {
1437
- position: absolute;
1438
- content: '';
1439
- display: inline-block;
1440
- height: 5px;
1441
- width: 8px;
1442
- border-left: 2px solid #fff;
1443
- border-bottom: 2px solid #fff;
1444
- top: 4px;
1445
- left: 4px;
1446
- transform: translateY(4px) rotate(-45deg);
1447
- }
1448
- }
1449
- }
1450
- }
1451
- }
1452
-
1453
- .datagrid-spinner {
1454
- top: 0.6rem;
1455
- height: calc(100% - 0.6rem);
1456
- }
1457
-
1458
- .datagrid-footer-description {
1459
- flex: 1 1 auto;
1460
-
1461
- :deep(svg) {
1462
- fill: var(--table-switch-color);
1463
- }
1464
- }
1465
-
1466
- .clr-radio-wrapper,
1467
- .clr-checkbox-wrapper {
1468
- height: 18px;
1469
- }
1470
-
1471
- .clr-radio-wrapper label,
1472
- .clr-checkbox-wrapper label {
1473
- padding-left: 16px;
1474
- }
1475
- }
1476
- }
1477
- //.vertical-divider {
1478
- // width: 1px;
1479
- // height: 22px;
1480
- // background: #bbb;
1481
- // margin: 2px 2px 0 -5px;
1482
- //}
1483
-
1484
- .hidden-features {
1485
- padding: 9px 14px;
1486
- background-color: var(--global-bg-color);
1487
- color: var(--global-font-color2);
1488
- border: 1px solid var(--global-border-color);
1489
- border-left: none;
1490
- overflow-y: auto;
1491
- overflow-x: hidden;
1492
- width: 65%;
1493
-
1494
- .header {
1495
- display: flex;
1496
- align-items: center;
1497
- justify-content: space-between;
1498
- background-color: inherit;
1499
-
1500
- h3 {
1501
- font-size: 1rem;
1502
- color: var(--global-font-color2) !important;
1503
- line-height: 1.7rem;
1504
- }
1505
- button {
1506
- line-height: 24px;
1507
-
1508
- .close-icon {
1509
- margin-left: 10px;
1510
- width: 24px;
1511
- height: 24px;
1512
- }
1513
- }
1514
- }
1515
- }
1516
- .double-arrow-width {
1517
- width: 25px;
1518
- }
1519
- .double-arrow-wrap {
1520
- width: 30px;
1521
- height: 20px;
1522
- padding-top: 1px;
1523
- padding-left: 5px;
1524
- cursor: pointer;
1525
- background-color: transparent;
1526
-
1527
- .double-arrow {
1528
- background-color: transparent;
1529
- transform: rotate(90deg);
1530
- width: 16px;
1531
- height: 16px;
1532
- }
1533
-
1534
- .double-arrow.arrow-selected {
1535
- transform: rotate(-90deg) !important;
1536
- background-color: #0079b8;
1537
- }
1538
- }
1539
- .double-arrow-wrap.arrow-selected {
1540
- background-color: #0079b8;
1541
- border-radius: 3px;
1542
- }
1543
- </style>
1544
-
1545
- <style>
1546
- :root {
1547
- --table-color: #565656;
1548
- --table-active-color: #fff;
1549
- --table-checkbox-color: #454545;
1550
- --table-caret-color: #454545;
1551
- --table-switch-color: #575757;
1552
- --table-hover-row-border-color: #666;
1553
- --table-hover-row-background-color: #e8e8e8;
1554
- --table-hover-row-color: #454545;
1555
- --table-spinner-bg-color: #ffffff99;
1556
- }
1557
-
1558
- :root.dark-theme {
1559
- --table-color: #fff;
1560
- --table-active-color: #565656;
1561
- --table-checkbox-color: #49aeda;
1562
- --table-caret-color: #ffffff;
1563
- --table-switch-color: #b3b3b3;
1564
- --table-hover-row-border-color: #fff;
1565
- --table-hover-row-background-color: #324f61;
1566
- --table-hover-row-color: #e9ecef;
1567
- --table-spinner-bg-color: rgba(0, 0, 0, 0.5);
1568
- }
1569
- </style>
1
+ <template>
2
+ <div class="relative" style="display: flex">
3
+ <div
4
+ :id="outerWrapper"
5
+ :class="[
6
+ 'datagrid-outer-wrapper',
7
+ {
8
+ 'datagrid-outer-wrapper-opened-info': isShowHiddenInfo,
9
+ },
10
+ ]"
11
+ >
12
+ <div class="datagrid-inner-wrapper">
13
+ <div
14
+ v-if="props.isMainFilter"
15
+ class="main-filter-content flex-justify-end"
16
+ >
17
+ <atoms-the-icon class="filter-icon" name="filter" />
18
+ <input
19
+ v-model.trim="mainFilter"
20
+ :id="`${props.testId}-main-filter-input`"
21
+ :placeholder="props.mainFilterPlaceholder"
22
+ type="text"
23
+ @input="emits('main-filter', mainFilter)"
24
+ />
25
+ </div>
26
+ <div
27
+ :class="[
28
+ 'datagrid',
29
+ {
30
+ 'datagrid-opened-info': isShowHiddenInfo,
31
+ },
32
+ ]"
33
+ >
34
+ <div :id="tableWrapperId" class="datagrid-table-wrapper">
35
+ <div class="datagrid-table">
36
+ <div class="datagrid-header">
37
+ <div class="datagrid-row">
38
+ <div class="datagrid-row-master datagrid-row-flex">
39
+ <div
40
+ v-if="props.type || $slots.toggleBlock"
41
+ class="datagrid-row-sticky"
42
+ >
43
+ <div
44
+ v-if="props.type"
45
+ :id="expandableCaret"
46
+ class="datagrid-column datagrid-expandable-caret datagrid-fixed-column flex-align-center flex-justify-center"
47
+ >
48
+ <template v-if="props.type === 'checkbox'">
49
+ <div
50
+ class="clr-checkbox-wrapper flex-align-center flex-justify-center w-100"
51
+ >
52
+ <input
53
+ :id="`${props.testId}-${inputId}-all`"
54
+ v-model="selectedAll"
55
+ type="checkbox"
56
+ class="checkbox-btn"
57
+ :value="-1"
58
+ @change="changeAll"
59
+ />
60
+ <label
61
+ :for="`${props.testId}-${inputId}-all`"
62
+ class="clr-control-label"
63
+ />
64
+ </div>
65
+ <div class="datagrid-column-separator"></div>
66
+ </template>
67
+ </div>
68
+ <div
69
+ v-if="$slots.toggleBlock"
70
+ class="datagrid-toggle-block datagrid-column datagrid-fixed-width"
71
+ >
72
+ <div class="datagrid-column-flex">
73
+ <div class="datagrid-column-separator">
74
+ <span class="clr-sr-only" />
75
+ <div class="datagrid-column-resize-tracker" />
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <div class="datagrid-row-scrollable">
81
+ <div
82
+ v-for="(item, key) in headItemsPresent"
83
+ :key="key"
84
+ :style="{
85
+ width: columnsWidth[key][0],
86
+ minWidth: columnsWidth[key][1],
87
+ }"
88
+ class="datagrid-column datagrid-fixed-width"
89
+ >
90
+ <div class="datagrid-column-flex">
91
+ <button
92
+ :id="`${props.testId}-sort-column-${key}`"
93
+ :class="[
94
+ 'datagrid-column-title',
95
+ {
96
+ 'default text-decoration-none':
97
+ !item.sortColumn,
98
+ },
99
+ ]"
100
+ @click="sortTable(item.sortColumn)"
101
+ >
102
+ <slot :key="key" name="th" :item="item">
103
+ <span
104
+ :title="item.text"
105
+ :style="{
106
+ width:
107
+ columnsWidth[key][0]?.slice(0, -2) -
108
+ (item.hasFilter ? 65 : 40) +
109
+ 'px',
110
+ }"
111
+ class="title-column"
112
+ >
113
+ {{ item.text }}
114
+ </span>
115
+ </slot>
116
+ <span
117
+ v-if="item.sortColumn"
118
+ class="sort-arrow-wrap"
119
+ >
120
+ <atoms-the-icon
121
+ v-show="sortInfo[0] === item.sortColumn"
122
+ :class="['sort-arrow', { down: sortInfo[1] }]"
123
+ name="sort-arrow"
124
+ />
125
+ </span>
126
+ </button>
127
+ <button
128
+ v-if="item.hasFilter"
129
+ :id="`${props.testId}-filter-icon-${key}`"
130
+ class="datagrid-filter-toggle clr-anchor clr-smart-open-close"
131
+ @click="filterShow[key] = !filterShow[key]"
132
+ >
133
+ <atoms-the-icon
134
+ v-if="filterTerm[key]"
135
+ class="filter-icon"
136
+ name="filter-solid"
137
+ style="fill: #0079b8"
138
+ />
139
+ <atoms-the-icon
140
+ v-else
141
+ class="filter-icon"
142
+ name="filter"
143
+ />
144
+ </button>
145
+ <atoms-popup-simple-popup
146
+ v-model="filterShow[key]"
147
+ :test-id="`${props.testId}-filter`"
148
+ top="100%"
149
+ :left="key === 0 ? '0' : ''"
150
+ :right="key !== 0 ? '0' : ''"
151
+ >
152
+ <input
153
+ :id="`${props.testId}-filter-input-${key}`"
154
+ v-model="filterTerm[key]"
155
+ type="text"
156
+ @input="filtering"
157
+ />
158
+ </atoms-popup-simple-popup>
159
+ <div
160
+ v-show="
161
+ !isShowHiddenInfo ||
162
+ (isShowHiddenInfo && key === 0)
163
+ "
164
+ :class="[
165
+ 'datagrid-column-separator',
166
+ {
167
+ 'double-arrow-separator':
168
+ key === 0 && props.withInfo,
169
+ },
170
+ ]"
171
+ @mousedown="setGrab(key, $event)"
172
+ >
173
+ <button
174
+ :id="`${props.testId}-resize-tracker-${key}`"
175
+ class="datagrid-column-handle drag-handle draggable"
176
+ />
177
+ <span class="clr-sr-only" />
178
+ <div class="datagrid-column-resize-tracker" />
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ </div>
186
+
187
+ <template v-if="bodyItemsPresent.length">
188
+ <div
189
+ v-for="(item, key) in bodyItemsPresent"
190
+ :key="item.id"
191
+ :class="[
192
+ 'datagrid-body-row datagrid-row animation',
193
+ {
194
+ 'datagrid-selected active':
195
+ !props.withInfo && checkIsSelectedRow(item[0].id),
196
+ 'datagrid-selected-info':
197
+ props.withInfo &&
198
+ isShowHiddenInfo &&
199
+ checkIsSelectedRow(item[0].id),
200
+ },
201
+ ]"
202
+ :[props.rowAttributeIdName]="item[0].dataId"
203
+ >
204
+ <div>
205
+ <div
206
+ class="datagrid-row-master datagrid-row-flex"
207
+ @click.stop="selectRowById(item[0])"
208
+ >
209
+ <div
210
+ v-if="props.type || $slots.toggleBlock"
211
+ class="datagrid-row-sticky"
212
+ @click.stop
213
+ >
214
+ <div
215
+ :id="expandableCaret"
216
+ :class="[
217
+ 'datagrid-expandable-caret flex-justify-center datagrid-cell',
218
+ {
219
+ 'datagrid-fixed-column': !props.withInfo,
220
+ 'datagrid-fixed-column-without-separator':
221
+ props.withInfo,
222
+ },
223
+ ]"
224
+ >
225
+ <!--TODO refactoring (duplicate)-->
226
+ <div
227
+ v-if="$slots.toggleBlock && !props.type"
228
+ class="datagrid-cell datagrid-fixed-width"
229
+ >
230
+ <div class="flex-align-center">
231
+ <button
232
+ :id="`${props.testId}-toggle-icon-${key}`"
233
+ class="datagrid-expandable-caret-button reset-btn"
234
+ @click="toggle(key)"
235
+ >
236
+ <atoms-the-icon
237
+ :class="[
238
+ 'datagrid-expandable-caret-icon',
239
+ { toggle: toggedItems[key] },
240
+ ]"
241
+ name="angle"
242
+ />
243
+ </button>
244
+ </div>
245
+ </div>
246
+ <slot
247
+ v-if="props.type"
248
+ :key="key"
249
+ name="type"
250
+ :item="item"
251
+ >
252
+ <div
253
+ :class="
254
+ item[0]?.disabled && 'clr-form-control-disabled'
255
+ "
256
+ >
257
+ <div
258
+ :class="`clr-${props.type}-wrapper flex-justify-center flex-align-center`"
259
+ >
260
+ <input
261
+ :id="`${props.testId}-${inputId}-${item[0].id}`"
262
+ :key="item[0].id"
263
+ v-model="selectedRowLocal"
264
+ :type="props.type"
265
+ :class="`${props.type}-btn`"
266
+ :value="item[0].id"
267
+ :disabled="item[0]?.disabled || false"
268
+ name="selected-store"
269
+ @change="
270
+ changeSelectedRow($event, item[0].id)
271
+ "
272
+ />
273
+ <label
274
+ :for="`${props.testId}-${inputId}-${item[0].id}`"
275
+ class="clr-control-label"
276
+ />
277
+ </div>
278
+ </div>
279
+ </slot>
280
+ </div>
281
+ <!--TODO refactoring (duplicate)-->
282
+ <div
283
+ v-if="$slots.toggleBlock && props.type"
284
+ class="datagrid-cell datagrid-fixed-width"
285
+ >
286
+ <div class="flex-align-center">
287
+ <button
288
+ :id="`${props.testId}-toggle-icon-${key}`"
289
+ class="datagrid-expandable-caret-button reset-btn"
290
+ @click="toggle(key)"
291
+ >
292
+ <atoms-the-icon
293
+ :class="[
294
+ 'datagrid-expandable-caret-icon',
295
+ { toggle: toggedItems[key] },
296
+ ]"
297
+ name="angle"
298
+ />
299
+ </button>
300
+ </div>
301
+ </div>
302
+ </div>
303
+ <div class="datagrid-row-scrollable">
304
+ <div class="datagrid-scrolling-cells">
305
+ <div
306
+ v-for="(item2, key2) in item"
307
+ v-show="
308
+ !isShowHiddenInfo ||
309
+ item2.key === 'col1' ||
310
+ item2.key === 'icon'
311
+ "
312
+ :key="key2"
313
+ :style="{
314
+ width: columnsWidth[key2][0],
315
+ minWidth: columnsWidth[key2][1],
316
+ }"
317
+ :class="[
318
+ 'datagrid-cell datagrid-fixed-width',
319
+ {
320
+ 'hidden-text-triangle':
321
+ isShowHiddenInfo &&
322
+ item2.data?.name === 'hidden-text-triangle',
323
+ },
324
+ ]"
325
+ >
326
+ <div
327
+ :class="[
328
+ 'flex-align-center h-100',
329
+ {
330
+ 'double-arrow-width':
331
+ item2.data?.name === 'doubleArrows',
332
+ },
333
+ ]"
334
+ >
335
+ <div
336
+ v-if="item2.data?.name === 'doubleArrows'"
337
+ :id="`show-info-${item[0].data.id}`"
338
+ :class="[
339
+ 'double-arrow-wrap',
340
+ {
341
+ 'arrow-selected':
342
+ isShowHiddenInfo &&
343
+ item2.id === selectedRow,
344
+ },
345
+ ]"
346
+ @click.prevent.stop="
347
+ doubleArrowClick(item2, item)
348
+ "
349
+ >
350
+ <atoms-the-icon
351
+ v-if="item2.data?.name === 'doubleArrows'"
352
+ name="doubleArrows"
353
+ :class="[
354
+ 'double-arrow',
355
+ {
356
+ 'arrow-selected':
357
+ isShowHiddenInfo &&
358
+ item2.id === selectedRow,
359
+ },
360
+ ]"
361
+ />
362
+ </div>
363
+ <span
364
+ v-if="item2.text && item2.data?.iconClassName"
365
+ class="vertical-divider"
366
+ />
367
+ <slot :name="item2.key" :item="item2">
368
+ <span class="text-ellipsis" :title="item2.text"
369
+ >{{ item2.text }}
370
+ </span>
371
+ </slot>
372
+ </div>
373
+ </div>
374
+ </div>
375
+ <div
376
+ v-show="toggedItems[key]"
377
+ class="datagrid-row-flex datagrid-row-detail datagrid-container"
378
+ >
379
+ <slot name="toggleBlock" :item="item" />
380
+ </div>
381
+ </div>
382
+ </div>
383
+ </div>
384
+ </div>
385
+ </template>
386
+ <template v-else>
387
+ <div class="datagrid-placeholder-container">
388
+ <div class="datagrid-placeholder datagrid-empty">
389
+ <div class="datagrid-placeholder-image"></div>
390
+
391
+ <span>No items found</span>
392
+ </div>
393
+ </div>
394
+ </template>
395
+ </div>
396
+ </div>
397
+ </div>
398
+
399
+ <div
400
+ v-if="!hideFooter"
401
+ :class="[
402
+ 'datagrid-footer',
403
+ {
404
+ 'datagrid-footer-opened-info': isShowHiddenInfo,
405
+ },
406
+ ]"
407
+ >
408
+ <div
409
+ v-if="props.type === 'checkbox' && props.selectedRow?.length"
410
+ class="clr-form-control-disabled"
411
+ >
412
+ <div class="clr-checkbox-wrapper">
413
+ <input
414
+ :id="`${props.testId}-check-all`"
415
+ type="checkbox"
416
+ checked
417
+ />
418
+ <label class="clr-control-label">
419
+ {{ props.selectedRow?.length }}
420
+ </label>
421
+ </div>
422
+ </div>
423
+ <div class="datagrid-footer-description flex-align-center">
424
+ <atoms-table-data-grid-column-switch
425
+ v-if="columnKeysLocal"
426
+ v-model:column-keys="columnKeysLocal"
427
+ :test-id="`${props.testId}-footer-description`"
428
+ class="switch-icon"
429
+ />
430
+
431
+ <div v-if="$slots.action" class="datagrid-footer__action">
432
+ <slot name="action" />
433
+ </div>
434
+ </div>
435
+
436
+ <atoms-table-data-grid-pagination
437
+ test-id="props.testId"
438
+ :page-size="props.pageSize"
439
+ :page="props.page"
440
+ :options="mergeOptions"
441
+ :total-items="props.totalItems"
442
+ :total-pages="props.totalPages"
443
+ :hide-pagination="props.hidePagination"
444
+ :hide-page-size="props.hidePageSize"
445
+ :show-page-info="props.showPageInfo"
446
+ :page-items-count="props.bodyItems.length"
447
+ :is-show-hidden-info="isShowHiddenInfo"
448
+ @change-page-size="changePageSize"
449
+ @change-page="changePage"
450
+ />
451
+ </div>
452
+
453
+ <atoms-loader v-show="props.loading" class="datagrid-spinner" />
454
+ </div>
455
+ </div>
456
+ <div
457
+ v-if="isShowInfo"
458
+ id="hidden-features"
459
+ :class="[
460
+ 'hidden-features',
461
+ {
462
+ 'show-hidden-info': isShowHiddenInfo,
463
+ },
464
+ ]"
465
+ >
466
+ <div class="header">
467
+ <slot name="hiddenInfoHeader" :item="showedInfoCol" />
468
+ <button
469
+ :id="`${props.testId}-hidden-info-toggle-icon-${showedInfoRow?.key}-${showedInfoRow?.data.name}`"
470
+ class="signpost-action close"
471
+ @click="isShowHiddenInfo = false"
472
+ >
473
+ <atoms-the-icon class="close-icon" name="close" />
474
+ </button>
475
+ </div>
476
+ <slot name="hiddenInfoBody" />
477
+ </div>
478
+ </div>
479
+ </template>
480
+
481
+ <script setup lang="ts">
482
+ import { UI_I_HTMLSelectElement } from '~/lib/models/interfaces'
483
+ import { itemsPerPage } from '~/components/atoms/table/dataGrid/lib/config/itemsPerPage'
484
+ import {
485
+ UI_I_HeadItem,
486
+ UI_I_BodyItem,
487
+ UI_I_ColumnKey,
488
+ } from '~/components/atoms/table/dataGrid/lib/models/interfaces'
489
+ import { UI_I_OptionItem } from '~/components/atoms/lib/models/interfaces'
490
+ import {
491
+ UI_T_ColumnKeys,
492
+ UI_T_DataGridType,
493
+ UI_T_SelectedRow,
494
+ } from '~/components/atoms/table/dataGrid/lib/models/types'
495
+
496
+ const props = withDefaults(
497
+ defineProps<{
498
+ headItems: UI_I_HeadItem[]
499
+ bodyItems: UI_I_BodyItem[][]
500
+ pageSize: number
501
+ page: number
502
+ totalItems: number
503
+ totalPages: number
504
+ loading?: boolean
505
+ columnKeys?: UI_I_ColumnKey[]
506
+ selectedRow?: UI_T_SelectedRow
507
+ type?: UI_T_DataGridType
508
+ itemsPerPage?: UI_I_OptionItem[]
509
+ offSelectByRow?: boolean
510
+ hidePageSize?: boolean
511
+ showPageInfo?: boolean
512
+ serverOff?: boolean
513
+ fillWidth?: boolean
514
+ hideFooter?: boolean
515
+ hidePagination?: boolean
516
+ testId?: string
517
+ withInfo?: boolean
518
+ rowAttributeIdName?: string
519
+ isMainFilter?: boolean
520
+ mainFilterPlaceholder?: string
521
+ }>(),
522
+ {
523
+ columnKeys: undefined,
524
+ selectedRow: undefined,
525
+ type: undefined,
526
+ itemsPerPage: undefined,
527
+ fillWidth: true,
528
+ testId: 'ui-data-grid',
529
+ withInfo: false,
530
+ rowAttributeIdName: 'data-id',
531
+ }
532
+ )
533
+
534
+ const emits = defineEmits<{
535
+ (event: 'update:column-keys', value: UI_T_ColumnKeys): void
536
+ (event: 'update:selected-row', value: UI_T_SelectedRow): void
537
+ (event: 'update:page-size', value: number): void
538
+ (event: 'update:page', value: number): void
539
+ (event: 'main-filter', value: string): void
540
+ (event: 'filtering', value: string[][]): void
541
+ (event: 'sorting', value: [string, boolean]): void
542
+ (event: 'change', value: any): void
543
+ (event: 'row-detail', value: number): void
544
+ }>()
545
+
546
+ const mainFilter = ref<string>('')
547
+
548
+ const mergeOptions = computed<UI_I_OptionItem[]>(
549
+ () => props.itemsPerPage || itemsPerPage
550
+ )
551
+
552
+ const inputId = ref<string>(`radio-input-${useUniqueId()}`)
553
+
554
+ const columnKeysLocal = computed<UI_T_ColumnKeys>({
555
+ get() {
556
+ return props.columnKeys
557
+ },
558
+ set(newValue) {
559
+ emits('update:column-keys', newValue)
560
+ },
561
+ })
562
+
563
+ const selectedAll = ref<boolean>(false)
564
+ const changeAll = (e: UI_I_HTMLSelectElement): void => {
565
+ const newSelectedRow: (number | string)[] = []
566
+ if (e.target.checked) {
567
+ bodyItemsPresent.value.forEach((row) => {
568
+ if (row[0]?.disabled) return
569
+
570
+ newSelectedRow.push(row[0].id)
571
+ })
572
+ }
573
+
574
+ emits('update:selected-row', newSelectedRow)
575
+ }
576
+
577
+ const selectedRowLocal = ref<UI_T_SelectedRow>([])
578
+ const isShowHiddenInfo = ref<boolean>(false)
579
+ const tableWrapperId = `table-wrapper-${useUniqueId()}`
580
+ let memoryWidth = '0'
581
+
582
+ const showedInfoRow = ref<UI_I_BodyItem | null>(null)
583
+ const showedInfoCol = ref<UI_I_BodyItem[] | null>(null)
584
+
585
+ const isShowInfo = computed(
586
+ () =>
587
+ showedInfoRow.value &&
588
+ showedInfoRow.value.id === props.selectedRow &&
589
+ !showedInfoRow.value.data?.text &&
590
+ isShowHiddenInfo.value
591
+ )
592
+
593
+ const setShowedInfoData = (
594
+ item: UI_I_BodyItem | null,
595
+ items: UI_I_BodyItem[] | null,
596
+ reset: boolean = false
597
+ ): void => {
598
+ showedInfoRow.value = item
599
+ showedInfoCol.value = items
600
+
601
+ reset && (isShowHiddenInfo.value = false)
602
+ item && selectRowById(item)
603
+ reset && (isShowHiddenInfo.value = true)
604
+ }
605
+
606
+ const doubleArrowClick = (
607
+ item: UI_I_BodyItem,
608
+ items: UI_I_BodyItem[]
609
+ ): void => {
610
+ if (!isShowHiddenInfo.value) {
611
+ setShowedInfoData(item, items)
612
+ } else {
613
+ if (showedInfoRow.value?.id !== item.id) {
614
+ setShowedInfoData(item, items, true)
615
+
616
+ return
617
+ } else {
618
+ setShowedInfoData(null, null)
619
+ }
620
+ }
621
+
622
+ isShowHiddenInfo.value = !isShowHiddenInfo.value
623
+ }
624
+
625
+ watch(
626
+ () => props.selectedRow,
627
+ (newValue) => {
628
+ if (newValue === undefined) return
629
+
630
+ if (Array.isArray(newValue) && !newValue.length) selectedAll.value = false
631
+
632
+ selectedRowLocal.value = newValue
633
+ },
634
+ { immediate: true }
635
+ )
636
+ const selectRowById = (item: UI_I_BodyItem): void => {
637
+ const { id, disabled } = item
638
+
639
+ if (props.offSelectByRow || isShowHiddenInfo.value || disabled) return
640
+
641
+ if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
642
+ const has = selectedRowLocal.value.includes(id)
643
+ if (has) {
644
+ selectedRowLocal.value = selectedRowLocal.value.filter(
645
+ (rowId: string | number) => rowId !== id
646
+ )
647
+ } else {
648
+ selectedRowLocal.value.push(id)
649
+ }
650
+
651
+ emits('change', selectedRowLocal.value)
652
+ emits('update:selected-row', selectedRowLocal.value)
653
+
654
+ changeSelectedAll(!has)
655
+ return
656
+ }
657
+
658
+ emits('change', id)
659
+ emits('update:selected-row', id)
660
+ }
661
+ const changeSelectedRow = (
662
+ e: UI_I_HTMLSelectElement,
663
+ id: number | string
664
+ ): void => {
665
+ if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
666
+ const newSelectedRow = [...selectedRowLocal.value]
667
+ emits('change', newSelectedRow)
668
+ emits('update:selected-row', newSelectedRow)
669
+
670
+ changeSelectedAll(e.target.checked)
671
+ return
672
+ }
673
+
674
+ emits('change', id)
675
+ emits('update:selected-row', id)
676
+ }
677
+ const changeSelectedAll = (checked: boolean): void => {
678
+ if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
679
+ const newSelectedRow = [...selectedRowLocal.value]
680
+
681
+ if (!checked) {
682
+ selectedAll.value = false
683
+ } else if (newSelectedRow.length === bodyItemsPresent.value.length) {
684
+ selectedAll.value = true
685
+ }
686
+ }
687
+ }
688
+
689
+ const checkIsSelectedRow = (id: number | string): boolean => {
690
+ if (props.type === 'checkbox' && Array.isArray(props.selectedRow)) {
691
+ return props.selectedRow.includes(id)
692
+ }
693
+ return props.selectedRow === id
694
+ }
695
+
696
+ // Sorting
697
+ const sortInfo = ref<[string, boolean]>(['', true])
698
+ const sortedColumnIndex = computed<number>(() => {
699
+ let index = -1
700
+ headItemsPresent.value.forEach((item, key) => {
701
+ if (item.sortColumn === sortInfo.value[0]) index = key
702
+ })
703
+
704
+ return index
705
+ })
706
+ const sortTable = (sortName: string): void => {
707
+ if (!sortName) return
708
+
709
+ emits('update:selected-row', selectedRowLocal.value)
710
+
711
+ if (sortInfo.value[0] === sortName) {
712
+ sortInfo.value[1] = !sortInfo.value[1]
713
+
714
+ emits('sorting', sortInfo.value)
715
+ return
716
+ }
717
+ sortInfo.value[0] = sortName
718
+ sortInfo.value[1] = true
719
+
720
+ emits('sorting', sortInfo.value)
721
+ }
722
+
723
+ // Filtering
724
+ const filterShow = ref<boolean[]>([])
725
+ const filterTerm = ref<string[]>([])
726
+ const filtering = (): void => {
727
+ const filter: string[][] = []
728
+ headItemsPresent.value.forEach((item, key) => {
729
+ if (filterTerm.value[key]) filter.push([item.key, filterTerm.value[key]])
730
+ })
731
+
732
+ emits('filtering', filter)
733
+ }
734
+
735
+ // Pagination
736
+ const changePageSize = (value: number): void => {
737
+ emits('update:page-size', value)
738
+ }
739
+ const changePage = (value: number): void => {
740
+ emits('update:page', value)
741
+ }
742
+
743
+ const headItemsPresent = computed<UI_I_HeadItem[]>(() => {
744
+ if (!columnKeysLocal.value) {
745
+ return props.headItems
746
+ }
747
+
748
+ return props.headItems.filter((item, key) => {
749
+ return columnKeysLocal.value?.find(
750
+ (item2, key2) => item2.key === item.key && key === key2
751
+ )?.show
752
+ })
753
+ })
754
+
755
+ const bodyItemsPresent = computed<UI_I_BodyItem[][]>(() => {
756
+ let items: UI_I_BodyItem[][] = props.bodyItems
757
+
758
+ // Filtering by column
759
+ if (columnKeysLocal.value) {
760
+ items = items.map((arr) => {
761
+ arr = arr.filter((item, key) => {
762
+ return columnKeysLocal.value?.find(
763
+ (item2, key2) => item2.key === item.key && key === key2
764
+ )?.show
765
+ })
766
+ return arr
767
+ })
768
+ }
769
+
770
+ if (props.serverOff) {
771
+ // Sorting
772
+ if (sortInfo.value[0] !== '') {
773
+ console.log(items, 222, sortedColumnIndex.value, sortInfo.value[1])
774
+ items = useDeepCopy(items).sort(
775
+ (a: UI_I_BodyItem[], b: UI_I_BodyItem[]) => {
776
+ let first = a[sortedColumnIndex.value].text.toString().toLowerCase()
777
+ let second = b[sortedColumnIndex.value].text.toString().toLowerCase()
778
+
779
+ const sortValueA = a[sortedColumnIndex.value]?.data?.sortValue
780
+ const sortValueB = b[sortedColumnIndex.value]?.data?.sortValue
781
+ if (sortValueA || sortValueA === 0) {
782
+ first = sortValueA
783
+ }
784
+ if (sortValueB || sortValueB === 0) {
785
+ second = sortValueB
786
+ }
787
+
788
+ console.log(
789
+ first,
790
+ 333,
791
+ second,
792
+ 333,
793
+ a[sortedColumnIndex.value]?.data?.sortValue,
794
+ 333,
795
+ b[sortedColumnIndex.value]?.data?.sortValue
796
+ )
797
+
798
+ if (sortInfo.value[1]) {
799
+ return first > second ? 1 : first < second ? -1 : 0
800
+ } else {
801
+ return first < second ? 1 : first > second ? -1 : 0
802
+ }
803
+ }
804
+ )
805
+ }
806
+ // Filtering
807
+ const hasFilter = headItemsPresent.value.some(
808
+ (_, key) => filterTerm.value[key]
809
+ )
810
+ if (hasFilter) {
811
+ items = items.filter((row) => {
812
+ // 0 - начальное значение
813
+ // 1 - найден элемент
814
+ // -1 - ненайден элемент
815
+ let hasItem = 0
816
+ headItemsPresent.value.forEach((item, key) => {
817
+ if (!filterTerm.value[key]) return
818
+ const term = filterTerm.value[key].toLowerCase()
819
+
820
+ row.forEach((col) => {
821
+ if (
822
+ col.key === item.key &&
823
+ typeof col.text === 'string' &&
824
+ hasItem != -1
825
+ ) {
826
+ hasItem = col.text.toLowerCase().includes(term) ? 1 : -1
827
+ }
828
+ })
829
+ })
830
+
831
+ return hasItem === 1
832
+ })
833
+ }
834
+ }
835
+
836
+ return items
837
+ })
838
+
839
+ const toggedItems = ref<boolean[]>([])
840
+
841
+ const toggle = (key: number): void => {
842
+ toggedItems.value[key] = !toggedItems.value[key]
843
+ if (!toggedItems.value[key]) return
844
+ emits('row-detail', key)
845
+ }
846
+
847
+ const outerWrapper = `datagrid-outer-wrapper${useUniqueId()}`
848
+ const expandableCaret = `datagrid-expandable-caret${useUniqueId()}`
849
+
850
+ // Resize
851
+ let helper = false
852
+ let setColumnWidth = (): void => {
853
+ if (!helper) {
854
+ columnsWidth.value = []
855
+ headItemsPresent.value.forEach((item) => {
856
+ columnsWidth.value.push([
857
+ item.width, // width
858
+ item.width, // min-width
859
+ ])
860
+ })
861
+
862
+ helper = true
863
+ setTimeout(() => setColumnWidth(), 0)
864
+ return
865
+ }
866
+ // Не продолжаем, чтобы ширина калонок была так как заданно в headItemsPresent
867
+ if (!props.fillWidth) return
868
+
869
+ const dataGridWidth = document.getElementById(outerWrapper)?.clientWidth || 0
870
+ const leftColumnWidth =
871
+ document.getElementById(expandableCaret)?.clientWidth || 0
872
+ const bordersWidth = 2
873
+ const columnWidth =
874
+ (dataGridWidth - leftColumnWidth - bordersWidth) /
875
+ headItemsPresent.value.length
876
+
877
+ headItemsPresent.value.forEach((item) => {
878
+ columnsWidth.value.push([
879
+ `${columnWidth}px`, // width
880
+ item.width, // min-width
881
+ ])
882
+ })
883
+ }
884
+ setColumnWidth = useThrottle(setColumnWidth)
885
+
886
+ const columnsWidth = ref<[string, string][]>([])
887
+ watch(
888
+ bodyItemsPresent,
889
+ (newValue: UI_I_BodyItem[][]) => {
890
+ newValue.forEach(() => {
891
+ toggedItems.value.push(false)
892
+ })
893
+ setColumnWidth()
894
+ },
895
+ {
896
+ immediate: true,
897
+ deep: true,
898
+ }
899
+ )
900
+
901
+ watch(
902
+ headItemsPresent,
903
+ (newValue: UI_I_HeadItem[]) => {
904
+ filterShow.value = newValue.map(() => false)
905
+ filterTerm.value = newValue.map(() => '')
906
+ },
907
+ {
908
+ immediate: true,
909
+ deep: true,
910
+ }
911
+ )
912
+
913
+ const grabColumn = ref<number>(-1)
914
+ const grabStartX = ref<number>(0)
915
+ const setGrab = (key: number, e: MouseEvent): void => {
916
+ if (props.withInfo && key === 0) return
917
+
918
+ if (!isShowHiddenInfo.value) {
919
+ grabColumn.value = key
920
+ const currentWidth = parseInt(columnsWidth.value[grabColumn.value][0])
921
+ grabStartX.value = e.clientX - currentWidth
922
+ }
923
+ }
924
+
925
+ const isDrag = ref<boolean>(false)
926
+
927
+ const mouseup = (): void => {
928
+ if (grabColumn.value === -1) {
929
+ return
930
+ }
931
+
932
+ grabColumn.value = -1
933
+ isDrag.value = false
934
+ }
935
+
936
+ let resizeObserve: ResizeObserver
937
+ let mousemove = (e: MouseEvent): void => {
938
+ if (grabColumn.value === -1) return
939
+
940
+ e.preventDefault()
941
+ isDrag.value = true
942
+ resizeObserve.disconnect()
943
+
944
+ const minWidth = parseInt(columnsWidth.value[grabColumn.value][1])
945
+ const changeX = Math.max(e.clientX - grabStartX.value, minWidth)
946
+
947
+ columnsWidth.value[grabColumn.value] = [`${changeX}px`, `${minWidth}px`]
948
+ }
949
+ mousemove = useThrottle(mousemove)
950
+
951
+ const setResizeObserve = (): void => {
952
+ const el = document.getElementById(outerWrapper)
953
+
954
+ if (!el) {
955
+ setTimeout(setResizeObserve, 0)
956
+ return
957
+ }
958
+
959
+ resizeObserve = new ResizeObserver(setColumnWidth)
960
+ resizeObserve.observe(el)
961
+ }
962
+
963
+ let resizeObserveWithInfo: ResizeObserver
964
+
965
+ const setColumnWidthWithInfo = (ent: ResizeObserverEntry[]): void => {
966
+ if (isShowHiddenInfo.value) {
967
+ memoryWidth = columnsWidth.value[1][0]
968
+ columnsWidth.value[1][0] = `${ent[0].contentBoxSize[0].inlineSize - 86}px`
969
+ } else {
970
+ columnsWidth.value[1][0] = memoryWidth
971
+ }
972
+ }
973
+
974
+ const setResizeObserveWithInfo = (): void => {
975
+ const el = document.querySelector('.datagrid')
976
+
977
+ if (!el) {
978
+ setTimeout(setResizeObserveWithInfo, 0)
979
+ return
980
+ }
981
+
982
+ resizeObserveWithInfo = new ResizeObserver(setColumnWidthWithInfo)
983
+ resizeObserveWithInfo.observe(el)
984
+ }
985
+
986
+ onMounted(() => {
987
+ window.addEventListener('mousemove', mousemove)
988
+ window.addEventListener('mouseup', mouseup)
989
+
990
+ if (props.withInfo) {
991
+ setResizeObserveWithInfo()
992
+ }
993
+
994
+ setResizeObserve()
995
+ })
996
+ onUnmounted(() => {
997
+ window.removeEventListener('mouseup', mouseup)
998
+ window.removeEventListener('mousemove', mousemove)
999
+ })
1000
+ </script>
1001
+
1002
+ <style scoped lang="scss">
1003
+ @import '~/assets/scss/common/mixins';
1004
+ .datagrid-outer-wrapper {
1005
+ @include flex($dir: row);
1006
+ padding-top: 12px;
1007
+ flex-grow: 1;
1008
+ overflow: auto;
1009
+
1010
+ &.datagrid-outer-wrapper-opened-info {
1011
+ width: 35%;
1012
+ min-width: 195px;
1013
+ }
1014
+
1015
+ & * {
1016
+ box-sizing: border-box;
1017
+ }
1018
+
1019
+ & svg {
1020
+ fill: var(--table-color);
1021
+ }
1022
+
1023
+ .datagrid-inner-wrapper {
1024
+ @include flex($dir: column);
1025
+ flex-grow: 1;
1026
+ overflow: auto;
1027
+
1028
+ .main-filter-content {
1029
+ align-items: center;
1030
+
1031
+ .filter-icon {
1032
+ width: 16px;
1033
+ height: 16px;
1034
+ margin-right: 10px;
1035
+ }
1036
+ }
1037
+ .datagrid {
1038
+ overflow: auto;
1039
+ flex: 1 1 auto;
1040
+ border-radius: 0.125rem 0.125rem 0 0;
1041
+ background-color: var(--block-view-bg-color);
1042
+ border-color: var(--global-border-color);
1043
+
1044
+ &.datagrid-opened-info {
1045
+ border-radius: 0.125rem 0 0 0;
1046
+ overflow-x: hidden;
1047
+ }
1048
+
1049
+ .datagrid-table-wrapper {
1050
+ min-width: max-content;
1051
+ display: flex;
1052
+ flex: 1 1 auto;
1053
+ min-height: 100%;
1054
+
1055
+ .datagrid-table {
1056
+ @include flex($dir: column);
1057
+ flex: 1 1 auto;
1058
+ align-content: flex-start;
1059
+ position: relative;
1060
+
1061
+ .datagrid-header {
1062
+ position: sticky;
1063
+ top: 0;
1064
+ z-index: 501;
1065
+ width: auto;
1066
+
1067
+ .datagrid-row-scrollable {
1068
+ flex-direction: row;
1069
+
1070
+ .datagrid-column-separator {
1071
+ user-select: none;
1072
+
1073
+ &::after {
1074
+ cursor: col-resize;
1075
+ }
1076
+ &.double-arrow-separator .datagrid-column-handle {
1077
+ cursor: unset;
1078
+ }
1079
+ &.double-arrow-separator::after {
1080
+ cursor: unset;
1081
+ }
1082
+ }
1083
+ }
1084
+
1085
+ .datagrid-row {
1086
+ color: var(--table-color);
1087
+ background-color: var(--block-view-bg-color);
1088
+
1089
+ &.datagrid-selected {
1090
+ background-color: var(--row-selected-bg-color);
1091
+ border-bottom: 1px solid var(--global-border-color);
1092
+
1093
+ & :deep(*) {
1094
+ color: var(--table-active-color);
1095
+ }
1096
+ }
1097
+
1098
+ .datagrid-column {
1099
+ background-color: var(--block-view-bg-color);
1100
+ border-bottom: 1px solid var(--global-border-color);
1101
+ padding: 6px 12px 5px;
1102
+ position: relative;
1103
+ //flex: 1 1 auto;
1104
+
1105
+ &:last-child {
1106
+ flex: 1 1 auto;
1107
+ }
1108
+
1109
+ &.datagrid-toggle-block {
1110
+ width: 38px;
1111
+ min-width: 38px;
1112
+
1113
+ .datagrid-column-separator {
1114
+ cursor: default;
1115
+
1116
+ &::after {
1117
+ cursor: default;
1118
+ }
1119
+ }
1120
+ }
1121
+ }
1122
+
1123
+ .datagrid-column-title {
1124
+ align-self: auto;
1125
+ color: var(--table-color);
1126
+ background-color: var(--block-view-bg-color);
1127
+ border-bottom-color: var(--global-border-color);
1128
+ font-size: 11px;
1129
+ @include flex($align: center);
1130
+ display: flex;
1131
+ flex-direction: row;
1132
+ justify-content: flex-start;
1133
+ align-items: center;
1134
+ //line-height: 24px;
1135
+ line-height: normal;
1136
+
1137
+ .title-column {
1138
+ font-weight: bold;
1139
+ font-size: 11px;
1140
+ overflow: hidden;
1141
+ text-wrap: none;
1142
+ text-overflow: ellipsis;
1143
+ }
1144
+
1145
+ .sort-arrow-wrap {
1146
+ margin-left: auto;
1147
+ height: 14px;
1148
+ width: 14px;
1149
+ min-height: 14px;
1150
+ min-width: 14px;
1151
+ vertical-align: middle;
1152
+
1153
+ .sort-arrow {
1154
+ &.down {
1155
+ transform: rotate(180deg);
1156
+ }
1157
+ }
1158
+ }
1159
+ .title-icon {
1160
+ width: 24px;
1161
+ height: 24px;
1162
+ }
1163
+ }
1164
+
1165
+ .datagrid-filter-toggle {
1166
+ background: unset;
1167
+ margin-top: -4px;
1168
+ align-self: center;
1169
+
1170
+ .filter-icon {
1171
+ width: 16px;
1172
+ height: 16px;
1173
+ }
1174
+ }
1175
+ }
1176
+ }
1177
+
1178
+ .datagrid-placeholder-container {
1179
+ .datagrid-placeholder.datagrid-empty {
1180
+ background: var(--block-view-bg-color);
1181
+ }
1182
+ span {
1183
+ font-size: 16px;
1184
+ color: var(--global-font-color4);
1185
+ }
1186
+ }
1187
+
1188
+ .datagrid-row {
1189
+ width: 100%;
1190
+ min-width: max-content;
1191
+ border-top: none;
1192
+ color: var(--table-color);
1193
+ background-color: var(--block-view-bg-color);
1194
+ border-bottom: 1px solid var(--global-border-color);
1195
+
1196
+ &.datagrid-selected {
1197
+ & :deep(*) {
1198
+ color: var(--table-active-color);
1199
+ }
1200
+
1201
+ .datagrid-cell {
1202
+ background-color: var(--row-selected-bg-color);
1203
+ border-bottom: 1px solid var(--global-border-color);
1204
+ position: relative;
1205
+ line-height: 1rem;
1206
+ }
1207
+
1208
+ .datagrid-row-detail {
1209
+ background-color: var(--row-selected-bg-color);
1210
+ border-bottom: 1px solid var(--global-border-color);
1211
+ }
1212
+ }
1213
+
1214
+ .datagrid-cell {
1215
+ min-width: 38px;
1216
+ min-height: 28px;
1217
+ padding: 2px 12px 3px 12px;
1218
+ position: relative;
1219
+
1220
+ &:has(.double-arrow-wrap) {
1221
+ padding-left: 4px;
1222
+ }
1223
+
1224
+ &:has(.double-arrow-wrap)::after {
1225
+ content: '';
1226
+ width: 0.5px;
1227
+ height: calc(100% - 6px);
1228
+ position: absolute;
1229
+ right: 2px;
1230
+ top: 3px;
1231
+ background-color: var(--global-border-color);
1232
+ }
1233
+
1234
+ &:last-child {
1235
+ flex: 1 1 auto;
1236
+ }
1237
+
1238
+ button {
1239
+ height: 0.9rem;
1240
+ width: 0.9rem;
1241
+
1242
+ .arrow-icon {
1243
+ width: 16px;
1244
+ height: 16px;
1245
+ transform: rotate(90deg);
1246
+ }
1247
+ }
1248
+
1249
+ .datagrid-cell-icon {
1250
+ display: inline-block;
1251
+ width: 16px;
1252
+ height: 16px;
1253
+ }
1254
+
1255
+ .datagrid-expandable-caret-button {
1256
+ cursor: pointer;
1257
+ width: 100%;
1258
+
1259
+ .datagrid-expandable-caret-icon {
1260
+ width: 16px;
1261
+ height: 16px;
1262
+ transform: rotate(90deg);
1263
+ fill: var(--table-caret-color);
1264
+
1265
+ &.toggle {
1266
+ transform: rotate(180deg);
1267
+ }
1268
+ }
1269
+ }
1270
+ }
1271
+
1272
+ &.datagrid-selected-info {
1273
+ width: 100%;
1274
+ min-width: max-content;
1275
+ border-top: none;
1276
+ color: var(--table-color);
1277
+ background-color: var(--block-view-bg-color);
1278
+
1279
+ .datagrid-cell {
1280
+ position: relative;
1281
+
1282
+ &.hidden-text-triangle::after {
1283
+ content: '';
1284
+ position: absolute;
1285
+ transform: rotate(225deg);
1286
+ border-bottom: 15px solid transparent;
1287
+ border-right: 15px solid var(--global-bg-color);
1288
+ bottom: 26%;
1289
+ right: -16px;
1290
+ z-index: 1000;
1291
+ }
1292
+
1293
+ &.hidden-text-triangle::before {
1294
+ content: '';
1295
+ transform: rotate(-135deg);
1296
+ position: absolute;
1297
+ border-bottom: 16px solid transparent;
1298
+ border-right: 16px solid var(--global-border-color);
1299
+ bottom: 23%;
1300
+ right: -17px;
1301
+ z-index: 999;
1302
+ }
1303
+ }
1304
+ }
1305
+ }
1306
+
1307
+ .datagrid-row-sticky {
1308
+ @include flex($w: nowrap);
1309
+ position: sticky;
1310
+ left: 0;
1311
+ z-index: 500;
1312
+ background-color: var(--block-view-bg-color);
1313
+
1314
+ .datagrid-column {
1315
+ color: var(--table-color);
1316
+ background-color: var(--block-view-bg-color);
1317
+ border-bottom-color: var(--global-border-color);
1318
+ text-align: left;
1319
+ display: flex;
1320
+ flex: 1 1 auto;
1321
+ vertical-align: top;
1322
+ border: none;
1323
+
1324
+ &.datagrid-expandable-caret {
1325
+ .datagrid-column-separator {
1326
+ display: block;
1327
+
1328
+ &::after {
1329
+ top: 0;
1330
+ height: 18px;
1331
+ }
1332
+ }
1333
+
1334
+ .radio-btn {
1335
+ width: 16px;
1336
+ height: 16px;
1337
+ }
1338
+ }
1339
+
1340
+ .datagrid-column-separator {
1341
+ position: relative;
1342
+ //left: 0.6rem;
1343
+ flex: 0 0 auto;
1344
+ width: 0.05rem;
1345
+ order: 100;
1346
+ margin-left: auto;
1347
+ height: 100%;
1348
+ }
1349
+ }
1350
+
1351
+ .datagrid-fixed-column-without-separator {
1352
+ background-color: var(--block-view-bg-color);
1353
+
1354
+ &::after {
1355
+ background-color: transparent;
1356
+ }
1357
+ }
1358
+
1359
+ .datagrid-fixed-column {
1360
+ background-color: var(--block-view-bg-color);
1361
+
1362
+ &::after {
1363
+ content: '';
1364
+ width: 0.05rem;
1365
+ height: calc(100% - 0.5rem);
1366
+ position: absolute;
1367
+ right: 0;
1368
+ top: 0.25rem;
1369
+ background-color: var(--global-border-color);
1370
+ }
1371
+
1372
+ .clr-form-control-disabled {
1373
+ .clr-checkbox-wrapper {
1374
+ label {
1375
+ cursor: not-allowed;
1376
+ }
1377
+ }
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ .datagrid-row-scrollable {
1383
+ @include flex($ff: row nowrap);
1384
+ flex: 1 1 auto;
1385
+
1386
+ .datagrid-scrolling-cells {
1387
+ @include flex($ff: row nowrap);
1388
+ flex: 1 1 auto;
1389
+ }
1390
+ }
1391
+ .datagrid-body-row {
1392
+ .datagrid-row-scrollable {
1393
+ @include flex($ff: column nowrap);
1394
+
1395
+ .datagrid-row-detail {
1396
+ flex: 1;
1397
+ }
1398
+ }
1399
+
1400
+ &:not(.datagrid-selected):hover {
1401
+ border-bottom: 1px solid var(--table-hover-row-border-color);
1402
+ background-color: var(--table-hover-row-background-color);
1403
+ color: var(--table-hover-row-color);
1404
+
1405
+ .datagrid-fixed-column {
1406
+ background-color: var(--table-hover-row-background-color);
1407
+ }
1408
+ .datagrid-cell {
1409
+ background-color: var(--table-hover-row-background-color);
1410
+ }
1411
+ }
1412
+ }
1413
+ }
1414
+ }
1415
+ }
1416
+
1417
+ .datagrid-footer {
1418
+ flex: 0 0 auto;
1419
+ @include flex($ff: row nowrap, $just: space-between, $align: stretch);
1420
+ font-size: 0.55rem;
1421
+ background-color: var(--block-view-bg-color);
1422
+ border: 0.05rem solid var(--global-border-color);
1423
+ border-top: none;
1424
+ border-radius: 0 0 0.15rem 0.15rem;
1425
+ padding: 0 0.6rem;
1426
+ height: 28px;
1427
+
1428
+ &.datagrid-footer-opened-info {
1429
+ border-radius: 0 0 0 0.15rem;
1430
+ flex-direction: row-reverse;
1431
+ }
1432
+
1433
+ .clr-form-control-disabled {
1434
+ opacity: 1;
1435
+
1436
+ .clr-checkbox-wrapper {
1437
+ label {
1438
+ color: #8c8c8c;
1439
+ margin-right: 9px;
1440
+ padding-left: 22px;
1441
+ &:before {
1442
+ position: absolute;
1443
+ top: 4px;
1444
+ left: 0;
1445
+ content: '';
1446
+ display: inline-block;
1447
+ height: 16px;
1448
+ width: 16px;
1449
+ border: none;
1450
+ border-radius: 3px;
1451
+ background-color: var(--table-checkbox-color);
1452
+ }
1453
+
1454
+ &:after {
1455
+ position: absolute;
1456
+ content: '';
1457
+ display: inline-block;
1458
+ height: 5px;
1459
+ width: 8px;
1460
+ border-left: 2px solid #fff;
1461
+ border-bottom: 2px solid #fff;
1462
+ top: 4px;
1463
+ left: 4px;
1464
+ transform: translateY(4px) rotate(-45deg);
1465
+ }
1466
+ }
1467
+ }
1468
+ }
1469
+ }
1470
+
1471
+ .datagrid-spinner {
1472
+ top: 0.6rem;
1473
+ height: calc(100% - 0.6rem);
1474
+ }
1475
+
1476
+ .datagrid-footer-description {
1477
+ flex: 1 1 auto;
1478
+
1479
+ :deep(svg) {
1480
+ fill: var(--table-switch-color);
1481
+ }
1482
+ }
1483
+
1484
+ .clr-radio-wrapper,
1485
+ .clr-checkbox-wrapper {
1486
+ height: 18px;
1487
+ }
1488
+
1489
+ .clr-radio-wrapper label,
1490
+ .clr-checkbox-wrapper label {
1491
+ padding-left: 16px;
1492
+ }
1493
+ }
1494
+ }
1495
+ //.vertical-divider {
1496
+ // width: 1px;
1497
+ // height: 22px;
1498
+ // background: #bbb;
1499
+ // margin: 2px 2px 0 -5px;
1500
+ //}
1501
+
1502
+ .hidden-features {
1503
+ padding: 9px 14px;
1504
+ background-color: var(--global-bg-color);
1505
+ color: var(--global-font-color2);
1506
+ border: 1px solid var(--global-border-color);
1507
+ border-left: none;
1508
+ overflow-y: auto;
1509
+ overflow-x: hidden;
1510
+ width: 65%;
1511
+
1512
+ .header {
1513
+ display: flex;
1514
+ align-items: center;
1515
+ justify-content: space-between;
1516
+ background-color: inherit;
1517
+
1518
+ h3 {
1519
+ font-size: 1rem;
1520
+ color: var(--global-font-color2) !important;
1521
+ line-height: 1.7rem;
1522
+ }
1523
+ button {
1524
+ line-height: 24px;
1525
+
1526
+ .close-icon {
1527
+ margin-left: 10px;
1528
+ width: 24px;
1529
+ height: 24px;
1530
+ }
1531
+ }
1532
+ }
1533
+ }
1534
+ .double-arrow-width {
1535
+ width: 25px;
1536
+ }
1537
+ .double-arrow-wrap {
1538
+ width: 30px;
1539
+ height: 20px;
1540
+ padding-top: 1px;
1541
+ padding-left: 5px;
1542
+ cursor: pointer;
1543
+ background-color: transparent;
1544
+
1545
+ .double-arrow {
1546
+ background-color: transparent;
1547
+ transform: rotate(90deg);
1548
+ width: 16px;
1549
+ height: 16px;
1550
+ }
1551
+
1552
+ .double-arrow.arrow-selected {
1553
+ transform: rotate(-90deg) !important;
1554
+ background-color: #0079b8;
1555
+ }
1556
+ }
1557
+ .double-arrow-wrap.arrow-selected {
1558
+ background-color: #0079b8;
1559
+ border-radius: 3px;
1560
+ }
1561
+ </style>
1562
+
1563
+ <style>
1564
+ :root {
1565
+ --table-color: #565656;
1566
+ --table-active-color: #fff;
1567
+ --table-checkbox-color: #454545;
1568
+ --table-caret-color: #454545;
1569
+ --table-switch-color: #575757;
1570
+ --table-hover-row-border-color: #666;
1571
+ --table-hover-row-background-color: #e8e8e8;
1572
+ --table-hover-row-color: #454545;
1573
+ --table-spinner-bg-color: #ffffff99;
1574
+ }
1575
+
1576
+ :root.dark-theme {
1577
+ --table-color: #fff;
1578
+ --table-active-color: #565656;
1579
+ --table-checkbox-color: #49aeda;
1580
+ --table-caret-color: #ffffff;
1581
+ --table-switch-color: #b3b3b3;
1582
+ --table-hover-row-border-color: #fff;
1583
+ --table-hover-row-background-color: #324f61;
1584
+ --table-hover-row-color: #e9ecef;
1585
+ --table-spinner-bg-color: rgba(0, 0, 0, 0.5);
1586
+ }
1587
+ </style>