|
1 | 1 | <template> |
2 | 2 | <div> |
3 | | - <div :style="depthMargin"> |
| 3 | + <div |
| 4 | + :style="depthMargin" |
| 5 | + :draggable="monitor.type !== 'group'" |
| 6 | + :class="{ 'drag-over': dragOver }" |
| 7 | + @dragstart="onDragStart" |
| 8 | + @dragend="onDragEnd" |
| 9 | + @dragenter.prevent="onDragEnter" |
| 10 | + @dragleave.prevent="onDragLeave" |
| 11 | + @dragover.prevent |
| 12 | + @drop.prevent="onDrop" |
| 13 | + > |
4 | 14 | <!-- Checkbox --> |
5 | 15 | <div v-if="isSelectMode" class="select-input-wrapper"> |
6 | 16 | <input |
@@ -116,6 +126,8 @@ export default { |
116 | 126 | data() { |
117 | 127 | return { |
118 | 128 | isCollapsed: true, |
| 129 | + dragging: false, |
| 130 | + dragOver: false, |
119 | 131 | }; |
120 | 132 | }, |
121 | 133 | computed: { |
@@ -187,6 +199,101 @@ export default { |
187 | 199 |
|
188 | 200 | window.localStorage.setItem("monitorCollapsed", JSON.stringify(storageObject)); |
189 | 201 | }, |
| 202 | + /** |
| 203 | + * Initializes the drag operation if the monitor is draggable. |
| 204 | + * Prevents dragging of group monitors. |
| 205 | + * @param {DragEvent} event - The dragstart event triggered by the browser. |
| 206 | + * @returns {void} This method does not return anything. |
| 207 | + */ |
| 208 | + onDragStart(event) { |
| 209 | + // Only allow dragging non-group monitors (so groups act as drop targets) |
| 210 | + if (this.monitor.type === "group") { |
| 211 | + event.preventDefault(); |
| 212 | + return; |
| 213 | + } |
| 214 | +
|
| 215 | + try { |
| 216 | + event.dataTransfer.setData("text/monitor-id", String(this.monitor.id)); |
| 217 | + event.dataTransfer.effectAllowed = "move"; |
| 218 | + this.dragging = true; |
| 219 | + } catch (e) { |
| 220 | + // ignore |
| 221 | + } |
| 222 | + }, |
| 223 | +
|
| 224 | + onDragEnd() { |
| 225 | + this.dragging = false; |
| 226 | + }, |
| 227 | +
|
| 228 | + onDragEnter(event) { |
| 229 | + // show visual feedback if this item is a group |
| 230 | + if (this.monitor.type === "group") { |
| 231 | + this.dragOver = true; |
| 232 | + } |
| 233 | + }, |
| 234 | +
|
| 235 | + onDragLeave(event) { |
| 236 | + if (this.monitor.type === "group") { |
| 237 | + this.dragOver = false; |
| 238 | + } |
| 239 | + }, |
| 240 | +
|
| 241 | + async onDrop(event) { |
| 242 | + event.preventDefault(); |
| 243 | + this.dragOver = false; |
| 244 | +
|
| 245 | + // Only groups accept drops |
| 246 | + if (this.monitor.type !== "group") { |
| 247 | + return; |
| 248 | + } |
| 249 | +
|
| 250 | + const draggedId = event.dataTransfer.getData("text/monitor-id"); |
| 251 | + if (!draggedId) { |
| 252 | + return; |
| 253 | + } |
| 254 | +
|
| 255 | + const draggedMonitorId = parseInt(draggedId); |
| 256 | + if (isNaN(draggedMonitorId) || draggedMonitorId === this.monitor.id) { |
| 257 | + return; |
| 258 | + } |
| 259 | +
|
| 260 | + const draggedMonitor = this.$root.monitorList[draggedMonitorId]; |
| 261 | + if (!draggedMonitor) { |
| 262 | + return; |
| 263 | + } |
| 264 | +
|
| 265 | + // Save original parent so we can revert locally if server returns error |
| 266 | + const originalParent = draggedMonitor.parent; |
| 267 | +
|
| 268 | + // Prepare a full monitor object (clone) and set new parent |
| 269 | + const monitorToSave = JSON.parse(JSON.stringify(draggedMonitor)); |
| 270 | + monitorToSave.parent = this.monitor.id; |
| 271 | +
|
| 272 | + // Optimistically update local state so UI updates immediately |
| 273 | + this.$root.monitorList[draggedMonitorId].parent = this.monitor.id; |
| 274 | +
|
| 275 | + // Send updated monitor state via socket |
| 276 | + try { |
| 277 | + this.$root.getSocket().emit("editMonitor", monitorToSave, (res) => { |
| 278 | + if (!res || !res.ok) { |
| 279 | + // Revert local change on error |
| 280 | + if (this.$root.monitorList[draggedMonitorId]) { |
| 281 | + this.$root.monitorList[draggedMonitorId].parent = originalParent; |
| 282 | + } |
| 283 | + if (res && res.msg) { |
| 284 | + this.$root.toastError(res.msg); |
| 285 | + } |
| 286 | + } else { |
| 287 | + this.$root.toastRes(res); |
| 288 | + } |
| 289 | + }); |
| 290 | + } catch (e) { |
| 291 | + // revert on exception |
| 292 | + if (this.$root.monitorList[draggedMonitorId]) { |
| 293 | + this.$root.monitorList[draggedMonitorId].parent = originalParent; |
| 294 | + } |
| 295 | + } |
| 296 | + }, |
190 | 297 | /** |
191 | 298 | * Get URL of monitor |
192 | 299 | * @param {number} id ID of monitor |
@@ -253,4 +360,8 @@ export default { |
253 | 360 | z-index: 15; |
254 | 361 | } |
255 | 362 |
|
| 363 | +.drag-over { |
| 364 | + background-color: rgba(6, 182, 212, 0.04); |
| 365 | +} |
| 366 | +
|
256 | 367 | </style> |
0 commit comments