mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-12 17:39:42 +08:00
💄 style(query-editor): 调整 v2 查询工具栏布局样式
- 为查询工具栏控件增加 v2 专用 class,移除 v2 下 inline 固定宽度依赖 - 使用内容宽度约束选择区,避免最大行数后出现多余空白 - 覆盖 Ant Design Button.Group 负 margin 和伪元素合并效果 - 增加 CSS 静态断言覆盖对齐、间距和响应式布局
This commit is contained in:
@@ -2359,6 +2359,41 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(css).toContain('body[data-ui-version="v2"] .gn-v2-query-results .query-result-tab-text {');
|
||||
});
|
||||
|
||||
it('keeps the v2 query editor toolbar grouped and compact', () => {
|
||||
const source = readFileSync(new URL('./QueryEditor.tsx', import.meta.url), 'utf8');
|
||||
const css = readFileSync(new URL('../v2-theme.css', import.meta.url), 'utf8');
|
||||
|
||||
expect(source).toContain('gn-v2-query-toolbar-selects');
|
||||
expect(source).toContain('gn-v2-query-toolbar-actions');
|
||||
expect(source).toContain('gn-v2-query-toolbar-connection-select');
|
||||
expect(source).toContain('gn-v2-query-toolbar-database-select');
|
||||
expect(source).toContain('gn-v2-query-toolbar-max-rows-select');
|
||||
expect(source).toContain('gn-v2-query-toolbar-action-group');
|
||||
expect(source).toContain('style={isV2Ui ? undefined : { width: 150 }}');
|
||||
expect(source).toContain('style={isV2Ui ? undefined : { width: 200 }}');
|
||||
expect(source).toContain('style={isV2Ui ? undefined : { width: 170 }}');
|
||||
|
||||
expect(css).toContain('body[data-ui-version="v2"] .gn-v2-query-toolbar-selects');
|
||||
expect(css).toContain('body[data-ui-version="v2"] .gn-v2-query-toolbar-actions');
|
||||
expect(css).toContain('flex: 0 1 auto !important;');
|
||||
expect(css).toContain('justify-content: flex-start;');
|
||||
expect(css).toContain('height: 32px !important;');
|
||||
expect(css).toContain('line-height: 30px !important;');
|
||||
expect(css).toContain('display: inline-flex !important;');
|
||||
expect(css).toContain('gap: 6px;');
|
||||
expect(css).toContain('margin-left: 0 !important;');
|
||||
expect(css).toContain('max-width: 520px;');
|
||||
expect(css).toContain('width: 140px !important;');
|
||||
expect(css).toContain('width: 166px !important;');
|
||||
expect(css).toContain('width: 132px !important;');
|
||||
expect(css).toContain('width: 34px !important;');
|
||||
expect(css).toContain('@media (max-width: 900px)');
|
||||
|
||||
const queryToolbarCss = css.slice(css.indexOf('body[data-ui-version="v2"] .gn-v2-query-toolbar {'), css.indexOf('body[data-ui-version="v2"] .gn-v2-query-monaco-shell {'));
|
||||
expect(queryToolbarCss).not.toContain('margin-left: auto;');
|
||||
expect(queryToolbarCss).not.toContain('justify-content: flex-end;');
|
||||
});
|
||||
|
||||
it('coalesces editor result splitter dragging through requestAnimationFrame', async () => {
|
||||
const moveListeners: Array<(event: MouseEvent) => void> = [];
|
||||
const upListeners: Array<() => void> = [];
|
||||
|
||||
@@ -4875,92 +4875,105 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
`}</style>
|
||||
<div ref={editorPaneRef} className={isV2Ui ? 'gn-v2-query-editor-pane' : undefined}>
|
||||
<div className={isV2Ui ? 'gn-v2-query-toolbar' : undefined} style={{ padding: '4px 8px 8px', display: 'flex', gap: '8px', flexShrink: 0, alignItems: 'center' }}>
|
||||
<Select
|
||||
style={{ width: 150 }}
|
||||
placeholder="选择连接"
|
||||
value={currentConnectionId}
|
||||
onChange={(val) => {
|
||||
setCurrentConnectionId(val);
|
||||
setCurrentDb('');
|
||||
}}
|
||||
options={queryCapableConnections.map(c => ({ label: c.name, value: c.id }))}
|
||||
showSearch
|
||||
/>
|
||||
<Select
|
||||
style={{ width: 200 }}
|
||||
placeholder="选择数据库"
|
||||
value={currentDb}
|
||||
onChange={setCurrentDb}
|
||||
options={dbList.map(db => ({ label: db, value: db }))}
|
||||
showSearch
|
||||
/>
|
||||
<Tooltip title="最大返回行数(会对 SELECT 自动加 LIMIT,防止大结果集卡死)">
|
||||
<Select
|
||||
style={{ width: 170 }}
|
||||
value={queryOptions?.maxRows ?? 5000}
|
||||
onChange={(val) => setQueryOptions({ maxRows: Number(val) })}
|
||||
options={[
|
||||
{ label: '最大行数:500', value: 500 },
|
||||
{ label: '最大行数:1000', value: 1000 },
|
||||
{ label: '最大行数:5000', value: 5000 },
|
||||
{ label: '最大行数:20000', value: 20000 },
|
||||
{ label: '最大行数:不限', value: 0 },
|
||||
]}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Button.Group>
|
||||
<Tooltip
|
||||
title={
|
||||
runQueryShortcutBinding.enabled && runQueryShortcutBinding.combo
|
||||
? `运行(${getShortcutDisplayLabel(runQueryShortcutBinding.combo, activeShortcutPlatform)})`
|
||||
: '运行'
|
||||
}
|
||||
>
|
||||
<Button type="primary" icon={<PlayCircleOutlined />} onMouseDown={captureEditorCursorPosition} onClick={handleRun} loading={loading}>
|
||||
运行
|
||||
</Button>
|
||||
<div
|
||||
className={isV2Ui ? 'gn-v2-query-toolbar-selects' : undefined}
|
||||
style={{ display: 'flex', gap: '8px', flexShrink: 0, alignItems: 'center' }}
|
||||
>
|
||||
<Select
|
||||
className={isV2Ui ? 'gn-v2-query-toolbar-select gn-v2-query-toolbar-connection-select' : undefined}
|
||||
style={isV2Ui ? undefined : { width: 150 }}
|
||||
placeholder="选择连接"
|
||||
value={currentConnectionId}
|
||||
onChange={(val) => {
|
||||
setCurrentConnectionId(val);
|
||||
setCurrentDb('');
|
||||
}}
|
||||
options={queryCapableConnections.map(c => ({ label: c.name, value: c.id }))}
|
||||
showSearch
|
||||
/>
|
||||
<Select
|
||||
className={isV2Ui ? 'gn-v2-query-toolbar-select gn-v2-query-toolbar-database-select' : undefined}
|
||||
style={isV2Ui ? undefined : { width: 200 }}
|
||||
placeholder="选择数据库"
|
||||
value={currentDb}
|
||||
onChange={setCurrentDb}
|
||||
options={dbList.map(db => ({ label: db, value: db }))}
|
||||
showSearch
|
||||
/>
|
||||
<Tooltip title="最大返回行数(会对 SELECT 自动加 LIMIT,防止大结果集卡死)">
|
||||
<Select
|
||||
className={isV2Ui ? 'gn-v2-query-toolbar-select gn-v2-query-toolbar-max-rows-select' : undefined}
|
||||
style={isV2Ui ? undefined : { width: 170 }}
|
||||
value={queryOptions?.maxRows ?? 5000}
|
||||
onChange={(val) => setQueryOptions({ maxRows: Number(val) })}
|
||||
options={[
|
||||
{ label: '最大行数:500', value: 500 },
|
||||
{ label: '最大行数:1000', value: 1000 },
|
||||
{ label: '最大行数:5000', value: 5000 },
|
||||
{ label: '最大行数:20000', value: 20000 },
|
||||
{ label: '最大行数:不限', value: 0 },
|
||||
]}
|
||||
/>
|
||||
</Tooltip>
|
||||
{loading && (
|
||||
<Button type="primary" danger icon={<StopOutlined />} onClick={handleCancel}>
|
||||
停止
|
||||
</Button>
|
||||
)}
|
||||
</Button.Group>
|
||||
<Button.Group>
|
||||
</div>
|
||||
<div
|
||||
className={isV2Ui ? 'gn-v2-query-toolbar-actions' : undefined}
|
||||
style={{ display: 'flex', gap: '8px', flexShrink: 0, alignItems: 'center' }}
|
||||
>
|
||||
<Button.Group className={isV2Ui ? 'gn-v2-query-toolbar-action-group' : undefined}>
|
||||
<Tooltip
|
||||
title={
|
||||
saveQueryShortcutBinding.enabled && saveQueryShortcutBinding.combo
|
||||
? `保存(${getShortcutDisplayLabel(saveQueryShortcutBinding.combo, activeShortcutPlatform)})`
|
||||
: '保存'
|
||||
runQueryShortcutBinding.enabled && runQueryShortcutBinding.combo
|
||||
? `运行(${getShortcutDisplayLabel(runQueryShortcutBinding.combo, activeShortcutPlatform)})`
|
||||
: '运行'
|
||||
}
|
||||
>
|
||||
<Button icon={<SaveOutlined />} onClick={handleQuickSave}>
|
||||
保存
|
||||
<Button className={isV2Ui ? 'gn-v2-query-toolbar-run-action' : undefined} type="primary" icon={<PlayCircleOutlined />} onMouseDown={captureEditorCursorPosition} onClick={handleRun} loading={loading}>
|
||||
运行
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{loading && (
|
||||
<Button type="primary" danger icon={<StopOutlined />} onClick={handleCancel}>
|
||||
停止
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Dropdown menu={{ items: saveMoreMenuItems }} placement="bottomRight">
|
||||
<Button>更多</Button>
|
||||
</Dropdown>
|
||||
</Button.Group>
|
||||
|
||||
<Button.Group>
|
||||
<Tooltip title="美化 SQL">
|
||||
<Button icon={<FormatPainterOutlined />} onClick={handleFormat}>美化</Button>
|
||||
</Tooltip>
|
||||
<Dropdown menu={{ items: formatSettingsMenu }} placement="bottomRight">
|
||||
<Button icon={<SettingOutlined />} />
|
||||
</Dropdown>
|
||||
</Button.Group>
|
||||
)}
|
||||
</Button.Group>
|
||||
<Button.Group className={isV2Ui ? 'gn-v2-query-toolbar-action-group' : undefined}>
|
||||
<Tooltip
|
||||
title={
|
||||
saveQueryShortcutBinding.enabled && saveQueryShortcutBinding.combo
|
||||
? `保存(${getShortcutDisplayLabel(saveQueryShortcutBinding.combo, activeShortcutPlatform)})`
|
||||
: '保存'
|
||||
}
|
||||
>
|
||||
<Button icon={<SaveOutlined />} onClick={handleQuickSave}>
|
||||
保存
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Dropdown menu={{ items: saveMoreMenuItems }} placement="bottomRight">
|
||||
<Button>更多</Button>
|
||||
</Dropdown>
|
||||
</Button.Group>
|
||||
|
||||
<Dropdown menu={{ items: [
|
||||
{ key: 'ai-generate', label: '生成 SQL', icon: <RobotOutlined />, onClick: () => handleAIAction('generate') },
|
||||
{ key: 'ai-explain', label: '解释 SQL', icon: <RobotOutlined />, onClick: () => handleAIAction('explain') },
|
||||
{ key: 'ai-optimize', label: '优化 SQL', icon: <RobotOutlined />, onClick: () => handleAIAction('optimize') },
|
||||
{ type: 'divider' as const },
|
||||
{ key: 'ai-schema', label: 'Schema 分析', icon: <RobotOutlined />, onClick: () => handleAIAction('schema') },
|
||||
] }} placement="bottomRight">
|
||||
<Button icon={<RobotOutlined />} style={{ color: '#818cf8' }}>AI</Button>
|
||||
</Dropdown>
|
||||
<Button.Group className={isV2Ui ? 'gn-v2-query-toolbar-action-group' : undefined}>
|
||||
<Tooltip title="美化 SQL">
|
||||
<Button icon={<FormatPainterOutlined />} onClick={handleFormat}>美化</Button>
|
||||
</Tooltip>
|
||||
<Dropdown menu={{ items: formatSettingsMenu }} placement="bottomRight">
|
||||
<Button className={isV2Ui ? 'gn-v2-query-toolbar-icon-action' : undefined} icon={<SettingOutlined />} />
|
||||
</Dropdown>
|
||||
</Button.Group>
|
||||
|
||||
<Dropdown menu={{ items: [
|
||||
{ key: 'ai-generate', label: '生成 SQL', icon: <RobotOutlined />, onClick: () => handleAIAction('generate') },
|
||||
{ key: 'ai-explain', label: '解释 SQL', icon: <RobotOutlined />, onClick: () => handleAIAction('explain') },
|
||||
{ key: 'ai-optimize', label: '优化 SQL', icon: <RobotOutlined />, onClick: () => handleAIAction('optimize') },
|
||||
{ type: 'divider' as const },
|
||||
{ key: 'ai-schema', label: 'Schema 分析', icon: <RobotOutlined />, onClick: () => handleAIAction('schema') },
|
||||
] }} placement="bottomRight">
|
||||
<Button className={isV2Ui ? 'gn-v2-query-toolbar-ai-action' : undefined} icon={<RobotOutlined />} style={{ color: '#818cf8' }}>AI</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ref={editorShellRef} className={isV2Ui ? 'gn-v2-query-monaco-shell' : undefined} style={{ height: editorHeight, minHeight: '100px' }}>
|
||||
|
||||
@@ -4662,8 +4662,117 @@ body[data-ui-version="v2"] .gn-v2-designer-toolbar {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar {
|
||||
min-height: 48px;
|
||||
padding: 8px 12px !important;
|
||||
gap: 6px 10px !important;
|
||||
align-items: center !important;
|
||||
background: var(--gn-bg-panel) !important;
|
||||
border-bottom: 0.5px solid var(--gn-br-1) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-selects,
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-actions {
|
||||
min-width: 0;
|
||||
gap: 6px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-selects {
|
||||
flex: 0 1 auto !important;
|
||||
flex-wrap: nowrap;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-actions {
|
||||
flex: 0 1 auto !important;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .ant-select {
|
||||
min-width: 132px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-connection-select {
|
||||
width: 140px !important;
|
||||
flex: 0 1 140px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-database-select {
|
||||
width: 166px !important;
|
||||
flex: 1 1 166px !important;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-max-rows-select {
|
||||
width: 132px !important;
|
||||
flex: 0 0 132px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .ant-select-selector {
|
||||
height: 32px !important;
|
||||
padding: 0 10px !important;
|
||||
border-radius: 9px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .ant-select-selection-item,
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .ant-select-selection-placeholder {
|
||||
line-height: 30px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .ant-btn {
|
||||
height: 32px !important;
|
||||
padding: 0 11px !important;
|
||||
border-radius: 9px !important;
|
||||
font-size: 12.5px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-action-group.ant-btn-group {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-action-group.ant-btn-group > .ant-btn {
|
||||
flex: 0 0 auto;
|
||||
border-radius: 9px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-action-group.ant-btn-group > .ant-btn:not(:first-child) {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-action-group.ant-btn-group > .ant-btn::before {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-icon-action.ant-btn,
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .ant-btn-icon-only {
|
||||
width: 34px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-run-action.ant-btn {
|
||||
min-width: 64px;
|
||||
padding: 0 13px !important;
|
||||
font-weight: 650 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-ai-action.ant-btn {
|
||||
font-weight: 650 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-selects {
|
||||
flex: 1 1 100% !important;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-monaco-shell {
|
||||
|
||||
Reference in New Issue
Block a user