mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 17:09:56 +00:00
fix(tabs): reload missing table data
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
TableProperties,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
RefreshCcw,
|
||||
} from "lucide-vue-next";
|
||||
import { Splitpanes, Pane } from "splitpanes";
|
||||
import "splitpanes/dist/splitpanes.css";
|
||||
@@ -709,6 +710,14 @@ defineExpose({ focusSearch, refreshData, handleModRTarget });
|
||||
{{ t("toolbar.stopQuery") }}
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else class="h-full flex flex-col items-center justify-center gap-3 text-muted-foreground text-sm">
|
||||
<Inbox class="h-8 w-8 opacity-60" />
|
||||
<div>{{ t("grid.dataUnavailable") }}</div>
|
||||
<Button variant="outline" size="sm" class="h-7 gap-1.5" @click="emit('reload')">
|
||||
<RefreshCcw class="h-3.5 w-3.5" />
|
||||
{{ t("grid.refresh") }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -602,6 +602,7 @@ export default {
|
||||
tableInfoSearch: "Search...",
|
||||
tableInfoNoResults: "No results",
|
||||
queryError: "Query Error",
|
||||
dataUnavailable: "Table data needs to be reloaded.",
|
||||
refresh: "Refresh",
|
||||
commit: "Commit",
|
||||
rollback: "Rollback",
|
||||
|
||||
@@ -561,6 +561,7 @@ export default {
|
||||
tableInfoSearch: "Buscar...",
|
||||
tableInfoNoResults: "Sin resultados",
|
||||
queryError: "Error de consulta",
|
||||
dataUnavailable: "Los datos de la tabla deben volver a cargarse.",
|
||||
refresh: "Actualizar",
|
||||
commit: "Confirmar",
|
||||
rollback: "Revertir",
|
||||
|
||||
@@ -597,6 +597,7 @@ export default {
|
||||
tableInfoSearch: "搜索...",
|
||||
tableInfoNoResults: "无匹配结果",
|
||||
queryError: "查询出错",
|
||||
dataUnavailable: "表数据需要重新加载。",
|
||||
refresh: "刷新",
|
||||
commit: "提交",
|
||||
rollback: "回滚",
|
||||
|
||||
@@ -1126,13 +1126,22 @@ export const useQueryStore = defineStore("query", () => {
|
||||
|
||||
async function reloadEvictedTab(id: string) {
|
||||
const tab = tabs.value.find((t) => t.id === id);
|
||||
if (!tab || !tab.resultEvicted) return;
|
||||
const shouldReloadMissingDataTab = tab?.mode === "data" && !tab.result && !tab.isExecuting;
|
||||
if (!tab || (!tab.resultEvicted && !shouldReloadMissingDataTab)) return;
|
||||
tab.resultEvicted = false;
|
||||
const sql = tab.lastExecutedSql ?? tab.sql;
|
||||
if (!sql?.trim()) return;
|
||||
const settingsStore = useSettingsStore();
|
||||
await executeTabSql(tab.id, sql, {
|
||||
resultBaseSql: tab.resultBaseSql ?? sql,
|
||||
resultSortedSql: tab.resultSortedSql,
|
||||
pagination:
|
||||
tab.mode === "data"
|
||||
? {
|
||||
limit: tab.resultPageLimit ?? settingsStore.editorSettings.pageSize,
|
||||
offset: tab.resultPageOffset ?? 0,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -364,6 +364,50 @@ test("data tab execution preserves pagination offset metadata", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("reloading an empty data tab fetches table results again", async () => {
|
||||
const restoreStorage = installMemoryStorage();
|
||||
setActivePinia(createPinia());
|
||||
const connectionStore = useConnectionStore();
|
||||
const store = useQueryStore();
|
||||
const originalFetch = globalThis.fetch;
|
||||
let executeBody: any;
|
||||
|
||||
connectionStore.addEphemeralConnection(conn("conn-1"));
|
||||
const tabId = store.createTab("conn-1", "db", "users", "data", "public");
|
||||
const tab = store.tabs.find((item) => item.id === tabId);
|
||||
assert.ok(tab);
|
||||
tab.sql = 'SELECT * FROM "public"."users" LIMIT 50 OFFSET 50;';
|
||||
tab.lastExecutedSql = tab.sql;
|
||||
tab.resultPageLimit = 50;
|
||||
tab.resultPageOffset = 50;
|
||||
|
||||
globalThis.fetch = (async (input, init) => {
|
||||
const url = String(input);
|
||||
if (url === "/api/query/execute-multi") {
|
||||
executeBody = JSON.parse(String(init?.body ?? "{}"));
|
||||
return new Response(JSON.stringify([{ columns: ["id"], rows: [[51]], affected_rows: 0, execution_time_ms: 1 }]), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
return new Response("unexpected request", { status: 500 });
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
await store.reloadEvictedTab(tabId);
|
||||
|
||||
assert.equal(executeBody.sql, 'SELECT * FROM "public"."users" LIMIT 50 OFFSET 50;');
|
||||
assert.equal(executeBody.maxRows, 50);
|
||||
assert.equal(executeBody.fetchSize, 50);
|
||||
assert.deepEqual(tab.result?.rows, [[51]]);
|
||||
assert.equal(tab.resultPageLimit, 50);
|
||||
assert.equal(tab.resultPageOffset, 50);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
restoreStorage();
|
||||
}
|
||||
});
|
||||
|
||||
test("query result export fetches every paginated page", async () => {
|
||||
const restoreStorage = installMemoryStorage();
|
||||
setActivePinia(createPinia());
|
||||
|
||||
Reference in New Issue
Block a user