🐛 fix(data-grid): 修复 DDL 视图常驻与侧栏交互

记忆 DDL 底部/侧栏布局并支持切表常驻刷新

修复侧栏关闭、拖拽预览和首次加载布局抖动

优化 DDL 行号 gutter,并保留文本选择时的横向视角
This commit is contained in:
Syngnat
2026-06-25 21:36:14 +08:00
parent 8dde4c3c6d
commit ce30de20b6
5 changed files with 356 additions and 30 deletions

View File

@@ -1322,6 +1322,7 @@ const DataGrid: React.FC<DataGridProps> = ({
handleViewModeChange,
handleDdlSidebarResizeStart,
resetDdlViewState,
closeDdlView,
} = useDataGridDdlView({
canViewDdl,
currentConnConfig,
@@ -1329,6 +1330,7 @@ const DataGrid: React.FC<DataGridProps> = ({
dbType,
tableName,
isV2Ui,
isActive,
cellEditMode,
selectedRowKeys,
mergedDisplayDataRef,
@@ -1833,8 +1835,19 @@ const DataGrid: React.FC<DataGridProps> = ({
}, [displayData, modifiedRows, deletedRowKeys]);
mergedDisplayDataRef.current = mergedDisplayData;
const dataSourceContextKey = useMemo(
() => `${connectionId || ''}\u0001${dbName || ''}\u0001${tableName || ''}`,
[connectionId, dbName, tableName],
);
const previousDataSourceContextKeyRef = useRef<string | null>(null);
// Reset local state when data source likely changes (e.g. tableName change)
useEffect(() => {
const previousContextKey = previousDataSourceContextKeyRef.current;
const contextChanged = previousContextKey !== dataSourceContextKey;
previousDataSourceContextKeyRef.current = dataSourceContextKey;
if (!contextChanged) return;
setAddedRows([]);
setModifiedRows({});
setDeletedRowKeys(new Set());
@@ -1843,11 +1856,30 @@ const DataGrid: React.FC<DataGridProps> = ({
setCopiedCellPatch(null);
setCopiedRowsForPaste([]);
closeRowEditor();
resetDdlViewState();
const shouldKeepOpenV2DdlView = previousContextKey !== null
&& isV2Ui
&& viewMode === 'ddl'
&& canViewDdl
&& !!currentConnConfig
&& !!tableName;
if (!shouldKeepOpenV2DdlView && previousContextKey !== null) {
resetDdlViewState();
}
closeVirtualInlineEditor();
closeCellEditor();
formRef.current.resetFields();
}, [tableName, dbName, connectionId, closeRowEditor, resetDdlViewState, closeVirtualInlineEditor, closeCellEditor]); // Reset on context change
}, [
canViewDdl,
closeCellEditor,
closeRowEditor,
closeVirtualInlineEditor,
currentConnConfig,
dataSourceContextKey,
isV2Ui,
resetDdlViewState,
tableName,
viewMode,
]); // Reset on context change
useEffect(() => {
const next = new Map<string, Item>();
@@ -4260,6 +4292,7 @@ const DataGrid: React.FC<DataGridProps> = ({
handleCopyUpdate,
handleDataPanelFormatJson,
handleDataPanelSave,
closeDdlView,
handleDdlSidebarResizeStart,
handleDeleteSelected,
handleDragEnd,

View File

@@ -83,6 +83,7 @@ const DataGridShell: React.FC<DataGridShellProps> = (props) => {
closeBatchEditModal,
closeCellEditMode,
closeCellEditor,
closeDdlView,
closeJsonEditor,
closeRowEditor,
closestCenter,
@@ -755,6 +756,7 @@ const renderDataTableView = () => (
ddlText={ddlText}
darkMode={darkMode}
onDdlViewLayoutChange={setDdlViewLayout}
onClose={closeDdlView}
onReload={() => {
void handleOpenTableDdl({ asView: true });
}}
@@ -773,6 +775,7 @@ const renderDataTableView = () => (
ddlText={ddlText}
darkMode={darkMode}
onDdlViewLayoutChange={setDdlViewLayout}
onClose={closeDdlView}
onReload={() => {
void handleOpenTableDdl({ asView: true });
}}

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Button, Segmented } from 'antd';
import { CopyOutlined } from '@ant-design/icons';
import Editor from './MonacoEditor';
import Editor, { type OnMount } from './MonacoEditor';
import { t as defaultTranslate, type I18nParams } from '../i18n';
type DdlViewLayoutMode = 'bottom' | 'side';
@@ -16,10 +16,82 @@ export interface DataGridV2DdlViewProps {
ddlText: string;
darkMode: boolean;
onDdlViewLayoutChange: (layout: DdlViewLayoutMode) => void;
onClose?: () => void;
onReload: () => void;
onCopy: () => void;
}
const handleReadOnlyDdlEditorMount: OnMount = (editor, monaco) => {
const contentMouseTargetTypes = new Set([
monaco.editor.MouseTargetType.CONTENT_TEXT,
monaco.editor.MouseTargetType.CONTENT_EMPTY,
]);
let pendingContentInteraction:
| { x: number; y: number; scrollLeft: number }
| null = null;
const getMousePoint = (event: any) => ({
x: Number.isFinite(Number(event?.posx)) ? Number(event.posx) : Number(event?.browserEvent?.clientX ?? 0),
y: Number.isFinite(Number(event?.posy)) ? Number(event.posy) : Number(event?.browserEvent?.clientY ?? 0),
});
const restoreScrollLeft = (scrollLeft: number) => {
const apply = () => {
if (typeof editor.getScrollLeft === 'function' && editor.getScrollLeft() === scrollLeft) return;
editor.setScrollLeft?.(scrollLeft);
};
apply();
if (typeof requestAnimationFrame === 'function') {
requestAnimationFrame(() => {
apply();
requestAnimationFrame(apply);
});
}
};
editor.onDidScrollChange?.((event: any) => {
if (!pendingContentInteraction) return;
if (event?.scrollLeftChanged === false) return;
restoreScrollLeft(pendingContentInteraction.scrollLeft);
});
editor.onMouseDown((event: any) => {
pendingContentInteraction = null;
if (!contentMouseTargetTypes.has(event.target?.type)) return;
const mouseEvent = event.event;
if (mouseEvent?.browserEvent && mouseEvent.browserEvent.button !== 0) return;
if (mouseEvent?.leftButton === false) return;
const point = getMousePoint(mouseEvent);
pendingContentInteraction = {
...point,
scrollLeft: typeof editor.getScrollLeft === 'function' ? editor.getScrollLeft() : 0,
};
});
editor.onMouseUp((event: any) => {
const interaction = pendingContentInteraction;
if (!interaction) return;
const point = getMousePoint(event.event);
const moved = Math.abs(point.x - interaction.x) > 3 || Math.abs(point.y - interaction.y) > 3;
restoreScrollLeft(interaction.scrollLeft);
if (!moved) {
pendingContentInteraction = null;
return;
}
if (typeof requestAnimationFrame === 'function') {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (pendingContentInteraction === interaction) {
pendingContentInteraction = null;
}
});
});
return;
}
pendingContentInteraction = null;
});
};
export const DataGridV2DdlView: React.FC<DataGridV2DdlViewProps> = ({
layout,
translate = defaultTranslate,
@@ -29,16 +101,17 @@ export const DataGridV2DdlView: React.FC<DataGridV2DdlViewProps> = ({
ddlText,
darkMode,
onDdlViewLayoutChange,
onClose,
onReload,
onCopy,
}) => (
<div data-grid-ddl-view={layout} className={`gn-v2-data-grid-ddl-view${layout === 'side' ? ' is-side' : ''}`}>
<div className="gn-v2-data-grid-alt-toolbar">
<div>
<div className="gn-v2-data-grid-ddl-title">
<span>DDL</span>
<strong>{tableName ? `DDL - ${tableName}` : 'DDL'}</strong>
</div>
<div>
<div className="gn-v2-data-grid-ddl-actions">
<Segmented
size="small"
value={ddlViewLayout}
@@ -55,7 +128,7 @@ export const DataGridV2DdlView: React.FC<DataGridV2DdlViewProps> = ({
{translate('data_grid.ddl.copy')}
</Button>
{layout === 'side' && (
<Button size="small" onClick={() => onDdlViewLayoutChange('bottom')}>
<Button size="small" onClick={onClose}>
{translate('common.close')}
</Button>
)}
@@ -68,13 +141,21 @@ export const DataGridV2DdlView: React.FC<DataGridV2DdlViewProps> = ({
language="sql"
theme={darkMode ? 'transparent-dark' : 'transparent-light'}
value={ddlLoading ? translate('data_grid.ddl.loading') : ddlText}
onMount={handleReadOnlyDdlEditorMount}
options={{
readOnly: true,
domReadOnly: true,
minimap: { enabled: false },
scrollBeyondLastLine: false,
wordWrap: 'off',
tabSize: 2,
automaticLayout: true,
mouseStyle: 'default',
renderLineHighlight: 'none',
glyphMargin: false,
folding: false,
lineDecorationsWidth: 8,
lineNumbersMinChars: 2,
}}
/>
</div>

View File

@@ -7,6 +7,70 @@ import { formatDdlForDisplay } from '../utils/ddlFormat';
type GridViewMode = 'table' | 'json' | 'text' | 'fields' | 'ddl' | 'er' | 'sqlLog';
type DdlViewLayoutMode = 'bottom' | 'side';
type TranslateParams = Record<string, string | number | boolean | null | undefined>;
const DDL_VIEW_LAYOUT_STORAGE_KEY = 'gonavi.dataGrid.ddlViewLayout';
let sharedDdlViewOpen = false;
let sharedDdlViewLayout: DdlViewLayoutMode | null = null;
const ddlViewLayoutListeners = new Set<(layout: DdlViewLayoutMode) => void>();
const sanitizeDdlViewLayout = (value: unknown): DdlViewLayoutMode => (
value === 'side' ? 'side' : 'bottom'
);
const readPersistedDdlViewLayout = (): DdlViewLayoutMode => {
try {
const storage = typeof window !== 'undefined' ? window.localStorage : undefined;
return sanitizeDdlViewLayout(storage?.getItem(DDL_VIEW_LAYOUT_STORAGE_KEY));
} catch {
return 'bottom';
}
};
const persistDdlViewLayout = (layout: DdlViewLayoutMode) => {
try {
if (typeof window !== 'undefined') {
window.localStorage?.setItem(DDL_VIEW_LAYOUT_STORAGE_KEY, layout);
}
} catch {
// Ignore storage failures in restricted runtimes.
}
};
const readSharedDdlViewLayout = (): DdlViewLayoutMode => {
if (!sharedDdlViewLayout) {
sharedDdlViewLayout = readPersistedDdlViewLayout();
}
return sharedDdlViewLayout;
};
const setSharedDdlViewLayout = (layout: DdlViewLayoutMode) => {
sharedDdlViewLayout = layout;
persistDdlViewLayout(layout);
ddlViewLayoutListeners.forEach((listener) => listener(layout));
};
const setSharedDdlViewOpen = (open: boolean) => {
sharedDdlViewOpen = open;
};
const shouldRestoreSharedDdlView = () => sharedDdlViewOpen;
export const resetDataGridDdlViewSharedStateForTests = () => {
sharedDdlViewOpen = false;
sharedDdlViewLayout = null;
ddlViewLayoutListeners.clear();
};
const buildDdlContextKey = (currentConnConfig: unknown, dbName?: string, tableName?: string) => {
const config = (currentConnConfig || {}) as Record<string, unknown>;
return [
String(config.type || ''),
String(config.host || ''),
String(config.port || ''),
String(config.database || ''),
dbName || '',
tableName || '',
].join('\u0001');
};
interface UseDataGridDdlViewParams {
canViewDdl: boolean;
@@ -14,6 +78,7 @@ interface UseDataGridDdlViewParams {
dbName?: string;
tableName?: string;
isV2Ui: boolean;
isActive?: boolean;
cellEditMode: boolean;
selectedRowKeys: React.Key[];
mergedDisplayDataRef: React.MutableRefObject<any[]>;
@@ -44,6 +109,7 @@ export interface UseDataGridDdlViewResult {
handleViewModeChange: (nextMode: GridViewMode) => void;
handleDdlSidebarResizeStart: (event: React.MouseEvent<HTMLDivElement>) => void;
resetDdlViewState: () => void;
closeDdlView: () => void;
}
export const useDataGridDdlView = ({
@@ -52,6 +118,7 @@ export const useDataGridDdlView = ({
dbName,
tableName,
isV2Ui,
isActive = true,
cellEditMode,
selectedRowKeys,
mergedDisplayDataRef,
@@ -62,28 +129,71 @@ export const useDataGridDdlView = ({
dbType,
translate,
}: UseDataGridDdlViewParams): UseDataGridDdlViewResult => {
const [viewMode, setViewMode] = React.useState<GridViewMode>('table');
const canRestoreSharedDdlView = isV2Ui && canViewDdl && !!currentConnConfig && !!tableName && shouldRestoreSharedDdlView();
const shouldStartWithSharedDdlView = isActive && canRestoreSharedDdlView;
const [viewMode, setViewMode] = React.useState<GridViewMode>(() => (shouldStartWithSharedDdlView ? 'ddl' : 'table'));
const [ddlModalOpen, setDdlModalOpen] = React.useState(false);
const [ddlLoading, setDdlLoading] = React.useState(false);
const [ddlLoading, setDdlLoading] = React.useState(shouldStartWithSharedDdlView);
const [ddlText, setDdlText] = React.useState('');
const [ddlViewLayout, setDdlViewLayout] = React.useState<DdlViewLayoutMode>('bottom');
const [ddlViewLayoutState, setDdlViewLayoutState] = React.useState<DdlViewLayoutMode>(readSharedDdlViewLayout);
const [ddlSidebarWidth, setDdlSidebarWidth] = React.useState(420);
const [ddlSidebarResizePreviewX, setDdlSidebarResizePreviewX] = React.useState<number | null>(null);
const ddlSidebarResizeRef = React.useRef<{
startX: number;
startWidth: number;
previewWidth: number;
previewX: number | null;
previewElement?: HTMLElement | null;
previewFrame?: number | null;
moveHandler?: (event: MouseEvent) => void;
upHandler?: () => void;
} | null>(null);
const ddlRequestSeqRef = React.useRef(0);
const ddlRequestedContextKeyRef = React.useRef<string | null>(null);
const ddlContextKey = React.useMemo(
() => buildDdlContextKey(currentConnConfig, dbName, tableName),
[currentConnConfig, dbName, tableName],
);
const isTableSurfaceActive = viewMode === 'table' || (isV2Ui && viewMode === 'ddl' && ddlViewLayout === 'side');
const ddlViewLayout = ddlViewLayoutState;
const resolvedViewMode: GridViewMode = isActive
&& canRestoreSharedDdlView
&& (viewMode === 'table' || viewMode === 'ddl')
? 'ddl'
: viewMode;
const isDdlContextPending = resolvedViewMode === 'ddl'
&& isActive
&& canRestoreSharedDdlView
&& ddlRequestedContextKeyRef.current !== ddlContextKey;
const resolvedDdlLoading = ddlLoading || isDdlContextPending;
const resolvedDdlText = isDdlContextPending ? '' : ddlText;
const isTableSurfaceActive = resolvedViewMode === 'table' || (isV2Ui && resolvedViewMode === 'ddl' && ddlViewLayout === 'side');
const translateMessage = React.useCallback((key: string, params?: TranslateParams) => {
return translate ? translate(key, params) : catalogTranslate('zh-CN', key, params);
}, [translate]);
const setDdlViewLayout: React.Dispatch<React.SetStateAction<DdlViewLayoutMode>> = React.useCallback((nextLayout) => {
const currentLayout = readSharedDdlViewLayout();
const resolvedLayout = sanitizeDdlViewLayout(
typeof nextLayout === 'function' ? nextLayout(currentLayout) : nextLayout,
);
setSharedDdlViewLayout(resolvedLayout);
}, []);
React.useEffect(() => {
const handleSharedDdlViewLayoutChange = (nextLayout: DdlViewLayoutMode) => {
setDdlViewLayoutState((currentLayout) => (
currentLayout === nextLayout ? currentLayout : nextLayout
));
};
ddlViewLayoutListeners.add(handleSharedDdlViewLayoutChange);
handleSharedDdlViewLayoutChange(readSharedDdlViewLayout());
return () => {
ddlViewLayoutListeners.delete(handleSharedDdlViewLayoutChange);
};
}, []);
const handleOpenTableDdl = React.useCallback(async (options?: { asView?: boolean }) => {
if (!canViewDdl || !currentConnConfig || !tableName) {
messageApi.error(translateMessage('data_grid.message.ddl_missing_context'));
@@ -91,7 +201,9 @@ export const useDataGridDdlView = ({
}
const asView = options?.asView === true && isV2Ui;
const requestSeq = ++ddlRequestSeqRef.current;
ddlRequestedContextKeyRef.current = ddlContextKey;
if (asView) {
setSharedDdlViewOpen(true);
setViewMode('ddl');
setDdlModalOpen(false);
} else {
@@ -115,27 +227,51 @@ export const useDataGridDdlView = ({
setDdlLoading(false);
}
}
}, [canViewDdl, currentConnConfig, dbName, dbType, isV2Ui, messageApi, tableName, translateMessage]);
}, [canViewDdl, currentConnConfig, dbName, dbType, ddlContextKey, isV2Ui, messageApi, tableName, translateMessage]);
React.useEffect(() => {
if (isV2Ui || (viewMode !== 'fields' && viewMode !== 'ddl' && viewMode !== 'er' && viewMode !== 'sqlLog')) return;
setViewMode('table');
}, [isV2Ui, viewMode]);
const closeDdlView = React.useCallback(() => {
setSharedDdlViewOpen(false);
ddlRequestedContextKeyRef.current = null;
ddlRequestSeqRef.current += 1;
setViewMode('table');
setDdlModalOpen(false);
setDdlLoading(false);
setDdlText('');
setDdlSidebarResizePreviewX(null);
}, []);
React.useEffect(() => {
if (!isActive || !isV2Ui || !shouldRestoreSharedDdlView()) return;
if (!canViewDdl || !currentConnConfig || !tableName) return;
if (ddlRequestedContextKeyRef.current === ddlContextKey) return;
void handleOpenTableDdl({ asView: true });
}, [canViewDdl, currentConnConfig, ddlContextKey, handleOpenTableDdl, isActive, isV2Ui, tableName]);
const handleViewModeChange = React.useCallback((nextMode: GridViewMode) => {
if ((nextMode === 'fields' || nextMode === 'ddl' || nextMode === 'er' || nextMode === 'sqlLog') && !isV2Ui) {
setSharedDdlViewOpen(false);
setViewMode('table');
return;
}
if (nextMode === 'sqlLog') {
setSharedDdlViewOpen(false);
setViewMode('sqlLog');
return;
}
if (nextMode === 'ddl') {
if (isV2Ui && resolvedViewMode === 'ddl') {
closeDdlView();
return;
}
void handleOpenTableDdl({ asView: true });
setViewMode('ddl');
return;
}
setSharedDdlViewOpen(false);
if (nextMode === 'json' && cellEditMode) {
closeCellEditModeRef.current();
}
@@ -151,22 +287,69 @@ export const useDataGridDdlView = ({
}
setViewMode(nextMode);
}, [cellEditMode, closeCellEditModeRef, handleOpenTableDdl, isV2Ui, mergedDisplayDataRef, rowKeyStr, selectedRowKeys, setTextRecordIndex]);
}, [cellEditMode, closeCellEditModeRef, closeDdlView, handleOpenTableDdl, isV2Ui, mergedDisplayDataRef, resolvedViewMode, rowKeyStr, selectedRowKeys, setTextRecordIndex]);
const handleDdlSidebarResizeStart = React.useCallback((event: React.MouseEvent<HTMLDivElement>) => {
event.preventDefault();
event.stopPropagation();
const startX = event.clientX;
const startWidth = ddlSidebarWidth;
const resizerElement = event.currentTarget;
const workspaceElement = resizerElement.parentElement;
const previewElement = workspaceElement?.querySelector?.('[data-grid-ddl-resize-preview="true"]') as HTMLElement | null | undefined;
const workspaceWidth = workspaceElement?.getBoundingClientRect?.().width;
const resizerWidth = resizerElement.getBoundingClientRect?.().width || 8;
const resolvePreviewX = (width: number, fallbackX: number) => (
typeof workspaceWidth === 'number' && workspaceWidth > 0
? Math.max(0, workspaceWidth - width - resizerWidth / 2)
: fallbackX
);
const applyPreviewElementPosition = (x: number | null) => {
if (!previewElement) return;
if (x === null) {
previewElement.style.opacity = '0';
previewElement.style.transform = 'translate3d(0, 0, 0)';
return;
}
previewElement.style.opacity = '1';
previewElement.style.transform = `translateX(${x}px)`;
};
const schedulePreviewElementPosition = (x: number) => {
const state = ddlSidebarResizeRef.current;
if (!state?.previewElement) return false;
state.previewX = x;
if (state.previewFrame !== null && state.previewFrame !== undefined) return true;
const run = () => {
const current = ddlSidebarResizeRef.current;
if (!current?.previewElement) return;
current.previewFrame = null;
applyPreviewElementPosition(current.previewX);
};
if (typeof requestAnimationFrame === 'function') {
state.previewFrame = requestAnimationFrame(run);
} else {
run();
}
return true;
};
const startPreviewX = resolvePreviewX(startWidth, startX);
const moveHandler = (moveEvent: MouseEvent) => {
const nextWidth = Math.max(320, Math.min(760, startWidth + (startX - moveEvent.clientX)));
if (ddlSidebarResizeRef.current) {
ddlSidebarResizeRef.current.previewWidth = nextWidth;
}
setDdlSidebarResizePreviewX(moveEvent.clientX);
const nextPreviewX = resolvePreviewX(nextWidth, moveEvent.clientX);
if (!schedulePreviewElementPosition(nextPreviewX)) {
setDdlSidebarResizePreviewX(nextPreviewX);
}
};
const upHandler = () => {
const nextWidth = ddlSidebarResizeRef.current?.previewWidth ?? startWidth;
const resizeState = ddlSidebarResizeRef.current;
const nextWidth = resizeState?.previewWidth ?? startWidth;
if (resizeState?.previewFrame !== null && resizeState?.previewFrame !== undefined && typeof cancelAnimationFrame === 'function') {
cancelAnimationFrame(resizeState.previewFrame);
}
applyPreviewElementPosition(null);
setDdlSidebarWidth(nextWidth);
setDdlSidebarResizePreviewX(null);
document.removeEventListener('mousemove', moveHandler);
@@ -174,27 +357,41 @@ export const useDataGridDdlView = ({
ddlSidebarResizeRef.current = null;
};
ddlSidebarResizeRef.current = { startX, startWidth, previewWidth: startWidth, moveHandler, upHandler };
ddlSidebarResizeRef.current = {
startX,
startWidth,
previewWidth: startWidth,
previewX: startPreviewX,
previewElement,
previewFrame: null,
moveHandler,
upHandler,
};
if (previewElement) {
applyPreviewElementPosition(startPreviewX);
} else {
setDdlSidebarResizePreviewX(startPreviewX);
}
document.addEventListener('mousemove', moveHandler);
document.addEventListener('mouseup', upHandler);
}, [ddlSidebarWidth]);
const resetDdlViewState = React.useCallback(() => {
ddlRequestedContextKeyRef.current = null;
ddlRequestSeqRef.current += 1;
setDdlModalOpen(false);
setDdlLoading(false);
setDdlText('');
setDdlViewLayout('bottom');
setDdlSidebarResizePreviewX(null);
}, []);
return {
viewMode,
viewMode: resolvedViewMode,
setViewMode,
ddlModalOpen,
setDdlModalOpen,
ddlLoading,
ddlText,
ddlLoading: resolvedDdlLoading,
ddlText: resolvedDdlText,
ddlViewLayout,
setDdlViewLayout,
ddlSidebarWidth,
@@ -205,5 +402,6 @@ export const useDataGridDdlView = ({
handleViewModeChange,
handleDdlSidebarResizeStart,
resetDdlViewState,
closeDdlView,
};
};

View File

@@ -819,24 +819,35 @@ body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side {
}
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-alt-toolbar {
min-height: 52px;
align-items: flex-start;
padding: 8px 10px;
min-height: 46px;
align-items: center;
gap: 8px;
padding: 7px 10px;
}
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-alt-toolbar > div:first-child {
flex: 1 1 auto;
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-ddl-title {
flex: 1 1 72px;
overflow: hidden;
}
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-alt-toolbar > div:last-child {
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-ddl-actions {
justify-content: flex-end;
flex: 0 1 auto;
flex-wrap: wrap;
gap: 6px;
flex: 0 0 auto;
flex-wrap: nowrap;
gap: 4px;
white-space: nowrap;
}
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-ddl-actions .ant-btn-sm {
padding-inline: 7px;
}
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-ddl-actions .ant-segmented-small .ant-segmented-item-label {
padding-inline: 8px;
}
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-view.is-side .gn-v2-data-grid-alt-toolbar strong {
max-width: 210px;
max-width: 150px;
}
body[data-ui-version="v2"] .gn-v2-data-grid-ddl-code {