bfg-common 1.5.447 → 1.5.449

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