Browse Source

feat: drag and drop the existing block to the blocks group

Ahmad Kholid 3 years ago
parent
commit
cde1070002

+ 1 - 0
src/components/block/BlockBase.vue

@@ -1,5 +1,6 @@
 <template>
 <template>
   <div class="block-base relative" @dblclick="$emit('edit')">
   <div class="block-base relative" @dblclick="$emit('edit')">
+    <slot name="prepend" />
     <div
     <div
       :class="contentClass"
       :class="contentClass"
       class="z-10 bg-white relative rounded-lg overflow-hidden w-full p-4"
       class="z-10 bg-white relative rounded-lg overflow-hidden w-full p-4"

+ 28 - 0
src/components/block/BlockBasic.vue

@@ -4,6 +4,7 @@
     :hide-edit="block.details.disableEdit"
     :hide-edit="block.details.disableEdit"
     :hide-delete="block.details.disableDelete"
     :hide-delete="block.details.disableDelete"
     content-class="flex items-center"
     content-class="flex items-center"
+    class="block-basic"
     @edit="editBlock"
     @edit="editBlock"
     @delete="editor.removeNodeId(`node-${block.id}`)"
     @delete="editor.removeNodeId(`node-${block.id}`)"
   >
   >
@@ -30,6 +31,18 @@
         @change="handleDataChange"
         @change="handleDataChange"
       />
       />
     </div>
     </div>
+    <template #prepend>
+      <div
+        v-if="block.details.id !== 'trigger'"
+        :title="t('workflow.blocks.base.moveToGroup')"
+        draggable="true"
+        class="bg-white invisible move-to-group z-50 absolute -top-2 -right-2 rounded-md p-1 shadow-md"
+        @dragstart="handleStartDrag"
+        @mousedown.stop
+      >
+        <v-remixicon name="riDragDropLine" size="20" />
+      </div>
+    </template>
   </block-base>
   </block-base>
 </template>
 </template>
 <script setup>
 <script setup>
@@ -62,4 +75,19 @@ function handleDataChange() {
 
 
   block.data = data;
   block.data = data;
 }
 }
+function handleStartDrag(event) {
+  const payload = {
+    data: block.data,
+    id: block.details.id,
+    blockId: block.id,
+  };
+
+  event.dataTransfer.setData('block', JSON.stringify(payload));
+}
 </script>
 </script>
+<style>
+.drawflow-node.selected .move-to-group,
+.block-basic:hover .move-to-group {
+  visibility: visible;
+}
+</style>

+ 30 - 3
src/components/block/BlockGroup.vue

@@ -39,6 +39,8 @@
         <div
         <div
           class="p-2 rounded-lg bg-input space-x-2 flex items-center group"
           class="p-2 rounded-lg bg-input space-x-2 flex items-center group"
           style="cursor: grab"
           style="cursor: grab"
+          @dragstart="onDragStart(element, $event)"
+          @dragend="onDragEnd(element.itemId)"
         >
         >
           <v-remixicon
           <v-remixicon
             :name="tasks[element.id].icon"
             :name="tasks[element.id].icon"
@@ -109,7 +111,6 @@ const block = useEditorBlock(`#${componentId}`, props.editor);
 const excludeBlocks = [
 const excludeBlocks = [
   'trigger',
   'trigger',
   'repeat-task',
   'repeat-task',
-  'export-data',
   'loop-data',
   'loop-data',
   'loop-breakpoint',
   'loop-breakpoint',
   'blocks-group',
   'blocks-group',
@@ -118,6 +119,28 @@ const excludeBlocks = [
   'delay',
   'delay',
 ];
 ];
 
 
+function onDragStart(item, event) {
+  event.dataTransfer.setData(
+    'block',
+    JSON.stringify({ ...tasks[item.id], ...item, fromGroup: true })
+  );
+}
+function onDragEnd(itemId) {
+  setTimeout(() => {
+    const blockEl = document.querySelector(`[group-item-id="${itemId}"]`);
+
+    if (blockEl) {
+      const blockIndex = block.data.blocks.findIndex(
+        (item) => item.itemId === itemId
+      );
+
+      if (blockIndex !== -1) {
+        emitter.emit('editor:delete-block', { itemId, isInGroup: true });
+        block.data.blocks.splice(blockIndex, 1);
+      }
+    }
+  }, 200);
+}
 function handleDataChange({ detail }) {
 function handleDataChange({ detail }) {
   if (!detail) return;
   if (!detail) return;
 
 
@@ -147,9 +170,9 @@ function handleDrop(event) {
 
 
   const droppedBlock = JSON.parse(event.dataTransfer.getData('block') || null);
   const droppedBlock = JSON.parse(event.dataTransfer.getData('block') || null);
 
 
-  if (!droppedBlock) return;
+  if (!droppedBlock || droppedBlock.fromGroup) return;
 
 
-  const { id, data } = droppedBlock;
+  const { id, data, blockId } = droppedBlock;
 
 
   if (excludeBlocks.includes(id)) {
   if (excludeBlocks.includes(id)) {
     toast.error(
     toast.error(
@@ -161,6 +184,10 @@ function handleDrop(event) {
     return;
     return;
   }
   }
 
 
+  if (blockId) {
+    props.editor.removeNodeId(`node-${blockId}`);
+  }
+
   block.data.blocks.push({ id, data, itemId: nanoid(5) });
   block.data.blocks.push({ id, data, itemId: nanoid(5) });
 }
 }
 
 

+ 7 - 1
src/components/newtab/workflow/WorkflowBuilder.vue

@@ -160,7 +160,7 @@ export default {
         block.id === 'trigger' &&
         block.id === 'trigger' &&
         editor.value.getNodesFromName('trigger').length !== 0;
         editor.value.getNodesFromName('trigger').length !== 0;
 
 
-      if (!block || isTriggerExists) return;
+      if (isTriggerExists) return;
 
 
       const xPosition =
       const xPosition =
         clientX *
         clientX *
@@ -189,6 +189,12 @@ export default {
         'vue'
         'vue'
       );
       );
 
 
+      if (block.fromGroup) {
+        const blockEl = document.getElementById(`node-${blockId}`);
+
+        blockEl.setAttribute('group-item-id', block.itemId);
+      }
+
       if (isConnectionEl(target)) {
       if (isConnectionEl(target)) {
         target.classList.remove('selected');
         target.classList.remove('selected');
 
 

+ 1 - 0
src/locales/en/blocks.json

@@ -10,6 +10,7 @@
   "workflow": {
   "workflow": {
     "blocks": {
     "blocks": {
       "base": {
       "base": {
+        "moveToGroup": "Move block to blocks group",
         "selector": "Element selector",
         "selector": "Element selector",
         "findElement": {
         "findElement": {
           "placeholder": "Find element by",
           "placeholder": "Find element by",

+ 1 - 1
src/models/workflow.js

@@ -16,7 +16,7 @@ class Workflow extends Model {
       name: this.string(''),
       name: this.string(''),
       icon: this.string('riGlobalLine'),
       icon: this.string('riGlobalLine'),
       data: this.attr(null),
       data: this.attr(null),
-      drawflow: this.attr('{ "drawflow": { "Home": { "data": {} } } }'),
+      drawflow: this.attr(''),
       dataColumns: this.attr([]),
       dataColumns: this.attr([]),
       description: this.string(''),
       description: this.string(''),
       version: this.string(''),
       version: this.string(''),