Browse Source

feat: save exported data as file

Ahmad Kholid 3 years ago
parent
commit
510b983cc7

+ 1 - 1
src/background/blocks-handler.js

@@ -119,7 +119,7 @@ export function delay(block) {
 
 
 export function exportData(block) {
 export function exportData(block) {
   return new Promise((resolve) => {
   return new Promise((resolve) => {
-    dataExporter(this.data, block.data.type);
+    dataExporter(this.data, block.data);
 
 
     resolve({
     resolve({
       data: '',
       data: '',

+ 17 - 6
src/components/block/BlockExportData.vue

@@ -19,12 +19,17 @@
         @click="editor.removeNodeId(`node-${block.id}`)"
         @click="editor.removeNodeId(`node-${block.id}`)"
       />
       />
     </div>
     </div>
+    <input
+      v-model="block.data.name"
+      class="w-full bg-input rounded-lg transition mb-2 py-2 px-4 block"
+      placeholder="File name"
+    />
     <select
     <select
-      :value="block.data.type"
+      v-model="block.data.type"
       class="px-4 py-2 rounded-lg w-40 bg-input"
       class="px-4 py-2 rounded-lg w-40 bg-input"
       required
       required
-      @input="handleInput"
     >
     >
+      <option value="" disabled selected>Export as</option>
       <option v-for="type in exportTypes" :key="type.id" :value="type.id">
       <option v-for="type in exportTypes" :key="type.id" :value="type.id">
         {{ type.name }}
         {{ type.name }}
       </option>
       </option>
@@ -32,9 +37,11 @@
   </div>
   </div>
 </template>
 </template>
 <script setup>
 <script setup>
+import { watch } from 'vue';
 import { VRemixIcon as VRemixicon } from 'v-remixicon';
 import { VRemixIcon as VRemixicon } from 'v-remixicon';
 import emitter from 'tiny-emitter/instance';
 import emitter from 'tiny-emitter/instance';
 import { icons } from '@/lib/v-remixicon';
 import { icons } from '@/lib/v-remixicon';
+import { debounce } from '@/utils/helper';
 import { useComponentId } from '@/composable/componentId';
 import { useComponentId } from '@/composable/componentId';
 import { useEditorBlock } from '@/composable/editorBlock';
 import { useEditorBlock } from '@/composable/editorBlock';
 
 
@@ -54,8 +61,12 @@ const exportTypes = [
   { name: 'Plain text', id: 'plain-text' },
   { name: 'Plain text', id: 'plain-text' },
 ];
 ];
 
 
-function handleInput({ target }) {
-  props.editor.updateNodeDataFromId(block.id, { type: target.value });
-  emitter.emit('editor:data-changed', block.id);
-}
+watch(
+  () => block.data,
+  debounce((value) => {
+    props.editor.updateNodeDataFromId(block.id, value);
+    emitter.emit('editor:data-changed', block.id);
+  }, 250),
+  { deep: true }
+);
 </script>
 </script>

+ 60 - 0
src/utils/data-exporter.js

@@ -0,0 +1,60 @@
+import Papa from 'papaparse';
+
+function generateJSON(keys, data) {
+  const result = [];
+
+  keys.forEach((key) => {
+    for (let index = 0; index < data[key].length; index += 1) {
+      const currData = data[key][index];
+
+      if (typeof result[index] === 'undefined') {
+        result.push({ [key]: currData });
+      } else {
+        result[index][key] = currData;
+      }
+    }
+  });
+
+  return result;
+}
+
+const files = {
+  'plain-text': {
+    mime: 'text/plain',
+    ext: '.txt',
+  },
+  json: {
+    mime: 'application/json',
+    ext: '.json',
+  },
+  csv: {
+    mime: 'text/csv',
+    ext: '.csv',
+  },
+};
+
+export default function (data, { name, type }) {
+  let result = data;
+
+  if (type === 'csv' || type === 'json') {
+    const jsonData = generateJSON(Object.keys(data), data);
+
+    result =
+      type === 'csv'
+        ? `data:text/csv;charset=utf-8,${Papa.unparse(jsonData)}`
+        : JSON.stringify(jsonData);
+  } else if (type === 'plain-text') {
+    result = Object.values(data).join(' ');
+  }
+
+  const { mime, ext } = files[type];
+  const blob = new Blob([result], {
+    type: mime,
+  });
+
+  const anchor = document.createElement('a');
+  anchor.download = `${name || 'unnamed'}${ext}`;
+  anchor.href = URL.createObjectURL(blob);
+
+  anchor.dispatchEvent(new MouseEvent('click'));
+}

+ 1 - 0
src/utils/shared.js

@@ -76,6 +76,7 @@ export const tasks = {
     allowedInputs: true,
     allowedInputs: true,
     maxConnection: 1,
     maxConnection: 1,
     data: {
     data: {
+      name: '',
       type: 'json',
       type: 'json',
     },
     },
   },
   },