feat(grid): add pinned query result history
This commit is contained in:
1 parent
fe39a38dd4
commit
c155443d4b
7 files changed
+167
-30
No files matched your search
@@ -2,7 +2,7 @@
|
||||
import { computed, ref, defineAsyncComponent, watch, nextTick, onMounted, onUnmounted } from "vue";
|
||||
import type { CSSProperties } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Check, Columns3, Loader2, Search, Bot, GitBranch, BarChart3, TableProperties, ChevronDown, ChevronUp, Inbox, RefreshCcw, Wrench, Toolbox, ListChecks, Database, FileUp, Download, X } from "@lucide/vue";
|
||||
import { Check, Columns3, Loader2, Search, Bot, GitBranch, BarChart3, TableProperties, ChevronDown, ChevronUp, Inbox, RefreshCcw, Wrench, Toolbox, ListChecks, Database, FileUp, Download, X, Pin } from "@lucide/vue";
|
||||
import { Splitpanes, Pane } from "splitpanes";
|
||||
import "splitpanes/dist/splitpanes.css";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -230,9 +230,11 @@ const activeQueryError = computed(() => {
|
||||
const hasQueryOutput = computed(() => !!props.activeTab.result || !!props.activeTab.explainPlan || !!props.activeTab.explainError || props.activeTab.isExecuting === true || props.activeTab.isExplaining === true);
|
||||
const tabularResults = computed(() => tabularResultItems(props.activeTab.results));
|
||||
const resultRuns = computed(() => resultRunItems(props.activeTab));
|
||||
const activeResultRunItem = computed(() => resultRuns.value.find((run) => run.active));
|
||||
const activeResultGridCacheKey = computed(() => resultGridCacheKey(props.activeTab));
|
||||
const resultArchiveExporting = ref(false);
|
||||
const canExportResultArchive = computed(() => props.activeTab.mode === "query" && (!!props.activeTab.result || !!props.activeTab.results?.length || !!props.activeTab.resultRuns?.length));
|
||||
const resultAutoSave = computed(() => props.activeTab.resultAutoSave === true);
|
||||
watch(
|
||||
() => tabularResults.value.map((item) => item.index).join(","),
|
||||
() => {
|
||||
@@ -482,6 +484,19 @@ function removeResultRun(runId: string) {
|
||||
if (removed && removedActiveRun) emit("update:activeOutputView", "result");
|
||||
}
|
||||
|
||||
async function selectResultRun(runId: string) {
|
||||
if (!(await queryStore.setActiveResultRun(props.activeTab.id, runId))) {
|
||||
toast(t("tabs.missingResultRun"), 4000);
|
||||
return;
|
||||
}
|
||||
emit("update:activeOutputView", "result");
|
||||
}
|
||||
|
||||
function toggleResultAutoSave() {
|
||||
const enabled = queryStore.toggleResultAutoSave(props.activeTab.id);
|
||||
toast(t(enabled ? "tabs.autoKeepResultsEnabled" : "tabs.autoKeepResultsDisabled"), 2500);
|
||||
}
|
||||
|
||||
function handleModRTarget(target: Element): boolean {
|
||||
if (target.closest("[data-query-editor-root]")) return queryEditorRef.value?.openReplace() ?? false;
|
||||
if (target.closest("[data-cell-detail-editor-root]")) return dataGridRef.value?.openCellDetailSearch() ?? false;
|
||||
@@ -545,26 +560,45 @@ defineExpose({ focusSearch, refreshData, handleModRTarget });
|
||||
{{ t("tabs.tableData") }}
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
v-if="activeTab.mode === 'query' && activeTab.result"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-6 w-7 shrink-0 text-muted-foreground hover:text-foreground"
|
||||
:class="{ 'text-primary': resultAutoSave }"
|
||||
:title="resultAutoSave ? t('tabs.autoKeepResultsEnabled') : t('tabs.autoKeepResults')"
|
||||
:aria-label="resultAutoSave ? t('tabs.autoKeepResultsEnabled') : t('tabs.autoKeepResults')"
|
||||
:aria-pressed="resultAutoSave"
|
||||
@click="toggleResultAutoSave"
|
||||
>
|
||||
<Pin class="h-3.5 w-3.5" :class="{ 'fill-current': resultAutoSave }" />
|
||||
</Button>
|
||||
<template v-if="resultRuns.length > 0">
|
||||
<span class="mx-1 h-4 w-px shrink-0 bg-border" />
|
||||
<div class="flex min-w-0 max-w-[35%] items-center gap-1 overflow-x-auto overflow-y-hidden px-1" :aria-label="t('tabs.resultRuns')">
|
||||
<div v-for="run in resultRuns" :key="run.id" class="inline-flex shrink-0 items-center">
|
||||
<Button
|
||||
size="sm"
|
||||
:variant="run.active ? 'default' : 'ghost'"
|
||||
class="h-6 rounded-r-none px-2 text-xs"
|
||||
@click="
|
||||
queryStore.setActiveResultRun(activeTab.id, run.id);
|
||||
emit('update:activeOutputView', 'result');
|
||||
"
|
||||
>
|
||||
{{ t("tabs.runN", { n: run.sequence }) }}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="ghost" size="sm" class="h-6 shrink-0 gap-1 px-2 text-xs">
|
||||
{{ activeResultRunItem ? t("tabs.runN", { n: activeResultRunItem.sequence }) : t("tabs.resultRuns") }}
|
||||
<ChevronDown class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button size="icon" :variant="run.active ? 'default' : 'ghost'" class="h-6 w-6 rounded-l-none border-l border-border/50 px-0" :title="t('tabs.removeRun', { n: run.sequence })" :aria-label="t('tabs.removeRun', { n: run.sequence })" @click.stop="removeResultRun(run.id)">
|
||||
<X class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" class="w-48">
|
||||
<DropdownMenuItem v-for="run in resultRuns" :key="run.id" class="flex items-center gap-2 pr-1" @select="selectResultRun(run.id)">
|
||||
<Check v-if="run.active" class="h-3.5 w-3.5 shrink-0" />
|
||||
<span v-else class="h-3.5 w-3.5 shrink-0" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ t("tabs.runN", { n: run.sequence }) }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-sm text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||
:title="t('tabs.removeRun', { n: run.sequence })"
|
||||
:aria-label="t('tabs.removeRun', { n: run.sequence })"
|
||||
@click.stop.prevent="removeResultRun(run.id)"
|
||||
>
|
||||
<X class="h-3 w-3" />
|
||||
</button>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</template>
|
||||
<template v-if="tabularResults.length > 1">
|
||||
<span class="mx-1 h-4 w-px shrink-0 bg-border" />
|
||||
|
||||
Reference in new issue
Block a user