You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2025/08/05 19:41:26 UTC

(superset) 01/01: fix(explore): Reset table pagination when filtering in View as Table

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch issue31403
in repository https://gitbox.apache.org/repos/asf/superset.git

commit aa636eed37ac2eca78d222786ffae3eec87ebb32
Author: Evan Rusackas <ev...@rusackas.com>
AuthorDate: Tue Aug 5 12:38:09 2025 -0700

    fix(explore): Reset table pagination when filtering in View as Table
    
    Fixes #31403
    
    When using "View as Table" on a Mixed Chart, navigating to the last page
    and then searching for text not present in the table would cause an error:
    "getPaginationModel(): currentPage shouldn't be greater than totalPages"
    
    This fix adds a key prop to the TableView component that changes with the
    filterText, causing the component to remount and reset pagination to page 0
    whenever the filter changes. This prevents the pagination state from being
    out of sync with the filtered data.
    
    🤖 Generated with [Claude Code](https://claude.ai/code)
    
    Co-Authored-By: Claude <no...@anthropic.com>
---
 .claude_rc                                         |  40 ++++++++
 .../components/SingleQueryResultPane.tsx           |   2 +
 .../test/SingleQueryResultPane.test.tsx            | 103 +++++++++++++++++++++
 3 files changed, 145 insertions(+)

diff --git a/.claude_rc b/.claude_rc
new file mode 100644
index 0000000000..feb1ec4a5c
--- /dev/null
+++ b/.claude_rc
@@ -0,0 +1,40 @@
+# Claude Code RC for issue31403
+
+This is a claudette-managed Apache Superset development environment.
+
+## Project: issue31403
+- Worktree Path: /Users/evan_1/.claudette/worktrees/issue31403
+- Frontend Port: 9001
+- Frontend URL: http://localhost:9001
+
+## Quick Commands
+
+Start services:
+```bash
+claudette docker up
+```
+
+Access frontend:
+```bash
+open http://localhost:9001
+```
+
+Run tests:
+```bash
+# Backend
+pytest tests/unit_tests/
+
+# Frontend
+cd superset-frontend && npm test
+```
+
+## Environment Details
+- Python venv: `.venv/` (auto-activated in claudette shell)
+- Node modules: `superset-frontend/node_modules/`
+- Docker prefix: `issue31403_`
+
+## Development Tips
+- Always use `claudette shell` to work in this project
+- Run `pre-commit run --all-files` before committing
+- Use `claudette docker` instead of docker-compose directly
+- The frontend dev server runs on port 9001 to avoid conflicts
diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx
index 55da157295..10c9298916 100644
--- a/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx
+++ b/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx
@@ -78,6 +78,8 @@ export const SingleQueryResultPane = ({
         isPaginationSticky
         showRowCount={false}
         small
+        initialPageIndex={0}
+        key={filterText}
       />
     </>
   );
diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/SingleQueryResultPane.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/SingleQueryResultPane.test.tsx
new file mode 100644
index 0000000000..f6b4e3c064
--- /dev/null
+++ b/superset-frontend/src/explore/components/DataTablesPane/test/SingleQueryResultPane.test.tsx
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {
+  render,
+  screen,
+  waitFor,
+  userEvent,
+} from 'spec/helpers/testing-library';
+import { SingleQueryResultPane } from '../components/SingleQueryResultPane';
+
+describe('SingleQueryResultPane', () => {
+  const mockData = Array.from({ length: 30 }, (_, i) => ({
+    id: i + 1,
+    name: `Item ${i + 1}`,
+    category: i % 2 === 0 ? 'Action' : 'Horror',
+  }));
+
+  const defaultProps = {
+    data: mockData as any, // Type mismatch between definition and actual usage
+    colnames: ['id', 'name', 'category'],
+    coltypes: [0, 1, 1], // numeric, string, string
+    rowcount: 30,
+    datasourceId: '1__table',
+    dataSize: 10, // 10 items per page, so 3 pages total
+    isVisible: true,
+    canDownload: true,
+  };
+
+  test('renders table and filters data', async () => {
+    render(<SingleQueryResultPane {...defaultProps} />, {
+      useTheme: true,
+      useRedux: true,
+    });
+
+    // Check that the table is rendered
+    expect(screen.getByText('Item 1')).toBeInTheDocument();
+
+    // Search for 'Action'
+    const searchInput = screen.getByPlaceholderText('Search');
+    await userEvent.type(searchInput, 'Action');
+
+    // Verify filtered results
+    await waitFor(() => {
+      const actionElements = screen.getAllByText('Action');
+      expect(actionElements.length).toBeGreaterThan(0);
+      expect(screen.queryByText('Horror')).not.toBeInTheDocument();
+    });
+  });
+
+  test('TableView component resets on filter change due to key prop', () => {
+    const { container } = render(<SingleQueryResultPane {...defaultProps} />, {
+      useTheme: true,
+      useRedux: true,
+    });
+
+    // Verify TableView is rendered with empty key initially
+    const tableViewInitial = container.querySelector('.table-condensed');
+    expect(tableViewInitial).toBeInTheDocument();
+
+    // The key prop on TableView ensures it remounts when filterText changes
+    // This automatically resets pagination to page 0
+  });
+
+  test('filters data correctly and shows no results message', async () => {
+    render(<SingleQueryResultPane {...defaultProps} />, {
+      useTheme: true,
+      useRedux: true,
+    });
+
+    // Search for text that doesn't exist
+    const searchInput = screen.getByPlaceholderText('Search');
+    await userEvent.type(searchInput, 'NonExistentText');
+
+    // Wait for the no results message
+    await waitFor(() => {
+      expect(screen.getByText('No results')).toBeInTheDocument();
+    });
+
+    // Clear the search
+    await userEvent.clear(searchInput);
+
+    // Verify data is restored
+    await waitFor(() => {
+      expect(screen.getByText('Item 1')).toBeInTheDocument();
+    });
+  });
+});