mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-10 16:53:35 +08:00
🐛 fix(sidebar): 将表置顶星标改为只读状态指示
- 仅为已置顶表展示非交互实心星标 - 保留右键菜单中的置顶与取消置顶入口 - 补充侧边栏置顶指示器回归测试
This commit is contained in:
@@ -2292,17 +2292,45 @@ describe('Sidebar locate toolbar', () => {
|
||||
}).map((entry) => entry.tableName)).toEqual(['orders', 'users', 'audit']);
|
||||
});
|
||||
|
||||
it('keeps the v2 table pin action on sidebar table rows', () => {
|
||||
const source = readSidebarSource();
|
||||
it('renders a non-interactive pin indicator only for pinned v2 sidebar tables', () => {
|
||||
const source = readSourceFile('./sidebar/SidebarTreeTitle.tsx');
|
||||
const css = readV2ThemeCss();
|
||||
const baseOptions = {
|
||||
hoverTitle: 'orders',
|
||||
statusBadge: null,
|
||||
getV2TreeMetaText: () => '',
|
||||
sidebarTableMetadataFields: [],
|
||||
snapshotTreeSelectionBeforeDrag: vi.fn(),
|
||||
restoreTreeSelectionAfterDrag: vi.fn(),
|
||||
treeDragSelectSuppressUntilRef: { current: 0 },
|
||||
setIsTreeDragging: vi.fn(),
|
||||
};
|
||||
const renderTableTitle = (pinnedSidebarTable: boolean) => renderToStaticMarkup(renderSidebarV2TreeTitle({
|
||||
...baseOptions,
|
||||
node: {
|
||||
type: 'table',
|
||||
title: 'orders',
|
||||
key: 'conn-main-orders',
|
||||
dataRef: {
|
||||
id: 'conn',
|
||||
dbName: 'main',
|
||||
tableName: 'orders',
|
||||
pinnedSidebarTable,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
expect(source).toContain('data-v2-sidebar-table-pin-action="true"');
|
||||
expect(source).toContain('node?.dataRef?.pinnedSidebarTable ? <StarFilled /> : <StarOutlined />');
|
||||
expect(source).toContain('toggleSidebarTablePinned(node);');
|
||||
expect(source).toContain("message.success(shouldPin ? t('sidebar.message.table_pinned') : t('sidebar.message.table_unpinned'));");
|
||||
expect(css).toMatch(/\.gn-v2-table-pin-action \{[^}]*opacity: 0;/s);
|
||||
expect(css).toMatch(/\.gn-v2-table-pin-action\.is-pinned \{[^}]*color: #f59e0b;[^}]*opacity: 1;/s);
|
||||
expect(css).toMatch(/\.ant-tree-node-content-wrapper:hover \.gn-v2-table-pin-action,/s);
|
||||
const unpinnedMarkup = renderTableTitle(false);
|
||||
const pinnedMarkup = renderTableTitle(true);
|
||||
expect(unpinnedMarkup).not.toContain('data-v2-sidebar-table-pin-indicator');
|
||||
expect(pinnedMarkup).toContain('data-v2-sidebar-table-pin-indicator="true"');
|
||||
expect(pinnedMarkup).toContain(`aria-label="${t('sidebar.status.pinned')}"`);
|
||||
expect(pinnedMarkup).not.toContain('<button');
|
||||
expect(pinnedMarkup).not.toContain('aria-pressed');
|
||||
expect(source).not.toContain('toggleSidebarTablePinned');
|
||||
expect(source).not.toContain('StarOutlined');
|
||||
expect(css).toMatch(/\.gn-v2-table-pin-indicator \{[^}]*pointer-events: none;[^}]*cursor: default;[^}]*color: var\(--gn-warn\);/s);
|
||||
expect(css).not.toContain('.gn-v2-table-pin-action');
|
||||
});
|
||||
|
||||
it('splits v2 sidebar pinned tables into a dedicated table section', () => {
|
||||
@@ -2887,23 +2915,19 @@ describe('Sidebar locate toolbar', () => {
|
||||
expect(source).toContain("t('connection.sidebar.delete.failureFallback')");
|
||||
});
|
||||
|
||||
it('localizes the sidebar table pin action title and aria-label via i18n keys', () => {
|
||||
const source = readSidebarSource();
|
||||
const tablePinActionStart = source.indexOf("const tablePinAction = node.type === 'table' ? (");
|
||||
const tablePinActionEnd = source.indexOf('aria-pressed=', tablePinActionStart);
|
||||
const tablePinActionSource = source.slice(tablePinActionStart, tablePinActionEnd);
|
||||
const normalizedTablePinActionSource = tablePinActionSource.replace(/\s+/g, ' ');
|
||||
it('localizes the sidebar table pin indicator via the pinned status key', () => {
|
||||
const source = readSourceFile('./sidebar/SidebarTreeTitle.tsx');
|
||||
const tablePinIndicatorStart = source.indexOf("const tablePinIndicator = node.type === 'table'");
|
||||
const tablePinIndicatorEnd = source.indexOf('</span>', tablePinIndicatorStart);
|
||||
const tablePinIndicatorSource = source.slice(tablePinIndicatorStart, tablePinIndicatorEnd);
|
||||
const normalizedTablePinIndicatorSource = tablePinIndicatorSource.replace(/\s+/g, ' ');
|
||||
|
||||
expect(tablePinActionStart).toBeGreaterThanOrEqual(0);
|
||||
expect(tablePinActionEnd).toBeGreaterThan(tablePinActionStart);
|
||||
expect(normalizedTablePinActionSource).toContain(
|
||||
"title={node?.dataRef?.pinnedSidebarTable ? t('sidebar.action.unpin_table') : t('sidebar.action.pin_table')}",
|
||||
);
|
||||
expect(normalizedTablePinActionSource).toContain(
|
||||
"aria-label={node?.dataRef?.pinnedSidebarTable ? t('sidebar.action.unpin_table') : t('sidebar.action.pin_table')}",
|
||||
);
|
||||
expect(tablePinActionSource).not.toContain("'取消置顶表'");
|
||||
expect(tablePinActionSource).not.toContain("'置顶表'");
|
||||
expect(tablePinIndicatorStart).toBeGreaterThanOrEqual(0);
|
||||
expect(tablePinIndicatorEnd).toBeGreaterThan(tablePinIndicatorStart);
|
||||
expect(normalizedTablePinIndicatorSource).toContain("title={t('sidebar.status.pinned')}");
|
||||
expect(normalizedTablePinIndicatorSource).toContain("aria-label={t('sidebar.status.pinned')}");
|
||||
expect(tablePinIndicatorSource).not.toContain('sidebar.action.pin_table');
|
||||
expect(tablePinIndicatorSource).not.toContain('sidebar.action.unpin_table');
|
||||
});
|
||||
|
||||
it('localizes legacy sidebar connection and redis menu labels', () => {
|
||||
@@ -3324,7 +3348,6 @@ describe('Sidebar locate toolbar', () => {
|
||||
hoverTitle: 'users',
|
||||
statusBadge: null,
|
||||
getV2TreeMetaText: () => '',
|
||||
toggleSidebarTablePinned: vi.fn(),
|
||||
snapshotTreeSelectionBeforeDrag: vi.fn(),
|
||||
restoreTreeSelectionAfterDrag: vi.fn(),
|
||||
treeDragSelectSuppressUntilRef: { current: 0 },
|
||||
|
||||
@@ -2388,7 +2388,6 @@ const Sidebar: React.FC<{
|
||||
|
||||
const {
|
||||
getConnectionNodeForAction,
|
||||
toggleSidebarTablePinned,
|
||||
handleV2TableContextMenuAction,
|
||||
handleTableGroupSortAction,
|
||||
handleV2TableGroupContextMenuAction,
|
||||
@@ -2577,8 +2576,6 @@ const Sidebar: React.FC<{
|
||||
refreshV2TableContextMenuStatsRef.current = refreshV2TableContextMenuStats;
|
||||
const getV2TreeMetaTextRef = useRef(getV2TreeMetaText);
|
||||
getV2TreeMetaTextRef.current = getV2TreeMetaText;
|
||||
const toggleSidebarTablePinnedRef = useRef(toggleSidebarTablePinned);
|
||||
toggleSidebarTablePinnedRef.current = toggleSidebarTablePinned;
|
||||
|
||||
const renderV2TreeTitle = useCallback((node: any, hoverTitle: string, statusBadge: React.ReactNode) => renderSidebarV2TreeTitle({
|
||||
node,
|
||||
@@ -2586,7 +2583,6 @@ const Sidebar: React.FC<{
|
||||
statusBadge,
|
||||
getV2TreeMetaText: getV2TreeMetaTextRef.current,
|
||||
sidebarTableMetadataFields,
|
||||
toggleSidebarTablePinned: toggleSidebarTablePinnedRef.current,
|
||||
snapshotTreeSelectionBeforeDrag,
|
||||
restoreTreeSelectionAfterDrag,
|
||||
treeDragSelectSuppressUntilRef,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Tooltip } from 'antd';
|
||||
import { StarFilled, StarOutlined } from '@ant-design/icons';
|
||||
import { StarFilled } from '@ant-design/icons';
|
||||
import { t } from '../../i18n';
|
||||
import { SIDEBAR_SQL_EDITOR_DRAG_MIME, encodeSidebarSqlEditorDragPayload } from '../../utils/sidebarSqlDrag';
|
||||
import {
|
||||
@@ -25,7 +25,6 @@ type SidebarV2TreeTitleOptions = {
|
||||
statusBadge: React.ReactNode;
|
||||
getV2TreeMetaText: (node: any) => string;
|
||||
sidebarTableMetadataFields: SidebarTableMetadataField[];
|
||||
toggleSidebarTablePinned: (node: any) => void;
|
||||
snapshotTreeSelectionBeforeDrag: () => void;
|
||||
restoreTreeSelectionAfterDrag: () => void;
|
||||
treeDragSelectSuppressUntilRef: React.MutableRefObject<number>;
|
||||
@@ -116,7 +115,6 @@ export const renderSidebarV2TreeTitle = ({
|
||||
statusBadge,
|
||||
getV2TreeMetaText,
|
||||
sidebarTableMetadataFields,
|
||||
toggleSidebarTablePinned,
|
||||
snapshotTreeSelectionBeforeDrag,
|
||||
restoreTreeSelectionAfterDrag,
|
||||
treeDragSelectSuppressUntilRef,
|
||||
@@ -178,33 +176,16 @@ export const renderSidebarV2TreeTitle = ({
|
||||
node.type === 'redis-db' ? 'is-redis-db' : '',
|
||||
node.type === 'table' && node?.dataRef?.pinnedSidebarTable ? 'is-pinned-table' : '',
|
||||
].filter(Boolean).join(' ');
|
||||
const tablePinAction = node.type === 'table' ? (
|
||||
<button
|
||||
type="button"
|
||||
className={[
|
||||
'gn-v2-table-pin-action',
|
||||
node?.dataRef?.pinnedSidebarTable ? 'is-pinned' : '',
|
||||
].filter(Boolean).join(' ')}
|
||||
title={node?.dataRef?.pinnedSidebarTable ? t('sidebar.action.unpin_table') : t('sidebar.action.pin_table')}
|
||||
aria-label={node?.dataRef?.pinnedSidebarTable ? t('sidebar.action.unpin_table') : t('sidebar.action.pin_table')}
|
||||
aria-pressed={node?.dataRef?.pinnedSidebarTable ? true : false}
|
||||
data-v2-sidebar-table-pin-action="true"
|
||||
onMouseDown={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
toggleSidebarTablePinned(node);
|
||||
}}
|
||||
onDoubleClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
const tablePinIndicator = node.type === 'table' && node?.dataRef?.pinnedSidebarTable ? (
|
||||
<span
|
||||
className="gn-v2-table-pin-indicator"
|
||||
title={t('sidebar.status.pinned')}
|
||||
role="img"
|
||||
aria-label={t('sidebar.status.pinned')}
|
||||
data-v2-sidebar-table-pin-indicator="true"
|
||||
>
|
||||
{node?.dataRef?.pinnedSidebarTable ? <StarFilled /> : <StarOutlined />}
|
||||
</button>
|
||||
<StarFilled aria-hidden="true" />
|
||||
</span>
|
||||
) : null;
|
||||
if (node.type === 'connection') {
|
||||
return (
|
||||
@@ -287,7 +268,7 @@ export const renderSidebarV2TreeTitle = ({
|
||||
return (
|
||||
<>
|
||||
{wrappedTitleNode}
|
||||
{tablePinAction}
|
||||
{tablePinIndicator}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -558,7 +558,6 @@ export const useSidebarV2ActionHandlers = ({
|
||||
|
||||
return {
|
||||
getConnectionNodeForAction,
|
||||
toggleSidebarTablePinned,
|
||||
handleV2TableContextMenuAction,
|
||||
handleTableGroupSortAction,
|
||||
handleV2TableGroupContextMenuAction,
|
||||
|
||||
@@ -3117,7 +3117,7 @@ body[data-ui-version="v2"] .gn-v2-tree-count {
|
||||
opacity: 0.82;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-pin-action {
|
||||
body[data-ui-version="v2"] .gn-v2-table-pin-indicator {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
flex: 0 0 18px;
|
||||
@@ -3126,28 +3126,9 @@ body[data-ui-version="v2"] .gn-v2-table-pin-action {
|
||||
justify-content: center;
|
||||
margin-left: 2px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: var(--gn-fg-5);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.12s ease, color 0.12s ease, background 0.12s ease;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-pin-action:hover {
|
||||
background: var(--gn-bg-hover);
|
||||
color: var(--gn-fg-2);
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-table-pin-action.is-pinned {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
color: var(--gn-warn);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .ant-tree-node-content-wrapper:hover .gn-v2-table-pin-action,
|
||||
body[data-ui-version="v2"] .gn-v2-table-pin-action:focus-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
body[data-ui-version="v2"] .gn-v2-object-explorer .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected::before {
|
||||
|
||||
Reference in New Issue
Block a user