bfg-common 1.5.92 → 1.5.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/assets/scss/common/normalize.scss +347 -347
  2. package/components/atoms/alert/Notification.vue +169 -169
  3. package/components/atoms/autocomplete/Autocomplete.vue +361 -362
  4. package/components/atoms/collapse/CollapseNav.vue +169 -169
  5. package/components/atoms/comboDropdownMenu/ComboDropdownMenu.vue +357 -357
  6. package/components/atoms/combobox/Combobox.vue +154 -154
  7. package/components/atoms/datepicker/Datepicker.vue +639 -639
  8. package/components/atoms/dropdown/Portlet.vue +113 -113
  9. package/components/atoms/dropdown/dropdown/Dropdown.vue +168 -168
  10. package/components/atoms/dropdown/tree/Tree.vue +137 -137
  11. package/components/atoms/list/SelectList.vue +63 -63
  12. package/components/atoms/list/dragDropList/DragDropList.vue +148 -148
  13. package/components/atoms/modal/Modal.vue +250 -250
  14. package/components/atoms/modal/bySteps/BySteps.vue +253 -253
  15. package/components/atoms/notificationBar/NotificationBar.vue +178 -178
  16. package/components/atoms/popover/Popover.vue +58 -58
  17. package/components/atoms/popover/lib/models/interfaces.ts +4 -4
  18. package/components/atoms/select/TheSelect.vue +187 -187
  19. package/components/atoms/stack/StackBlock.vue +185 -185
  20. package/components/atoms/stack/StackContent.vue +63 -63
  21. package/components/atoms/step/lib/models/verticalStepItem.ts +5 -5
  22. package/components/atoms/switch/Switch.vue +111 -111
  23. package/components/atoms/table/compact/Compact.vue +529 -529
  24. package/components/atoms/table/dataGrid/DataGrid.vue +1716 -1713
  25. package/components/atoms/table/dataGrid/DataGridPage.vue +195 -195
  26. package/components/atoms/table/info/Info.vue +2 -2
  27. package/components/atoms/table/simpleEvent/SimpleEvent.vue +98 -98
  28. package/components/atoms/table/simpleInfo/SimpleInfo.vue +73 -73
  29. package/components/atoms/tabs/Tabs.vue +217 -217
  30. package/components/atoms/wizard/Wizard.vue +341 -341
  31. package/components/common/accordion/Recursion.vue +222 -222
  32. package/components/common/adapterManager/AddAdapterModal.vue +561 -561
  33. package/components/common/adapterManager/ui/actions/AddAdapterButton.vue +30 -30
  34. package/components/common/adapterManager/ui/table/Table.vue +162 -162
  35. package/components/common/browse/BrowseNew.vue +237 -237
  36. package/components/common/browse/BrowseOld.vue +217 -217
  37. package/components/common/browse/blocks/TitleNew.vue +145 -145
  38. package/components/common/browse/blocks/TitleOld.vue +91 -91
  39. package/components/common/browse/blocks/contents/FilesOld.vue +72 -72
  40. package/components/common/chartOptionsModal/counters/timespan/form/FormNew.vue +262 -262
  41. package/components/common/context/Context.vue +111 -111
  42. package/components/common/context/recursion/RecursionOld.vue +228 -228
  43. package/components/common/details/DetailsItem.vue +109 -109
  44. package/components/common/feedback/Buttons.vue +229 -229
  45. package/components/common/feedback/Feedback.vue +270 -270
  46. package/components/common/feedback/Message.vue +519 -519
  47. package/components/common/graph/graphNew/GraphNew.vue +194 -194
  48. package/components/common/graph/lib/utils/renderGraph.ts +389 -389
  49. package/components/common/layout/theHeader/feedback/new/New.vue +227 -227
  50. package/components/common/layout/theHeader/feedback/new/additionalDetails/AdditionalDetails.vue +606 -606
  51. package/components/common/layout/theHeader/feedback/new/additionalDetails/Headline.vue +98 -98
  52. package/components/common/layout/theHeader/feedback/new/description/Description.vue +59 -59
  53. package/components/common/layout/theHeader/feedback/new/email/Email.vue +43 -43
  54. package/components/common/layout/theHeader/feedback/new/subtitle/Subtitle.vue +103 -103
  55. package/components/common/layout/theHeader/helpMenu/aboutNew/AboutNew.vue +112 -112
  56. package/components/common/layout/theHeader/helpMenu/aboutOld/AboutOld.vue +80 -80
  57. package/components/common/layout/theHeader/helpMenu/helpMenuOld/HelpMenuOld.vue +1 -1
  58. package/components/common/layout/theHeader/modals/Reconnect.vue +2 -2
  59. package/components/common/layout/theHeader/modals/RedirectLogin.vue +3 -3
  60. package/components/common/layout/theHeader/userMenu/modals/changePassword/ChangePassword.vue +1 -1
  61. package/components/common/layout/theHeader/userMenu/modals/changePassword/ChangePasswordNew.vue +8 -8
  62. package/components/common/layout/theHeader/userMenu/modals/changePassword/ChangePasswordOld.vue +3 -3
  63. package/components/common/layout/theHeader/userMenu/modals/preferences/PreferencesNew.vue +1 -1
  64. package/components/common/layout/theHeader/userMenu/modals/preferences/PreferencesOld.vue +1 -1
  65. package/components/common/layout/theHeader/userMenu/modals/preferences/changeLanguage/ChangeLanguage.vue +1 -1
  66. package/components/common/layout/theHeader/userMenu/modals/preferences/changeLanguage/ChangeLanguageNew.vue +1 -1
  67. package/components/common/layout/theHeader/userMenu/modals/preferences/changeLanguage/ChangeLanguageOld.vue +2 -5
  68. package/components/common/layout/theHeader/userMenu/modals/preferences/defaultConsole/DefaultConsoleOld.vue +1 -1
  69. package/components/common/layout/theHeader/userMenu/modals/preferences/inventory/InventoryNew.vue +1 -1
  70. package/components/common/layout/theHeader/userMenu/userMenuNew/UserMenuNew.vue +2 -2
  71. package/components/common/layout/theHeader/userMenu/userMenuNew/lib/config/dropMenu.ts +1 -1
  72. package/components/common/layout/theHeader/userMenu/userMenuOld/UserMenuOld.vue +1 -1
  73. package/components/common/mainNavigationPanel/MainNavigationPanelOld.vue +2 -2
  74. package/components/common/modals/Rename.vue +2 -2
  75. package/components/common/modals/confirmByInput/ConfirmByInput.vue +2 -3
  76. package/components/common/modals/confirmByInput/ConfirmByInputOld.vue +3 -3
  77. package/components/common/modals/confirmation/ConfirmationOld.vue +1 -1
  78. package/components/common/modals/unsavedChanges/UnsavedChanges.vue +1 -1
  79. package/components/common/monitor/advanced/Advanced.vue +1 -1
  80. package/components/common/monitor/advanced/AdvancedNew.vue +1 -1
  81. package/components/common/monitor/advanced/AdvancedOld.vue +1 -1
  82. package/components/common/monitor/advanced/graphView/GraphViewNew.vue +1 -1
  83. package/components/common/monitor/advanced/graphView/GraphViewOld.vue +1 -1
  84. package/components/common/monitor/advanced/table/Table.vue +1 -1
  85. package/components/common/monitor/advanced/table/tableNew/TableNew.vue +2 -2
  86. package/components/common/monitor/advanced/table/tableOld/lib/config/performanceDatatable.ts +2 -2
  87. package/components/common/monitor/advanced/tools/ToolsOld.vue +2 -2
  88. package/components/common/monitor/advanced/tools/chartOptionsModal/ChartOptionsModalOld.vue +1 -1
  89. package/components/common/monitor/advanced/tools/chartOptionsModal/NotificationOld.vue +1 -1
  90. package/components/common/monitor/advanced/tools/chartOptionsModal/actions/ActionsOld.vue +1 -1
  91. package/components/common/monitor/advanced/tools/chartOptionsModal/actions/saveOptionsModal/SaveOptionsModal.vue +1 -1
  92. package/components/common/monitor/advanced/tools/chartOptionsModal/counters/CountersNew.vue +1 -1
  93. package/components/common/monitor/advanced/tools/chartOptionsModal/counters/table/tableOld/lib/config/tableConfig.ts +2 -2
  94. package/components/common/monitor/advanced/tools/chartOptionsModal/counters/timespan/object/lib/config/objectTable.ts +10 -3
  95. package/components/common/monitor/advanced/tools/chartOptionsModal/counters/timespan/object/objectNew/ObjectNew.vue +1 -1
  96. package/components/common/monitor/advanced/tools/chartOptionsModal/counters/timespan/object/objectOld/ObjectOld.vue +2 -2
  97. package/components/common/monitor/advanced/tools/lib/utils/countCores.ts +1 -1
  98. package/components/common/monitor/lib/models/interfaces.ts +1 -1
  99. package/components/common/monitor/overview/filters/customIntervalModal/CustomIntervalModalOld.vue +3 -3
  100. package/components/common/monitor/overview/filters/customIntervalModal/customIntervalModalNew/CustomIntervalModalNew.vue +4 -3
  101. package/components/common/monitor/resourceAllocation/lib/models/interfaces.ts +8 -8
  102. package/components/common/monitor/resourceAllocation/resourceAllocation.vue +2 -2
  103. package/components/common/pages/hardwareHealth/historyTestimony/tools/chartOptionsModal/ChartOptionsModal.vue +1 -1
  104. package/components/common/pages/hardwareHealth/historyTestimony/tools/chartOptionsModal/Notification.vue +1 -1
  105. package/components/common/pages/hardwareHealth/historyTestimony/tools/chartOptionsModal/actions/SaveOptionsModal.vue +1 -1
  106. package/components/common/pages/hardwareHealth/tableView/lib/config/alertWarningTable.ts +1 -1
  107. package/components/common/pages/hardwareHealth/tableView/lib/config/historyTestimonyTable.ts +5 -5
  108. package/components/common/wizards/vm/migrate/Migrate.vue +39 -2
  109. package/components/common/wizards/vm/migrate/vmOrigin/VmOrigin.vue +92 -0
  110. package/components/common/wizards/vm/migrate/vmOrigin/lib/models/interfaces.ts +19 -0
  111. package/components/common/wizards/vm/migrate/vmOrigin/lib/utils/constructItems.ts +62 -0
  112. package/package.json +1 -1
@@ -1,606 +1,606 @@
1
- <template>
2
- <div class="additional-details">
3
- <template v-if="!optionsModel.isAnnotateImage">
4
- <common-layout-the-header-feedback-new-additional-details-headline />
5
-
6
- <ui-alert
7
- v-if="optionsModel.hasTakeScreenshot"
8
- test-id="additional-details-info-alert"
9
- :messages="[localization.common.screenshotQualityMayVary]"
10
- type="info"
11
- class="additional-details__alert"
12
- ></ui-alert>
13
- </template>
14
-
15
- <div
16
- v-if="!optionsModel.hasTakeScreenshot"
17
- class="flex gap-4 button-container"
18
- >
19
- <ui-button
20
- test-id="feedback-take-screenshot-btn"
21
- size="md"
22
- type="default"
23
- variant="outline"
24
- min-width="96px"
25
- class="take-screenshot"
26
- @click="onTakeScreenshot"
27
- >
28
- <ui-icon
29
- name="take-screenshot"
30
- width="18"
31
- height="18"
32
- class="feedback__btn-icon"
33
- />
34
- {{ localization.common.takeScreenshot }}
35
- </ui-button>
36
-
37
- <ui-button
38
- test-id="feedback-upload-file-btn"
39
- size="md"
40
- type="default"
41
- variant="outline"
42
- min-width="96px"
43
- class="upload-image"
44
- >
45
- <label id="labelFileLoad" for="fileLoad">
46
- <ui-icon
47
- name="upload-icon"
48
- width="18"
49
- height="18"
50
- class="feedback__btn-icon"
51
- />
52
- {{ localization.common.uploadImage }}
53
- </label>
54
- <input
55
- id="fileLoad"
56
- ref="isFileLoad"
57
- type="file"
58
- accept=".png, .jpeg"
59
- data-id="feedback-file-load-input"
60
- @change="onUploadFile"
61
- />
62
- </ui-button>
63
- </div>
64
-
65
- <div v-if="optionsModel.isAnnotateImage" class="drawer-btn-container">
66
- <div>
67
- <ui-button
68
- test-id="feedback-use-red-marker-button"
69
- size="sm"
70
- type="default"
71
- variant="outline"
72
- class="btn marker"
73
- :class="drawerMarker === 'marker' && 'active'"
74
- @click="onUseRedMarker"
75
- >
76
- <ui-icon
77
- name="marker"
78
- width="16"
79
- height="16"
80
- class="feedback__btn-icon"
81
- />
82
- {{ localization.common.useRedMarker }}
83
- </ui-button>
84
-
85
- <ui-button
86
- test-id="feedback-use-grey-marker-button"
87
- size="sm"
88
- type="default"
89
- variant="outline"
90
- class="btn eraser"
91
- :class="drawerMarker === 'eraser' && 'active'"
92
- @click="onUseGrayEraser"
93
- >
94
- <ui-icon
95
- name="grey-eraser"
96
- width="16"
97
- height="16"
98
- class="feedback__btn-icon"
99
- />
100
- {{ localization.common.useGrayEraser }}
101
- </ui-button>
102
- <div class="separator-line"></div>
103
- <ui-button
104
- :disabled="isDisabledButton"
105
- test-id="feedback-undo-button"
106
- size="sm"
107
- type="default"
108
- variant="outline"
109
- class="btn undo"
110
- @click="onUndoLast"
111
- >
112
- <ui-icon
113
- name="reset"
114
- width="16"
115
- height="16"
116
- class="feedback__btn-icon"
117
- />
118
- {{ localization.common.undo }}
119
- </ui-button>
120
- </div>
121
-
122
- <ui-button
123
- :disabled="isDisabledButton"
124
- test-id="feedback-clear-all-button"
125
- size="sm"
126
- type="default"
127
- variant="outline"
128
- class="btn clear-all"
129
- @click="clearAll"
130
- >
131
- <ui-icon
132
- name="delete"
133
- width="16"
134
- height="16"
135
- class="feedback__btn-icon"
136
- />
137
- {{ localization.common.clearAll }}
138
- </ui-button>
139
- </div>
140
-
141
- <div
142
- :class="[
143
- 'preview-container',
144
- {
145
- disabled: !optionsModel.hasTakeScreenshot,
146
- annotate: optionsModel.isAnnotateImage,
147
- },
148
- ]"
149
- id="feedbackImgWrap"
150
- ref="feedbackImgWrap"
151
- >
152
- <div class="preview-container__backdrop">
153
- <div>
154
- <ui-button
155
- test-id="feedback-image-annotate-btn"
156
- size="sm"
157
- type="default"
158
- variant="outline"
159
- class=""
160
- @click="onAnnotateImage"
161
- >
162
- <ui-icon
163
- name="annotate-icon"
164
- width="16"
165
- height="16"
166
- class="feedback__btn-icon"
167
- />
168
- {{ localization.feedback.annotate }}
169
- </ui-button>
170
-
171
- <ui-button
172
- test-id="feedback-image-remove-btn"
173
- size="sm"
174
- type="default"
175
- variant="outline"
176
- class=""
177
- @click="onRemoveScreenshot"
178
- >
179
- <ui-icon
180
- name="delete"
181
- width="16"
182
- height="16"
183
- class="feedback__btn-icon"
184
- />
185
- {{ localization.common.remove }}
186
- </ui-button>
187
- </div>
188
- </div>
189
- <canvas
190
- id="feedbackImg"
191
- ref="feedbackImg"
192
- class="preview-container__image"
193
- ></canvas>
194
- <canvas id="feedbackImgBlank" class="d-none"></canvas>
195
- </div>
196
- </div>
197
- </template>
198
-
199
- <script lang="ts" setup>
200
- import html2canvas from 'html2canvas'
201
- import type { UI_I_Localization } from '~/lib/models/interfaces'
202
- import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
203
-
204
- const optionsModel = defineModel<UI_I_FeedbackCanvasOptions>({ required: true })
205
-
206
- const localization = computed<UI_I_Localization>(() => useLocal())
207
-
208
- const drawerMarker = ref<'marker' | 'eraser' | null>(null)
209
- const isFileLoad = ref(null)
210
- const feedbackImgWrap = ref()
211
- const feedbackImg = ref()
212
- const memoryParentModalDialog = ref<string>('')
213
- const memoryParentMain = ref<string>('')
214
-
215
- let drawingArray: any = []
216
- const indexArray = ref<number>(0) // index of feedbackImg itself
217
- let isDrawing = false
218
- let startDrawingX: number | null = null
219
- let startDrawingY: number | null = null
220
- let drawColor = ''
221
- let drawWidth = ''
222
-
223
- const isDisabledButton = computed<boolean>(() => indexArray.value === 0)
224
-
225
- const onTakeScreenshot = (): void => {
226
- optionsModel.value.hasTakeScreenshot = true
227
-
228
- const feedbackDialog = document.getElementById('feedback-dialog')
229
- if (!feedbackDialog) return
230
-
231
- const display = feedbackDialog.style.display
232
- feedbackDialog.style.display = 'none'
233
- html2canvas(document.body).then(function (thisCanvas) {
234
- feedbackDialog.style.display = display
235
-
236
- const context = feedbackImg.value.getContext('2d')
237
- feedbackImg.value.width = thisCanvas.width
238
- feedbackImg.value.height = thisCanvas.height
239
-
240
- feedbackImg.value.style.width = '500px'
241
- feedbackImg.value.style.height =
242
- thisCanvas.height / (thisCanvas.width / 500) + 'px'
243
-
244
- context.drawImage(
245
- thisCanvas,
246
- 0,
247
- 0,
248
- feedbackImg.value.width,
249
- feedbackImg.value.height
250
- )
251
- drawingArray.length = 0
252
- indexArray.value = 0
253
- drawingArray.push(
254
- context.getImageData(
255
- 0,
256
- 0,
257
- feedbackImg.value.width,
258
- feedbackImg.value.height
259
- )
260
- )
261
- })
262
- }
263
- const onUploadFile = (): void => {
264
- optionsModel.value.hasTakeScreenshot = true
265
- if (!isFileLoad.value) return
266
-
267
- const isFileRead = new FileReader()
268
- if (!isFileRead) return
269
-
270
- isFileRead.readAsDataURL(isFileLoad.value.files[0])
271
- isFileRead.onload = (): void => {
272
- const img = new Image()
273
- if (!feedbackImg.value) return
274
-
275
- const context = feedbackImg.value.getContext('2d')
276
- img.onload = (): void => {
277
- feedbackImg.value.width = img.width
278
- feedbackImg.value.height = img.height
279
-
280
- updateFeedbackImageDimensions()
281
-
282
- context.drawImage(img, 0, 0, img.width, img.height)
283
- drawingArray.length = 0
284
- indexArray.value = 0
285
- drawingArray.push(
286
- context.getImageData(
287
- 0,
288
- 0,
289
- feedbackImg.value.width,
290
- feedbackImg.value.height
291
- )
292
- )
293
- }
294
- img.src = isFileRead.result
295
- }
296
- }
297
-
298
- const start = (event: MouseEvent): void => {
299
- if (!drawColor) return
300
- const context = feedbackImg.value.getContext('2d')
301
- const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
302
- startDrawingX = event.pageX - canvasCoordinates.left
303
- startDrawingY = event.pageY - canvasCoordinates.top
304
- isDrawing = true
305
- context.beginPath()
306
- context.moveTo(
307
- event.pageX - canvasCoordinates.left,
308
- event.pageY - canvasCoordinates.top
309
- )
310
- event.preventDefault()
311
- }
312
- const draw = (event: MouseEvent): void => {
313
- if (!drawColor) return
314
- const context = feedbackImg.value.getContext('2d')
315
- const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
316
- if (!isDrawing) return
317
- context.lineTo(
318
- event.pageX - canvasCoordinates.left,
319
- event.pageY - canvasCoordinates.top
320
- )
321
- context.strokeStyle = drawColor
322
- context.lineWidth = drawWidth
323
- context.lineCap = 'round'
324
- context.lineJoin = 'round'
325
- context.stroke()
326
- event.preventDefault()
327
- }
328
-
329
- const stop = (event: MouseEvent): void => {
330
- if (!drawColor) return
331
-
332
- const context = feedbackImg.value.getContext('2d')
333
- const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
334
- if (!isDrawing) return
335
-
336
- context.stroke()
337
- context.closePath()
338
- isDrawing = false
339
- event.preventDefault()
340
- if (
341
- startDrawingX !== event.pageX - canvasCoordinates.left &&
342
- startDrawingY !== event.pageY - canvasCoordinates.top
343
- ) {
344
- drawingArray.push(
345
- context.getImageData(
346
- 0,
347
- 0,
348
- feedbackImg.value.width,
349
- feedbackImg.value.height
350
- )
351
- )
352
- indexArray.value += 1
353
- }
354
- }
355
- const onRemoveScreenshot = (): void => {
356
- optionsModel.value.hasTakeScreenshot = false
357
- const parentMain = document.getElementById('feedback-dialog')
358
- const parentModalDialog = document.getElementById('feedback-modal-dialog-Id')
359
- if (!parentMain || !parentModalDialog) return
360
-
361
- parentMain.style.width = memoryParentMain.value
362
- parentModalDialog.style.width = memoryParentModalDialog.value
363
- const context = feedbackImg.value.getContext('2d')
364
- context.fillStyle = 'green'
365
- context.fillRect(0, 0, feedbackImg.value.width, feedbackImg.value.height)
366
- feedbackImg.value.width = 0
367
- feedbackImg.value.height = 0
368
- feedbackImgWrap.value.style.width = 0 + 'px'
369
- feedbackImgWrap.value.style.height = 0 + 'px'
370
- // const value = {
371
- // width: memoryParentModalDialog.value,
372
- // }
373
- // emits('screen-shot', value)
374
- clearAll()
375
- }
376
- const onUseRedMarker = (): void => {
377
- drawerMarker.value = 'marker'
378
- drawColor = '#f76945'
379
- drawWidth = '5'
380
- }
381
- const onUseGrayEraser = (): void => {
382
- drawerMarker.value = 'eraser'
383
- drawColor = 'lightgray'
384
- drawWidth = '14'
385
- }
386
-
387
- const onUndoLast = (): void => {
388
- drawColor = ''
389
- drawWidth = ''
390
- drawerMarker.value = null
391
- const context = feedbackImg.value.getContext('2d')
392
- if (indexArray.value > 0) {
393
- indexArray.value -= 1
394
- drawingArray.pop()
395
- context.putImageData(drawingArray[indexArray.value], 0, 0)
396
- }
397
- }
398
- const clearAll = (): void => {
399
- const context = feedbackImg.value.getContext('2d')
400
- drawColor = ''
401
- drawWidth = ''
402
- drawerMarker.value = null
403
- if (indexArray.value <= 0) return
404
- while (indexArray.value > 0) {
405
- drawingArray.pop()
406
- indexArray.value -= 1
407
- context.putImageData(drawingArray[indexArray.value], 0, 0)
408
- }
409
- }
410
-
411
- onMounted(() => {
412
- feedbackImg.value.addEventListener('touchstart', start, false)
413
- feedbackImg.value.addEventListener('touchmove', draw, false)
414
- feedbackImg.value.addEventListener('mousedown', start, false)
415
- feedbackImg.value.addEventListener('mousemove', draw, false)
416
- feedbackImg.value.addEventListener('touchend', stop, false)
417
- feedbackImg.value.addEventListener('mouseup', stop, false)
418
- feedbackImg.value.addEventListener('mouseout', stop, false)
419
- })
420
-
421
- onBeforeUnmount(() => {
422
- onRemoveScreenshot()
423
- feedbackImg.value.removeEventListener('touchstart', start, false)
424
- feedbackImg.value.removeEventListener('touchmove', draw, false)
425
- feedbackImg.value.removeEventListener('mousedown', start, false)
426
- feedbackImg.value.removeEventListener('mousemove', draw, false)
427
- feedbackImg.value.removeEventListener('touchend', stop, false)
428
- feedbackImg.value.removeEventListener('mouseup', stop, false)
429
- feedbackImg.value.removeEventListener('mouseout', stop, false)
430
- })
431
- const onAnnotateImage = (): void => {
432
- feedbackImg.value.style.width = feedbackImg.value.width + 'px'
433
- feedbackImg.value.style.height = feedbackImg.value.height + 'px'
434
-
435
- optionsModel.value.isAnnotateImage = true
436
- }
437
-
438
- const updateFeedbackImageDimensions = (): void => {
439
- if (feedbackImg.value) {
440
- feedbackImg.value.style.width = '500px'
441
- feedbackImg.value.style.height =
442
- feedbackImg.value.height / (feedbackImg.value.width / 500) + 'px'
443
- }
444
- }
445
- const resetDrawingState = (): void => {
446
- drawingArray = [drawingArray.at(-1)]
447
- indexArray.value = 0
448
- }
449
-
450
- watch(
451
- optionsModel,
452
- (newValue: UI_I_FeedbackCanvasOptions) => {
453
- if (!newValue.isAnnotateImage) {
454
- updateFeedbackImageDimensions()
455
- resetDrawingState()
456
- }
457
- },
458
- { deep: true, immediate: true }
459
- )
460
- </script>
461
-
462
- <style>
463
- :root {
464
- --upload-image-hover-bg-color: #f6f7f8;
465
- }
466
- :root.dark-theme {
467
- --upload-image-hover-bg-color: #283948;
468
- }
469
- </style>
470
-
471
- <style lang="scss" scoped>
472
- @import 'assets/scss/common/mixins.scss';
473
- .additional-details {
474
- .button-container {
475
- :deep(.ui-btn) {
476
- font-size: 13px;
477
- gap: 8px;
478
- }
479
- .upload-image {
480
- &:hover {
481
- background-color: var(--upload-image-hover-bg-color);
482
- }
483
- label {
484
- @include flex($align: center, $just: center);
485
- width: 100%;
486
- height: 100%;
487
- color: inherit;
488
- //font-size: 13px;
489
- font-weight: 500;
490
- gap: 8px;
491
- cursor: pointer;
492
- }
493
- input {
494
- display: none;
495
- }
496
- }
497
- }
498
- .drawer-btn-container {
499
- @include flex($align: center, $just: space-between);
500
- margin-bottom: 12px;
501
- & > div {
502
- @include flex($align: center, $just: space-between);
503
- gap: 15px;
504
-
505
- .separator-line {
506
- width: 1px;
507
- height: 24px;
508
- background: #e9ebed1f;
509
- margin: 0;
510
- }
511
- }
512
-
513
- .ui-btn {
514
- width: initial;
515
- height: 28px;
516
- font-size: 12px;
517
- padding: 0 8px;
518
- column-gap: 4px;
519
- border-radius: 6px;
520
-
521
- &.undo {
522
- &:disabled {
523
- color: var(--btn-primary-outline-disabled-color);
524
- }
525
- svg {
526
- transform: scaleX(-1);
527
- }
528
- }
529
- &.clear-all {
530
- color: #ea3223;
531
- &:disabled {
532
- color: var(--btn-primary-outline-disabled-color);
533
- }
534
- }
535
-
536
- &.active {
537
- color: var(--feedback-tab-active-text-color);
538
- border: 1.4px solid var(--feedback-tab-active-text-color);
539
- &:hover {
540
- background: var(--feedback-tab-active-bg-color);
541
- }
542
- }
543
- }
544
- }
545
-
546
- &__alert {
547
- margin-bottom: 16px;
548
- }
549
- }
550
- .preview-container {
551
- width: 500px;
552
- height: 280px;
553
- position: relative;
554
- &.annotate {
555
- width: 100%;
556
- height: 460px;
557
- overflow: auto;
558
- }
559
- &.disabled {
560
- display: none;
561
- }
562
-
563
- &__backdrop {
564
- display: none;
565
- position: absolute;
566
- top: 0;
567
- left: 0;
568
- width: 100%;
569
- height: 100%;
570
- background: rgba(27, 42, 55, 0.32);
571
- backdrop-filter: blur(1.5px);
572
- border-radius: 8px;
573
- transition: opacity 0.3s ease;
574
- opacity: 0;
575
-
576
- & > div {
577
- @include flex($align: center);
578
- gap: 12px;
579
- .ui-btn {
580
- width: initial;
581
- font-size: 12px;
582
- line-height: 14.52px;
583
- column-gap: 4px;
584
-
585
- &:last-child {
586
- color: #ea3223;
587
- }
588
- }
589
- }
590
- }
591
-
592
- &__image {
593
- width: inherit;
594
- height: inherit;
595
- border-radius: 8px;
596
- .disabled & {
597
- display: none;
598
- }
599
- }
600
-
601
- &:hover:not(&.annotate) &__backdrop {
602
- @include flex($align: center, $just: center);
603
- opacity: 1;
604
- }
605
- }
606
- </style>
1
+ <template>
2
+ <div class="additional-details">
3
+ <template v-if="!optionsModel.isAnnotateImage">
4
+ <common-layout-the-header-feedback-new-additional-details-headline />
5
+
6
+ <ui-alert
7
+ v-if="optionsModel.hasTakeScreenshot"
8
+ test-id="additional-details-info-alert"
9
+ :messages="[localization.common.screenshotQualityMayVary]"
10
+ type="info"
11
+ class="additional-details__alert"
12
+ ></ui-alert>
13
+ </template>
14
+
15
+ <div
16
+ v-if="!optionsModel.hasTakeScreenshot"
17
+ class="flex gap-4 button-container"
18
+ >
19
+ <ui-button
20
+ test-id="feedback-take-screenshot-btn"
21
+ size="md"
22
+ type="default"
23
+ variant="outline"
24
+ min-width="96px"
25
+ class="take-screenshot"
26
+ @click="onTakeScreenshot"
27
+ >
28
+ <ui-icon
29
+ name="take-screenshot"
30
+ width="18"
31
+ height="18"
32
+ class="feedback__btn-icon"
33
+ />
34
+ {{ localization.common.takeScreenshot }}
35
+ </ui-button>
36
+
37
+ <ui-button
38
+ test-id="feedback-upload-file-btn"
39
+ size="md"
40
+ type="default"
41
+ variant="outline"
42
+ min-width="96px"
43
+ class="upload-image"
44
+ >
45
+ <label id="labelFileLoad" for="fileLoad">
46
+ <ui-icon
47
+ name="upload-icon"
48
+ width="18"
49
+ height="18"
50
+ class="feedback__btn-icon"
51
+ />
52
+ {{ localization.common.uploadImage }}
53
+ </label>
54
+ <input
55
+ id="fileLoad"
56
+ ref="isFileLoad"
57
+ type="file"
58
+ accept=".png, .jpeg"
59
+ data-id="feedback-file-load-input"
60
+ @change="onUploadFile"
61
+ />
62
+ </ui-button>
63
+ </div>
64
+
65
+ <div v-if="optionsModel.isAnnotateImage" class="drawer-btn-container">
66
+ <div>
67
+ <ui-button
68
+ test-id="feedback-use-red-marker-button"
69
+ size="sm"
70
+ type="default"
71
+ variant="outline"
72
+ class="btn marker"
73
+ :class="drawerMarker === 'marker' && 'active'"
74
+ @click="onUseRedMarker"
75
+ >
76
+ <ui-icon
77
+ name="marker"
78
+ width="16"
79
+ height="16"
80
+ class="feedback__btn-icon"
81
+ />
82
+ {{ localization.common.useRedMarker }}
83
+ </ui-button>
84
+
85
+ <ui-button
86
+ test-id="feedback-use-grey-marker-button"
87
+ size="sm"
88
+ type="default"
89
+ variant="outline"
90
+ class="btn eraser"
91
+ :class="drawerMarker === 'eraser' && 'active'"
92
+ @click="onUseGrayEraser"
93
+ >
94
+ <ui-icon
95
+ name="grey-eraser"
96
+ width="16"
97
+ height="16"
98
+ class="feedback__btn-icon"
99
+ />
100
+ {{ localization.common.useGrayEraser }}
101
+ </ui-button>
102
+ <div class="separator-line"></div>
103
+ <ui-button
104
+ :disabled="isDisabledButton"
105
+ test-id="feedback-undo-button"
106
+ size="sm"
107
+ type="default"
108
+ variant="outline"
109
+ class="btn undo"
110
+ @click="onUndoLast"
111
+ >
112
+ <ui-icon
113
+ name="reset"
114
+ width="16"
115
+ height="16"
116
+ class="feedback__btn-icon"
117
+ />
118
+ {{ localization.common.undo }}
119
+ </ui-button>
120
+ </div>
121
+
122
+ <ui-button
123
+ :disabled="isDisabledButton"
124
+ test-id="feedback-clear-all-button"
125
+ size="sm"
126
+ type="default"
127
+ variant="outline"
128
+ class="btn clear-all"
129
+ @click="clearAll"
130
+ >
131
+ <ui-icon
132
+ name="delete"
133
+ width="16"
134
+ height="16"
135
+ class="feedback__btn-icon"
136
+ />
137
+ {{ localization.common.clearAll }}
138
+ </ui-button>
139
+ </div>
140
+
141
+ <div
142
+ id="feedbackImgWrap"
143
+ :class="[
144
+ 'preview-container',
145
+ {
146
+ disabled: !optionsModel.hasTakeScreenshot,
147
+ annotate: optionsModel.isAnnotateImage,
148
+ },
149
+ ]"
150
+ ref="feedbackImgWrap"
151
+ >
152
+ <div class="preview-container__backdrop">
153
+ <div>
154
+ <ui-button
155
+ test-id="feedback-image-annotate-btn"
156
+ size="sm"
157
+ type="default"
158
+ variant="outline"
159
+ class=""
160
+ @click="onAnnotateImage"
161
+ >
162
+ <ui-icon
163
+ name="annotate-icon"
164
+ width="16"
165
+ height="16"
166
+ class="feedback__btn-icon"
167
+ />
168
+ {{ localization.feedback.annotate }}
169
+ </ui-button>
170
+
171
+ <ui-button
172
+ test-id="feedback-image-remove-btn"
173
+ size="sm"
174
+ type="default"
175
+ variant="outline"
176
+ class=""
177
+ @click="onRemoveScreenshot"
178
+ >
179
+ <ui-icon
180
+ name="delete"
181
+ width="16"
182
+ height="16"
183
+ class="feedback__btn-icon"
184
+ />
185
+ {{ localization.common.remove }}
186
+ </ui-button>
187
+ </div>
188
+ </div>
189
+ <canvas
190
+ id="feedbackImg"
191
+ ref="feedbackImg"
192
+ class="preview-container__image"
193
+ ></canvas>
194
+ <canvas id="feedbackImgBlank" style="display: none"></canvas>
195
+ </div>
196
+ </div>
197
+ </template>
198
+
199
+ <script lang="ts" setup>
200
+ import html2canvas from 'html2canvas'
201
+ import type { UI_I_Localization } from '~/lib/models/interfaces'
202
+ import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
203
+
204
+ const optionsModel = defineModel<UI_I_FeedbackCanvasOptions>({ required: true })
205
+
206
+ const localization = computed<UI_I_Localization>(() => useLocal())
207
+
208
+ const drawerMarker = ref<'marker' | 'eraser' | null>(null)
209
+ const isFileLoad = ref(null)
210
+ const feedbackImgWrap = ref()
211
+ const feedbackImg = ref()
212
+ const memoryParentModalDialog = ref<string>('')
213
+ const memoryParentMain = ref<string>('')
214
+
215
+ let drawingArray: any = []
216
+ const indexArray = ref<number>(0) // index of feedbackImg itself
217
+ let isDrawing = false
218
+ let startDrawingX: number | null = null
219
+ let startDrawingY: number | null = null
220
+ let drawColor = ''
221
+ let drawWidth = ''
222
+
223
+ const isDisabledButton = computed<boolean>(() => indexArray.value === 0)
224
+
225
+ const onTakeScreenshot = (): void => {
226
+ optionsModel.value.hasTakeScreenshot = true
227
+
228
+ const feedbackDialog = document.getElementById('feedback-dialog')
229
+ if (!feedbackDialog) return
230
+
231
+ const display = feedbackDialog.style.display
232
+ feedbackDialog.style.display = 'none'
233
+ html2canvas(document.body).then(function (thisCanvas) {
234
+ feedbackDialog.style.display = display
235
+
236
+ const context = feedbackImg.value.getContext('2d')
237
+ feedbackImg.value.width = thisCanvas.width
238
+ feedbackImg.value.height = thisCanvas.height
239
+
240
+ feedbackImg.value.style.width = '500px'
241
+ feedbackImg.value.style.height =
242
+ thisCanvas.height / (thisCanvas.width / 500) + 'px'
243
+
244
+ context.drawImage(
245
+ thisCanvas,
246
+ 0,
247
+ 0,
248
+ feedbackImg.value.width,
249
+ feedbackImg.value.height
250
+ )
251
+ drawingArray.length = 0
252
+ indexArray.value = 0
253
+ drawingArray.push(
254
+ context.getImageData(
255
+ 0,
256
+ 0,
257
+ feedbackImg.value.width,
258
+ feedbackImg.value.height
259
+ )
260
+ )
261
+ })
262
+ }
263
+ const onUploadFile = (): void => {
264
+ optionsModel.value.hasTakeScreenshot = true
265
+ if (!isFileLoad.value) return
266
+
267
+ const isFileRead = new FileReader()
268
+ if (!isFileRead) return
269
+
270
+ isFileRead.readAsDataURL(isFileLoad.value.files[0])
271
+ isFileRead.onload = (): void => {
272
+ const img = new Image()
273
+ if (!feedbackImg.value) return
274
+
275
+ const context = feedbackImg.value.getContext('2d')
276
+ img.onload = (): void => {
277
+ feedbackImg.value.width = img.width
278
+ feedbackImg.value.height = img.height
279
+
280
+ updateFeedbackImageDimensions()
281
+
282
+ context.drawImage(img, 0, 0, img.width, img.height)
283
+ drawingArray.length = 0
284
+ indexArray.value = 0
285
+ drawingArray.push(
286
+ context.getImageData(
287
+ 0,
288
+ 0,
289
+ feedbackImg.value.width,
290
+ feedbackImg.value.height
291
+ )
292
+ )
293
+ }
294
+ img.src = isFileRead.result
295
+ }
296
+ }
297
+
298
+ const start = (event: MouseEvent): void => {
299
+ if (!drawColor) return
300
+ const context = feedbackImg.value.getContext('2d')
301
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
302
+ startDrawingX = event.pageX - canvasCoordinates.left
303
+ startDrawingY = event.pageY - canvasCoordinates.top
304
+ isDrawing = true
305
+ context.beginPath()
306
+ context.moveTo(
307
+ event.pageX - canvasCoordinates.left,
308
+ event.pageY - canvasCoordinates.top
309
+ )
310
+ event.preventDefault()
311
+ }
312
+ const draw = (event: MouseEvent): void => {
313
+ if (!drawColor) return
314
+ const context = feedbackImg.value.getContext('2d')
315
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
316
+ if (!isDrawing) return
317
+ context.lineTo(
318
+ event.pageX - canvasCoordinates.left,
319
+ event.pageY - canvasCoordinates.top
320
+ )
321
+ context.strokeStyle = drawColor
322
+ context.lineWidth = drawWidth
323
+ context.lineCap = 'round'
324
+ context.lineJoin = 'round'
325
+ context.stroke()
326
+ event.preventDefault()
327
+ }
328
+
329
+ const stop = (event: MouseEvent): void => {
330
+ if (!drawColor) return
331
+
332
+ const context = feedbackImg.value.getContext('2d')
333
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
334
+ if (!isDrawing) return
335
+
336
+ context.stroke()
337
+ context.closePath()
338
+ isDrawing = false
339
+ event.preventDefault()
340
+ if (
341
+ startDrawingX !== event.pageX - canvasCoordinates.left &&
342
+ startDrawingY !== event.pageY - canvasCoordinates.top
343
+ ) {
344
+ drawingArray.push(
345
+ context.getImageData(
346
+ 0,
347
+ 0,
348
+ feedbackImg.value.width,
349
+ feedbackImg.value.height
350
+ )
351
+ )
352
+ indexArray.value += 1
353
+ }
354
+ }
355
+ const onRemoveScreenshot = (): void => {
356
+ optionsModel.value.hasTakeScreenshot = false
357
+ const parentMain = document.getElementById('feedback-dialog')
358
+ const parentModalDialog = document.getElementById('feedback-modal-dialog-Id')
359
+ if (!parentMain || !parentModalDialog) return
360
+
361
+ parentMain.style.width = memoryParentMain.value
362
+ parentModalDialog.style.width = memoryParentModalDialog.value
363
+ const context = feedbackImg.value.getContext('2d')
364
+ context.fillStyle = 'green'
365
+ context.fillRect(0, 0, feedbackImg.value.width, feedbackImg.value.height)
366
+ feedbackImg.value.width = 0
367
+ feedbackImg.value.height = 0
368
+ feedbackImgWrap.value.style.width = 0 + 'px'
369
+ feedbackImgWrap.value.style.height = 0 + 'px'
370
+ // const value = {
371
+ // width: memoryParentModalDialog.value,
372
+ // }
373
+ // emits('screen-shot', value)
374
+ clearAll()
375
+ }
376
+ const onUseRedMarker = (): void => {
377
+ drawerMarker.value = 'marker'
378
+ drawColor = '#f76945'
379
+ drawWidth = '5'
380
+ }
381
+ const onUseGrayEraser = (): void => {
382
+ drawerMarker.value = 'eraser'
383
+ drawColor = 'lightgray'
384
+ drawWidth = '14'
385
+ }
386
+
387
+ const onUndoLast = (): void => {
388
+ drawColor = ''
389
+ drawWidth = ''
390
+ drawerMarker.value = null
391
+ const context = feedbackImg.value.getContext('2d')
392
+ if (indexArray.value > 0) {
393
+ indexArray.value -= 1
394
+ drawingArray.pop()
395
+ context.putImageData(drawingArray[indexArray.value], 0, 0)
396
+ }
397
+ }
398
+ const clearAll = (): void => {
399
+ const context = feedbackImg.value.getContext('2d')
400
+ drawColor = ''
401
+ drawWidth = ''
402
+ drawerMarker.value = null
403
+ if (indexArray.value <= 0) return
404
+ while (indexArray.value > 0) {
405
+ drawingArray.pop()
406
+ indexArray.value -= 1
407
+ context.putImageData(drawingArray[indexArray.value], 0, 0)
408
+ }
409
+ }
410
+
411
+ onMounted(() => {
412
+ feedbackImg.value.addEventListener('touchstart', start, false)
413
+ feedbackImg.value.addEventListener('touchmove', draw, false)
414
+ feedbackImg.value.addEventListener('mousedown', start, false)
415
+ feedbackImg.value.addEventListener('mousemove', draw, false)
416
+ feedbackImg.value.addEventListener('touchend', stop, false)
417
+ feedbackImg.value.addEventListener('mouseup', stop, false)
418
+ feedbackImg.value.addEventListener('mouseout', stop, false)
419
+ })
420
+
421
+ onBeforeUnmount(() => {
422
+ onRemoveScreenshot()
423
+ feedbackImg.value.removeEventListener('touchstart', start, false)
424
+ feedbackImg.value.removeEventListener('touchmove', draw, false)
425
+ feedbackImg.value.removeEventListener('mousedown', start, false)
426
+ feedbackImg.value.removeEventListener('mousemove', draw, false)
427
+ feedbackImg.value.removeEventListener('touchend', stop, false)
428
+ feedbackImg.value.removeEventListener('mouseup', stop, false)
429
+ feedbackImg.value.removeEventListener('mouseout', stop, false)
430
+ })
431
+ const onAnnotateImage = (): void => {
432
+ feedbackImg.value.style.width = feedbackImg.value.width + 'px'
433
+ feedbackImg.value.style.height = feedbackImg.value.height + 'px'
434
+
435
+ optionsModel.value.isAnnotateImage = true
436
+ }
437
+
438
+ const updateFeedbackImageDimensions = (): void => {
439
+ if (feedbackImg.value) {
440
+ feedbackImg.value.style.width = '500px'
441
+ feedbackImg.value.style.height =
442
+ feedbackImg.value.height / (feedbackImg.value.width / 500) + 'px'
443
+ }
444
+ }
445
+ const resetDrawingState = (): void => {
446
+ drawingArray = [drawingArray.at(-1)]
447
+ indexArray.value = 0
448
+ }
449
+
450
+ watch(
451
+ optionsModel,
452
+ (newValue: UI_I_FeedbackCanvasOptions) => {
453
+ if (!newValue.isAnnotateImage) {
454
+ updateFeedbackImageDimensions()
455
+ resetDrawingState()
456
+ }
457
+ },
458
+ { deep: true, immediate: true }
459
+ )
460
+ </script>
461
+
462
+ <style>
463
+ :root {
464
+ --upload-image-hover-bg-color: #f6f7f8;
465
+ }
466
+ :root.dark-theme {
467
+ --upload-image-hover-bg-color: #283948;
468
+ }
469
+ </style>
470
+
471
+ <style lang="scss" scoped>
472
+ @import 'assets/scss/common/mixins.scss';
473
+ .additional-details {
474
+ .button-container {
475
+ :deep(.ui-btn) {
476
+ font-size: 13px;
477
+ gap: 8px;
478
+ }
479
+ .upload-image {
480
+ &:hover {
481
+ background-color: var(--upload-image-hover-bg-color);
482
+ }
483
+ label {
484
+ @include flex($align: center, $just: center);
485
+ width: 100%;
486
+ height: 100%;
487
+ color: inherit;
488
+ //font-size: 13px;
489
+ font-weight: 500;
490
+ gap: 8px;
491
+ cursor: pointer;
492
+ }
493
+ input {
494
+ display: none;
495
+ }
496
+ }
497
+ }
498
+ .drawer-btn-container {
499
+ @include flex($align: center, $just: space-between);
500
+ margin-bottom: 12px;
501
+ & > div {
502
+ @include flex($align: center, $just: space-between);
503
+ gap: 15px;
504
+
505
+ .separator-line {
506
+ width: 1px;
507
+ height: 24px;
508
+ background: #e9ebed1f;
509
+ margin: 0;
510
+ }
511
+ }
512
+
513
+ .ui-btn {
514
+ width: initial;
515
+ height: 28px;
516
+ font-size: 12px;
517
+ padding: 0 8px;
518
+ column-gap: 4px;
519
+ border-radius: 6px;
520
+
521
+ &.undo {
522
+ &:disabled {
523
+ color: var(--btn-primary-outline-disabled-color);
524
+ }
525
+ svg {
526
+ transform: scaleX(-1);
527
+ }
528
+ }
529
+ &.clear-all {
530
+ color: #ea3223;
531
+ &:disabled {
532
+ color: var(--btn-primary-outline-disabled-color);
533
+ }
534
+ }
535
+
536
+ &.active {
537
+ color: var(--feedback-tab-active-text-color);
538
+ border: 1.4px solid var(--feedback-tab-active-text-color);
539
+ &:hover {
540
+ background: var(--feedback-tab-active-bg-color);
541
+ }
542
+ }
543
+ }
544
+ }
545
+
546
+ &__alert {
547
+ margin-bottom: 16px;
548
+ }
549
+ }
550
+ .preview-container {
551
+ width: 500px;
552
+ height: 280px;
553
+ position: relative;
554
+ &.annotate {
555
+ width: 100%;
556
+ height: 460px;
557
+ overflow: auto;
558
+ }
559
+ &.disabled {
560
+ display: none;
561
+ }
562
+
563
+ &__backdrop {
564
+ display: none;
565
+ position: absolute;
566
+ top: 0;
567
+ left: 0;
568
+ width: 100%;
569
+ height: 100%;
570
+ background: rgba(27, 42, 55, 0.32);
571
+ backdrop-filter: blur(1.5px);
572
+ border-radius: 8px;
573
+ transition: opacity 0.3s ease;
574
+ opacity: 0;
575
+
576
+ & > div {
577
+ @include flex($align: center);
578
+ gap: 12px;
579
+ .ui-btn {
580
+ width: initial;
581
+ font-size: 12px;
582
+ line-height: 14.52px;
583
+ column-gap: 4px;
584
+
585
+ &:last-child {
586
+ color: #ea3223;
587
+ }
588
+ }
589
+ }
590
+ }
591
+
592
+ &__image {
593
+ width: inherit;
594
+ height: inherit;
595
+ border-radius: 8px;
596
+ .disabled & {
597
+ display: none;
598
+ }
599
+ }
600
+
601
+ &:hover:not(&.annotate) &__backdrop {
602
+ @include flex($align: center, $just: center);
603
+ opacity: 1;
604
+ }
605
+ }
606
+ </style>