feat(export-tracker): 增强导出任务跟踪功能 (#1958)
- 添加了对数据库导出、SQL 文件导出和数据传输任务的支持 - 引入了新的状态和错误处理机制 - 实现了任务的重叠检查,防止同时进行相同目标表的数据传输 - 更新了 API 调用以支持新的任务类型 - 增加了相应的国际化文本 - 添加了单元测试以确保新功能的正确性
This commit is contained in:
15 files changed
+838
-208
No files matched your search
@@ -14,11 +14,13 @@ import { useToast } from "@/composables/useToast";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { databaseOptionsForConnection } from "@/composables/useDatabaseOptions";
|
||||
import { cancelSqlFileExecution, executeSqlFile, listenSqlFileProgress, listDatabases, previewSqlFile, type SqlFilePreview, type SqlFileProgress, type SqlFileStatus } from "@/lib/api";
|
||||
import { useExportTracker } from "@/composables/useExportTracker";
|
||||
import { Check, CheckSquare, FileCode, FolderOpen, Loader2, Play, Square, X } from "@lucide/vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const { toast } = useToast();
|
||||
const { highlight } = useSqlHighlighter();
|
||||
const { addSqlFileTask, updateSqlFileTask } = useExportTracker();
|
||||
const open = defineModel<boolean>("open", { default: false });
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -282,6 +284,7 @@ async function startExecution() {
|
||||
terminalStatus.value = "running";
|
||||
terminalError.value = "";
|
||||
progress.value = null;
|
||||
addSqlFileTask(id, preview.value.fileName, preview.value.filePath);
|
||||
|
||||
let unlisten: (() => void) | undefined;
|
||||
try {
|
||||
@@ -296,6 +299,7 @@ async function startExecution() {
|
||||
progress.value = next;
|
||||
terminalStatus.value = next.status;
|
||||
terminalError.value = next.error ?? terminalError.value;
|
||||
updateSqlFileTask(id, next);
|
||||
if (isTerminalStatus(next.status)) {
|
||||
running.value = false;
|
||||
cancelling.value = false;
|
||||
@@ -320,6 +324,18 @@ async function startExecution() {
|
||||
});
|
||||
if (!isTerminalStatus(terminalStatus.value)) {
|
||||
terminalStatus.value = cancelRequested.value ? "cancelled" : "done";
|
||||
const lastProgress = progress.value as SqlFileProgress | null;
|
||||
updateSqlFileTask(id, {
|
||||
executionId: id,
|
||||
status: terminalStatus.value,
|
||||
statementIndex: lastProgress?.statementIndex ?? 0,
|
||||
successCount: lastProgress?.successCount ?? 0,
|
||||
failureCount: lastProgress?.failureCount ?? 0,
|
||||
affectedRows: lastProgress?.affectedRows ?? 0,
|
||||
elapsedMs: lastProgress?.elapsedMs ?? 0,
|
||||
statementSummary: lastProgress?.statementSummary ?? "",
|
||||
error: lastProgress?.error ?? null,
|
||||
});
|
||||
if (terminalStatus.value === "done") {
|
||||
await refreshTargetAfterImport();
|
||||
}
|
||||
@@ -327,6 +343,18 @@ async function startExecution() {
|
||||
} catch (e: any) {
|
||||
terminalStatus.value = cancelRequested.value ? "cancelled" : "error";
|
||||
terminalError.value = e?.message || String(e);
|
||||
const lastProgress = progress.value as SqlFileProgress | null;
|
||||
updateSqlFileTask(id, {
|
||||
executionId: id,
|
||||
status: terminalStatus.value,
|
||||
statementIndex: lastProgress?.statementIndex ?? 0,
|
||||
successCount: lastProgress?.successCount ?? 0,
|
||||
failureCount: lastProgress?.failureCount ?? 0,
|
||||
affectedRows: lastProgress?.affectedRows ?? 0,
|
||||
elapsedMs: lastProgress?.elapsedMs ?? 0,
|
||||
statementSummary: lastProgress?.statementSummary ?? "",
|
||||
error: terminalError.value,
|
||||
});
|
||||
if (!cancelRequested.value) {
|
||||
toast(terminalError.value, 5000);
|
||||
}
|
||||
@@ -356,7 +384,6 @@ async function cancelExecution() {
|
||||
}
|
||||
|
||||
function handleOpenChange(nextOpen: boolean) {
|
||||
if (!nextOpen && running.value) return;
|
||||
open.value = nextOpen;
|
||||
}
|
||||
|
||||
@@ -373,6 +400,7 @@ watch(
|
||||
open,
|
||||
(value) => {
|
||||
if (!value) return;
|
||||
if (running.value) return;
|
||||
resetState();
|
||||
if (connectionId.value) {
|
||||
loadDatabasesForConnection(connectionId.value);
|
||||
@@ -543,6 +571,9 @@ watch(
|
||||
|
||||
<DialogFooter>
|
||||
<template v-if="running">
|
||||
<Button variant="outline" size="sm" @click="open = false">
|
||||
{{ t("sqlFile.runInBackground") }}
|
||||
</Button>
|
||||
<Button variant="destructive" size="sm" :disabled="cancelling" @click="cancelExecution">
|
||||
<Loader2 v-if="cancelling" class="w-3.5 h-3.5 mr-1.5 animate-spin" />
|
||||
<X v-else class="w-3.5 h-3.5 mr-1.5" />
|
||||
|
||||
Reference in new issue
Block a user