feat(query): pin, rename and label result run tabs
This commit is contained in:
26 files changed
+319
-32
No files matched your search
@@ -661,6 +661,7 @@ const debugLogCopied = ref(false);
|
||||
const debugLogDownloaded = ref(false);
|
||||
const editShowColumnCommentsInHeader = ref(settingsStore.editorSettings.showColumnCommentsInHeader);
|
||||
const editShowColumnTypesInHeader = ref(settingsStore.editorSettings.showColumnTypesInHeader);
|
||||
const editShowResultSourceDatabase = ref(settingsStore.editorSettings.showResultSourceDatabase);
|
||||
const editDataGridShowTransposeFieldMetadata = ref(settingsStore.editorSettings.dataGridShowTransposeFieldMetadata);
|
||||
const editColorizeDataGridCellTypes = ref(settingsStore.editorSettings.colorizeDataGridCellTypes);
|
||||
const editShowIndexIndicatorsInHeader = ref(settingsStore.editorSettings.showIndexIndicatorsInHeader);
|
||||
@@ -1002,6 +1003,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
|
||||
tabSortMode: editTabSortMode.value,
|
||||
showColumnCommentsInHeader: editShowColumnCommentsInHeader.value,
|
||||
showColumnTypesInHeader: editShowColumnTypesInHeader.value,
|
||||
showResultSourceDatabase: editShowResultSourceDatabase.value,
|
||||
dataGridShowTransposeFieldMetadata: editDataGridShowTransposeFieldMetadata.value,
|
||||
colorizeDataGridCellTypes: editColorizeDataGridCellTypes.value,
|
||||
dataGridTypeColorSchemes: editDataGridTypeColorSchemes.value,
|
||||
@@ -1647,6 +1649,7 @@ function syncEditorSettingsDraftFromStore() {
|
||||
editTabSortMode.value = settingsStore.editorSettings.tabSortMode;
|
||||
editShowColumnCommentsInHeader.value = settingsStore.editorSettings.showColumnCommentsInHeader;
|
||||
editShowColumnTypesInHeader.value = settingsStore.editorSettings.showColumnTypesInHeader;
|
||||
editShowResultSourceDatabase.value = settingsStore.editorSettings.showResultSourceDatabase;
|
||||
editDataGridShowTransposeFieldMetadata.value = settingsStore.editorSettings.dataGridShowTransposeFieldMetadata;
|
||||
editColorizeDataGridCellTypes.value = settingsStore.editorSettings.colorizeDataGridCellTypes;
|
||||
editDataGridTypeColorSchemes.value = cloneDataGridTypeColorSchemes(settingsStore.editorSettings.dataGridTypeColorSchemes);
|
||||
@@ -1780,6 +1783,7 @@ const editorSettingsDraftRefs: EditorSettingsDraftRefMap = {
|
||||
tabSortMode: editTabSortMode,
|
||||
showColumnCommentsInHeader: editShowColumnCommentsInHeader,
|
||||
showColumnTypesInHeader: editShowColumnTypesInHeader,
|
||||
showResultSourceDatabase: editShowResultSourceDatabase,
|
||||
dataGridShowTransposeFieldMetadata: editDataGridShowTransposeFieldMetadata,
|
||||
colorizeDataGridCellTypes: editColorizeDataGridCellTypes,
|
||||
dataGridTypeColorSchemes: editDataGridTypeColorSchemes,
|
||||
@@ -2304,6 +2308,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
|
||||
historyRetention.reset();
|
||||
editShowColumnCommentsInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnCommentsInHeader;
|
||||
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
|
||||
editShowResultSourceDatabase.value = DEFAULT_EDITOR_SETTINGS.showResultSourceDatabase;
|
||||
editDataGridShowTransposeFieldMetadata.value = DEFAULT_EDITOR_SETTINGS.dataGridShowTransposeFieldMetadata;
|
||||
editColorizeDataGridCellTypes.value = DEFAULT_EDITOR_SETTINGS.colorizeDataGridCellTypes;
|
||||
// Back to the built-in palette, but keep the user's saved schemes available.
|
||||
@@ -7908,6 +7913,17 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<Switch id="show-column-types-in-header" v-model="editShowColumnTypesInHeader" />
|
||||
</div>
|
||||
<div class="settings-item flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="space-y-1">
|
||||
<Label for="show-result-source-database">
|
||||
{{ t("settings.showResultSourceDatabase") }}
|
||||
</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ t("settings.showResultSourceDatabaseDescription") }}
|
||||
</p>
|
||||
</div>
|
||||
<Switch id="show-result-source-database" v-model="editShowResultSourceDatabase" />
|
||||
</div>
|
||||
<div class="settings-item flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="space-y-1">
|
||||
<Label for="data-grid-show-transpose-field-metadata">
|
||||
|
||||
@@ -494,8 +494,10 @@ const activeQueryError = computed(() => {
|
||||
return String(result.rows[0]?.[0] ?? "");
|
||||
});
|
||||
const hasQueryOutput = computed(() => tabHasQueryOutput(props.activeTab));
|
||||
const visibleResultItems = computed(() => tabularResultItems(props.activeTab.results ?? (props.activeTab.result ? [props.activeTab.result] : undefined)));
|
||||
const tabularResults = computed(() => tabularResultItems(props.activeTab.results));
|
||||
// 结果集页签/列表的名称是否带库名,由编辑器设置控制(默认带库名)
|
||||
const includeResultSourceDatabase = computed(() => settingsStore.editorSettings.showResultSourceDatabase);
|
||||
const visibleResultItems = computed(() => tabularResultItems(props.activeTab.results ?? (props.activeTab.result ? [props.activeTab.result] : undefined), { includeSourceDatabase: includeResultSourceDatabase.value }));
|
||||
const tabularResults = computed(() => tabularResultItems(props.activeTab.results, { includeSourceDatabase: includeResultSourceDatabase.value }));
|
||||
const allResultExportSheets = computed(() =>
|
||||
tabularResults.value.map((item) => ({
|
||||
sheetName: item.label || t("tabs.resultN", { n: item.n }),
|
||||
@@ -503,7 +505,14 @@ const allResultExportSheets = computed(() =>
|
||||
sql: item.index === props.activeTab.activeResultIndex ? queryResultExecutionSql(props.activeTab) : item.result.sourceStatement,
|
||||
})),
|
||||
);
|
||||
const resultRuns = computed(() => resultRunItems(props.activeTab));
|
||||
// 结果标签优先显示来源(表名),历史批次缺少来源信息时按批次 SQL 重新解析
|
||||
const resultRuns = computed(() =>
|
||||
resultRunItems(props.activeTab, {
|
||||
includeSourceDatabase: includeResultSourceDatabase.value,
|
||||
database: props.activeTab.database,
|
||||
databaseType: activeEffectiveDatabaseType.value,
|
||||
}),
|
||||
);
|
||||
const activeResultGridCacheKey = computed(() => resultGridCacheKey(props.activeTab));
|
||||
const activeResultGridColumnWidthCacheKey = computed(() => resultGridColumnWidthCacheKey(props.activeTab));
|
||||
const activeResultGridInstanceKey = computed(() => resultGridInstanceKey(props.activeTab));
|
||||
@@ -1243,7 +1252,7 @@ async function closeResultRunsToRight(runId: string) {
|
||||
|
||||
function openResultRunRename(run: (typeof resultRuns.value)[number]) {
|
||||
resultRunRenameId.value = run.id;
|
||||
resultRunRenameTitle.value = run.title || t("tabs.runN", { n: run.sequence });
|
||||
resultRunRenameTitle.value = run.title || run.sourceLabel || t("tabs.runN", { n: run.sequence });
|
||||
resultRunRenameOpen.value = true;
|
||||
nextTick(() => {
|
||||
const input = document.querySelector<HTMLInputElement>("[data-result-run-name-input]");
|
||||
@@ -1314,6 +1323,16 @@ async function selectResultRun(runId: string) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击结果标签:切换显示的同时固定该结果(issue #9975)。
|
||||
* 未固定的结果会被下一次普通查询复用/覆盖,点击后固定即可保留下来。
|
||||
*/
|
||||
async function selectResultRunFromTab(runId: string) {
|
||||
if (!(await selectResultRun(runId))) return;
|
||||
const run = resultRuns.value.find((item) => item.id === runId);
|
||||
if (run && !run.pinned) toggleResultRunPinned(runId);
|
||||
}
|
||||
|
||||
async function focusResultRunByIndex(index: number) {
|
||||
const run = resultRuns.value[index];
|
||||
if (!run) return;
|
||||
@@ -1743,11 +1762,11 @@ defineExpose({
|
||||
:aria-selected="run.active"
|
||||
:data-active-result-run="run.active ? 'true' : undefined"
|
||||
class="flex h-full select-none items-center gap-1 whitespace-nowrap pl-2.5 pr-1 text-xs font-medium outline-none focus-visible:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/50"
|
||||
@click="selectResultRun(run.id)"
|
||||
@click="selectResultRunFromTab(run.id)"
|
||||
@keydown="onResultRunTabKeydown($event, runIndex)"
|
||||
>
|
||||
<Pin v-if="run.pinned" class="h-3 w-3 shrink-0 fill-current text-primary" />
|
||||
{{ run.title || t("tabs.runN", { n: run.sequence }) }}
|
||||
{{ run.title || run.sourceLabel || t("tabs.runN", { n: run.sequence }) }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -1767,17 +1786,17 @@ defineExpose({
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="ghost" size="sm" class="h-6 max-w-48 gap-1 px-2 text-xs">
|
||||
<span class="min-w-0 truncate">{{ activeResultRunItem ? activeResultRunItem.title || t("tabs.runN", { n: activeResultRunItem.sequence }) : t("tabs.resultRuns") }}</span>
|
||||
<span class="min-w-0 truncate">{{ activeResultRunItem ? activeResultRunItem.title || activeResultRunItem.sourceLabel || t("tabs.runN", { n: activeResultRunItem.sequence }) : t("tabs.resultRuns") }}</span>
|
||||
<ChevronDown class="h-3.5 w-3.5 shrink-0" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" class="w-48">
|
||||
<CustomContextMenu v-for="run in resultRuns" :key="run.id" :items="() => resultRunContextMenuItems(run)" v-slot="{ onContextMenu }">
|
||||
<DropdownMenuItem class="flex items-center gap-2 pr-1" @select="selectResultRun(run.id)" @contextmenu="onContextMenu">
|
||||
<DropdownMenuItem class="flex items-center gap-2 pr-1" @select="selectResultRunFromTab(run.id)" @contextmenu="onContextMenu">
|
||||
<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" />
|
||||
<Pin v-if="run.pinned" class="h-3 w-3 shrink-0 fill-current text-primary" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ run.title || t("tabs.runN", { n: run.sequence }) }}</span>
|
||||
<span class="min-w-0 flex-1 truncate">{{ run.title || run.sourceLabel || 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"
|
||||
|
||||
Reference in new issue
Block a user