Browse Source

feat: export workflow logs

Ahmad Kholid 2 years ago
parent
commit
70d752507f
1 changed files with 115 additions and 2 deletions
  1. 115 2
      src/components/newtab/logs/LogsHistory.vue

+ 115 - 2
src/components/newtab/logs/LogsHistory.vue

@@ -44,6 +44,25 @@
           </div>
           <slot name="header-prepend" />
           <div class="flex-grow" />
+          <ui-popover trigger-width class="mr-4">
+            <template #trigger>
+              <ui-button>
+                <span>Export logs</span>
+                <v-remixicon name="riArrowDropDownLine" class="ml-2 -mr-1" />
+              </ui-button>
+            </template>
+            <ui-list class="space-y-1">
+              <ui-list-item
+                v-for="type in dataExportTypes"
+                :key="type.id"
+                v-close-popover
+                class="cursor-pointer"
+                @click="exportLogs(type.id)"
+              >
+                {{ t(`log.exportData.types.${type.id}`) }}
+              </ui-list-item>
+            </ui-list>
+          </ui-popover>
           <ui-input
             v-model="state.search"
             :placeholder="t('common.search')"
@@ -268,10 +287,12 @@ import {
   shallowRef,
 } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { countDuration } from '@/utils/helper';
+import Papa from 'papaparse';
+import objectPath from 'object-path';
+import { countDuration, fileSaver } from '@/utils/helper';
 import { getBlocks } from '@/utils/getSharedData';
+import { dataExportTypes } from '@/utils/shared';
 import dayjs from '@/lib/dayjs';
-import objectPath from 'object-path';
 
 const SharedCodemirror = defineAsyncComponent(() =>
   import('@/components/newtab/shared/SharedCodemirror.vue')
@@ -293,6 +314,20 @@ const props = defineProps({
   },
 });
 
+const files = {
+  'plain-text': {
+    mime: 'text/plain',
+    ext: '.txt',
+  },
+  json: {
+    mime: 'application/json',
+    ext: '.json',
+  },
+  csv: {
+    mime: 'text/csv',
+    ext: '.csv',
+  },
+};
 const logsType = {
   success: {
     color: 'text-green-400',
@@ -389,6 +424,84 @@ const logCtxData = computed(() => {
   return JSON.stringify(logData, null, 2);
 });
 
+function exportLogs(type) {
+  let data = type === 'plain-text' ? '' : [];
+  const getItemData = {
+    'plain-text': ([
+      timestamp,
+      status,
+      name,
+      description,
+      message,
+      ctxData,
+    ]) => {
+      data += `${timestamp} - ${status} - ${name} - ${description} - ${message} - ${JSON.stringify(
+        ctxData
+      )} \n`;
+    },
+    json: ([timestamp, status, name, description, message, ctxData]) => {
+      data.push({
+        timestamp,
+        status,
+        name,
+        description,
+        message,
+        data: ctxData,
+      });
+    },
+    csv: (item, index) => {
+      if (index === 0) {
+        data.unshift([
+          'timestamp',
+          'status',
+          'name',
+          'description',
+          'message',
+          'data',
+        ]);
+      }
+
+      item[item.length - 1] = JSON.stringify(item[item.length - 1]);
+
+      data.push(item);
+    },
+  };
+  translatedLog.value.forEach((item, index) => {
+    getItemData[type](
+      [
+        dayjs(item.timestamp || Date.now()).format('DD-MM-YYYY, hh:mm:ss'),
+        item.type.toUpperCase(),
+        item.name,
+        item.description || 'NULL',
+        item.message || 'NULL',
+        props.ctxData[item.id] || null,
+      ],
+      index
+    );
+  });
+
+  switch (type) {
+    case 'plain-text':
+      data = [data];
+      break;
+    case 'csv':
+      data = [Papa.unparse(data)];
+      data.unshift(new Uint8Array([0xef, 0xbb, 0xbf]));
+      break;
+    case 'json':
+      data = [JSON.stringify(data, null, 2)];
+      break;
+    default:
+  }
+
+  const { mime, ext } = files[type];
+  const blobUrl = URL.createObjectURL(new Blob(data, { type: mime }));
+  const filename = `[${dayjs().format('DD-MM-YYYY, HH:mm:ss')}] ${
+    props.currentLog.name
+  } - logs`;
+
+  fileSaver(`${filename}${ext}`, blobUrl);
+}
 function clearActiveItem() {
   state.itemId = '';
   activeLog.value = null;