fix(grid): allow resizing the transposed metadata info column
This commit is contained in:
1 parent
fbb588eecb
commit
045715a90d
4 files changed
+114
-3
No files matched your search
@@ -149,9 +149,12 @@ import { sumGridCountValues } from "@/lib/dataGrid/dataGridCountValue";
|
||||
import {
|
||||
buildVisibleTransposeRows,
|
||||
averageTransposeRecordWidth,
|
||||
calculateTransposeInfoWidth,
|
||||
calculateTransposeRecordWidth,
|
||||
defaultTransposeInfoWidth,
|
||||
defaultTransposeRecordWidth,
|
||||
minTransposeFieldWidth,
|
||||
minTransposeInfoWidth,
|
||||
minTransposeRecordWidth,
|
||||
nextContextTransposeState,
|
||||
nextKeyboardTransposeState,
|
||||
@@ -12416,7 +12419,8 @@ const transposeReserveTypeLine = computed(() => showTransposeFieldMetadata.value
|
||||
const transposeReserveCommentLine = computed(() => showTransposeFieldMetadata.value && showTransposeColumnComments.value && transposeRows.value.some((row) => row.comment));
|
||||
const transposeRowHeight = computed(() => 30 + (transposeReserveTypeLine.value ? 14 : 0) + (transposeReserveCommentLine.value ? 14 : 0));
|
||||
const isTransposeMode = computed(() => showTranspose.value && transposeRows.value.length > 0);
|
||||
const transposeInfoWidth = computed(() => (transposeMetadataInInfoColumn.value ? 360 : 0));
|
||||
const transposeInfoWidthOverride = ref<number | null>(null);
|
||||
const transposeInfoWidth = computed(() => (transposeMetadataInInfoColumn.value ? (transposeInfoWidthOverride.value ?? defaultTransposeInfoWidth(columnWidthDensity.value)) : 0));
|
||||
const transposeTotalWidth = computed(() => transposePinnedWidth.value + transposeRecordOffsets.value[transposeRecordOffsets.value.length - 1] + transposeEndSpacerWidth.value + transposeInfoWidth.value);
|
||||
|
||||
function transposeScrollElement(): HTMLElement | undefined {
|
||||
@@ -12604,6 +12608,28 @@ function autoFitTransposeRecord(recordIndex: number) {
|
||||
transposeRecordWidths.value = next;
|
||||
}
|
||||
|
||||
function onTransposeInfoResizeStart(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
const startX = event.clientX;
|
||||
const startWidth = transposeInfoWidth.value;
|
||||
const onMove = (e: MouseEvent) => {
|
||||
transposeInfoWidthOverride.value = Math.max(minTransposeInfoWidth(columnWidthDensity.value), startWidth + e.clientX - startX);
|
||||
updateTransposeViewport();
|
||||
};
|
||||
const onUp = () => {
|
||||
document.removeEventListener("mousemove", onMove);
|
||||
document.removeEventListener("mouseup", onUp);
|
||||
};
|
||||
document.addEventListener("mousemove", onMove);
|
||||
document.addEventListener("mouseup", onUp);
|
||||
}
|
||||
|
||||
function autoFitTransposeInfo() {
|
||||
const texts = visibleColumnIndexes.value.map((columnIndex) => columnInfoText(columnIndex, false));
|
||||
transposeInfoWidthOverride.value = calculateTransposeInfoWidth(texts, { density: columnWidthDensity.value });
|
||||
updateTransposeViewport();
|
||||
}
|
||||
|
||||
function currentTransposeViewportRowIndex(): number {
|
||||
if (displayRowCount.value === 0) return 0;
|
||||
const rowIndex = transposeRowIndex.value ?? transposeScopeRecordIndexes.value[transposeRecordWindow.value.start] ?? 0;
|
||||
@@ -15651,8 +15677,9 @@ useUpdateBlocker(() => (hasPendingChanges.value || hasPendingDataEditorDraft.val
|
||||
<div class="absolute right-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-primary/30" @mousedown.stop="onTransposeRecordResizeStart(recordIndex, $event)" @dblclick.stop="autoFitTransposeRecord(recordIndex)" />
|
||||
</div>
|
||||
<div class="shrink-0" :style="{ width: `${transposeAfterSpacerWidth}px` }" />
|
||||
<div v-if="transposeMetadataInInfoColumn" class="data-grid-header-cell shrink-0 border-r border-border px-3 py-1.5" :style="{ width: `${transposeInfoWidth}px` }">
|
||||
{{ t("grid.columnInfo") }}
|
||||
<div v-if="transposeMetadataInInfoColumn" class="data-grid-header-cell relative flex shrink-0 items-center border-r border-border px-3 py-1.5 truncate" :style="{ width: `${transposeInfoWidth}px` }">
|
||||
<span class="min-w-0 flex-1 truncate">{{ t("grid.columnInfo") }}</span>
|
||||
<div data-grid-transpose-info-resize-handle class="absolute right-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-primary/30" @mousedown.stop="onTransposeInfoResizeStart" @dblclick.stop="autoFitTransposeInfo" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -238,4 +238,45 @@ describe("DataGrid transpose sorting", () => {
|
||||
await settle();
|
||||
expect(transposeFieldNames(host)).toEqual(["zeta", "alpha"]);
|
||||
});
|
||||
|
||||
it("allows resizing and auto-fitting the independent transpose info column", async () => {
|
||||
const { host, settingsStore } = mountGrid();
|
||||
settingsStore.updateEditorSettings({ dataGridTransposeMetadataInInfoColumn: true });
|
||||
await settle();
|
||||
await openTranspose(host);
|
||||
|
||||
const handle = host.querySelector<HTMLElement>("[data-grid-transpose-info-resize-handle]");
|
||||
expect(handle).not.toBeNull();
|
||||
|
||||
const headerInfoCell = handle!.parentElement as HTMLElement;
|
||||
expect(headerInfoCell.style.width).toBe("360px");
|
||||
const rowInfoCell = host.querySelector<HTMLElement>("[data-grid-transpose-column-info]");
|
||||
expect(rowInfoCell?.style.width).toBe("360px");
|
||||
|
||||
// Drag to widen (+150px)
|
||||
handle!.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true, clientX: 200 }));
|
||||
document.dispatchEvent(new MouseEvent("mousemove", { bubbles: true, cancelable: true, clientX: 350 }));
|
||||
document.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, cancelable: true }));
|
||||
await settle();
|
||||
|
||||
expect(headerInfoCell.style.width).toBe("510px");
|
||||
expect(rowInfoCell?.style.width).toBe("510px");
|
||||
|
||||
// Drag to narrow below min width (should clamp to minTransposeInfoWidth = 120px)
|
||||
handle!.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true, clientX: 350 }));
|
||||
document.dispatchEvent(new MouseEvent("mousemove", { bubbles: true, cancelable: true, clientX: -100 }));
|
||||
document.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, cancelable: true }));
|
||||
await settle();
|
||||
|
||||
expect(headerInfoCell.style.width).toBe("120px");
|
||||
expect(rowInfoCell?.style.width).toBe("120px");
|
||||
|
||||
// Double-click to auto-fit
|
||||
handle!.dispatchEvent(new MouseEvent("dblclick", { bubbles: true, cancelable: true }));
|
||||
await settle();
|
||||
|
||||
const autoFittedWidth = parseInt(headerInfoCell.style.width, 10);
|
||||
expect(autoFittedWidth).toBeGreaterThan(120);
|
||||
expect(rowInfoCell?.style.width).toBe(`${autoFittedWidth}px`);
|
||||
});
|
||||
});
|
||||
@@ -3,8 +3,11 @@ import {
|
||||
averageTransposeRecordWidth,
|
||||
buildVisibleTransposeRows,
|
||||
calculateTransposeRecordWidth,
|
||||
calculateTransposeInfoWidth,
|
||||
defaultTransposeInfoWidth,
|
||||
defaultTransposeRecordWidth,
|
||||
minTransposeFieldWidth,
|
||||
minTransposeInfoWidth,
|
||||
shouldAutoTransposeSingleRow,
|
||||
transposeAnchorRowIndex,
|
||||
transposeEndAlignmentSpacerWidth,
|
||||
@@ -59,6 +62,23 @@ describe("dataGridTranspose density widths", () => {
|
||||
expect(transposeFieldWidth([], { density: "compact" })).toBe(minTransposeFieldWidth("compact"));
|
||||
});
|
||||
|
||||
it("scales default and min transpose info width with density", () => {
|
||||
expect(defaultTransposeInfoWidth("compact")).toBeLessThan(defaultTransposeInfoWidth("standard"));
|
||||
expect(defaultTransposeInfoWidth("standard")).toBe(360);
|
||||
expect(defaultTransposeInfoWidth("standard")).toBeLessThan(defaultTransposeInfoWidth("comfortable"));
|
||||
|
||||
expect(minTransposeInfoWidth("compact")).toBeLessThan(minTransposeInfoWidth("standard"));
|
||||
expect(minTransposeInfoWidth("standard")).toBe(120);
|
||||
expect(minTransposeInfoWidth("standard")).toBeLessThan(minTransposeInfoWidth("comfortable"));
|
||||
|
||||
const longMetadata = ["varchar(255) · Nullable: Yes · " + "a".repeat(120)];
|
||||
const compactWidth = calculateTransposeInfoWidth(longMetadata, { density: "compact" });
|
||||
const standardWidth = calculateTransposeInfoWidth(longMetadata, { density: "standard" });
|
||||
expect(compactWidth).toBeLessThan(standardWidth);
|
||||
expect(standardWidth).toBeGreaterThan(defaultTransposeInfoWidth("standard"));
|
||||
expect(calculateTransposeInfoWidth([])).toBe(defaultTransposeInfoWidth("standard"));
|
||||
});
|
||||
|
||||
it("keeps compact record width independent of field order", () => {
|
||||
const longValue = "x".repeat(100);
|
||||
|
||||
|
||||
@@ -105,6 +105,9 @@ const TRANSPOSE_RECORD_MIN_WIDTH = 96;
|
||||
const TRANSPOSE_RECORD_DEFAULT_WIDTH = 168;
|
||||
const TRANSPOSE_FIELD_MIN_WIDTH = 104;
|
||||
const TRANSPOSE_FIELD_MAX_WIDTH = 220;
|
||||
export const TRANSPOSE_INFO_DEFAULT_WIDTH = 360;
|
||||
export const TRANSPOSE_INFO_MIN_WIDTH = 120;
|
||||
export const TRANSPOSE_INFO_MAX_WIDTH = 800;
|
||||
|
||||
// 转置视图每种密度对应的缩放因子(不再依赖 charWidth)
|
||||
const TRANSPOSE_DENSITY_SCALE: Record<ColumnWidthDensity, number> = {
|
||||
@@ -134,6 +137,26 @@ export function minTransposeFieldWidth(density: ColumnWidthDensity): number {
|
||||
return densityScaledWidth(TRANSPOSE_FIELD_MIN_WIDTH, density);
|
||||
}
|
||||
|
||||
export function defaultTransposeInfoWidth(density: ColumnWidthDensity): number {
|
||||
return densityScaledWidth(TRANSPOSE_INFO_DEFAULT_WIDTH, density);
|
||||
}
|
||||
|
||||
export function minTransposeInfoWidth(density: ColumnWidthDensity): number {
|
||||
return densityScaledWidth(TRANSPOSE_INFO_MIN_WIDTH, density);
|
||||
}
|
||||
|
||||
export function calculateTransposeInfoWidth(texts: readonly string[], options: TransposeFieldWidthOptions = {}): number {
|
||||
const density = options.density ?? "standard";
|
||||
const preset = COLUMN_WIDTH_DENSITY_PRESETS[density];
|
||||
const minWidth = options.minWidth ?? minTransposeInfoWidth(density);
|
||||
const maxWidth = options.maxWidth ?? densityScaledWidth(TRANSPOSE_INFO_MAX_WIDTH, density);
|
||||
const charWidth = options.charWidth ?? preset.charWidth;
|
||||
const padding = options.padding ?? preset.cellPadding + 16;
|
||||
const longest = texts.reduce((max, text) => Math.max(max, text.length), 0);
|
||||
if (longest === 0) return defaultTransposeInfoWidth(density);
|
||||
return Math.min(maxWidth, Math.max(minWidth, Math.ceil(longest * charWidth + padding)));
|
||||
}
|
||||
|
||||
export function calculateTransposeRecordWidth(values: readonly unknown[], density: ColumnWidthDensity): number {
|
||||
const preset = COLUMN_WIDTH_DENSITY_PRESETS[density];
|
||||
const minWidth = minTransposeRecordWidth(density);
|
||||
|
||||
Reference in new issue
Block a user