mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-07 07:03:34 +08:00
🎨 style(theme): 对齐表概览主题表面并优化工具栏与时间展示
- 主内容区与侧栏统一 panel-2,消除表概览空白区色差 - 查询工具栏保存按钮改为 default 图标样式,提升暗色可读性 - 表概览时间格式化为 YYYY-MM-DD HH:mm:ss,保留小数秒 - 补充多语言文案与相关测试
This commit is contained in:
@@ -1 +1 @@
|
||||
83b4b7d166ed9172beba2d6236382c0b
|
||||
339d5c974e6ab5cba2d5def171f5ce0a
|
||||
@@ -557,7 +557,9 @@ const QueryEditorToolbar: React.FC<QueryEditorToolbarProps> = ({
|
||||
<Button
|
||||
aria-label={t("query_editor.action.save")}
|
||||
className={isV2Ui ? "gn-v2-query-toolbar-icon-action gn-v2-query-toolbar-save-action" : undefined}
|
||||
type="primary"
|
||||
/* v2 与终端等工具按钮同族(default),避免 primary 的 on-accent 前景在暗色下发脏绿;
|
||||
可读性靠 CSS 把图标提到 fg-1。legacy 仍用 primary 实心按钮。 */
|
||||
type={isV2Ui ? "default" : "primary"}
|
||||
icon={<SaveOutlined />}
|
||||
onClick={onQuickSave}
|
||||
>
|
||||
|
||||
@@ -588,6 +588,7 @@ describe('TableOverview metadata compatibility', () => {
|
||||
const renderedText = collectText(renderer!.toJSON());
|
||||
expect(renderedText).toContain('orders');
|
||||
expect(renderedText).toContain('订单表');
|
||||
// 展示统一为 YYYY-MM-DD HH:mm:ss(有小数秒时保留,与侧栏 formatSidebarTableTimestamp 一致)
|
||||
expect(renderedText).toContain('2026-06-02 10:30:00');
|
||||
expect(renderedText).toContain('2026-05-01 09:00:00');
|
||||
});
|
||||
|
||||
@@ -32,6 +32,7 @@ import { extractTableNameFromMetadataRow } from '../utils/tableMetadataRows';
|
||||
import { V2TableContextMenuView, type V2TableContextMenuActionKey } from './V2TableContextMenu';
|
||||
import { confirmCopyTable } from './tableCopyAction';
|
||||
import { APP_POPUP_Z_INDEX } from '../utils/overlayZIndex';
|
||||
import { formatSidebarTableTimestamp } from './sidebar/sidebarHelpers';
|
||||
|
||||
interface TableOverviewProps {
|
||||
tab: TabData;
|
||||
@@ -816,14 +817,15 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
}, [addAIContext, buildConfig, connection?.id, setAIPanelVisible, tab.dbName]);
|
||||
|
||||
// --- Theme ---
|
||||
const cardBg = darkMode ? 'rgba(255,255,255,0.04)' : 'rgba(0,0,0,0.02)';
|
||||
// v2 背景/边框/强调色交给 CSS token(跟自定义主题);legacy 仍用 darkMode 近似色。
|
||||
const cardBg = isV2Ui ? undefined : (darkMode ? 'rgba(255,255,255,0.04)' : 'rgba(0,0,0,0.02)');
|
||||
const cardHoverBg = darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.04)';
|
||||
const cardBorder = darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)';
|
||||
const textPrimary = darkMode ? 'rgba(255,255,255,0.88)' : 'rgba(0,0,0,0.88)';
|
||||
const textSecondary = darkMode ? 'rgba(255,255,255,0.55)' : 'rgba(0,0,0,0.55)';
|
||||
const textMuted = darkMode ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.35)';
|
||||
const accentColor = '#1677ff';
|
||||
const containerBg = darkMode ? 'rgba(0,0,0,0.15)' : 'rgba(0,0,0,0.01)';
|
||||
const cardBorder = isV2Ui ? undefined : (darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)');
|
||||
const textPrimary = isV2Ui ? 'var(--gn-fg-1)' : (darkMode ? 'rgba(255,255,255,0.88)' : 'rgba(0,0,0,0.88)');
|
||||
const textSecondary = isV2Ui ? 'var(--gn-fg-3)' : (darkMode ? 'rgba(255,255,255,0.55)' : 'rgba(0,0,0,0.55)');
|
||||
const textMuted = isV2Ui ? 'var(--gn-fg-4)' : (darkMode ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.35)');
|
||||
const accentColor = isV2Ui ? 'var(--gn-accent)' : '#1677ff';
|
||||
const containerBg = isV2Ui ? undefined : (darkMode ? 'rgba(0,0,0,0.15)' : 'rgba(0,0,0,0.01)');
|
||||
|
||||
const toggleSort = (field: SortField) => {
|
||||
if (sortField === field) {
|
||||
@@ -1065,17 +1067,24 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const formatOverviewTimestamp = useCallback((value?: string): string => {
|
||||
if (!value) return '';
|
||||
return formatSidebarTableTimestamp(value) || value;
|
||||
}, []);
|
||||
|
||||
const renderTableOverviewMetaBadges = useCallback((table: TableStatRow, compact = false) => {
|
||||
const items = [
|
||||
...(table.updateTime ? [{
|
||||
key: 'updated',
|
||||
label: t('table_overview.metric.updated_at'),
|
||||
value: table.updateTime,
|
||||
raw: table.updateTime,
|
||||
value: formatOverviewTimestamp(table.updateTime),
|
||||
}] : []),
|
||||
...(table.createTime ? [{
|
||||
key: 'created',
|
||||
label: t('table_overview.metric.created_at'),
|
||||
value: table.createTime,
|
||||
raw: table.createTime,
|
||||
value: formatOverviewTimestamp(table.createTime),
|
||||
}] : []),
|
||||
];
|
||||
if (items.length === 0) return null;
|
||||
@@ -1090,7 +1099,7 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
}}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<Tooltip key={item.key} title={`${item.label}: ${item.value}`} mouseEnterDelay={0.4}>
|
||||
<Tooltip key={item.key} title={`${item.label}: ${item.raw}`} mouseEnterDelay={0.4}>
|
||||
<span
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
@@ -1099,7 +1108,9 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
maxWidth: '100%',
|
||||
padding: compact ? '1px 7px' : '2px 8px',
|
||||
borderRadius: 999,
|
||||
background: darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)',
|
||||
background: isV2Ui
|
||||
? 'var(--gn-bg-active)'
|
||||
: (darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)'),
|
||||
color: textSecondary,
|
||||
fontSize: compact ? 10 : 11,
|
||||
lineHeight: compact ? '16px' : '18px',
|
||||
@@ -1115,7 +1126,7 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}, [darkMode, t, textPrimary, textSecondary]);
|
||||
}, [darkMode, formatOverviewTimestamp, isV2Ui, t, textPrimary, textSecondary]);
|
||||
|
||||
const renderCardTableContent = (table: TableStatRow) => (
|
||||
<div
|
||||
@@ -1123,8 +1134,10 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
onDoubleClick={() => openTableByDefaultAction(table.name)}
|
||||
onContextMenu={isV2Ui ? (event) => openV2OverviewContextMenu(event, table) : undefined}
|
||||
style={{
|
||||
background: cardBg,
|
||||
border: `1px solid ${cardBorder}`,
|
||||
...(isV2Ui ? {} : {
|
||||
background: cardBg,
|
||||
border: `1px solid ${cardBorder}`,
|
||||
}),
|
||||
borderRadius: 10,
|
||||
padding: '14px 16px',
|
||||
cursor: 'pointer',
|
||||
@@ -1132,7 +1145,7 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
userSelect: 'none',
|
||||
}}
|
||||
onMouseEnter={isV2Ui ? undefined : e => { (e.currentTarget as HTMLDivElement).style.background = cardHoverBg; (e.currentTarget as HTMLDivElement).style.borderColor = accentColor; }}
|
||||
onMouseLeave={isV2Ui ? undefined : e => { (e.currentTarget as HTMLDivElement).style.background = cardBg; (e.currentTarget as HTMLDivElement).style.borderColor = cardBorder; }}
|
||||
onMouseLeave={isV2Ui ? undefined : e => { (e.currentTarget as HTMLDivElement).style.background = cardBg || ''; (e.currentTarget as HTMLDivElement).style.borderColor = cardBorder || ''; }}
|
||||
>
|
||||
<div className={isV2Ui ? 'gn-v2-table-card-name' : undefined} style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
|
||||
<TableOutlined style={{ fontSize: 14, color: accentColor }} />
|
||||
@@ -1182,7 +1195,9 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
const combinedSize = getCombinedTableSize(table);
|
||||
const sizeRatio = maxCombinedSize > 0 && hasKnownTableSize(table) ? combinedSize / maxCombinedSize : 0;
|
||||
const fillWidth = maxCombinedSize > 0 && hasKnownTableSize(table) ? `${Math.max(10, Math.round(sizeRatio * 100))}%` : '0%';
|
||||
const fillColor = darkMode ? 'rgba(22,119,255,0.18)' : 'rgba(22,119,255,0.12)';
|
||||
const fillColor = isV2Ui
|
||||
? 'var(--gn-accent-soft, rgba(34, 197, 94, 0.16))'
|
||||
: (darkMode ? 'rgba(22,119,255,0.18)' : 'rgba(22,119,255,0.12)');
|
||||
const rowSecondary = table.comment || (table.engine
|
||||
? t('table_overview.row.engine_table', { engine: table.engine })
|
||||
: t('table_overview.row.open_hint'));
|
||||
@@ -1195,15 +1210,17 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
style={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
borderRadius: 10,
|
||||
border: `1px solid ${cardBorder}`,
|
||||
background: cardBg,
|
||||
borderRadius: isV2Ui ? undefined : 10,
|
||||
...(isV2Ui ? {} : {
|
||||
border: `1px solid ${cardBorder}`,
|
||||
background: cardBg,
|
||||
}),
|
||||
cursor: 'pointer',
|
||||
transition: isV2Ui ? undefined : 'all 0.15s ease',
|
||||
userSelect: 'none',
|
||||
}}
|
||||
onMouseEnter={isV2Ui ? undefined : e => { (e.currentTarget as HTMLDivElement).style.background = cardHoverBg; (e.currentTarget as HTMLDivElement).style.borderColor = accentColor; }}
|
||||
onMouseLeave={isV2Ui ? undefined : e => { (e.currentTarget as HTMLDivElement).style.background = cardBg; (e.currentTarget as HTMLDivElement).style.borderColor = cardBorder; }}
|
||||
onMouseLeave={isV2Ui ? undefined : e => { (e.currentTarget as HTMLDivElement).style.background = cardBg || ''; (e.currentTarget as HTMLDivElement).style.borderColor = cardBorder || ''; }}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
@@ -1244,7 +1261,9 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
borderRadius: 999,
|
||||
fontSize: 11,
|
||||
color: textMuted,
|
||||
background: darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.04)',
|
||||
background: isV2Ui
|
||||
? 'var(--gn-bg-active)'
|
||||
: (darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.04)'),
|
||||
}}
|
||||
>
|
||||
{table.engine}
|
||||
@@ -1379,11 +1398,16 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
alignItems: 'center',
|
||||
minWidth: 1120,
|
||||
minHeight: 32,
|
||||
borderBottom: `1px solid ${cardBorder}`,
|
||||
background: cardBg,
|
||||
color: textPrimary,
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
...(isV2Ui ? {
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
} : {
|
||||
borderBottom: `1px solid ${cardBorder}`,
|
||||
background: cardBg,
|
||||
color: textPrimary,
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<div className="gn-table-overview-compact-name" role="cell" title={table.name}>
|
||||
@@ -1395,8 +1419,20 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
<div className="gn-table-overview-compact-cell gn-table-overview-compact-number" role="cell" title={table.dataSize >= 0 ? String(table.dataSize) : undefined}>{formatSize(table.dataSize)}</div>
|
||||
<div className="gn-table-overview-compact-cell gn-table-overview-compact-number" role="cell" title={table.indexSize >= 0 ? String(table.indexSize) : undefined}>{formatSize(table.indexSize)}</div>
|
||||
<div className="gn-table-overview-compact-cell" role="cell" title={table.engine || undefined}>{table.engine || '—'}</div>
|
||||
<div className="gn-table-overview-compact-cell" role="cell" title={table.updateTime || undefined}>{table.updateTime || '—'}</div>
|
||||
<div className="gn-table-overview-compact-cell" role="cell" title={table.createTime || undefined}>{table.createTime || '—'}</div>
|
||||
<div
|
||||
className="gn-table-overview-compact-cell"
|
||||
role="cell"
|
||||
title={table.updateTime || undefined}
|
||||
>
|
||||
{table.updateTime ? formatOverviewTimestamp(table.updateTime) : '—'}
|
||||
</div>
|
||||
<div
|
||||
className="gn-table-overview-compact-cell"
|
||||
role="cell"
|
||||
title={table.createTime || undefined}
|
||||
>
|
||||
{table.createTime ? formatOverviewTimestamp(table.createTime) : '—'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1422,6 +1458,12 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const viewSwitchBtnClass = (mode: ViewMode) => (
|
||||
isV2Ui
|
||||
? `gn-v2-table-overview-view-switch-btn${viewMode === mode ? ' is-active' : ''}`
|
||||
: undefined
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={isV2Ui ? 'gn-table-overview gn-v2-table-overview' : 'gn-table-overview'} style={{ display: 'flex', flexDirection: 'column', height: '100%', background: containerBg, overflow: 'hidden' }}>
|
||||
{/* Toolbar */}
|
||||
@@ -1447,15 +1489,19 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
<Dropdown menu={{ items: sortMenuItems }} trigger={['click']}>
|
||||
<Tooltip title={t('table_overview.tooltip.sort')}><SortAscendingOutlined style={{ fontSize: 16, color: textSecondary, cursor: 'pointer' }} /></Tooltip>
|
||||
</Dropdown>
|
||||
<div style={{ display: 'flex', gap: 2, padding: 2, borderRadius: 6, background: darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)' }}>
|
||||
<div
|
||||
className={isV2Ui ? 'gn-v2-table-overview-view-switch' : undefined}
|
||||
style={isV2Ui ? undefined : { display: 'flex', gap: 2, padding: 2, borderRadius: 6, background: darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)' }}
|
||||
>
|
||||
<Tooltip title={t('table_overview.tooltip.card_view')}>
|
||||
<button
|
||||
type="button"
|
||||
className={viewSwitchBtnClass('card')}
|
||||
data-table-overview-view-mode="card"
|
||||
aria-label={t('table_overview.tooltip.card_view')}
|
||||
aria-pressed={viewMode === 'card'}
|
||||
onClick={() => setViewMode('card')}
|
||||
style={{
|
||||
style={isV2Ui ? undefined : {
|
||||
width: 28, height: 24, padding: 0, border: 0, borderRadius: 5, cursor: 'pointer', transition: 'all 0.15s',
|
||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center', font: 'inherit',
|
||||
background: viewMode === 'card' ? (darkMode ? 'rgba(255,255,255,0.12)' : '#fff') : 'transparent',
|
||||
@@ -1469,11 +1515,12 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
<Tooltip title={t('table_overview.tooltip.list_view')}>
|
||||
<button
|
||||
type="button"
|
||||
className={viewSwitchBtnClass('list')}
|
||||
data-table-overview-view-mode="list"
|
||||
aria-label={t('table_overview.tooltip.list_view')}
|
||||
aria-pressed={viewMode === 'list'}
|
||||
onClick={() => setViewMode('list')}
|
||||
style={{
|
||||
style={isV2Ui ? undefined : {
|
||||
width: 28, height: 24, padding: 0, border: 0, borderRadius: 5, cursor: 'pointer', transition: 'all 0.15s',
|
||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center', font: 'inherit',
|
||||
background: viewMode === 'list' ? (darkMode ? 'rgba(255,255,255,0.12)' : '#fff') : 'transparent',
|
||||
@@ -1487,11 +1534,12 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
<Tooltip title={t('table_overview.tooltip.table_view')}>
|
||||
<button
|
||||
type="button"
|
||||
className={viewSwitchBtnClass('table')}
|
||||
data-table-overview-view-mode="table"
|
||||
aria-label={t('table_overview.tooltip.table_view')}
|
||||
aria-pressed={viewMode === 'table'}
|
||||
onClick={() => setViewMode('table')}
|
||||
style={{
|
||||
style={isV2Ui ? undefined : {
|
||||
width: 28, height: 24, padding: 0, border: 0, borderRadius: 5, cursor: 'pointer', transition: 'all 0.15s',
|
||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center', font: 'inherit',
|
||||
background: viewMode === 'table' ? (darkMode ? 'rgba(255,255,255,0.12)' : '#fff') : 'transparent',
|
||||
@@ -1509,7 +1557,11 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
{/* Content Area */}
|
||||
<div
|
||||
className={isV2Ui ? 'gn-v2-table-overview-content' : undefined}
|
||||
style={{
|
||||
data-view-mode={isV2Ui ? viewMode : undefined}
|
||||
style={isV2Ui ? {
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
} : {
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflow: viewMode === 'table' ? 'hidden' : 'auto',
|
||||
@@ -1520,7 +1572,15 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
>
|
||||
{sortedFiltered.length > 0 && (isSearchPending || visibleOverview.hiddenCount > 0 || deferredSearchText.trim()) && (
|
||||
<div
|
||||
style={{
|
||||
className={isV2Ui ? 'gn-v2-table-overview-filter-bar' : undefined}
|
||||
style={isV2Ui ? {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: 12,
|
||||
fontSize: 12,
|
||||
flexShrink: 0,
|
||||
} : {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
@@ -1581,7 +1641,10 @@ const TableOverview: React.FC<TableOverviewProps> = ({ tab }) => {
|
||||
{section.rows.map(renderCardTable)}
|
||||
</div>
|
||||
) : (
|
||||
<div className={isV2Ui ? 'gn-v2-table-row-list' : undefined} style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
|
||||
<div
|
||||
className={isV2Ui ? 'gn-v2-table-row-list' : undefined}
|
||||
style={{ display: 'flex', flexDirection: 'column', gap: isV2Ui ? 0 : 10 }}
|
||||
>
|
||||
{section.rows.map(renderListTable)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -54,18 +54,36 @@ export const formatSidebarTableSize = (bytes: number): string => {
|
||||
const padSidebarTimestampPart = (value: number): string => String(value).padStart(2, '0');
|
||||
|
||||
/**
|
||||
* formatSidebarTableTimestamp 把数据库返回的时间值统一压缩成 `YYYY-MM-DD HH:mm`。
|
||||
* 若值无法被 Date 可靠解析,则尽量保留原始文本的可读部分。
|
||||
* formatSidebarTableTimestamp 把数据库返回的时间值格式化为
|
||||
* `YYYY-MM-DD HH:mm:ss`;若源值带小数秒(毫秒/微秒),则原样保留小数部分。
|
||||
* 例:
|
||||
* 2026-04-26T18:06:08+08:00 → 2026-04-26 18:06:08
|
||||
* 2026-05-10T09:12:33.456+08:00 → 2026-05-10 09:12:33.456
|
||||
* 若无法被 Date 可靠解析,则尽量保留原始文本的可读部分。
|
||||
*/
|
||||
export const formatSidebarTableTimestamp = (value: unknown): string => {
|
||||
const text = String(value ?? '').trim();
|
||||
if (!text) return '';
|
||||
const normalizedText = text.replace('T', ' ').replace(/\.\d+$/, '');
|
||||
|
||||
// 优先用正则剥离时区,保留秒与小数秒(避免 Date 丢弃微秒精度)
|
||||
const match = text.match(
|
||||
/^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}:\d{2})(\.\d+)?(?:\s*(?:Z|[+-]\d{2}:?\d{2})(?:\s+[A-Za-z_\/+-]+)?)?$/i,
|
||||
);
|
||||
if (match) {
|
||||
return `${match[1]} ${match[2]}${match[3] || ''}`;
|
||||
}
|
||||
|
||||
const parsed = new Date(text);
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
return normalizedText.length > 16 ? normalizedText.slice(0, 16) : normalizedText;
|
||||
// 无法解析时去掉 T/时区噪音,尽量给出可读截断
|
||||
const fallback = text
|
||||
.replace('T', ' ')
|
||||
.replace(/([+-]\d{2}:?\d{2}|Z)\s*$/i, '')
|
||||
.trim();
|
||||
return fallback.length > 23 ? fallback.slice(0, 23) : fallback;
|
||||
}
|
||||
return [
|
||||
|
||||
const base = [
|
||||
parsed.getFullYear(),
|
||||
'-',
|
||||
padSidebarTimestampPart(parsed.getMonth() + 1),
|
||||
@@ -75,7 +93,15 @@ export const formatSidebarTableTimestamp = (value: unknown): string => {
|
||||
padSidebarTimestampPart(parsed.getHours()),
|
||||
':',
|
||||
padSidebarTimestampPart(parsed.getMinutes()),
|
||||
':',
|
||||
padSidebarTimestampPart(parsed.getSeconds()),
|
||||
].join('');
|
||||
|
||||
const ms = parsed.getMilliseconds();
|
||||
if (ms > 0) {
|
||||
return `${base}.${String(ms).padStart(3, '0')}`;
|
||||
}
|
||||
return base;
|
||||
};
|
||||
|
||||
export interface SidebarTableMetadataDisplayItem {
|
||||
|
||||
@@ -34,8 +34,10 @@ export const useAppUtilityStyles = ({
|
||||
return `rgba(${r}, ${g}, ${b}, ${effectiveOpacity})`;
|
||||
};
|
||||
|
||||
const bgMain = getBg('#141414');
|
||||
const bgContent = getBg('#1d1d1d');
|
||||
// v2 / 自定义主题:走 CSS token,主内容与 sider 同为 panel-2,避免并排色差。
|
||||
// legacy 仍用 getBg 做透明度混合。
|
||||
const bgMain = isV2Ui ? 'var(--gn-bg-panel-2)' : getBg('#141414');
|
||||
const bgContent = isV2Ui ? 'var(--gn-bg-panel-2)' : getBg('#1d1d1d');
|
||||
const floatingLogButtonBorderColor = darkMode ? 'rgba(255,255,255,0.20)' : 'rgba(0,0,0,0.16)';
|
||||
const floatingLogButtonTextColor = darkMode ? 'rgba(255,255,255,0.92)' : 'rgba(0,0,0,0.82)';
|
||||
const floatingLogButtonBgColor = darkMode
|
||||
|
||||
@@ -336,6 +336,38 @@ body[data-ui-version="v2"] .gn-v2-query-toolbar-run-action.ant-btn {
|
||||
font-weight: 650 !important;
|
||||
}
|
||||
|
||||
/* 保存:与终端等 default 图标按钮同族,只把图标提到 fg-1,保证暗色下可读。
|
||||
不再用软绿底/描边——会在实心「执行」旁显得脏、不协调。 */
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled) {
|
||||
background: var(--gn-bg-panel) !important;
|
||||
border-color: var(--gn-br-2) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn .anticon,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled) .anticon {
|
||||
color: var(--gn-fg-1) !important;
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:hover,
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:focus-visible,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):hover,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):focus-visible {
|
||||
background: var(--gn-bg-hover) !important;
|
||||
border-color: var(--gn-br-3) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:hover .anticon,
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:focus-visible .anticon,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):hover .anticon,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):focus-visible .anticon {
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-ai-action.ant-btn {
|
||||
font-weight: 650 !important;
|
||||
}
|
||||
@@ -1904,16 +1936,55 @@ body[data-ui-version="v2"] .gn-nacos-service-list-footer {
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview {
|
||||
background: var(--gn-bg-app) !important;
|
||||
/* 与左侧 sider / 主内容区同用 panel-2,消除并排色差 */
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
color: var(--gn-fg-1);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-header {
|
||||
min-height: 54px;
|
||||
padding: 12px 16px !important;
|
||||
background: var(--gn-bg-panel) !important;
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
border-bottom: 0.5px solid var(--gn-br-1);
|
||||
}
|
||||
|
||||
/* 视图切换器:底/选中态跟主题,不再写死白/灰 */
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-view-switch {
|
||||
display: inline-flex;
|
||||
gap: 2px;
|
||||
padding: 2px;
|
||||
border-radius: 6px;
|
||||
background: var(--gn-bg-active) !important;
|
||||
border: 0.5px solid var(--gn-br-1);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-view-switch-btn {
|
||||
width: 28px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 5px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
color: var(--gn-fg-4);
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
transition: background 0.12s ease, color 0.12s ease;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-view-switch-btn.is-active {
|
||||
background: color-mix(in srgb, var(--gn-fg-1) 6%, var(--gn-bg-panel-2)) !important;
|
||||
color: var(--gn-accent) !important;
|
||||
box-shadow: var(--gn-shadow-sm);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-view-switch-btn:hover {
|
||||
color: var(--gn-fg-1);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
@@ -1961,15 +2032,48 @@ body[data-ui-version="v2"] .gn-v2-table-overview-summary strong {
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片保留内边距;列表/表格铺满内容区,去掉红框里那圈空白 */
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content {
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="card"] {
|
||||
padding: 14px 16px 20px !important;
|
||||
background: var(--gn-bg-app);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="list"],
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="table"] {
|
||||
padding: 0 !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="list"] {
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
background: var(--gn-bg-panel-2);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-section {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="list"] .gn-v2-table-overview-section-title {
|
||||
margin: 0 !important;
|
||||
padding: 8px 14px 6px !important;
|
||||
background: var(--gn-bg-panel-2);
|
||||
border-bottom: 0.5px solid var(--gn-br-1);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-section-title {
|
||||
@@ -2002,7 +2106,9 @@ body[data-ui-version="v2"] .gn-v2-table-card,
|
||||
body[data-ui-version="v2"] .gn-v2-table-row {
|
||||
border: 0.5px solid var(--gn-br-2) !important;
|
||||
border-radius: 8px !important;
|
||||
background: var(--gn-bg-panel) !important;
|
||||
/* 底已是 panel-2:卡片用轻微抬升混合色,避免与底/左侧同色糊成一片 */
|
||||
background: color-mix(in srgb, var(--gn-fg-1) 3.5%, var(--gn-bg-panel-2)) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
box-shadow: var(--gn-shadow-card);
|
||||
transition: background 0.08s, border-color 0.08s, box-shadow 0.08s;
|
||||
}
|
||||
@@ -2014,6 +2120,29 @@ body[data-ui-version="v2"] .gn-v2-table-row:hover {
|
||||
box-shadow: var(--gn-shadow-md);
|
||||
}
|
||||
|
||||
/* 列表铺满:去掉卡片间距与圆角容器,整列跟面板色 */
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="list"] .gn-v2-table-row-list {
|
||||
gap: 0 !important;
|
||||
border: none !important;
|
||||
border-radius: 0 !important;
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="list"] .gn-v2-table-row {
|
||||
border-radius: 0 !important;
|
||||
border-width: 0 0 0.5px !important;
|
||||
border-color: var(--gn-br-1) !important;
|
||||
box-shadow: none !important;
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-content[data-view-mode="list"] .gn-v2-table-row:hover {
|
||||
background: var(--gn-bg-hover) !important;
|
||||
border-color: var(--gn-br-1) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-card-name span {
|
||||
font-family: var(--gn-font-mono);
|
||||
}
|
||||
@@ -2059,6 +2188,7 @@ body[data-ui-version="v2"] .gn-v2-table-row:last-child {
|
||||
.gn-table-overview-compact-scroll {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
border: 1px solid rgba(15, 23, 42, 0.12);
|
||||
border-radius: 6px;
|
||||
@@ -2068,6 +2198,8 @@ body[data-ui-version="v2"] .gn-v2-table-row:last-child {
|
||||
|
||||
.gn-table-overview-compact-header,
|
||||
.gn-table-overview-compact-row {
|
||||
width: max(100%, 1120px);
|
||||
box-sizing: border-box;
|
||||
grid-template-columns:
|
||||
minmax(190px, 1.7fr)
|
||||
minmax(170px, 1.4fr)
|
||||
@@ -2176,18 +2308,24 @@ body[data-ui-version="legacy"][data-theme="dark"] .gn-table-overview-compact-row
|
||||
background: rgba(22, 119, 255, 0.16) !important;
|
||||
}
|
||||
|
||||
/* 表格视图:贴边铺满内容区,背景全程跟主题 token */
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-scroll {
|
||||
border-width: 0.5px;
|
||||
border-color: var(--gn-br-2);
|
||||
background: var(--gn-bg-panel);
|
||||
flex: 1 1 auto !important;
|
||||
min-height: 0 !important;
|
||||
width: 100% !important;
|
||||
border: none !important;
|
||||
border-radius: 0 !important;
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-header {
|
||||
min-height: 30px;
|
||||
min-width: 1120px;
|
||||
width: max(100%, 1120px);
|
||||
border-bottom-width: 0.5px;
|
||||
border-bottom-color: var(--gn-br-2);
|
||||
background: var(--gn-bg-panel-2);
|
||||
color: var(--gn-fg-3);
|
||||
background: color-mix(in srgb, var(--gn-fg-1) 2.5%, var(--gn-bg-panel-2)) !important;
|
||||
color: var(--gn-fg-3) !important;
|
||||
font-family: var(--gn-font-mono);
|
||||
}
|
||||
|
||||
@@ -2196,21 +2334,35 @@ body[data-ui-version="v2"] .gn-table-overview-compact-header > [role="columnhead
|
||||
border-right-color: var(--gn-br-1);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-sort-button {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-sort-button:hover {
|
||||
background: var(--gn-bg-hover) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-sort-button[aria-pressed="true"] {
|
||||
color: var(--gn-accent) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-section {
|
||||
min-width: 1120px;
|
||||
width: max(100%, 1120px);
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
border-bottom-width: 0.5px;
|
||||
border-bottom-color: var(--gn-br-1);
|
||||
background: var(--gn-bg-panel-2);
|
||||
background: color-mix(in srgb, var(--gn-fg-1) 2.5%, var(--gn-bg-panel-2)) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-row {
|
||||
min-height: 30px !important;
|
||||
min-width: 1120px !important;
|
||||
width: max(100%, 1120px) !important;
|
||||
border-bottom-width: 0.5px !important;
|
||||
border-bottom-color: var(--gn-br-1) !important;
|
||||
background: var(--gn-bg-panel) !important;
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
font-family: var(--gn-font-mono);
|
||||
}
|
||||
@@ -2225,10 +2377,21 @@ body[data-ui-version="v2"] .gn-table-overview-compact-cell {
|
||||
padding-bottom: 4px;
|
||||
font-size: 11.5px;
|
||||
line-height: 21px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-table-overview-compact-name .anticon {
|
||||
color: var(--gn-accent);
|
||||
color: var(--gn-accent) !important;
|
||||
}
|
||||
|
||||
/* 表概览筛选条也跟主题 */
|
||||
body[data-ui-version="v2"] .gn-v2-table-overview-filter-bar {
|
||||
margin: 0 !important;
|
||||
padding: 8px 14px !important;
|
||||
border-radius: 0 !important;
|
||||
border-bottom: 0.5px solid var(--gn-br-1);
|
||||
background: color-mix(in srgb, var(--gn-fg-1) 2.5%, var(--gn-bg-panel-2)) !important;
|
||||
color: var(--gn-fg-4) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-data-grid-column-quick-find {
|
||||
|
||||
@@ -72,6 +72,11 @@ describe('built-in custom theme presets', () => {
|
||||
expect(comfortDark.css).toContain('--gn-fg-5: #878e98');
|
||||
expect(comfortDark.css).toContain('--gn-on-accent: #142019');
|
||||
expect(comfortDark.css).toContain('.gn-v2-query-toolbar-save-action');
|
||||
// 保存:default 同族 + fg-1 图标,禁止软绿底/透明底踩 primary 前景
|
||||
expect(comfortDark.css).toContain('color: var(--gn-fg-1) !important');
|
||||
expect(comfortDark.css).not.toMatch(
|
||||
/\.gn-v2-query-toolbar-save-action[\s\S]{0,200}background:\s*transparent\s*!important/,
|
||||
);
|
||||
expect(comfortDark.css).toContain('.gn-v2-ai-panel .ai-logo');
|
||||
expect(comfortDark.css).toContain('.monaco-editor-background');
|
||||
expect(comfortDark.css).not.toContain('background-color: var(--gn-bg-input) !important;');
|
||||
|
||||
@@ -396,27 +396,38 @@ body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-transaction-commit-bu
|
||||
color: var(--gn-accent-text, var(--gn-accent)) !important;
|
||||
}
|
||||
|
||||
/* 「保存」降为次级样式:与 v2-theme.css 保持一致。
|
||||
原先填 --gn-info,而 info 与 accent 在内置主题下的区分度仅 1.05–1.25,
|
||||
两个相邻实心按钮一眼分不清;且 Midnight Navy / Nord Slate 的 accent 本身即蓝青系,
|
||||
靠色相无法拉开,故改用层级区分,只让「执行」保持实心主按钮。 */
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:not(:disabled) {
|
||||
background: transparent !important;
|
||||
border-color: var(--gn-br-3) !important;
|
||||
color: var(--gn-fg-2) !important;
|
||||
/* 「保存」与工具栏 default 图标按钮同族(v2 已不用 type=primary)。
|
||||
仅保证图标用 fg-1,避免与终端等按钮混成一摊灰时单独发闷。 */
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled) {
|
||||
background: var(--gn-bg-panel) !important;
|
||||
border-color: var(--gn-br-2) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:not(:disabled):hover,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:not(:disabled):focus-visible {
|
||||
background: var(--gn-bg-hover) !important;
|
||||
border-color: var(--gn-accent) !important;
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled) .anticon {
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:not(:disabled):active {
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):hover,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):focus-visible {
|
||||
background: var(--gn-bg-hover) !important;
|
||||
border-color: var(--gn-br-3) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):hover .anticon,
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):focus-visible .anticon {
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):active {
|
||||
background: var(--gn-bg-active) !important;
|
||||
border-color: var(--gn-accent) !important;
|
||||
border-color: var(--gn-br-3) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
body[data-custom-theme][data-ui-version="v2"] .gn-v2-query-toolbar .gn-v2-query-toolbar-save-action.ant-btn:not(:disabled):active .anticon {
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,11 +156,16 @@ body[data-ui-version="v2"] [class*="monospace"] {
|
||||
ANT DESIGN OVERRIDES — surfaces & chrome
|
||||
────────────────────────────────────────────────────────── */
|
||||
|
||||
body[data-ui-version="v2"] .ant-layout,
|
||||
body[data-ui-version="v2"] .ant-layout-content {
|
||||
body[data-ui-version="v2"] .ant-layout {
|
||||
background: var(--gn-bg-app) !important;
|
||||
}
|
||||
|
||||
/* 主内容区与左侧 sider 同用 panel-2:原先 app 近黑、panel 更深一档,
|
||||
与 sider 的 panel-2 并排时会出现明显色差(表概览空白区尤其扎眼)。 */
|
||||
body[data-ui-version="v2"] .ant-layout-content {
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-layout-sider {
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
border-right: 0.5px solid var(--gn-br-1) !important;
|
||||
@@ -319,31 +324,7 @@ body[data-ui-version="v2"] .ant-btn-primary:active {
|
||||
color: var(--gn-ant-on-primary, var(--gn-on-accent, #fff)) !important;
|
||||
}
|
||||
|
||||
/* 查询工具栏「保存」降为次级样式:描边 + 中性底。
|
||||
原先它与「执行」一样是实心饱满按钮,而两者在内置主题下的填充色(accent 与 info)
|
||||
区分度仅 1.05–1.25 —— 相邻两个同色实心方块,一眼分不出哪个是执行、哪个是保存。
|
||||
由于 Midnight Navy / Nord Slate 的 accent 本身就是蓝青系,靠拉开色相无法解决,
|
||||
改用层级区分:工具栏里只有「执行」是实心主按钮,其余降级,主操作因此真正突出。 */
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary {
|
||||
background: transparent !important;
|
||||
border-color: var(--gn-br-3) !important;
|
||||
color: var(--gn-fg-2) !important;
|
||||
font-weight: 600 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:hover,
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:focus-visible {
|
||||
background: var(--gn-bg-hover) !important;
|
||||
border-color: var(--gn-accent) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-query-toolbar-save-action.ant-btn-primary:active {
|
||||
background: var(--gn-bg-active) !important;
|
||||
border-color: var(--gn-accent) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
}
|
||||
/* 查询工具栏「保存」在 v2 已改为 default 图标按钮;样式见 v2-theme-workbench.css。 */
|
||||
|
||||
body[data-ui-version="v2"] .ant-btn-primary:disabled {
|
||||
background: var(--gn-bg-active) !important;
|
||||
@@ -454,17 +435,47 @@ body[data-ui-version="v2"] .ant-picker-dropdown .ant-picker-panel-container {
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-title,
|
||||
body[data-ui-version="v2"] .ant-select-item {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
gap: 0;
|
||||
border-radius: 6px !important;
|
||||
padding: 6px 10px !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
min-height: 28px !important;
|
||||
min-height: 32px !important;
|
||||
line-height: 1.25 !important;
|
||||
font-size: 12.5px !important;
|
||||
/* Flat item surface — no outline/box that makes submenu rows look different */
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
/* Icon + label share one baseline/vertical center (leaf and submenu rows) */
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-title-content {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
min-width: 0;
|
||||
line-height: 1.25 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item:hover,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item-active,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-title:hover,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-active > .ant-dropdown-menu-submenu-title,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-open > .ant-dropdown-menu-submenu-title,
|
||||
body[data-ui-version="v2"] .ant-select-item-option-active:not(.ant-select-item-option-disabled) {
|
||||
background: var(--gn-bg-active) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-selected > .ant-dropdown-menu-submenu-title {
|
||||
background: var(--gn-bg-active) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
|
||||
@@ -479,9 +490,43 @@ body[data-ui-version="v2"] .ant-dropdown-menu-item-divider {
|
||||
}
|
||||
|
||||
/* Right-click menu items get a tighter, sectioned look */
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item-icon {
|
||||
color: var(--gn-fg-4);
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item-icon,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-title .ant-dropdown-menu-item-icon,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-expand-icon {
|
||||
color: var(--gn-fg-4) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item-icon,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-title .ant-dropdown-menu-item-icon {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
flex: 0 0 16px !important;
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
margin-inline-end: 8px !important;
|
||||
margin-right: 8px !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item-icon > .anticon,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-title .ant-dropdown-menu-item-icon > .anticon {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-expand-icon {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
top: 50% !important;
|
||||
transform: translateY(-50%) !important;
|
||||
margin-inline-end: 2px !important;
|
||||
height: 16px !important;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item-danger {
|
||||
@@ -490,10 +535,62 @@ body[data-ui-version="v2"] .ant-dropdown-menu-item-danger {
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-item-danger:hover {
|
||||
background: rgba(220, 38, 38, 0.08) !important;
|
||||
}
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-title {
|
||||
border-radius: 6px !important;
|
||||
padding: 6px 10px !important;
|
||||
font-size: 12.5px !important;
|
||||
|
||||
/* Nested dropdown menus: collapse double border, no glow/halo */
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-popup,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-submenu,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-submenu-popup {
|
||||
margin-inline-start: -2px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-popup > .ant-dropdown-menu,
|
||||
body[data-ui-version="v2"] .ant-dropdown-menu-submenu-popup.ant-dropdown-menu,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-submenu .ant-dropdown-menu,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-submenu.ant-dropdown-menu {
|
||||
/* Match primary menu border only — strip outer glow that reads as white rim in dark theme */
|
||||
border: 0.5px solid var(--gn-br-2) !important;
|
||||
border-inline-start: none !important;
|
||||
border-radius: 10px !important;
|
||||
border-start-start-radius: 8px !important;
|
||||
border-end-start-radius: 8px !important;
|
||||
box-shadow: none !important;
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
/* Title-bar cascade: keep both levels flat (no shadow/halo on either panel) */
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu {
|
||||
box-shadow: none !important;
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
/* Title-bar more menu: leaf rows and submenu rows share the same hover fill + alignment */
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-item,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-submenu-title,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu .ant-dropdown-menu-item,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu .ant-dropdown-menu-submenu-title {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
min-height: 32px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-item:hover,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-item-active,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-submenu-title:hover,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-submenu-active > .ant-dropdown-menu-submenu-title,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-dropdown .ant-dropdown-menu-submenu-open > .ant-dropdown-menu-submenu-title,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu .ant-dropdown-menu-item:hover,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu .ant-dropdown-menu-item-active,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu .ant-dropdown-menu-submenu-title:hover,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu .ant-dropdown-menu-submenu-active > .ant-dropdown-menu-submenu-title,
|
||||
body[data-ui-version="v2"] .gn-v2-titlebar-quick-menu .ant-dropdown-menu-submenu-open > .ant-dropdown-menu-submenu-title {
|
||||
background: var(--gn-bg-active) !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* ─── Tables (ant-table, used by some legacy panes) ────── */
|
||||
@@ -1494,12 +1591,15 @@ body[data-ui-version="v2"] .ant-divider {
|
||||
body[data-ui-version="v2"] .gn-v2-object-explorer .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -6px;
|
||||
top: 4px;
|
||||
bottom: 4px;
|
||||
width: 2px;
|
||||
left: 2px;
|
||||
top: 5px;
|
||||
bottom: 5px;
|
||||
width: 3px;
|
||||
background: var(--gn-accent);
|
||||
border-radius: 2px;
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-tree .ant-tree-node-content-wrapper {
|
||||
@@ -1950,9 +2050,10 @@ body[data-ui-version="v2"] .gn-v2-connection-rail {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: calc(4px * var(--gn-v2-rail-scale));
|
||||
padding: calc(8px * var(--gn-v2-rail-scale)) 0;
|
||||
gap: 0;
|
||||
padding: calc(6px * var(--gn-v2-rail-scale)) 0 0;
|
||||
border-right: 0.5px solid var(--gn-br-1);
|
||||
/* Match explorer panel — no tint strip (tinted empty rail looked worse) */
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@@ -2087,17 +2188,21 @@ body[data-ui-version="v2"] .gn-v2-rail-secondary-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: calc(6px * var(--gn-v2-rail-scale));
|
||||
gap: calc(4px * var(--gn-v2-rail-scale));
|
||||
}
|
||||
|
||||
/* Top tool cluster — compact, not floating in empty space */
|
||||
body[data-ui-version="v2"] .gn-v2-rail-primary-actions {
|
||||
padding-top: calc(4px * var(--gn-v2-rail-scale));
|
||||
padding: calc(2px * var(--gn-v2-rail-scale)) 0 calc(4px * var(--gn-v2-rail-scale));
|
||||
}
|
||||
|
||||
/* Bottom system actions — pin to foot with a hairline only, no fill */
|
||||
body[data-ui-version="v2"] .gn-v2-rail-secondary-actions {
|
||||
margin-top: auto;
|
||||
flex: 0 0 auto;
|
||||
padding-bottom: calc(4px * var(--gn-v2-rail-scale));
|
||||
padding: calc(6px * var(--gn-v2-rail-scale)) 0 calc(8px * var(--gn-v2-rail-scale));
|
||||
border-top: 0.5px solid var(--gn-br-1);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-rail-action-group,
|
||||
@@ -2148,19 +2253,39 @@ body[data-ui-version="v2"] .gn-v2-rail-tool {
|
||||
justify-content: center;
|
||||
gap: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
transition: background-color 140ms ease, color 140ms ease, box-shadow 140ms ease;
|
||||
}
|
||||
|
||||
/* Compact square hit target for rail tools (locate / AI / settings) */
|
||||
body[data-ui-version="v2"] .gn-v2-rail-tool {
|
||||
width: calc(24px * var(--gn-v2-rail-scale));
|
||||
height: calc(32px * var(--gn-v2-rail-scale));
|
||||
border-radius: calc(8px * var(--gn-v2-rail-scale));
|
||||
width: calc(28px * var(--gn-v2-rail-scale));
|
||||
height: calc(28px * var(--gn-v2-rail-scale));
|
||||
border-radius: calc(7px * var(--gn-v2-rail-scale));
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
color: var(--gn-fg-3);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-rail-tool .anticon {
|
||||
font-size: calc(15px * var(--gn-v2-rail-scale));
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-rail-item:hover,
|
||||
body[data-ui-version="v2"] .gn-v2-rail-tool:hover {
|
||||
body[data-ui-version="v2"] .gn-v2-rail-tool:hover:not(:disabled) {
|
||||
background: var(--gn-bg-hover);
|
||||
color: var(--gn-fg-1);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-rail-tool:hover:not(:disabled) {
|
||||
background: color-mix(in srgb, var(--gn-accent) 12%, var(--gn-bg-hover));
|
||||
color: var(--gn-accent);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-rail-tool:focus-visible {
|
||||
outline: 2px solid var(--gn-accent);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-rail-item.is-active {
|
||||
@@ -2326,7 +2451,7 @@ body[data-ui-version="v2"] .gn-v2-active-connection-copy span {
|
||||
body[data-ui-version="v2"] .gn-v2-active-connection-copy strong {
|
||||
color: var(--gn-fg-1);
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
@@ -2338,6 +2463,11 @@ body[data-ui-version="v2"] .gn-v2-active-connection-copy span {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* Empty database selection: guide tone, not error tone */
|
||||
body[data-ui-version="v2"] .gn-v2-active-connection-copy span.is-placeholder {
|
||||
color: var(--gn-fg-5);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-active-connection-tooltip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -2366,6 +2496,13 @@ body[data-ui-version="v2"] .gn-v2-active-connection-actions {
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex: 0 0 auto;
|
||||
opacity: 0.72;
|
||||
transition: opacity 140ms ease;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-active-connection-header:hover .gn-v2-active-connection-actions,
|
||||
body[data-ui-version="v2"] .gn-v2-active-connection-header:focus-within .gn-v2-active-connection-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@container gn-v2-object-explorer (max-width: 440px) {
|
||||
@@ -2815,19 +2952,26 @@ body[data-ui-version="v2"] .gn-v2-explorer-filter-tabs::-webkit-scrollbar {
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-filter-tabs button {
|
||||
flex: 0 0 auto;
|
||||
height: 22px;
|
||||
padding: 0 6px;
|
||||
padding: 0 7px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--gn-fg-4);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
transition: background-color 140ms ease, color 140ms ease;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-filter-tabs button:hover {
|
||||
background: var(--gn-bg-hover);
|
||||
color: var(--gn-fg-2);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-filter-tabs button.is-active {
|
||||
background: var(--gn-bg-active);
|
||||
color: var(--gn-fg-1);
|
||||
background: color-mix(in srgb, var(--gn-accent) 14%, var(--gn-bg-panel-2));
|
||||
color: var(--gn-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-toolbar {
|
||||
@@ -2910,6 +3054,11 @@ body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-treenode {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Connection rows sit one step taller than object rows for hierarchy */
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-treenode:has(.gn-v2-tree-title.is-connection) {
|
||||
min-height: 30px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-switcher {
|
||||
width: 16px !important;
|
||||
min-width: 16px !important;
|
||||
@@ -2919,6 +3068,10 @@ body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-switcher {
|
||||
color: var(--gn-fg-4);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-treenode:has(.gn-v2-tree-title.is-connection) .ant-tree-switcher {
|
||||
line-height: 30px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-indent-unit {
|
||||
width: 12px !important;
|
||||
}
|
||||
@@ -2927,21 +3080,26 @@ body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-node-content-wra
|
||||
min-width: 100%;
|
||||
width: max-content !important;
|
||||
min-height: 26px !important;
|
||||
padding: 0 6px !important;
|
||||
padding: 0 6px 0 8px !important;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
border-radius: 6px !important;
|
||||
color: var(--gn-fg-3) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-treenode:has(.gn-v2-tree-title.is-connection) .ant-tree-node-content-wrapper {
|
||||
min-height: 30px !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-node-content-wrapper:hover {
|
||||
background: var(--gn-bg-hover) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-node-content-wrapper.ant-tree-node-selected {
|
||||
background: var(--gn-bg-selected) !important;
|
||||
background: color-mix(in srgb, var(--gn-accent) 10%, var(--gn-bg-selected)) !important;
|
||||
color: var(--gn-fg-1) !important;
|
||||
font-weight: 400 !important;
|
||||
box-shadow: inset 0 0 0 0.5px color-mix(in srgb, var(--gn-accent) 16%, transparent);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-explorer-tree-shell .ant-tree-iconEle {
|
||||
@@ -3041,6 +3199,8 @@ body[data-ui-version="v2"] .gn-v2-tree-title.is-group {
|
||||
body[data-ui-version="v2"] .gn-v2-tree-title.is-connection {
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-weight: 500 !important;
|
||||
color: var(--gn-fg-1);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-tree-status {
|
||||
@@ -3243,9 +3403,7 @@ body[data-ui-version="v2"] .gn-v2-table-pin-indicator {
|
||||
color: var(--gn-warn);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-object-explorer .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected::before {
|
||||
display: none;
|
||||
}
|
||||
/* Selected accent bar kept on; see rule near Small additions block */
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-tree-title[data-node-type="database"] {
|
||||
font-weight: 400 !important;
|
||||
@@ -3747,7 +3905,7 @@ body[data-ui-version="v2"] .gn-v2-workspace-body {
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-workspace-main {
|
||||
background: var(--gn-bg-panel) !important;
|
||||
background: var(--gn-bg-panel-2) !important;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-ai-panel-dock {
|
||||
|
||||
@@ -2537,6 +2537,9 @@
|
||||
"app.connection_package.action.start_export": "Export starten",
|
||||
"app.connection_package.action.start_import": "Import starten",
|
||||
"app.connection_package.dialog.export_title": "Verbindungen exportieren",
|
||||
"app.connection_package.dialog.export_connections_label": "Zu exportierende Verbindungen",
|
||||
"app.connection_package.dialog.export_connections_placeholder": "Eine oder mehrere Verbindungen auswählen",
|
||||
"app.connection_package.dialog.export_connections_summary": "{{selected}} / {{total}} Verbindung(en) ausgewählt",
|
||||
"app.connection_package.dialog.file_password_placeholder": "Dateischutzpasswort eingeben (optional)",
|
||||
"app.connection_package.dialog.help.encrypted_passwords_recommend_file_password": "Passwörter sind verschlüsselt. Für die Übertragung über öffentliche Netzwerke sollten Sie ein Dateischutzpasswort festlegen.",
|
||||
"app.connection_package.dialog.help.exclude_passwords": "Es werden nur Verbindungseinstellungen exportiert. Passwörter sind nicht enthalten.",
|
||||
@@ -2546,6 +2549,7 @@
|
||||
"app.connection_package.dialog.option.use_file_password": "Dateischutzpasswort festlegen",
|
||||
"app.connection_package.dialog.restore_password_placeholder": "Passwort des Wiederherstellungspakets eingeben",
|
||||
"app.connection_package.error.export_capability_unavailable": "Export fehlgeschlagen: Das aktuelle Backend stellt die neue Exportfunktion nicht bereit",
|
||||
"app.connection_package.error.no_selected_connections": "Wählen Sie mindestens eine Verbindung zum Exportieren",
|
||||
"app.connection_package.error.file_password_required": "Das Dateischutzpasswort darf nicht leer sein",
|
||||
"app.connection_package.error.import_capability_unavailable": "Import fehlgeschlagen: Das aktuelle Backend stellt die neue Importfunktion nicht bereit",
|
||||
"app.connection_package.error.import_no_connections": "Import fehlgeschlagen: Das Backend hat keine Verbindungsliste zurückgegeben",
|
||||
@@ -3957,6 +3961,14 @@
|
||||
"data_export.workbench.helper.available_objects": "{{available}} Objekte sind in der aktuellen Datenbank verfügbar, {{selected}} ausgewählt.",
|
||||
"data_export.workbench.helper.batch_database_output": "Beim Start des Exports wählen Sie zuerst ein Ausgabeverzeichnis, danach werden für jede Datenbank separate SQL-Dateien erzeugt.",
|
||||
"data_export.workbench.helper.batch_databases_start": "Beim Stapel-Export von Datenbanken wählen Sie zuerst ein Ausgabeverzeichnis. Danach werden pro Datenbank separate SQL-Dateien erzeugt und rechts der Gesamtfortschritt angezeigt.",
|
||||
"data_export.workbench.intent.label": "Aktion",
|
||||
"data_export.workbench.intent.export": "Export",
|
||||
"data_export.workbench.intent.delete": "Löschen",
|
||||
"data_export.workbench.intent.batch_tables_delete_description": "Ausgewählte Tabellen leeren oder löschen. Nicht rückgängig machbar.",
|
||||
"data_export.workbench.intent.batch_databases_delete_description": "Ausgewählte Datenbanken und alle Daten löschen. Nicht rückgängig machbar.",
|
||||
"data_export.workbench.helper.batch_tables_delete": "Zielumgebung vor dem Leeren oder Löschen prüfen.",
|
||||
"data_export.workbench.helper.batch_databases_delete": "Zielumgebung vor dem Löschen prüfen.",
|
||||
"data_export.workbench.strategy.batch_delete": "Stapellöschung",
|
||||
"data_export.workbench.helper.batch_tables_start": "Beim Stapel-Export von Objekten wird eine gemeinsame SQL-Datei erzeugt. Rechts sehen Sie den Gesamtfortschritt und aktuelle Aufgabenübersichten.",
|
||||
"data_export.workbench.helper.single_export_start": "Nach dem Start des Exports wählen Sie zuerst die Zieldatei. Rechts werden dann ein einzelner Fortschrittsbalken, die Dauer und der Ausgabepfad angezeigt.",
|
||||
"data_export.workbench.history.count": "{{count}} Einträge",
|
||||
@@ -7181,6 +7193,7 @@
|
||||
"sidebar.action.cancel": "Abbrechen",
|
||||
"sidebar.action.clear_selection": "Alle abwählen",
|
||||
"sidebar.action.clear_tables": "Tabellen leeren",
|
||||
"sidebar.action.truncate_tables": "Tabellen abschneiden",
|
||||
"sidebar.action.close": "Schließen",
|
||||
"sidebar.action.continue": "Fortfahren",
|
||||
"sidebar.action.delete": "Löschen",
|
||||
@@ -7201,7 +7214,7 @@
|
||||
"sidebar.action.unpin_table": "Anheften aufheben",
|
||||
"sidebar.active_connection.actions": "Verbindungsaktionen",
|
||||
"sidebar.active_connection.current_host_database": "Aktueller Host und Datenbank",
|
||||
"sidebar.active_connection.no_database_selected": "Keine Datenbank ausgewählt",
|
||||
"sidebar.active_connection.no_database_selected": "Datenbank wählen, um Objekte zu browsen",
|
||||
"sidebar.active_connection.no_host_selected": "Kein Host ausgewählt",
|
||||
"sidebar.ai_prompt.explain.detail": "Gehe besonders auf Feldbedeutungen, Primärschlüssel/Indizes, mögliche Beziehungen, typische Abfrageszenarien und Risiken ein.",
|
||||
"sidebar.ai_prompt.explain.intro": "Erkläre die Struktur und fachliche Bedeutung der Tabelle {{table}}.",
|
||||
@@ -7433,6 +7446,9 @@
|
||||
"sidebar.message.clear_failed": "Leeren fehlgeschlagen: {{error}}",
|
||||
"sidebar.message.clear_success": "Leeren erfolgreich.",
|
||||
"sidebar.message.clearing_selected_tables": "{{count}} ausgewählte Tabellen werden geleert...",
|
||||
"sidebar.message.truncate_selected_tables_failed": "Tabellen abschneiden fehlgeschlagen: {{error}}",
|
||||
"sidebar.message.truncate_selected_tables_success": "{{count}} Tabelle(n) abgeschnitten.",
|
||||
"sidebar.message.truncating_selected_tables": "{{count}} Tabelle(n) werden abgeschnitten…",
|
||||
"sidebar.message.connection_config_not_found": "Verbindungskonfiguration wurde nicht gefunden.",
|
||||
"sidebar.message.connection_deleted": "Verbindung gelöscht.",
|
||||
"sidebar.message.connection_failed": "Verbindung fehlgeschlagen: {{error}}",
|
||||
@@ -7597,6 +7613,8 @@
|
||||
"sidebar.modal.batch_tables.title": "Stapeloperationen für Objekte",
|
||||
"sidebar.modal.confirm_clear_selected_tables.content": "Daten der ausgewählten Objekte unter {{connection}} / {{database}} leeren? Dies kann nicht rückgängig gemacht werden.",
|
||||
"sidebar.modal.confirm_clear_selected_tables.title": "Ausgewählte Tabellen leeren",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.content": "Daten in {{count}} ausgewählten Tabelle(n) unter {{connection}} / {{database}} abschneiden (TRUNCATE)? Meist nicht rückgängig machbar.",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.title": "Abschneiden der ausgewählten Tabellen bestätigen",
|
||||
"sidebar.modal.confirm_delete.title": "Löschen bestätigen",
|
||||
"sidebar.modal.confirm_delete_connection.content": "{{name}} löschen?",
|
||||
"sidebar.modal.confirm_delete_database.content": "{{name}} löschen? Dies kann nicht rückgängig gemacht werden.",
|
||||
|
||||
@@ -2537,6 +2537,9 @@
|
||||
"app.connection_package.action.start_export": "Start Export",
|
||||
"app.connection_package.action.start_import": "Start Import",
|
||||
"app.connection_package.dialog.export_title": "Export Connections",
|
||||
"app.connection_package.dialog.export_connections_label": "Connections to export",
|
||||
"app.connection_package.dialog.export_connections_placeholder": "Select one or more connections",
|
||||
"app.connection_package.dialog.export_connections_summary": "Selected {{selected}} / {{total}} connection(s)",
|
||||
"app.connection_package.dialog.file_password_placeholder": "Enter file protection password (optional)",
|
||||
"app.connection_package.dialog.help.encrypted_passwords_recommend_file_password": "Passwords are encrypted. For public transfer, set a file protection password.",
|
||||
"app.connection_package.dialog.help.exclude_passwords": "Only connection settings will be exported. Passwords are not included.",
|
||||
@@ -2546,6 +2549,7 @@
|
||||
"app.connection_package.dialog.option.use_file_password": "Set file protection password",
|
||||
"app.connection_package.dialog.restore_password_placeholder": "Enter recovery package password",
|
||||
"app.connection_package.error.export_capability_unavailable": "Export failed: the current backend does not provide the new export capability",
|
||||
"app.connection_package.error.no_selected_connections": "Select at least one connection to export",
|
||||
"app.connection_package.error.file_password_required": "File protection password cannot be empty",
|
||||
"app.connection_package.error.import_capability_unavailable": "Import failed: the current backend does not provide the new import capability",
|
||||
"app.connection_package.error.import_no_connections": "Import failed: the backend did not return a connection list",
|
||||
@@ -3957,6 +3961,14 @@
|
||||
"data_export.workbench.helper.available_objects": "{{available}} objects are available in the current database, {{selected}} selected.",
|
||||
"data_export.workbench.helper.batch_database_output": "When export starts, choose an output directory first, then generate separate SQL files for each database.",
|
||||
"data_export.workbench.helper.batch_databases_start": "Batch database export lets you choose an output directory first, then generates separate SQL files per database and shows overall database progress on the right.",
|
||||
"data_export.workbench.intent.label": "Action",
|
||||
"data_export.workbench.intent.export": "Export",
|
||||
"data_export.workbench.intent.delete": "Delete",
|
||||
"data_export.workbench.intent.batch_tables_delete_description": "Clear or drop the selected tables. This cannot be undone.",
|
||||
"data_export.workbench.intent.batch_databases_delete_description": "Drop the selected databases and all of their data. This cannot be undone.",
|
||||
"data_export.workbench.helper.batch_tables_delete": "Confirm the target environment before clearing or deleting tables.",
|
||||
"data_export.workbench.helper.batch_databases_delete": "Confirm the target environment before deleting databases.",
|
||||
"data_export.workbench.strategy.batch_delete": "Batch delete",
|
||||
"data_export.workbench.helper.batch_tables_start": "Batch object export generates one SQL file and shows overall object progress plus recent task summaries on the right.",
|
||||
"data_export.workbench.helper.single_export_start": "After export starts, you will choose the target file first, and the right panel will show a single progress bar, elapsed time, and output path.",
|
||||
"data_export.workbench.history.count": "{{count}} records",
|
||||
@@ -7181,6 +7193,7 @@
|
||||
"sidebar.action.cancel": "Cancel",
|
||||
"sidebar.action.clear_selection": "Deselect all",
|
||||
"sidebar.action.clear_tables": "Clear tables",
|
||||
"sidebar.action.truncate_tables": "Truncate tables",
|
||||
"sidebar.action.close": "Close",
|
||||
"sidebar.action.continue": "Continue",
|
||||
"sidebar.action.delete": "Delete",
|
||||
@@ -7201,7 +7214,7 @@
|
||||
"sidebar.action.unpin_table": "Unpin table",
|
||||
"sidebar.active_connection.actions": "Connection actions",
|
||||
"sidebar.active_connection.current_host_database": "Current host and database",
|
||||
"sidebar.active_connection.no_database_selected": "No database selected",
|
||||
"sidebar.active_connection.no_database_selected": "Select a database to browse objects",
|
||||
"sidebar.active_connection.no_host_selected": "No host selected",
|
||||
"sidebar.ai_prompt.explain.detail": "Focus on field meanings, primary keys/indexes, potential relationships, typical query scenarios, and risks.",
|
||||
"sidebar.ai_prompt.explain.intro": "Explain the structure and business meaning of table {{table}}.",
|
||||
@@ -7433,6 +7446,9 @@
|
||||
"sidebar.message.clear_failed": "Clear failed: {{error}}",
|
||||
"sidebar.message.clear_success": "Clear completed.",
|
||||
"sidebar.message.clearing_selected_tables": "Clearing {{count}} selected tables...",
|
||||
"sidebar.message.truncate_selected_tables_failed": "Failed to truncate tables: {{error}}",
|
||||
"sidebar.message.truncate_selected_tables_success": "Truncated {{count}} table(s).",
|
||||
"sidebar.message.truncating_selected_tables": "Truncating {{count}} table(s)…",
|
||||
"sidebar.message.connection_config_not_found": "Connection configuration was not found.",
|
||||
"sidebar.message.connection_deleted": "Connection deleted.",
|
||||
"sidebar.message.connection_failed": "Connection failed: {{error}}",
|
||||
@@ -7597,6 +7613,8 @@
|
||||
"sidebar.modal.batch_tables.title": "Batch object operations",
|
||||
"sidebar.modal.confirm_clear_selected_tables.content": "Clear data in selected objects under {{connection}} / {{database}}? This cannot be undone.",
|
||||
"sidebar.modal.confirm_clear_selected_tables.title": "Confirm clear selected tables",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.content": "Truncate data in {{count}} selected table(s) under {{connection}} / {{database}} (TRUNCATE)? This usually cannot be rolled back.",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.title": "Confirm truncate selected tables",
|
||||
"sidebar.modal.confirm_delete.title": "Confirm delete",
|
||||
"sidebar.modal.confirm_delete_connection.content": "Delete {{name}}?",
|
||||
"sidebar.modal.confirm_delete_database.content": "Delete {{name}}? This cannot be undone.",
|
||||
|
||||
@@ -2537,6 +2537,9 @@
|
||||
"app.connection_package.action.start_export": "エクスポート開始",
|
||||
"app.connection_package.action.start_import": "インポート開始",
|
||||
"app.connection_package.dialog.export_title": "接続をエクスポート",
|
||||
"app.connection_package.dialog.export_connections_label": "エクスポートする接続",
|
||||
"app.connection_package.dialog.export_connections_placeholder": "1 つ以上の接続を選択",
|
||||
"app.connection_package.dialog.export_connections_summary": "選択済み {{selected}} / {{total}} 件",
|
||||
"app.connection_package.dialog.file_password_placeholder": "ファイル保護パスワードを入力(任意)",
|
||||
"app.connection_package.dialog.help.encrypted_passwords_recommend_file_password": "パスワードは暗号化されています。公開ネットワークで転送する場合は、ファイル保護パスワードの設定を推奨します。",
|
||||
"app.connection_package.dialog.help.exclude_passwords": "接続設定のみをエクスポートし、パスワードは含めません。",
|
||||
@@ -2546,6 +2549,7 @@
|
||||
"app.connection_package.dialog.option.use_file_password": "ファイル保護パスワードを設定",
|
||||
"app.connection_package.dialog.restore_password_placeholder": "復元パッケージのパスワードを入力",
|
||||
"app.connection_package.error.export_capability_unavailable": "エクスポートに失敗しました: 現在のバックエンドは新しいエクスポート機能を提供していません",
|
||||
"app.connection_package.error.no_selected_connections": "エクスポートする接続を 1 件以上選択してください",
|
||||
"app.connection_package.error.file_password_required": "ファイル保護パスワードは空にできません",
|
||||
"app.connection_package.error.import_capability_unavailable": "インポートに失敗しました: 現在のバックエンドは新しいインポート機能を提供していません",
|
||||
"app.connection_package.error.import_no_connections": "インポートに失敗しました: バックエンドが接続リストを返しませんでした",
|
||||
@@ -3957,6 +3961,14 @@
|
||||
"data_export.workbench.helper.available_objects": "現在のデータベースで利用可能なオブジェクトは {{available}} 件、選択済みは {{selected}} 件です。",
|
||||
"data_export.workbench.helper.batch_database_output": "エクスポート開始時にまず出力ディレクトリを選択し、その後各データベースごとに個別の SQL ファイルを生成します。",
|
||||
"data_export.workbench.helper.batch_databases_start": "一括データベースエクスポートでは、まず出力ディレクトリを選択し、その後データベースごとに個別の SQL ファイルを生成し、右側に全体のデータベース進捗を表示します。",
|
||||
"data_export.workbench.intent.label": "操作種別",
|
||||
"data_export.workbench.intent.export": "エクスポート",
|
||||
"data_export.workbench.intent.delete": "削除",
|
||||
"data_export.workbench.intent.batch_tables_delete_description": "選択したテーブルをクリアまたは削除します。元に戻せません。",
|
||||
"data_export.workbench.intent.batch_databases_delete_description": "選択したデータベースとその全データを削除します。元に戻せません。",
|
||||
"data_export.workbench.helper.batch_tables_delete": "クリアまたは削除の前に対象環境を確認してください。",
|
||||
"data_export.workbench.helper.batch_databases_delete": "削除の前に対象環境を確認してください。",
|
||||
"data_export.workbench.strategy.batch_delete": "一括削除",
|
||||
"data_export.workbench.helper.batch_tables_start": "一括オブジェクトエクスポートでは 1 つの SQL ファイルを生成し、右側に全体のオブジェクト進捗と最近のタスク要約を表示します。",
|
||||
"data_export.workbench.helper.single_export_start": "エクスポート開始後、まず保存先ファイルを選択し、右側のメインパネルに単一の進捗バー、所要時間、出力パスを表示します。",
|
||||
"data_export.workbench.history.count": "{{count}} 件の記録",
|
||||
@@ -7181,6 +7193,7 @@
|
||||
"sidebar.action.cancel": "キャンセル",
|
||||
"sidebar.action.clear_selection": "すべて解除",
|
||||
"sidebar.action.clear_tables": "テーブルをクリア",
|
||||
"sidebar.action.truncate_tables": "テーブルを切り捨て",
|
||||
"sidebar.action.close": "閉じる",
|
||||
"sidebar.action.continue": "続行",
|
||||
"sidebar.action.delete": "削除",
|
||||
@@ -7201,7 +7214,7 @@
|
||||
"sidebar.action.unpin_table": "テーブル固定を解除",
|
||||
"sidebar.active_connection.actions": "接続操作",
|
||||
"sidebar.active_connection.current_host_database": "現在の Host とデータベース",
|
||||
"sidebar.active_connection.no_database_selected": "データベース未選択",
|
||||
"sidebar.active_connection.no_database_selected": "データベースを選択してオブジェクトを表示",
|
||||
"sidebar.active_connection.no_host_selected": "Host 未選択",
|
||||
"sidebar.ai_prompt.explain.detail": "フィールドの意味、主キー/インデックス、想定される関連、典型的なクエリ場面、リスクを重点的に説明してください。",
|
||||
"sidebar.ai_prompt.explain.intro": "テーブル {{table}} の構造と業務上の意味を説明してください。",
|
||||
@@ -7433,6 +7446,9 @@
|
||||
"sidebar.message.clear_failed": "クリアに失敗しました: {{error}}",
|
||||
"sidebar.message.clear_success": "クリア成功。",
|
||||
"sidebar.message.clearing_selected_tables": "選択した {{count}} 件のテーブルをクリアしています...",
|
||||
"sidebar.message.truncate_selected_tables_failed": "テーブルの切り捨てに失敗: {{error}}",
|
||||
"sidebar.message.truncate_selected_tables_success": "{{count}} テーブルを切り捨てました。",
|
||||
"sidebar.message.truncating_selected_tables": "{{count}} テーブルを切り捨て中…",
|
||||
"sidebar.message.connection_config_not_found": "接続設定が見つかりません。",
|
||||
"sidebar.message.connection_deleted": "接続を削除しました。",
|
||||
"sidebar.message.connection_failed": "接続に失敗しました: {{error}}",
|
||||
@@ -7597,6 +7613,8 @@
|
||||
"sidebar.modal.batch_tables.title": "オブジェクト一括操作",
|
||||
"sidebar.modal.confirm_clear_selected_tables.content": "{{connection}} / {{database}} の選択したオブジェクトのデータをクリアしますか?この操作は元に戻せません。",
|
||||
"sidebar.modal.confirm_clear_selected_tables.title": "選択したテーブルのクリアを確認",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.content": "{{connection}} / {{database}} の選択 {{count}} テーブルを TRUNCATE しますか?通常はロールバックできません。",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.title": "選択テーブルの切り捨て確認",
|
||||
"sidebar.modal.confirm_delete.title": "削除の確認",
|
||||
"sidebar.modal.confirm_delete_connection.content": "接続 {{name}} を削除しますか?",
|
||||
"sidebar.modal.confirm_delete_database.content": "{{name}} を削除しますか?この操作は元に戻せません。",
|
||||
|
||||
@@ -2537,6 +2537,9 @@
|
||||
"app.connection_package.action.start_export": "Начать экспорт",
|
||||
"app.connection_package.action.start_import": "Начать импорт",
|
||||
"app.connection_package.dialog.export_title": "Экспорт подключений",
|
||||
"app.connection_package.dialog.export_connections_label": "Подключения для экспорта",
|
||||
"app.connection_package.dialog.export_connections_placeholder": "Выберите одно или несколько подключений",
|
||||
"app.connection_package.dialog.export_connections_summary": "Выбрано {{selected}} / {{total}}",
|
||||
"app.connection_package.dialog.file_password_placeholder": "Введите пароль защиты файла (необязательно)",
|
||||
"app.connection_package.dialog.help.encrypted_passwords_recommend_file_password": "Пароли зашифрованы. Для передачи через публичную сеть рекомендуется задать пароль защиты файла.",
|
||||
"app.connection_package.dialog.help.exclude_passwords": "Будут экспортированы только настройки подключений. Пароли не включаются.",
|
||||
@@ -2546,6 +2549,7 @@
|
||||
"app.connection_package.dialog.option.use_file_password": "Задать пароль защиты файла",
|
||||
"app.connection_package.dialog.restore_password_placeholder": "Введите пароль пакета восстановления",
|
||||
"app.connection_package.error.export_capability_unavailable": "Экспорт не выполнен: текущий backend не предоставляет новую возможность экспорта",
|
||||
"app.connection_package.error.no_selected_connections": "Выберите хотя бы одно подключение для экспорта",
|
||||
"app.connection_package.error.file_password_required": "Пароль защиты файла не может быть пустым",
|
||||
"app.connection_package.error.import_capability_unavailable": "Импорт не выполнен: текущий backend не предоставляет новую возможность импорта",
|
||||
"app.connection_package.error.import_no_connections": "Импорт не выполнен: backend не вернул список подключений",
|
||||
@@ -3957,6 +3961,14 @@
|
||||
"data_export.workbench.helper.available_objects": "В текущей базе доступно {{available}} объектов, выбрано {{selected}}.",
|
||||
"data_export.workbench.helper.batch_database_output": "При запуске экспорта сначала выберите выходной каталог, затем для каждой базы данных будут созданы отдельные SQL-файлы.",
|
||||
"data_export.workbench.helper.batch_databases_start": "При пакетном экспорте баз данных сначала выбирается выходной каталог, затем для каждой базы создаётся отдельный SQL-файл, а справа показывается общий прогресс.",
|
||||
"data_export.workbench.intent.label": "Действие",
|
||||
"data_export.workbench.intent.export": "Экспорт",
|
||||
"data_export.workbench.intent.delete": "Удаление",
|
||||
"data_export.workbench.intent.batch_tables_delete_description": "Очистить или удалить выбранные таблицы. Отменить нельзя.",
|
||||
"data_export.workbench.intent.batch_databases_delete_description": "Удалить выбранные базы и все их данные. Отменить нельзя.",
|
||||
"data_export.workbench.helper.batch_tables_delete": "Перед очисткой или удалением проверьте целевую среду.",
|
||||
"data_export.workbench.helper.batch_databases_delete": "Перед удалением проверьте целевую среду.",
|
||||
"data_export.workbench.strategy.batch_delete": "Пакетное удаление",
|
||||
"data_export.workbench.helper.batch_tables_start": "Пакетный экспорт объектов создаёт один SQL-файл и показывает справа общий прогресс по объектам и последние сводки задач.",
|
||||
"data_export.workbench.helper.single_export_start": "После запуска экспорта сначала выбирается целевой файл, а справа отображаются единый индикатор прогресса, длительность и путь вывода.",
|
||||
"data_export.workbench.history.count": "{{count}} записей",
|
||||
@@ -7181,6 +7193,7 @@
|
||||
"sidebar.action.cancel": "Отмена",
|
||||
"sidebar.action.clear_selection": "Снять выбор со всех",
|
||||
"sidebar.action.clear_tables": "Очистить таблицы",
|
||||
"sidebar.action.truncate_tables": "Очистить таблицы (TRUNCATE)",
|
||||
"sidebar.action.close": "Закрыть",
|
||||
"sidebar.action.continue": "Продолжить",
|
||||
"sidebar.action.delete": "Удалить",
|
||||
@@ -7201,7 +7214,7 @@
|
||||
"sidebar.action.unpin_table": "Открепить таблицу",
|
||||
"sidebar.active_connection.actions": "Действия с подключением",
|
||||
"sidebar.active_connection.current_host_database": "Текущий Host и база данных",
|
||||
"sidebar.active_connection.no_database_selected": "База данных не выбрана",
|
||||
"sidebar.active_connection.no_database_selected": "Выберите БД для просмотра объектов",
|
||||
"sidebar.active_connection.no_host_selected": "Host не выбран",
|
||||
"sidebar.ai_prompt.explain.detail": "Особо опишите значения полей, первичные ключи/индексы, возможные связи, типовые сценарии запросов и риски.",
|
||||
"sidebar.ai_prompt.explain.intro": "Объясните структуру и бизнес-смысл таблицы {{table}}.",
|
||||
@@ -7433,6 +7446,9 @@
|
||||
"sidebar.message.clear_failed": "Ошибка очистки: {{error}}",
|
||||
"sidebar.message.clear_success": "Очистка завершена.",
|
||||
"sidebar.message.clearing_selected_tables": "Очищаются выбранные таблицы: {{count}}...",
|
||||
"sidebar.message.truncate_selected_tables_failed": "Не удалось выполнить TRUNCATE: {{error}}",
|
||||
"sidebar.message.truncate_selected_tables_success": "TRUNCATE выполнен для {{count}} таблиц.",
|
||||
"sidebar.message.truncating_selected_tables": "TRUNCATE {{count}} таблиц…",
|
||||
"sidebar.message.connection_config_not_found": "Конфигурация подключения не найдена.",
|
||||
"sidebar.message.connection_deleted": "Подключение удалено.",
|
||||
"sidebar.message.connection_failed": "Ошибка подключения: {{error}}",
|
||||
@@ -7597,6 +7613,8 @@
|
||||
"sidebar.modal.batch_tables.title": "Пакетные операции с объектами",
|
||||
"sidebar.modal.confirm_clear_selected_tables.content": "Очистить данные выбранных объектов в {{connection}} / {{database}}? Это действие нельзя отменить.",
|
||||
"sidebar.modal.confirm_clear_selected_tables.title": "Подтвердите очистку выбранных таблиц",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.content": "Выполнить TRUNCATE для {{count}} выбранных таблиц в {{connection}} / {{database}}? Обычно откат невозможен.",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.title": "Подтвердите TRUNCATE выбранных таблиц",
|
||||
"sidebar.modal.confirm_delete.title": "Подтвердите удаление",
|
||||
"sidebar.modal.confirm_delete_connection.content": "Удалить {{name}}?",
|
||||
"sidebar.modal.confirm_delete_database.content": "Удалить {{name}}? Это действие нельзя отменить.",
|
||||
|
||||
@@ -2537,6 +2537,9 @@
|
||||
"app.connection_package.action.start_export": "开始导出",
|
||||
"app.connection_package.action.start_import": "开始导入",
|
||||
"app.connection_package.dialog.export_title": "导出连接",
|
||||
"app.connection_package.dialog.export_connections_label": "选择要导出的连接",
|
||||
"app.connection_package.dialog.export_connections_placeholder": "选择一个或多个连接",
|
||||
"app.connection_package.dialog.export_connections_summary": "已选 {{selected}} / {{total}} 个连接",
|
||||
"app.connection_package.dialog.file_password_placeholder": "请输入文件保护密码(可选)",
|
||||
"app.connection_package.dialog.help.encrypted_passwords_recommend_file_password": "密码已加密保护。如需通过公网传输,建议设置文件保护密码。",
|
||||
"app.connection_package.dialog.help.exclude_passwords": "将仅导出连接配置,不包含密码。",
|
||||
@@ -2546,6 +2549,7 @@
|
||||
"app.connection_package.dialog.option.use_file_password": "设置文件保护密码",
|
||||
"app.connection_package.dialog.restore_password_placeholder": "请输入恢复包密码",
|
||||
"app.connection_package.error.export_capability_unavailable": "导出失败:当前后端未提供新版导出能力",
|
||||
"app.connection_package.error.no_selected_connections": "请至少选择一个连接再导出",
|
||||
"app.connection_package.error.file_password_required": "文件保护密码不能为空",
|
||||
"app.connection_package.error.import_capability_unavailable": "导入失败:当前后端未提供新版导入能力",
|
||||
"app.connection_package.error.import_no_connections": "导入失败:后端未返回连接列表",
|
||||
@@ -3957,6 +3961,14 @@
|
||||
"data_export.workbench.helper.available_objects": "当前库可选 {{available}} 个对象,已选 {{selected}} 个。",
|
||||
"data_export.workbench.helper.batch_database_output": "将在开始导出时先选择输出目录,再为每个数据库分别生成独立的 SQL 文件。",
|
||||
"data_export.workbench.helper.batch_databases_start": "批量库导出会先选择输出目录,再按库生成独立 SQL 文件,并在右侧展示整体库进度。",
|
||||
"data_export.workbench.intent.label": "操作类型",
|
||||
"data_export.workbench.intent.export": "导出",
|
||||
"data_export.workbench.intent.delete": "删除",
|
||||
"data_export.workbench.intent.batch_tables_delete_description": "清空或删除所选表,操作不可恢复。",
|
||||
"data_export.workbench.intent.batch_databases_delete_description": "删除所选数据库及其全部数据,操作不可恢复。",
|
||||
"data_export.workbench.helper.batch_tables_delete": "请先确认目标环境,再执行清空或删除。",
|
||||
"data_export.workbench.helper.batch_databases_delete": "请先确认目标环境,再执行删除。",
|
||||
"data_export.workbench.strategy.batch_delete": "批量删除",
|
||||
"data_export.workbench.helper.batch_tables_start": "批量对象导出会统一生成一个 SQL 文件,并在右侧展示整体对象进度与最近任务摘要。",
|
||||
"data_export.workbench.helper.single_export_start": "导出开始后会先选择目标文件,再在右侧主面板展示唯一进度条、导出耗时和输出路径。",
|
||||
"data_export.workbench.history.count": "{{count}} 条记录",
|
||||
@@ -7181,6 +7193,7 @@
|
||||
"sidebar.action.cancel": "取消",
|
||||
"sidebar.action.clear_selection": "取消全选",
|
||||
"sidebar.action.clear_tables": "清空表",
|
||||
"sidebar.action.truncate_tables": "截断表",
|
||||
"sidebar.action.close": "关闭",
|
||||
"sidebar.action.continue": "继续",
|
||||
"sidebar.action.delete": "删除",
|
||||
@@ -7201,7 +7214,7 @@
|
||||
"sidebar.action.unpin_table": "取消置顶",
|
||||
"sidebar.active_connection.actions": "连接操作",
|
||||
"sidebar.active_connection.current_host_database": "当前 Host 与数据库",
|
||||
"sidebar.active_connection.no_database_selected": "未选择数据库",
|
||||
"sidebar.active_connection.no_database_selected": "选择数据库以浏览对象",
|
||||
"sidebar.active_connection.no_host_selected": "未选择 Host",
|
||||
"sidebar.ai_prompt.explain.detail": "重点说明字段含义、主键/索引、潜在关联关系、典型查询场景和风险点。",
|
||||
"sidebar.ai_prompt.explain.intro": "请解释数据表 {{table}} 的结构和业务含义。",
|
||||
@@ -7433,6 +7446,9 @@
|
||||
"sidebar.message.clear_failed": "清空失败:{{error}}",
|
||||
"sidebar.message.clear_success": "清空成功。",
|
||||
"sidebar.message.clearing_selected_tables": "正在清空 {{count}} 个已选表...",
|
||||
"sidebar.message.truncate_selected_tables_failed": "截断表失败:{{error}}",
|
||||
"sidebar.message.truncate_selected_tables_success": "已截断 {{count}} 张表。",
|
||||
"sidebar.message.truncating_selected_tables": "正在截断 {{count}} 张表…",
|
||||
"sidebar.message.connection_config_not_found": "未找到连接配置。",
|
||||
"sidebar.message.connection_deleted": "连接已删除。",
|
||||
"sidebar.message.connection_failed": "连接失败:{{error}}",
|
||||
@@ -7597,6 +7613,8 @@
|
||||
"sidebar.modal.batch_tables.title": "批量操作表",
|
||||
"sidebar.modal.confirm_clear_selected_tables.content": "清空 {{connection}} / {{database}} 下已选对象的数据?此操作不可撤销。",
|
||||
"sidebar.modal.confirm_clear_selected_tables.title": "确认清空已选表",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.content": "截断 {{connection}} / {{database}} 下已选 {{count}} 张表的数据(TRUNCATE)?此操作通常不可回滚。",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.title": "确认截断已选表",
|
||||
"sidebar.modal.confirm_delete.title": "确认删除",
|
||||
"sidebar.modal.confirm_delete_connection.content": "删除连接 {{name}}?",
|
||||
"sidebar.modal.confirm_delete_database.content": "删除 {{name}}?此操作不可撤销。",
|
||||
|
||||
@@ -2537,6 +2537,9 @@
|
||||
"app.connection_package.action.start_export": "開始匯出",
|
||||
"app.connection_package.action.start_import": "開始匯入",
|
||||
"app.connection_package.dialog.export_title": "匯出連線",
|
||||
"app.connection_package.dialog.export_connections_label": "選擇要匯出的連線",
|
||||
"app.connection_package.dialog.export_connections_placeholder": "選擇一個或多個連線",
|
||||
"app.connection_package.dialog.export_connections_summary": "已選 {{selected}} / {{total}} 個連線",
|
||||
"app.connection_package.dialog.file_password_placeholder": "請輸入檔案保護密碼(選填)",
|
||||
"app.connection_package.dialog.help.encrypted_passwords_recommend_file_password": "密碼已加密保護。如需透過公網傳輸,建議設定檔案保護密碼。",
|
||||
"app.connection_package.dialog.help.exclude_passwords": "將只匯出連線設定,不包含密碼。",
|
||||
@@ -2546,6 +2549,7 @@
|
||||
"app.connection_package.dialog.option.use_file_password": "設定檔案保護密碼",
|
||||
"app.connection_package.dialog.restore_password_placeholder": "請輸入恢復包密碼",
|
||||
"app.connection_package.error.export_capability_unavailable": "匯出失敗:目前後端未提供新版匯出能力",
|
||||
"app.connection_package.error.no_selected_connections": "請至少選擇一個連線再匯出",
|
||||
"app.connection_package.error.file_password_required": "檔案保護密碼不能為空",
|
||||
"app.connection_package.error.import_capability_unavailable": "匯入失敗:目前後端未提供新版匯入能力",
|
||||
"app.connection_package.error.import_no_connections": "匯入失敗:後端未返回連線列表",
|
||||
@@ -3957,6 +3961,14 @@
|
||||
"data_export.workbench.helper.available_objects": "目前資料庫可選 {{available}} 個物件,已選 {{selected}} 個。",
|
||||
"data_export.workbench.helper.batch_database_output": "開始匯出時會先選擇輸出目錄,再為每個資料庫分別產生獨立的 SQL 檔案。",
|
||||
"data_export.workbench.helper.batch_databases_start": "批量資料庫匯出會先選擇輸出目錄,再按庫產生獨立 SQL 檔案,並在右側顯示整體資料庫進度。",
|
||||
"data_export.workbench.intent.label": "操作類型",
|
||||
"data_export.workbench.intent.export": "匯出",
|
||||
"data_export.workbench.intent.delete": "刪除",
|
||||
"data_export.workbench.intent.batch_tables_delete_description": "清空或刪除所選資料表,操作不可恢復。",
|
||||
"data_export.workbench.intent.batch_databases_delete_description": "刪除所選資料庫及其全部資料,操作不可恢復。",
|
||||
"data_export.workbench.helper.batch_tables_delete": "請先確認目標環境,再執行清空或刪除。",
|
||||
"data_export.workbench.helper.batch_databases_delete": "請先確認目標環境,再執行刪除。",
|
||||
"data_export.workbench.strategy.batch_delete": "批次刪除",
|
||||
"data_export.workbench.helper.batch_tables_start": "批量物件匯出會統一產生一個 SQL 檔案,並在右側顯示整體物件進度與最近任務摘要。",
|
||||
"data_export.workbench.helper.single_export_start": "匯出開始後會先選擇目標檔案,再在右側主面板顯示唯一進度條、匯出耗時與輸出路徑。",
|
||||
"data_export.workbench.history.count": "{{count}} 筆記錄",
|
||||
@@ -7181,6 +7193,7 @@
|
||||
"sidebar.action.cancel": "取消",
|
||||
"sidebar.action.clear_selection": "取消全選",
|
||||
"sidebar.action.clear_tables": "清除資料表",
|
||||
"sidebar.action.truncate_tables": "截斷資料表",
|
||||
"sidebar.action.close": "關閉",
|
||||
"sidebar.action.continue": "繼續",
|
||||
"sidebar.action.delete": "刪除",
|
||||
@@ -7201,7 +7214,7 @@
|
||||
"sidebar.action.unpin_table": "取消置頂",
|
||||
"sidebar.active_connection.actions": "連線操作",
|
||||
"sidebar.active_connection.current_host_database": "目前 Host 與資料庫",
|
||||
"sidebar.active_connection.no_database_selected": "未選擇資料庫",
|
||||
"sidebar.active_connection.no_database_selected": "選擇資料庫以瀏覽物件",
|
||||
"sidebar.active_connection.no_host_selected": "未選擇 Host",
|
||||
"sidebar.ai_prompt.explain.detail": "請重點說明欄位含義、主鍵/索引、潛在關聯、典型查詢場景與風險點。",
|
||||
"sidebar.ai_prompt.explain.intro": "請解釋資料表 {{table}} 的結構和業務含義。",
|
||||
@@ -7433,6 +7446,9 @@
|
||||
"sidebar.message.clear_failed": "清除失敗:{{error}}",
|
||||
"sidebar.message.clear_success": "清除成功。",
|
||||
"sidebar.message.clearing_selected_tables": "正在清除 {{count}} 個已選資料表...",
|
||||
"sidebar.message.truncate_selected_tables_failed": "截斷資料表失敗:{{error}}",
|
||||
"sidebar.message.truncate_selected_tables_success": "已截斷 {{count}} 張資料表。",
|
||||
"sidebar.message.truncating_selected_tables": "正在截斷 {{count}} 張資料表…",
|
||||
"sidebar.message.connection_config_not_found": "找不到連線設定。",
|
||||
"sidebar.message.connection_deleted": "連線已刪除。",
|
||||
"sidebar.message.connection_failed": "連線失敗:{{error}}",
|
||||
@@ -7597,6 +7613,8 @@
|
||||
"sidebar.modal.batch_tables.title": "批次操作資料表",
|
||||
"sidebar.modal.confirm_clear_selected_tables.content": "清除 {{connection}} / {{database}} 下已選物件的資料?此操作無法復原。",
|
||||
"sidebar.modal.confirm_clear_selected_tables.title": "確認清除已選資料表",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.content": "截斷 {{connection}} / {{database}} 下已選 {{count}} 張資料表的資料(TRUNCATE)?此操作通常無法復原。",
|
||||
"sidebar.modal.confirm_truncate_selected_tables.title": "確認截斷已選資料表",
|
||||
"sidebar.modal.confirm_delete.title": "確認刪除",
|
||||
"sidebar.modal.confirm_delete_connection.content": "刪除連線 {{name}}?",
|
||||
"sidebar.modal.confirm_delete_database.content": "刪除 {{name}}?此操作無法復原。",
|
||||
|
||||
Reference in New Issue
Block a user