feat(data-grid): color cells by database-aware types

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-08-13 02:10:37 +08:00
1 parent 0b5c0bdcc0
commit 433626f5c9
25 files changed
+619 -46

No files matched your search

@@ -2,7 +2,7 @@
import { computed, ref, nextTick, watch, onMounted, onBeforeUnmount } from "vue";
import { uuid } from "@/lib/common/utils";
import { useI18n } from "vue-i18n";
import { RefreshCw, Trash2, Plus, Save, ChevronDown, ChevronLeft, ChevronRight, Table2, Braces, X, Search, Wrench, Filter, Columns3Cog, SquareDashed, Minus, Rows3, AlignLeft, AlignRight, EyeOff } from "@lucide/vue";
import { RefreshCw, Trash2, Plus, Save, ChevronDown, ChevronLeft, ChevronRight, Table2, Braces, X, Search, Wrench, Filter, Columns3Cog, SquareDashed, Minus, Rows3, AlignLeft, AlignRight, EyeOff, Palette } from "@lucide/vue";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
@@ -135,6 +135,7 @@ const columnWidthDensity = computed(() => settingsStore.editorSettings.columnWid
const dataGridRenderMode = computed(() => settingsStore.editorSettings.dataGridRenderMode);
const tableFontSize = computed(() => settingsStore.editorSettings.tableFontSize);
const numericColumnRightAlign = computed(() => settingsStore.editorSettings.numericColumnRightAlign ?? true);
const colorizeDataGridCellTypes = computed(() => settingsStore.editorSettings.colorizeDataGridCellTypes);
const viewMode = computed<ViewMode>({
get: () => settingsStore.editorSettings.mongoViewMode,
set: (value) => settingsStore.updateEditorSettings({ mongoViewMode: value }),
@@ -177,6 +178,10 @@ function increaseTableFontSize() {
function setNumericColumnRightAlign(value: boolean) {
settingsStore.updateEditorSettings({ numericColumnRightAlign: value });
}
function setColorizeDataGridCellTypes(value: boolean) {
settingsStore.updateEditorSettings({ colorizeDataGridCellTypes: value });
}
const tableSearchSplitContainerRef = ref<HTMLDivElement>();
const tableFindPaneWidth = ref<number | null>(null);
const isResizingTableSearchSplit = ref(false);
@@ -1867,6 +1872,13 @@ defineExpose({ focusSearch });
</button>
</div>
</div>
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs">
<div class="min-w-0 flex items-center gap-2 font-medium">
<Palette class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
<span>{{ t("grid.colorizeDataTypes") }}</span>
</div>
<Switch size="sm" :model-value="colorizeDataGridCellTypes" :aria-label="t('grid.colorizeDataTypes')" @update:model-value="setColorizeDataGridCellTypes" />
</div>
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs" :class="{ 'opacity-60': !dataGridRef?.canToggleAllNullColumns }">
<span class="min-w-0 flex items-center gap-2 font-medium">
<EyeOff class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
@@ -309,6 +309,7 @@ const debugLogCopied = ref(false);
const debugLogDownloaded = ref(false);
const editShowColumnCommentsInHeader = ref(settingsStore.editorSettings.showColumnCommentsInHeader);
const editShowColumnTypesInHeader = ref(settingsStore.editorSettings.showColumnTypesInHeader);
const editColorizeDataGridCellTypes = ref(settingsStore.editorSettings.colorizeDataGridCellTypes);
const editShowIndexIndicatorsInHeader = ref(settingsStore.editorSettings.showIndexIndicatorsInHeader);
const editCompactColumnHeaderActions = ref(settingsStore.editorSettings.compactColumnHeaderActions);
const editDataGridQuickEntry = ref(settingsStore.editorSettings.dataGridQuickEntry);
@@ -482,6 +483,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
tabLayout: editTabLayout.value,
showColumnCommentsInHeader: editShowColumnCommentsInHeader.value,
showColumnTypesInHeader: editShowColumnTypesInHeader.value,
colorizeDataGridCellTypes: editColorizeDataGridCellTypes.value,
showIndexIndicatorsInHeader: editShowIndexIndicatorsInHeader.value,
compactColumnHeaderActions: editCompactColumnHeaderActions.value,
dataGridQuickEntry: editDataGridQuickEntry.value,
@@ -754,6 +756,7 @@ function syncEditorSettingsDraftFromStore() {
editTabLayout.value = settingsStore.editorSettings.tabLayout;
editShowColumnCommentsInHeader.value = settingsStore.editorSettings.showColumnCommentsInHeader;
editShowColumnTypesInHeader.value = settingsStore.editorSettings.showColumnTypesInHeader;
editColorizeDataGridCellTypes.value = settingsStore.editorSettings.colorizeDataGridCellTypes;
editShowIndexIndicatorsInHeader.value = settingsStore.editorSettings.showIndexIndicatorsInHeader;
editCompactColumnHeaderActions.value = settingsStore.editorSettings.compactColumnHeaderActions;
editDataGridQuickEntry.value = settingsStore.editorSettings.dataGridQuickEntry;
@@ -998,6 +1001,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
} else if (tab === "data") {
editShowColumnCommentsInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnCommentsInHeader;
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
editColorizeDataGridCellTypes.value = DEFAULT_EDITOR_SETTINGS.colorizeDataGridCellTypes;
editShowIndexIndicatorsInHeader.value = DEFAULT_EDITOR_SETTINGS.showIndexIndicatorsInHeader;
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
@@ -1065,6 +1069,7 @@ function resetAllDefaults() {
editSidebarTablePageSize.value = DEFAULT_SIDEBAR_TABLE_PAGE_SIZE;
editShowColumnCommentsInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnCommentsInHeader;
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
editColorizeDataGridCellTypes.value = DEFAULT_EDITOR_SETTINGS.colorizeDataGridCellTypes;
editShowIndexIndicatorsInHeader.value = DEFAULT_EDITOR_SETTINGS.showIndexIndicatorsInHeader;
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
@@ -4817,6 +4822,17 @@ onUnmounted(() => {
</div>
<Switch id="show-column-types-in-header" v-model="editShowColumnTypesInHeader" />
</div>
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
<div class="space-y-1">
<Label for="colorize-data-grid-cell-types">
{{ t("settings.colorizeDataGridCellTypes") }}
</Label>
<p class="text-xs text-muted-foreground">
{{ t("settings.colorizeDataGridCellTypesDescription") }}
</p>
</div>
<Switch id="colorize-data-grid-cell-types" v-model="editColorizeDataGridCellTypes" />
</div>
<div class="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-index-indicators-in-header">
+68 -40
View File
@@ -83,7 +83,8 @@ import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/table
import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit";
import { uuid } from "@/lib/common/utils";
import { generateCellValues, type CellValueGenerationKind } from "@/lib/dataGrid/cellValueGeneration";
import { compactHeaderColumnType, isNumericColumnType, resolveHeaderColumnType, resolveResultColumnType } from "@/lib/dataGrid/dataGridColumnType";
import { compactHeaderColumnType, isNumericColumnType, resolveDataGridTypeVisualKind, resolveHeaderColumnType, resolveResultColumnType } from "@/lib/dataGrid/dataGridColumnType";
import { dataGridCellTextClass, dataGridTypeVisualClass } from "@/lib/dataGrid/dataGridCellTextVisual";
import {
canDeleteExistingTdengineRows,
canEditExistingTableRows,
@@ -292,6 +293,7 @@ const multiRowTranspose = computed(() => settingsStore.editorSettings.dataGridMu
const hideNullColumns = computed(() => settingsStore.editorSettings.dataGridHideNullColumns);
const booleanCellsUseCheckbox = computed(() => settingsStore.editorSettings.dataGridBooleanDisplayMode === "checkbox");
const booleanDisplayMode = computed(() => settingsStore.editorSettings.dataGridBooleanDisplayMode);
const colorizeDataGridCellTypes = computed(() => settingsStore.editorSettings.colorizeDataGridCellTypes);
const { isDark, themePalette } = useTheme();
const { toast } = useToast();
// 外键单元格跳转复用导航入口;对话框引用传 stub(同 AiAssistant 模式)
@@ -657,23 +659,7 @@ function selectedSortMenuValue(column: string, columnIndex: number): SortMenuVal
}
function typeColorClass(t: string): string {
// Strip precision/scale suffix like (20,6)
const base = t.replace(/\(.*\)$/, "").toLowerCase();
if (["int", "int2", "int4", "int8", "smallint", "bigint", "integer", "serial", "bigserial", "tinyint", "mediumint"].includes(base)) return "text-blue-500";
// number: Oracle/Dameng NUMBER;binary_float/binary_double: Oracle IEEE 浮点
if (["float4", "float8", "double", "decimal", "numeric", "real", "float", "money", "number", "binary_float", "binary_double", "dec"].includes(base)) return "text-cyan-500";
// varchar2/nvarchar2/long: Oracle/Dameng 字符类型(LONG 在 Oracle 中是变长字符)
if (["varchar", "varchar2", "nvarchar2", "text", "char", "character varying", "character", "string", "nvarchar", "nchar", "ntext", "longtext", "mediumtext", "tinytext", "clob", "long"].includes(base)) return "text-green-500";
if (["bool", "boolean", "bit"].includes(base)) return "text-orange-500";
if (["timestamp", "timestamptz", "datetime", "date", "time", "timetz", "datetime2", "smalldatetime"].includes(base)) return "text-purple-500";
// xmltype: Oracle XMLType
if (["json", "jsonb", "xml", "xmltype", "array"].includes(base)) return "text-pink-500";
if (["uuid", "uniqueidentifier"].includes(base)) return "text-amber-500";
// raw/long raw/bfile: Oracle 二进制
if (["bytea", "blob", "binary", "varbinary", "image", "raw", "long raw", "bfile"].includes(base)) return "text-red-400";
// sdo_geometry: Oracle Spatial
if (["geometry", "geography", "sdo_geometry"].includes(base)) return "text-emerald-500";
return "text-muted-foreground";
return dataGridTypeVisualClass(resolveDataGridTypeVisualKind(t, resolvedDatabaseType.value));
}
const contextCell = ref<{
rowId: number;
@@ -1976,6 +1962,8 @@ const allColumnTypes = computed(() =>
),
);
const visibleColumnTypes = computed(() => visibleColumnIndexes.value.map((index) => allColumnTypes.value[index]));
const allColumnTypeVisualKinds = computed(() => allColumnTypes.value.map((type) => resolveDataGridTypeVisualKind(type, resolvedDatabaseType.value)));
const visibleColumnTypeVisualKinds = computed(() => visibleColumnIndexes.value.map((index) => allColumnTypeVisualKinds.value[index] ?? "unknown"));
const visibleColumnComments = computed(() => visibleColumnIndexes.value.map((index) => dataGridColumnCommentFor(columnCommentMap.value, props.result.columns[index] ?? "", props.sourceColumns?.[index])));
const visibleColumnCount = computed(() => visibleColumnIndexes.value.length);
@@ -1985,6 +1973,45 @@ const columnAligns = computed<("left" | "right")[]>(() => {
return visibleColumnTypes.value.map((type) => (isNumericColumnType(type) ? "right" : "left"));
});
function gridCellTextColorClass(item: RowItem, actualColIdx: number, visibleColIdx: number): string {
if (!colorizeDataGridCellTypes.value) return "text-foreground";
const value = item.data[actualColIdx];
const checkbox = booleanCellsUseCheckbox.value && isBooleanGridCell(item, actualColIdx) && value !== null;
return dataGridCellTextClass({
colorizeTypes: colorizeDataGridCellTypes.value,
typeKind: allColumnTypeVisualKinds.value[actualColIdx] ?? "unknown",
isNull: value === null,
isDraft: item.isDraft && value === null,
isEditing: editingCell.value?.rowId === item.id && editingCell.value.col === actualColIdx,
isControl: checkbox,
isSelected: rowCellsUseSelectionVisual(item.id) || cellIsSelected(item.displayIndex, visibleColIdx),
isCurrentSearchMatch: cellIsCurrentMatch(item.displayIndex, actualColIdx),
isSearchMatch: cellIsSearchMatch(item.displayIndex, actualColIdx),
isDirty: item.isDirtyCol[actualColIdx],
isDeleted: item.isDeleted,
});
}
function transposeCellTextColorClass(recordIndex: number, actualColIdx: number): string {
if (!colorizeDataGridCellTypes.value) return "text-foreground";
const item = displayItems.value[recordIndex];
if (!item) return "text-foreground";
const value = item.data[actualColIdx];
return dataGridCellTextClass({
colorizeTypes: colorizeDataGridCellTypes.value,
typeKind: allColumnTypeVisualKinds.value[actualColIdx] ?? "unknown",
isNull: value === null,
isDraft: item.isDraft && value === null,
isEditing: editingCell.value?.rowId === item.id && editingCell.value.col === actualColIdx,
isControl: booleanCellsUseCheckbox.value && isBooleanGridCell(item, actualColIdx) && value !== null,
isSelected: transposeRecordUsesSelectionVisual(recordIndex) || transposeCellIsSelected(recordIndex, actualColIdx),
isCurrentSearchMatch: cellIsCurrentMatch(recordIndex, actualColIdx),
isSearchMatch: cellIsSearchMatch(recordIndex, actualColIdx),
isDirty: item.isDirtyCol[actualColIdx],
isDeleted: item.isDeleted,
});
}
/** Preview actions from the result preview registry for the current result. */
const previewActions = computed(() => {
if (!props.result) return [];
@@ -5349,10 +5376,6 @@ function queryColumnRef(name: string): string {
return props.databaseType === "neo4j" ? `n.${quoted}` : quoted;
}
function isNull(value: unknown): boolean {
return value === null;
}
function rowNumberStatusClass(item: RowItem): string {
if (item.status === "draft") {
return "border-muted-foreground/20 bg-muted/20 font-semibold text-muted-foreground";
@@ -6077,6 +6100,8 @@ function drawCanvasGrid() {
pageOffset: rowNumberPageOffset(),
frozenColumnCount: frozenColumnCount.value,
columnAligns: columnAligns.value,
columnTypeVisualKinds: visibleColumnTypeVisualKinds.value,
colorizeDataTypes: colorizeDataGridCellTypes.value,
rightAlignedActionCell: canvasRightAlignedActionCell.value,
columnIsBoolean: isBooleanGridColumn,
booleanDisplayMode: booleanDisplayMode.value,
@@ -6097,6 +6122,7 @@ watch(showDataGridTopbar, () => nextTick(observeDataGridTopbarWidth), {
});
watch(columnAligns, () => scheduleCanvasDraw());
watch(booleanDisplayMode, () => scheduleCanvasDraw());
watch(colorizeDataGridCellTypes, () => scheduleCanvasDraw());
watch(
[
displayRowRefs,
@@ -10163,22 +10189,24 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
v-for="cell in item.values"
:key="`${item.id}:${cell.recordIndex}`"
class="relative flex shrink-0 items-center border-r border-border/70 px-2 py-0 truncate"
:class="{
'text-muted-foreground italic': cell.isNull,
'cell-selected': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'cell-selected-dirty': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'cell-selected--sparse': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'cell-selected-dirty--sparse': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'row-cell-selected': transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'row-cell-selected-dirty': transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'bg-primary/15': transposeRecordUsesActiveHighlight(cell.recordIndex) && !transposeRecordUsesSelectionVisual(cell.recordIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex] && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex),
'bg-yellow-500/10 cell-dirty': displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'bg-yellow-200/60 dark:bg-yellow-500/20': cellIsSearchMatch(cell.recordIndex, cell.valueIndex),
'ring-2 ring-inset ring-yellow-500 bg-yellow-300/60 dark:bg-yellow-500/40': cellIsCurrentMatch(cell.recordIndex, cell.valueIndex),
'cursor-text': !isScrolling && canEditCellItem(displayItems[cell.recordIndex], cell.valueIndex),
'hover:bg-gray-200 dark:hover:bg-gray-800':
!isScrolling && canEditCellItem(displayItems[cell.recordIndex], cell.valueIndex) && !transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeRecordUsesActiveHighlight(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex),
}"
:class="[
transposeCellTextColorClass(cell.recordIndex, cell.valueIndex),
{
'cell-selected': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'cell-selected-dirty': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'cell-selected--sparse': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'cell-selected-dirty--sparse': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'row-cell-selected': transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'row-cell-selected-dirty': transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'bg-primary/15': transposeRecordUsesActiveHighlight(cell.recordIndex) && !transposeRecordUsesSelectionVisual(cell.recordIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex] && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex),
'bg-yellow-500/10 cell-dirty': displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
'bg-yellow-200/60 dark:bg-yellow-500/20': cellIsSearchMatch(cell.recordIndex, cell.valueIndex),
'ring-2 ring-inset ring-yellow-500 bg-yellow-300/60 dark:bg-yellow-500/40': cellIsCurrentMatch(cell.recordIndex, cell.valueIndex),
'cursor-text': !isScrolling && canEditCellItem(displayItems[cell.recordIndex], cell.valueIndex),
'hover:bg-gray-200 hover:text-foreground dark:hover:bg-gray-800':
!isScrolling && canEditCellItem(displayItems[cell.recordIndex], cell.valueIndex) && !transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeRecordUsesActiveHighlight(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex),
},
]"
:style="{
width: `${getTransposeRecordWidth(cell.recordIndex)}px`,
}"
@@ -10915,12 +10943,12 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
class="data-grid-cell group/cell shrink-0 px-3 py-1 border-r border-border whitespace-nowrap overflow-hidden text-ellipsis relative select-none inline-block items-center tabular-nums"
:style="renderedColumnStyle(col.visibleColIdx)"
:class="[
gridCellTextColorClass(item, col.actualColIdx, col.visibleColIdx),
selectionFrameEdgeClass(item.displayIndex, col.visibleColIdx),
{
'data-grid-cell--frozen': col.visibleColIdx < frozenColumnCount,
'data-grid-cell--frozen-separator': frozenColumnCount > 0 && col.visibleColIdx === frozenColumnCount - 1,
'text-right': columnAligns[col.visibleColIdx] === 'right',
'text-muted-foreground italic': isNull(item.data[col.actualColIdx]),
'bg-yellow-500/10 cell-dirty': item.isDirtyCol[col.actualColIdx],
'cell-selected': cellIsSelected(item.displayIndex, col.visibleColIdx) && !item.isDirtyCol[col.actualColIdx],
'cell-selected-dirty': cellIsSelected(item.displayIndex, col.visibleColIdx) && item.isDirtyCol[col.actualColIdx],
@@ -10934,7 +10962,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
'bg-yellow-200/60 dark:bg-yellow-500/20': cellIsSearchMatch(item.displayIndex, col.actualColIdx),
'ring-2 ring-inset ring-yellow-500 bg-yellow-300/60 dark:bg-yellow-500/40': cellIsCurrentMatch(item.displayIndex, col.actualColIdx),
'tabular-nums': typeof item.data[col.actualColIdx] === 'number',
'cursor-text hover:bg-gray-200 dark:hover:bg-gray-800': !isScrolling && canEditCellItem(item, col.actualColIdx) && !(booleanCellsUseCheckbox && isBooleanGridCell(item, col.actualColIdx) && item.data[col.actualColIdx] !== null),
'cursor-text hover:bg-gray-200 hover:text-foreground dark:hover:bg-gray-800': !isScrolling && canEditCellItem(item, col.actualColIdx) && !(booleanCellsUseCheckbox && isBooleanGridCell(item, col.actualColIdx) && item.data[col.actualColIdx] !== null),
'cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-800': !isScrolling && booleanCellsUseCheckbox && isBooleanGridCell(item, col.actualColIdx) && item.data[col.actualColIdx] !== null && canEditCellItem(item, col.actualColIdx),
'line-through': item.isDeleted,
'overflow-visible z-20 border-r-transparent': editingCell?.rowId === item.id && editingCell?.col === col.actualColIdx,
@@ -7,7 +7,36 @@ import { defaultViewForResult } from "@/lib/query/queryResultDefaultView";
import { isQueryExecutionErrorResult } from "@/lib/query/queryResultError";
import type { CSSProperties } from "vue";
import { useI18n } from "vue-i18n";
import { Check, CheckSquare2, Columns3Cog, Copy, EyeOff, Loader2, Search, TableProperties, ChevronDown, ChevronUp, Inbox, RefreshCcw, Wrench, Toolbox, Database, Download, Upload, X, Pin, Rows3, SquareDashed, Minus, Plus, ShieldAlert, AlignLeft, AlignRight, PanelsTopLeft } from "@lucide/vue";
import {
Check,
CheckSquare2,
Columns3Cog,
Copy,
EyeOff,
Loader2,
Search,
TableProperties,
ChevronDown,
ChevronUp,
Inbox,
RefreshCcw,
Wrench,
Toolbox,
Database,
Download,
Upload,
X,
Pin,
Rows3,
SquareDashed,
Minus,
Plus,
ShieldAlert,
AlignLeft,
AlignRight,
PanelsTopLeft,
Palette,
} from "@lucide/vue";
import { Splitpanes, Pane } from "splitpanes";
import { DynamicScroller, DynamicScrollerItem } from "vue-virtual-scroller";
import "splitpanes/dist/splitpanes.css";
@@ -194,6 +223,8 @@ const connectionStore = useConnectionStore();
const settingsStore = useSettingsStore();
const booleanDisplayMode = computed(() => settingsStore.editorSettings.dataGridBooleanDisplayMode);
const setBooleanDisplayMode = (mode: "checkbox" | "dropdown") => settingsStore.updateEditorSettings({ dataGridBooleanDisplayMode: mode });
const colorizeDataGridCellTypes = computed(() => settingsStore.editorSettings.colorizeDataGridCellTypes);
const setColorizeDataGridCellTypes = (value: boolean) => settingsStore.updateEditorSettings({ colorizeDataGridCellTypes: value });
const { toast } = useToast();
const DEFAULT_QUERY_RESULTS_PANE_SIZE = 68;
@@ -1365,6 +1396,13 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
</button>
</div>
</div>
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs">
<div class="min-w-0 flex items-center gap-2 font-medium">
<Palette class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
<span>{{ t("grid.colorizeDataTypes") }}</span>
</div>
<Switch size="sm" :model-value="colorizeDataGridCellTypes" :aria-label="t('grid.colorizeDataTypes')" @update:model-value="setColorizeDataGridCellTypes" />
</div>
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs" :class="{ 'opacity-60': !dataGridRef?.canToggleAllNullColumns }">
<span class="min-w-0 flex items-center gap-2 font-medium">
<EyeOff class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
@@ -1858,6 +1896,13 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
</button>
</div>
</div>
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs">
<div class="min-w-0 flex items-center gap-2 font-medium">
<Palette class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
<span>{{ t("grid.colorizeDataTypes") }}</span>
</div>
<Switch size="sm" :model-value="colorizeDataGridCellTypes" :aria-label="t('grid.colorizeDataTypes')" @update:model-value="setColorizeDataGridCellTypes" />
</div>
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs" :class="{ 'opacity-60': !dataGridRef?.canToggleAllNullColumns }">
<span class="min-w-0 flex items-center gap-2 font-medium">
<EyeOff class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />