bfg-common 1.5.679 → 1.5.683

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