From e5fb03bbcdbef28d5202dacf57514a54bb0b3ed4 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Sun, 31 May 2026 13:33:46 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(data-grid):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=BD=93=E5=89=8D=E9=A1=B5=E6=9F=A5=E6=89=BE=E9=AB=98?= =?UTF-8?q?=E4=BA=AE=E6=AE=8B=E7=95=99=E5=B9=B6=E5=8E=8B=E7=BC=A9=E6=97=A7?= =?UTF-8?q?=E7=89=88=E7=BB=93=E6=9E=9C=E5=B7=A5=E5=85=B7=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 当前页查找改为即时响应,清空或按 Esc 后立即取消高亮 - 查找渲染版本元数据改为可透传,避免高亮状态残留 - 旧版结果工具栏调整为紧凑单行布局并移除重复分页信息 - JSON 和文本视图隐藏当前页查找入口 --- .../src/components/DataGrid.layout.test.tsx | 86 +++++++++++++++- frontend/src/components/DataGrid.tsx | 27 ++--- frontend/src/components/DataGridPageFind.tsx | 87 +++++++++------- .../src/components/DataGridPaginationBar.tsx | 5 +- .../components/DataGridSecondaryActions.tsx | 98 ++++++++++++++----- frontend/src/utils/dataGridFind.test.ts | 9 ++ frontend/src/utils/dataGridFind.ts | 2 +- 7 files changed, 228 insertions(+), 86 deletions(-) diff --git a/frontend/src/components/DataGrid.layout.test.tsx b/frontend/src/components/DataGrid.layout.test.tsx index 06d29f6..68680f7 100644 --- a/frontend/src/components/DataGrid.layout.test.tsx +++ b/frontend/src/components/DataGrid.layout.test.tsx @@ -10,6 +10,7 @@ import DataGrid, { resolveDefaultGridFilterOperator, resolveNextGridFilterOperatorForColumnChange, } from './DataGrid'; +import DataGridPaginationBar from './DataGridPaginationBar'; import { cloneShortcutOptions, DEFAULT_SHORTCUT_OPTIONS } from '../utils/shortcuts'; vi.mock('../store', () => ({ @@ -108,6 +109,85 @@ describe('DataGrid layout', () => { expect(markup).toContain('当前页查找...'); }); + it('hides current-page find in JSON and text record views', () => { + const source = readFileSync(new URL('./DataGrid.tsx', import.meta.url), 'utf8'); + + expect(source).toContain("const visiblePageFindContent = viewMode === 'table' ? pageFindContent : null;"); + expect(source).toContain('pageFindContent={visiblePageFindContent}'); + }); + + it('keeps legacy secondary actions aligned on a shared search-row baseline', () => { + const source = readFileSync(new URL('./DataGridSecondaryActions.tsx', import.meta.url), 'utf8'); + const columnQuickFindSource = readFileSync(new URL('./DataGridColumnQuickFind.tsx', import.meta.url), 'utf8'); + const pageFindSource = readFileSync(new URL('./DataGridPageFind.tsx', import.meta.url), 'utf8'); + const dataGridSource = readFileSync(new URL('./DataGrid.tsx', import.meta.url), 'utf8'); + const paginationSource = readFileSync(new URL('./DataGridPaginationBar.tsx', import.meta.url), 'utf8'); + + expect(source).toContain('data-grid-legacy-secondary-actions="true"'); + expect(source).toContain('data-grid-legacy-secondary-row="primary"'); + expect(source).toContain('data-grid-legacy-secondary-row="search"'); + expect(source).toContain('data-grid-legacy-result-view-switcher="true"'); + expect(source).toContain('data-grid-legacy-column-quick-find="true"'); + expect(source).toContain('data-grid-legacy-page-find="true"'); + expect(source).toContain('data-grid-legacy-pagination="true"'); + expect(source).toContain("justifyContent: 'flex-start'"); + expect(source).toContain('minHeight: 32'); + expect(source).toContain("style={{ display: 'flex', minWidth: 0, marginLeft: 'auto' }}"); + expect(source).toContain("flex: '0 1 240px'"); + expect(source).toContain("flex: '0 1 auto'"); + expect(columnQuickFindSource).not.toContain('定位字段列'); + expect(columnQuickFindSource).toContain("flexWrap: 'nowrap'"); + expect(columnQuickFindSource).toContain("width: 168"); + expect(columnQuickFindSource).toContain('height: 32'); + expect(columnQuickFindSource).toContain('const legacyDropdownOpen ='); + expect(columnQuickFindSource).toContain('open={isV2Ui ? undefined : legacyDropdownOpen}'); + expect(columnQuickFindSource).toContain('onSubmit: (value?: string) => void;'); + expect(columnQuickFindSource).toContain('onSubmit(nextValue);'); + expect(columnQuickFindSource).toContain('onPressEnter={() => onSubmit(value)}'); + expect(columnQuickFindSource).not.toContain('data-grid-column-quick-find-submit='); + expect(columnQuickFindSource).not.toContain(" '跳转'"); + expect(pageFindSource).toContain("gap: 8"); + expect(pageFindSource).toContain("flexWrap: 'nowrap'"); + expect(pageFindSource).toContain('height: 32'); + expect(pageFindSource).not.toContain("flexDirection: 'column'"); + expect(pageFindSource).not.toContain(" '上一个'"); + expect(pageFindSource).not.toContain(" '下一个'"); + expect(pageFindSource).toContain("paddingInline: 8"); + expect(pageFindSource).toContain("whiteSpace: 'nowrap'"); + expect(pageFindSource).toContain("onCancel: () => void;"); + expect(pageFindSource).toContain("if (event.key === 'Escape')"); + expect(pageFindSource).toContain('onCancel();'); + expect(pageFindSource).toContain("textAlign: 'left'"); + expect(dataGridSource).toContain("const normalizedPageFindText = useMemo(() => normalizeDataGridFindQuery(pageFindText), [pageFindText]);"); + expect(dataGridSource).not.toContain("const normalizedPageFindText = useMemo(() => normalizeDataGridFindQuery(deferredPageFindText), [deferredPageFindText]);"); + expect(paginationSource).toContain("padding: 0"); + expect(paginationSource).toContain("justifyContent: 'flex-start'"); + }); + + it('avoids duplicating legacy pagination page text beside the pager', () => { + const markup = renderToStaticMarkup( + {}} + onPageSizeChange={() => {}} + onV2PageStep={() => {}} + />, + ); + + expect(markup).toContain('class="ant-pagination'); + expect(markup).not.toContain('第 1 / 1 页'); + }); + it('renders the v2 DataGrid toolbar using the redesigned topbar hooks', () => { const markup = renderToStaticMarkup( { const css = readFileSync(new URL('../v2-theme.css', import.meta.url), 'utf8'); expect(source).toContain('virtualHorizontalElementsRef'); - expect(source).toContain('const handleSubmitColumnQuickFind = useCallback(() => {'); + expect(source).toContain('const handleSubmitColumnQuickFind = useCallback((submittedValue?: string) => {'); + expect(source).toContain('const effectiveQuery = String(submittedValue ?? columnQuickFindText);'); + expect(source).toContain('resolveDataGridColumnQuickFindTarget(displayColumnNames, query)'); + expect(source).toContain("onCancel={() => setPageFindText('')}"); + expect(source).toContain('enumerable: true'); expect(source).toContain('resolveDataGridColumnQuickFindScrollLeft({'); expect(source).toContain('const applied = applyVirtualHorizontalOffset(tableContainer, nextScrollLeft);'); expect(source).toContain('syncExternalScrollFromTargets();'); diff --git a/frontend/src/components/DataGrid.tsx b/frontend/src/components/DataGrid.tsx index 2da39c1..6bca574 100644 --- a/frontend/src/components/DataGrid.tsx +++ b/frontend/src/components/DataGrid.tsx @@ -36,7 +36,7 @@ import { resolveDataTableColumnWidth, resolveDataTableVerticalBorderColor, } from '../utils/dataGridDisplay'; -import { resolvePaginationPageText, resolvePaginationSummaryText, resolvePaginationTotalForControl } from '../utils/dataGridPagination'; +import { resolvePaginationSummaryText, resolvePaginationTotalForControl } from '../utils/dataGridPagination'; import { resolveGridSortInfoFromTableSorter } from '../utils/dataGridSort'; import { calculateExternalHorizontalScrollInnerWidth, @@ -393,7 +393,7 @@ export const attachDataGridVirtualEditRenderVersion = ( const nextRow = { ...(row as object) } as T; Object.defineProperty(nextRow, DATA_GRID_VIRTUAL_EDIT_RENDER_VERSION, { value: `${editingCell.rowKey}${CELL_KEY_SEP}${editingCell.dataIndex}`, - enumerable: false, + enumerable: true, }); return nextRow; }); @@ -410,7 +410,7 @@ export const attachDataGridDisplayRenderVersion = ( const nextRow = { ...(row as object) } as T; Object.defineProperty(nextRow, DATA_GRID_DISPLAY_RENDER_VERSION, { value: renderVersion, - enumerable: false, + enumerable: true, }); return nextRow; }); @@ -1568,9 +1568,9 @@ const DataGrid: React.FC = ({ const [pageFindText, setPageFindText] = useState(''); const [activePageFindMatchIndex, setActivePageFindMatchIndex] = useState(-1); const columnQuickFindHighlightTimerRef = useRef | null>(null); - const deferredPageFindText = useDeferredValue(pageFindText); const deferredColumnQuickFindText = useDeferredValue(columnQuickFindText); - const normalizedPageFindText = useMemo(() => normalizeDataGridFindQuery(deferredPageFindText), [deferredPageFindText]); + // 当前页查找需要即时反馈;否则清空输入框后高亮会继续停留一拍。 + const normalizedPageFindText = useMemo(() => normalizeDataGridFindQuery(pageFindText), [pageFindText]); const normalizedColumnQuickFindText = useMemo( () => normalizeDataGridFindQuery(deferredColumnQuickFindText), [deferredColumnQuickFindText], @@ -6531,8 +6531,8 @@ const DataGrid: React.FC = ({ const effectiveQuery = String(submittedValue ?? columnQuickFindText); const targetColumnName = resolveColumnQuickFindTarget(effectiveQuery); if (!targetColumnName) { - if (columnQuickFindText.trim()) { - void message.warning(`未找到字段列:${columnQuickFindText.trim()}`); + if (effectiveQuery.trim()) { + void message.warning(`未找到字段列:${effectiveQuery.trim()}`); } return; } @@ -6870,14 +6870,6 @@ const DataGrid: React.FC = ({ }); }, [pagination, prefersManualTotalCount, supportsApproximateTableCount]); - const paginationPageText = useMemo(() => { - if (!pagination) return ''; - return resolvePaginationPageText({ - pagination, - supportsApproximateTotalPages, - }); - }, [pagination, supportsApproximateTotalPages]); - const paginationControlTotal = useMemo(() => { if (!pagination) return 0; return resolvePaginationTotalForControl({ @@ -7024,10 +7016,12 @@ const DataGrid: React.FC = ({ occurrenceCount={pageFindSummary.occurrenceCount} matchedCellCount={pageFindSummary.matchedCellCount} onPageFindTextChange={setPageFindText} + onCancel={() => setPageFindText('')} onNavigatePrevious={() => handleNavigatePageFind('previous')} onNavigateNext={() => handleNavigatePageFind('next')} /> ); + const visiblePageFindContent = viewMode === 'table' ? pageFindContent : null; const columnQuickFindContent = isTableSurfaceActive ? ( = ({ pagination={pagination} paginationV2SummaryText={paginationV2SummaryText} paginationSummaryText={paginationSummaryText} - paginationPageText={paginationPageText} paginationControlTotal={paginationControlTotal} paginationTotalPages={paginationTotalPages} paginationPageSizeOptions={paginationPageSizeOptions} @@ -7513,7 +7506,7 @@ const DataGrid: React.FC = ({ resultViewSwitcher={resultViewSwitcher} columnInfoSettingContent={columnInfoSettingContent} columnQuickFindContent={columnQuickFindContent} - pageFindContent={pageFindContent} + pageFindContent={visiblePageFindContent} paginationContent={paginationContent} onViewModeChange={handleViewModeChange} dataPanelOpen={dataPanelOpen} diff --git a/frontend/src/components/DataGridPageFind.tsx b/frontend/src/components/DataGridPageFind.tsx index b7caca1..48bc011 100644 --- a/frontend/src/components/DataGridPageFind.tsx +++ b/frontend/src/components/DataGridPageFind.tsx @@ -14,6 +14,7 @@ export interface DataGridPageFindProps { occurrenceCount: number; matchedCellCount: number; onPageFindTextChange: (value: string) => void; + onCancel: () => void; onNavigatePrevious: () => void; onNavigateNext: () => void; } @@ -30,6 +31,7 @@ const DataGridPageFind: React.FC = ({ occurrenceCount, matchedCellCount, onPageFindTextChange, + onCancel, onNavigatePrevious, onNavigateNext, }) => ( @@ -37,44 +39,57 @@ const DataGridPageFind: React.FC = ({
-
- } - placeholder="当前页查找..." - value={pageFindText} - onChange={(event) => onPageFindTextChange(event.target.value)} - style={isV2Ui ? undefined : { width: 220 }} - /> - - -
+ } + placeholder="当前页查找..." + value={pageFindText} + onChange={(event) => onPageFindTextChange(event.target.value)} + onKeyDown={(event) => { + if (event.key === 'Escape') { + event.preventDefault(); + event.stopPropagation(); + onCancel(); + } + }} + style={isV2Ui ? undefined : { width: 168, height: 32 }} + /> + - - - - {columnQuickFindContent} - {canViewDdl && ( +
+
- )} - {pageFindContent} + + + + {canViewDdl && ( + + )} +
+
+ {resultViewSwitcher} +
+
+
+ {columnQuickFindContent ? ( +
+ {columnQuickFindContent} +
+ ) : null} +
+ {pageFindContent} +
+
+ {paginationContent} +
- {resultViewSwitcher}
- {paginationContent} ); }; diff --git a/frontend/src/utils/dataGridFind.test.ts b/frontend/src/utils/dataGridFind.test.ts index e7ecfa5..935837c 100644 --- a/frontend/src/utils/dataGridFind.test.ts +++ b/frontend/src/utils/dataGridFind.test.ts @@ -114,4 +114,13 @@ describe('dataGridFind', () => { expect(hasDataGridFindRenderVersionChanged(betaRows[0], alphaRows[0])).toBe(true); expect(hasDataGridFindRenderVersionChanged(rows[0], alphaRows[0])).toBe(true); }); + + it('keeps find render metadata on symbol keys while allowing wrapped rows to preserve it', () => { + const rows = [{ id: 1, name: 'Alpha' }]; + const alphaRows = attachDataGridFindRenderVersion(rows, 'alpha'); + + expect(Object.keys(alphaRows[0])).toEqual(['id', 'name']); + expect(Object.getOwnPropertySymbols(alphaRows[0]).length).toBeGreaterThan(0); + expect(hasDataGridFindRenderVersionChanged(alphaRows[0], rows[0])).toBe(true); + }); }); diff --git a/frontend/src/utils/dataGridFind.ts b/frontend/src/utils/dataGridFind.ts index 3d53a2f..f9a48fe 100644 --- a/frontend/src/utils/dataGridFind.ts +++ b/frontend/src/utils/dataGridFind.ts @@ -55,7 +55,7 @@ export const attachDataGridFindRenderVersion = (rows: T[], query: string): T[ const nextRow = { ...(row as object) } as T; Object.defineProperty(nextRow, DATA_GRID_FIND_RENDER_VERSION, { value: normalizedQuery, - enumerable: false, + enumerable: true, }); return nextRow; });