AppLogsItem.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <template>
  2. <div v-if="currentLog.id">
  3. <div class="flex items-center">
  4. <button
  5. v-tooltip:bottom="t('workflow.blocks.go-back.name')"
  6. role="button"
  7. class="h-12 px-1 transition mr-2 bg-input rounded-lg dark:text-gray-300 text-gray-600"
  8. @click="$emit('close')"
  9. >
  10. <v-remixicon name="riArrowLeftSLine" />
  11. </button>
  12. <div>
  13. <h1 class="text-2xl max-w-md text-overflow font-semibold">
  14. {{ currentLog.name }}
  15. </h1>
  16. <p class="text-gray-600 dark:text-gray-200">
  17. {{
  18. t(`log.description.text`, {
  19. status: t(
  20. `log.description.status.${currentLog.status || 'success'}`
  21. ),
  22. date: dayjs(currentLog.startedAt).format('DD MMM'),
  23. duration: countDuration(currentLog.startedAt, currentLog.endedAt),
  24. })
  25. }}
  26. </p>
  27. </div>
  28. <div class="flex-grow"></div>
  29. <ui-button
  30. v-if="state.workflowExists"
  31. v-tooltip="t('log.goWorkflow')"
  32. icon
  33. class="mr-4"
  34. @click="goToWorkflow"
  35. >
  36. <v-remixicon name="riExternalLinkLine" />
  37. </ui-button>
  38. <ui-button class="text-red-500 dark:text-red-400" @click="deleteLog">
  39. {{ t('common.delete') }}
  40. </ui-button>
  41. </div>
  42. <ui-tabs v-model="state.activeTab" class="mt-4" @change="onTabChange">
  43. <ui-tab v-for="tab in tabs" :key="tab.id" class="mr-4" :value="tab.id">
  44. {{ tab.name }}
  45. </ui-tab>
  46. </ui-tabs>
  47. <ui-tab-panels
  48. :model-value="state.activeTab"
  49. class="mt-4 pb-4 overflow-auto scroll px-2"
  50. style="min-height: 500px; max-height: calc(100vh - 15rem)"
  51. >
  52. <ui-tab-panel value="logs">
  53. <logs-history
  54. :current-log="currentLog"
  55. :ctx-data="ctxData"
  56. :parent-log="parentLog"
  57. />
  58. </ui-tab-panel>
  59. <ui-tab-panel value="table">
  60. <logs-table :current-log="currentLog" :table-data="tableData" />
  61. </ui-tab-panel>
  62. <ui-tab-panel value="variables">
  63. <logs-variables :current-log="currentLog" />
  64. </ui-tab-panel>
  65. </ui-tab-panels>
  66. </div>
  67. </template>
  68. <script setup>
  69. import { shallowReactive, shallowRef, watch } from 'vue';
  70. import { useRouter } from 'vue-router';
  71. import { useI18n } from 'vue-i18n';
  72. import dbLogs from '@/db/logs';
  73. import dayjs from '@/lib/dayjs';
  74. import { useWorkflowStore } from '@/stores/workflow';
  75. import { countDuration, convertArrObjTo2DArr } from '@/utils/helper';
  76. import LogsTable from '@/components/newtab/logs/LogsTable.vue';
  77. import LogsHistory from '@/components/newtab/logs/LogsHistory.vue';
  78. import LogsVariables from '@/components/newtab/logs/LogsVariables.vue';
  79. const props = defineProps({
  80. logId: {
  81. type: String,
  82. default: '',
  83. },
  84. });
  85. const emit = defineEmits(['close']);
  86. const { t } = useI18n();
  87. const router = useRouter();
  88. const workflowStore = useWorkflowStore();
  89. const ctxData = shallowRef({});
  90. const parentLog = shallowRef(null);
  91. const tabs = [
  92. { id: 'logs', name: t('common.log', 2) },
  93. { id: 'table', name: t('workflow.table.title') },
  94. { id: 'variables', name: t('workflow.variables.title', 2) },
  95. ];
  96. const state = shallowReactive({
  97. activeTab: 'logs',
  98. workflowExists: false,
  99. });
  100. const tableData = shallowReactive({
  101. converted: false,
  102. body: [],
  103. header: [],
  104. });
  105. const currentLog = shallowRef({
  106. history: [],
  107. data: {
  108. table: [],
  109. variables: {},
  110. },
  111. });
  112. function deleteLog() {
  113. dbLogs.items
  114. .where('id')
  115. .equals(props.logId)
  116. .delete()
  117. .then(() => {
  118. emit('close');
  119. });
  120. }
  121. function goToWorkflow() {
  122. const path = `/workflows/${currentLog.value.workflowId}`;
  123. router.push(path);
  124. emit('close', true);
  125. }
  126. function convertToTableData() {
  127. const data = currentLog.value.data?.table;
  128. if (!data) return;
  129. const [header] = convertArrObjTo2DArr(data);
  130. tableData.converted = true;
  131. tableData.body = data.map((item, index) => ({ ...item, id: index + 1 }));
  132. tableData.header = header.map((name) => ({
  133. text: name,
  134. value: name,
  135. filterable: true,
  136. }));
  137. tableData.header.unshift({ value: 'id', text: '', sortable: false });
  138. }
  139. function onTabChange(value) {
  140. if (value === 'table' && !tableData.converted) {
  141. convertToTableData();
  142. }
  143. }
  144. async function fetchLog() {
  145. if (!props.logId) return;
  146. const logDetail = await dbLogs.items.where('id').equals(props.logId).last();
  147. if (!logDetail) return;
  148. tableData.body = [];
  149. tableData.header = [];
  150. parentLog.value = null;
  151. tableData.converted = false;
  152. const [logCtxData, logHistory, logsData] = await Promise.all(
  153. ['ctxData', 'histories', 'logsData'].map((key) =>
  154. dbLogs[key].where('logId').equals(props.logId).last()
  155. )
  156. );
  157. ctxData.value = logCtxData?.data || {};
  158. currentLog.value = {
  159. history: logHistory?.data || [],
  160. data: logsData?.data || {},
  161. ...logDetail,
  162. };
  163. state.workflowExists = Boolean(workflowStore.getById(logDetail.workflowId));
  164. const parentLogId = logDetail.collectionLogId || logDetail.parentLog?.id;
  165. if (parentLogId) {
  166. parentLog.value =
  167. (await dbLogs.items.where('id').equals(parentLogId).last()) || null;
  168. }
  169. }
  170. watch(() => props.logId, fetchLog, { immediate: true });
  171. </script>
  172. <style>
  173. .logs-details .cm-editor {
  174. max-height: calc(100vh - 15rem);
  175. }
  176. </style>