fix(grid): stabilize header height during horizontal scroll
This commit is contained in:
1 parent
d3947d246c
commit
51b4c79847
5 files changed
+114
-2
No files matched your search
@@ -196,6 +196,7 @@ import type { DataGridSortDirection, DataGridSortMode } from "@/lib/dataGrid/dat
|
||||
import { DATA_GRID_COMPACT_TOPBAR_WIDTH, type DataGridReloadIntent, type DataGridToolbarActionCapability, type DataGridToolbarAutoRefreshCapability, type DataGridToolbarSaveCapability } from "@/lib/dataGrid/dataGridToolbar";
|
||||
import { getTableMetadataCapabilities } from "@/lib/table/tableMetadataCapabilities";
|
||||
import { getTableStructureCapabilities } from "@/lib/table/tableStructureCapabilities";
|
||||
import { reserveDataGridHeaderLine } from "@/lib/dataGrid/dataGridHeaderLayout";
|
||||
import { supportsTableStructureEditing } from "@/lib/database/databaseCapabilities";
|
||||
import { rememberDataGridConditionHistory } from "@/lib/dataGrid/dataGridConditionHistory";
|
||||
import { effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
|
||||
@@ -441,6 +442,10 @@ function headerColumnType(column: string, actualColIdx: number): string {
|
||||
return resolved ? shortTypeName(compactHeaderColumnType(resolved)) : "";
|
||||
}
|
||||
|
||||
const reserveColumnTypeLine = computed(() => reserveDataGridHeaderLine(showColumnTypesInHeader.value, props.result.columns, (column, index) => headerColumnType(column, index)));
|
||||
// Match the rendered header columns so comments from unprojected metadata cannot add an empty row.
|
||||
const reserveColumnCommentLine = computed(() => reserveDataGridHeaderLine(showColumnCommentsInHeader.value, props.result.columns, (column) => headerColumnComment(column)));
|
||||
|
||||
function shortTypeName(t: string): string {
|
||||
const s = t.toLowerCase();
|
||||
if (s === "character varying") return "varchar";
|
||||
@@ -7769,6 +7774,8 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
:tooltip-disabled="columnHeaderTooltipsDisabled"
|
||||
:column-type="headerColumnType(col.name, col.actualColIdx)"
|
||||
:column-comment="headerColumnComment(col.name)"
|
||||
:show-type-line="reserveColumnTypeLine"
|
||||
:show-comment-line="reserveColumnCommentLine"
|
||||
:tooltip-column-type="columnTypeMap.get(col.name)"
|
||||
:tooltip-column-comment="columnCommentMap.get(col.name)"
|
||||
:type-class="typeColorClass(headerColumnType(col.name, col.actualColIdx))"
|
||||
|
||||
@@ -15,6 +15,8 @@ defineProps<{
|
||||
columnComment?: string;
|
||||
tooltipColumnType?: string;
|
||||
tooltipColumnComment?: string;
|
||||
showTypeLine?: boolean;
|
||||
showCommentLine?: boolean;
|
||||
typeClass?: HTMLAttributes["class"];
|
||||
dragClass?: HTMLAttributes["class"];
|
||||
columnStyle?: CSSProperties;
|
||||
@@ -51,8 +53,10 @@ const emit = defineEmits<{
|
||||
<span class="flex min-w-0 items-center gap-1 overflow-hidden">
|
||||
<span class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<span class="min-w-0 truncate leading-4">{{ name }}</span>
|
||||
<span v-if="columnType" class="min-w-0 truncate text-[10px] font-normal leading-3" :class="typeClass" :title="columnType">{{ columnType }}</span>
|
||||
<span v-if="columnComment" class="min-w-0 truncate text-[10px] font-normal leading-3 text-muted-foreground" :title="columnComment">{{ columnComment }}</span>
|
||||
<span v-if="showTypeLine" data-grid-header-type-line class="h-3 min-w-0 truncate text-[10px] font-normal leading-3" :class="[typeClass, { invisible: !columnType }]" :title="columnType || undefined" :aria-hidden="columnType ? undefined : true">{{ columnType }}</span>
|
||||
<span v-if="showCommentLine" data-grid-header-comment-line class="h-3 min-w-0 truncate text-[10px] font-normal leading-3 text-muted-foreground" :class="{ invisible: !columnComment }" :title="columnComment || undefined" :aria-hidden="columnComment ? undefined : true">{{
|
||||
columnComment
|
||||
}}</span>
|
||||
</span>
|
||||
<slot name="actions" />
|
||||
</span>
|
||||
|
||||
@@ -212,6 +212,67 @@ describe("DataGridColumnHeader", () => {
|
||||
dispatch(handle, "dblclick");
|
||||
expect(autoFit).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("keeps configured type and comment lines mounted for columns without values", () => {
|
||||
const empty = mountComponent(DataGridColumnHeader, {
|
||||
name: "id",
|
||||
actualColumnIndex: 0,
|
||||
visibleColumnIndex: 0,
|
||||
showTypeLine: true,
|
||||
showCommentLine: true,
|
||||
copyColumnNameLabel: "copy",
|
||||
columnNameLabel: "name",
|
||||
columnTypeLabel: "type",
|
||||
columnCommentLabel: "comment",
|
||||
});
|
||||
const emptyType = findOne(empty.root, (node) => node.props["data-grid-header-type-line"] === "");
|
||||
const emptyComment = findOne(empty.root, (node) => node.props["data-grid-header-comment-line"] === "");
|
||||
|
||||
expect(String(emptyType.props.class)).toContain("h-3");
|
||||
expect(String(emptyType.props.class)).toContain("invisible");
|
||||
expect(emptyType.props.title).toBeUndefined();
|
||||
expect(String(emptyComment.props.class)).toContain("h-3");
|
||||
expect(String(emptyComment.props.class)).toContain("invisible");
|
||||
expect(emptyComment.props.title).toBeUndefined();
|
||||
|
||||
const populated = mountComponent(DataGridColumnHeader, {
|
||||
name: "status",
|
||||
actualColumnIndex: 1,
|
||||
visibleColumnIndex: 1,
|
||||
columnType: "varchar",
|
||||
columnComment: "Current status",
|
||||
showTypeLine: true,
|
||||
showCommentLine: true,
|
||||
copyColumnNameLabel: "copy",
|
||||
columnNameLabel: "name",
|
||||
columnTypeLabel: "type",
|
||||
columnCommentLabel: "comment",
|
||||
});
|
||||
const populatedType = findOne(populated.root, (node) => node.props["data-grid-header-type-line"] === "");
|
||||
const populatedComment = findOne(populated.root, (node) => node.props["data-grid-header-comment-line"] === "");
|
||||
|
||||
expect(String(populatedType.props.class)).not.toContain("invisible");
|
||||
expect(populatedType.props.title).toBe("varchar");
|
||||
expect(String(populatedComment.props.class)).not.toContain("invisible");
|
||||
expect(populatedComment.props.title).toBe("Current status");
|
||||
});
|
||||
|
||||
it("omits optional header lines when both display settings are off", () => {
|
||||
const mounted = mountComponent(DataGridColumnHeader, {
|
||||
name: "id",
|
||||
actualColumnIndex: 0,
|
||||
visibleColumnIndex: 0,
|
||||
columnType: "number",
|
||||
columnComment: "Identifier",
|
||||
copyColumnNameLabel: "copy",
|
||||
columnNameLabel: "name",
|
||||
columnTypeLabel: "type",
|
||||
columnCommentLabel: "comment",
|
||||
});
|
||||
|
||||
expect(findAll(mounted.root, (node) => node.props["data-grid-header-type-line"] === "")).toHaveLength(0);
|
||||
expect(findAll(mounted.root, (node) => node.props["data-grid-header-comment-line"] === "")).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("DataGridFilterBuilder", () => {
|
||||
|
||||
Reference in new issue
Block a user