mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-22 21:27:11 +08:00
✨ feat(query-editor): 记住查询编辑区结果区比例
- 持久化查询编辑器与结果面板的分割比例 - 新开查询 Tab 时按已保存比例恢复编辑区高度 - 补充分割比例计算与 QueryEditor 回归测试 Fixes #538
This commit is contained in:
43
frontend/src/utils/queryEditorSplitLayout.test.ts
Normal file
43
frontend/src/utils/queryEditorSplitLayout.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
DEFAULT_QUERY_EDITOR_EDITOR_HEIGHT_RATIO,
|
||||
MAX_QUERY_EDITOR_EDITOR_HEIGHT_RATIO,
|
||||
MIN_QUERY_EDITOR_EDITOR_HEIGHT,
|
||||
MIN_QUERY_EDITOR_EDITOR_HEIGHT_RATIO,
|
||||
MIN_QUERY_EDITOR_RESULT_HEIGHT,
|
||||
clampQueryEditorEditorHeight,
|
||||
resolveQueryEditorEditorHeightFromRatio,
|
||||
resolveQueryEditorEditorHeightRatio,
|
||||
sanitizeQueryEditorEditorHeightRatio,
|
||||
} from './queryEditorSplitLayout';
|
||||
|
||||
describe('query editor split layout', () => {
|
||||
it('sanitizes persisted editor height ratios', () => {
|
||||
expect(sanitizeQueryEditorEditorHeightRatio(undefined)).toBe(DEFAULT_QUERY_EDITOR_EDITOR_HEIGHT_RATIO);
|
||||
expect(sanitizeQueryEditorEditorHeightRatio(Number.NaN)).toBe(DEFAULT_QUERY_EDITOR_EDITOR_HEIGHT_RATIO);
|
||||
expect(sanitizeQueryEditorEditorHeightRatio(0.01)).toBe(MIN_QUERY_EDITOR_EDITOR_HEIGHT_RATIO);
|
||||
expect(sanitizeQueryEditorEditorHeightRatio(0.99)).toBe(MAX_QUERY_EDITOR_EDITOR_HEIGHT_RATIO);
|
||||
expect(sanitizeQueryEditorEditorHeightRatio(0.62)).toBe(0.62);
|
||||
});
|
||||
|
||||
it('resolves editor height from a persisted ratio while leaving room for results', () => {
|
||||
expect(resolveQueryEditorEditorHeightFromRatio(0.5, 800)).toBe(400);
|
||||
expect(resolveQueryEditorEditorHeightFromRatio(0.9, 800)).toBe(680);
|
||||
expect(resolveQueryEditorEditorHeightFromRatio(0.01, 800)).toBe(144);
|
||||
expect(resolveQueryEditorEditorHeightFromRatio(0.5, 0)).toBe(MIN_QUERY_EDITOR_EDITOR_HEIGHT);
|
||||
});
|
||||
|
||||
it('clamps editor height to valid split bounds', () => {
|
||||
expect(clampQueryEditorEditorHeight(20, 800)).toBe(MIN_QUERY_EDITOR_EDITOR_HEIGHT);
|
||||
expect(clampQueryEditorEditorHeight(760, 800)).toBe(800 - MIN_QUERY_EDITOR_RESULT_HEIGHT);
|
||||
expect(clampQueryEditorEditorHeight(360, 800)).toBe(360);
|
||||
});
|
||||
|
||||
it('resolves persisted ratio from the final editor height', () => {
|
||||
expect(resolveQueryEditorEditorHeightRatio(480, 800)).toBe(0.6);
|
||||
expect(resolveQueryEditorEditorHeightRatio(20, 800)).toBe(MIN_QUERY_EDITOR_EDITOR_HEIGHT_RATIO);
|
||||
expect(resolveQueryEditorEditorHeightRatio(760, 800)).toBe(MAX_QUERY_EDITOR_EDITOR_HEIGHT_RATIO);
|
||||
expect(resolveQueryEditorEditorHeightRatio(480, 0)).toBe(DEFAULT_QUERY_EDITOR_EDITOR_HEIGHT_RATIO);
|
||||
});
|
||||
});
|
||||
66
frontend/src/utils/queryEditorSplitLayout.ts
Normal file
66
frontend/src/utils/queryEditorSplitLayout.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
export const DEFAULT_QUERY_EDITOR_EDITOR_HEIGHT_RATIO = 0.5;
|
||||
export const MIN_QUERY_EDITOR_EDITOR_HEIGHT_RATIO = 0.18;
|
||||
export const MAX_QUERY_EDITOR_EDITOR_HEIGHT_RATIO = 0.85;
|
||||
export const MIN_QUERY_EDITOR_EDITOR_HEIGHT = 100;
|
||||
export const MIN_QUERY_EDITOR_RESULT_HEIGHT = 120;
|
||||
|
||||
export const sanitizeQueryEditorEditorHeightRatio = (value: unknown): number => {
|
||||
const ratio = Number(value);
|
||||
if (!Number.isFinite(ratio)) {
|
||||
return DEFAULT_QUERY_EDITOR_EDITOR_HEIGHT_RATIO;
|
||||
}
|
||||
return Math.min(
|
||||
MAX_QUERY_EDITOR_EDITOR_HEIGHT_RATIO,
|
||||
Math.max(MIN_QUERY_EDITOR_EDITOR_HEIGHT_RATIO, ratio),
|
||||
);
|
||||
};
|
||||
|
||||
export const clampQueryEditorEditorHeight = (
|
||||
height: unknown,
|
||||
availableHeight: unknown,
|
||||
): number => {
|
||||
const rawHeight = Number(height);
|
||||
const rawAvailableHeight = Number(availableHeight);
|
||||
const normalizedHeight = Number.isFinite(rawHeight) ? rawHeight : MIN_QUERY_EDITOR_EDITOR_HEIGHT;
|
||||
if (!Number.isFinite(rawAvailableHeight) || rawAvailableHeight <= 0) {
|
||||
return Math.max(MIN_QUERY_EDITOR_EDITOR_HEIGHT, Math.round(normalizedHeight));
|
||||
}
|
||||
const maxEditorHeight = Math.max(
|
||||
MIN_QUERY_EDITOR_EDITOR_HEIGHT,
|
||||
rawAvailableHeight - MIN_QUERY_EDITOR_RESULT_HEIGHT,
|
||||
);
|
||||
return Math.round(Math.max(
|
||||
MIN_QUERY_EDITOR_EDITOR_HEIGHT,
|
||||
Math.min(maxEditorHeight, normalizedHeight),
|
||||
));
|
||||
};
|
||||
|
||||
export const resolveQueryEditorEditorHeightFromRatio = (
|
||||
ratio: unknown,
|
||||
availableHeight: unknown,
|
||||
): number => {
|
||||
const rawAvailableHeight = Number(availableHeight);
|
||||
if (!Number.isFinite(rawAvailableHeight) || rawAvailableHeight <= 0) {
|
||||
return MIN_QUERY_EDITOR_EDITOR_HEIGHT;
|
||||
}
|
||||
return clampQueryEditorEditorHeight(
|
||||
rawAvailableHeight * sanitizeQueryEditorEditorHeightRatio(ratio),
|
||||
rawAvailableHeight,
|
||||
);
|
||||
};
|
||||
|
||||
export const resolveQueryEditorEditorHeightRatio = (
|
||||
editorHeight: unknown,
|
||||
availableHeight: unknown,
|
||||
): number => {
|
||||
const rawEditorHeight = Number(editorHeight);
|
||||
const rawAvailableHeight = Number(availableHeight);
|
||||
if (
|
||||
!Number.isFinite(rawEditorHeight)
|
||||
|| !Number.isFinite(rawAvailableHeight)
|
||||
|| rawAvailableHeight <= 0
|
||||
) {
|
||||
return DEFAULT_QUERY_EDITOR_EDITOR_HEIGHT_RATIO;
|
||||
}
|
||||
return sanitizeQueryEditorEditorHeightRatio(rawEditorHeight / rawAvailableHeight);
|
||||
};
|
||||
Reference in New Issue
Block a user