bfg-common 1.5.710 → 1.5.711

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 (105) 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/assets/localization/local_be.json +1 -2
  7. package/assets/localization/local_en.json +1 -2
  8. package/assets/localization/local_hy.json +1 -2
  9. package/assets/localization/local_kk.json +1 -2
  10. package/assets/localization/local_ru.json +1 -2
  11. package/assets/localization/local_zh.json +1 -2
  12. package/components/atoms/TheIcon3.vue +50 -50
  13. package/components/atoms/collapse/CollapseNav.vue +170 -170
  14. package/components/atoms/perPage/PerPage.vue +58 -58
  15. package/components/atoms/table/dataGrid/DataGrid.vue +1718 -1718
  16. package/components/atoms/table/dataGrid/DataGridPagination.vue +97 -97
  17. package/components/atoms/table/dataGrid/lib/config/settingsTable.ts +94 -94
  18. package/components/atoms/table/dataGrid/lib/utils/export.ts +16 -16
  19. package/components/common/backup/storage/actions/add/lib/utils.ts +51 -51
  20. package/components/common/browse/blocks/contents/filesNew/Skeleton.vue +18 -18
  21. package/components/common/diagramMain/modals/lib/config/vCenterModal.ts +48 -48
  22. package/components/common/diagramMain/port/Port.vue +580 -580
  23. package/components/common/layout/theHeader/TheHeader.vue +183 -191
  24. package/components/common/layout/theHeader/TheHeaderNew.vue +5 -11
  25. package/components/common/layout/theHeader/TheHeaderOld.vue +5 -11
  26. package/components/common/layout/theHeader/helpMenu/About.vue +79 -79
  27. package/components/common/layout/theHeader/helpMenu/aboutOld/AboutOld.vue +79 -79
  28. package/components/common/layout/theHeader/userMenu/UserMenu.vue +107 -113
  29. package/components/common/layout/theHeader/userMenu/modals/preferences/Preferences.vue +78 -86
  30. package/components/common/layout/theHeader/userMenu/modals/preferences/PreferencesNew.vue +111 -115
  31. package/components/common/layout/theHeader/userMenu/modals/preferences/PreferencesOld.vue +4 -8
  32. package/components/common/layout/theHeader/userMenu/modals/preferences/changeLanguage/ChangeLanguage.vue +114 -108
  33. package/components/common/layout/theHeader/userMenu/modals/preferences/changeLanguage/New.vue +65 -88
  34. package/components/common/layout/theHeader/userMenu/modals/preferences/changeLanguage/Old.vue +66 -89
  35. package/components/common/layout/theHeader/userMenu/modals/preferences/lib/models/types.ts +7 -7
  36. package/components/common/layout/theHeader/userMenu/modals/preferences/timeFormat/TimeFormat.vue +41 -54
  37. package/components/common/layout/theHeader/userMenu/modals/preferences/view/View.vue +33 -46
  38. package/components/common/pages/backups/DetailView.vue +52 -52
  39. package/components/common/pages/backups/lib/models/interfaces.ts +36 -36
  40. package/components/common/pages/backups/modals/Modals.vue +243 -243
  41. package/components/common/pages/backups/modals/createBackup/configuration/maxBandwidth/lib/config/options.ts +6 -6
  42. package/components/common/pages/backups/modals/createBackup/lib/config/readyToCompleteOptions.ts +69 -69
  43. package/components/common/pages/backups/modals/lib/config/restore.ts +115 -115
  44. package/components/common/pages/backups/modals/lib/models/interfaces.ts +186 -186
  45. package/components/common/pages/backups/modals/restore/name/lib/models/interfaces.ts +6 -6
  46. package/components/common/pages/home/lib/models/interfaces.ts +48 -48
  47. package/components/common/pages/home/widgets/hosts/Hosts.vue +27 -27
  48. package/components/common/pages/home/widgets/hosts/lib/config/items.ts +23 -23
  49. package/components/common/pages/home/widgets/vms/VmsOld.vue +35 -35
  50. package/components/common/pages/home/widgets/vms/lib/config/items.ts +19 -19
  51. package/components/common/pages/scheduledTasks/lib/utils/utils.ts +84 -84
  52. package/components/common/readyToComplete/ReadyToComplete.vue +17 -17
  53. package/components/common/select/radio/RadioGroup.vue +137 -137
  54. package/components/common/selectLanguage/SelectLanguage.vue +200 -200
  55. package/components/common/spiceConsole/Drawer.vue +420 -420
  56. package/components/common/spiceConsole/SpiceConsole.vue +184 -184
  57. package/components/common/spiceConsole/lib/models/interfaces.ts +5 -5
  58. package/components/common/tools/Actions.vue +207 -207
  59. package/components/common/treeView/TreeView.vue +52 -52
  60. package/components/common/vm/actions/clone/lib/config/steps.ts +295 -295
  61. package/components/common/vm/actions/clone/new/New.vue +438 -438
  62. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/shares/lib/config/options.ts +28 -28
  63. package/components/common/vm/actions/common/customizeHardware/virtualHardware/memory/Memory.vue +283 -283
  64. package/components/common/vm/actions/common/customizeHardware/vmoptions/bootOptions/order/Order.vue +156 -156
  65. package/components/common/vm/actions/common/select/compatibility/Old.vue +107 -107
  66. package/components/common/vm/actions/common/select/createType/lib/models/interfaces.ts +5 -5
  67. package/components/common/vm/actions/common/select/options/New.vue +264 -264
  68. package/components/common/vm/actions/common/select/options/Options.vue +58 -58
  69. package/components/common/vm/actions/common/select/storage/Old.vue +125 -125
  70. package/components/common/vm/actions/common/select/storage/new/New.vue +311 -311
  71. package/components/common/vm/actions/common/select/storage/new/lib/models/interfaces.ts +5 -5
  72. package/components/common/vm/actions/common/select/storage/new/lib/utils/utils.ts +21 -21
  73. package/components/common/vm/actions/common/select/template/old/Old.vue +50 -50
  74. package/components/common/vm/actions/editSettings/new/Skeleton.vue +88 -88
  75. package/components/common/wizards/common/compatibility/Compatibility.vue +35 -35
  76. package/components/common/wizards/common/steps/computeResource/New.vue +93 -93
  77. package/components/common/wizards/common/steps/name/Name.vue +178 -178
  78. package/components/common/wizards/common/steps/name/New.vue +221 -221
  79. package/components/common/wizards/common/steps/name/Old.vue +121 -121
  80. package/components/common/wizards/common/steps/name/lib/models/interfaces.ts +4 -4
  81. package/components/common/wizards/common/steps/name/location/New.vue +40 -40
  82. package/components/common/wizards/datastore/add/Add.vue +228 -228
  83. package/components/common/wizards/datastore/add/lib/utils.ts +85 -85
  84. package/components/common/wizards/datastore/add/steps/typeMode/lib/config/typeOptions.ts +43 -43
  85. package/composables/useAppVersion.ts +21 -21
  86. package/composables/useLocal.ts +6 -6
  87. package/composables/useLocalCommon.ts +39 -39
  88. package/package.json +1 -1
  89. package/plugins/console.ts +21 -21
  90. package/plugins/mouse.ts +21 -21
  91. package/plugins/panelStates.ts +70 -70
  92. package/plugins/text.ts +59 -59
  93. package/public/spice-console/application/clientgui.js +854 -854
  94. package/public/spice-console/application/packetfactory.js +211 -211
  95. package/public/spice-console/application/virtualmouse.js +147 -147
  96. package/public/spice-console/lib/images/bitmap.js +203 -203
  97. package/public/spice-console/network/spicechannel.js +440 -440
  98. package/public/spice-console/process/cursorprocess.js +128 -128
  99. package/public/spice-console/process/inputprocess.js +227 -227
  100. package/public/spice-console/process/mainprocess.js +212 -212
  101. package/public/spice-console/run.js +210 -210
  102. package/store/main/mutations.ts +7 -7
  103. package/store/main/state.ts +7 -7
  104. package/store/tasks/mappers/recentTasks.ts +123 -123
  105. package/store/tasks/mutations.ts +82 -82
@@ -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>