bfg-common 1.3.71 → 1.3.73

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