Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: refactor table widget UI code to use central context to reduce props drilling #39367

Open
wants to merge 13 commits into
base: release
Choose a base branch
from

Conversation

rahulbarwal
Copy link
Contributor

@rahulbarwal rahulbarwal commented Feb 19, 2025

Description

Refactor TableWidget for Improved Organization, Context Management & Rendering Efficiency

Overview

This PR restructures the TableWidget to enhance code organization, improve context management, and optimize rendering performance. Key improvements include extracting reusable components, introducing a shared TableContext, and simplifying table rendering logic.

Key Changes

✅ Improved Table Header Organization & Context Management
✅ Refactored Table & Virtualization Logic
✅ Simplified Header Components
✅ Enhanced Empty Row Handling
✅ Reorganized Core Components(Static table, virtual table)

Why These Changes?

•	Improves maintainability and readability by reducing prop drilling and redundant code.
•	Enhances performance through better state management and rendering optimizations.
•	Provides a scalable structure for future improvements in the TableWidget.

Fixes #39308
or
Fixes Issue URL

Warning

If no issue exists, please create an issue first, and check with the maintainers if the issue is valid.

Automation

/ok-to-test tags="@tag.Table"

🔍 Cypress test results

Tip

🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/13454159405
Commit: 6e90439
Cypress dashboard.
Tags: @tag.Table
Spec:


Fri, 21 Feb 2025 10:25:20 UTC

Communication

Should the DevRel and Marketing teams inform users about this change?

  • Yes
  • No

Summary by CodeRabbit

  • New Features

    • Introduced new components for static and virtual tables, enhancing rendering and interaction capabilities.
    • Added a new BannerNActions component for improved in-table controls and actions.
    • Implemented a context-based approach for managing table state and properties, improving modularity.
  • Bug Fixes

    • Enhanced error handling for context usage, ensuring appropriate warnings when components are used outside their intended context.
  • Refactor

    • Simplified props management across table components by leveraging hooks for state access.
    • Removed outdated components and interfaces, streamlining the codebase and improving maintainability.

…management

- Extracts table header logic into separate components
- Introduces TableProvider context to manage table state
- Moves types to separate file for better organization
- Adds default compact mode fallback
- Simplifies imports and reorganizes code structure
- Moves table state management to TableContext
- Adds memoization for computed values
- Extracts scroll container styles to context
- Simplifies StaticTable component props
- Adds SCROLL_BAR_OFFSET constant
- Removes redundant SimpleBar wrapper in Table component
- Adds SimpleBar directly in TableHeader for consistent scrolling
- Imports SimpleBar CSS for proper styling
…ering

- Refactors VirtualTable to use TableContext for props
- Simplifies Table component's conditional rendering
- Removes redundant prop passing in VirtualTable
- Adds type definition for StaticTable props
- Refactors HeaderCell to use TableContext for accessing shared props
- Removes redundant prop passing in HeaderCell
- Simplifies header cell rendering and interaction logic
- Improves component readability and reduces prop drilling
- Removes explicit prop passing in TableColumnHeader
- Uses TableContext to access shared table state
- Calculates header width using useMemo
- Simplifies header rendering and interaction logic
- Refactors renderEmptyRows to use TableContext for accessing table state
- Removes explicit prop passing in EmptyRows and EmptyRow components
- Simplifies empty row rendering logic
- Improves component readability and reduces prop drilling
Copy link
Contributor

coderabbitai bot commented Feb 19, 2025

Walkthrough

This pull request introduces several enhancements and refactors within the TableWidgetV2 code. A new constant has been added, and outdated components (such as the earlier StaticTable, TableBody, and VirtualTable variants) have been removed. New components have been implemented for both static and virtual table bodies, along with a dedicated TableContext to centralize state management via the useAppsmithTable hook. In addition, existing components including cells, headers, and utility functions have been refactored to simplify props management and streamline control flows.

Changes

Files Change Summary
.../Constants.ts Added new constant SCROLL_BAR_OFFSET = 2.
.../StaticTable.tsx, .../TableBody/index.tsx, .../VirtualTable.tsx, .../header/VirtualTableInnerElement.tsx Removed deprecated/unused table components.
.../StaticTable/StaticTableBody/index.tsx, .../StaticTable/index.tsx, .../TableContext.tsx, .../VirtualTable/VirtualTableBodyComponent.tsx, .../VirtualTable/VirtualTableInnerElement.tsx, .../VirtualTable/index.tsx, .../header/BannerNActions.tsx, .../types.ts Introduced new components and type definitions to support enhanced table state management, rendering, and UI behaviors.
.../Table.tsx, .../TableBodyCoreComponents/Row.tsx, .../TableBodyCoreComponents/VirtualList.tsx, .../VirtualTable/InifiniteScrollBody/index.tsx, .../cellComponents/EmptyCell.tsx, .../cellComponents/HeaderCell.tsx, .../header/TableColumnHeader.tsx, .../header/index.tsx, .../index.tsx Refactored existing components to utilize the useAppsmithTable hook, simplified control flows, removed redundant prop definitions, and updated type signatures.

Sequence Diagram(s)

sequenceDiagram
    participant TP as TableProvider (useAppsmithTable)
    participant VT as VirtualTable
    participant ISB as InfiniteScrollBody
    participant VTBC as VirtualTableBodyComponent
    participant FV as FixedVirtualList

    User->>TP: Initialize table state
    VT->>TP: Retrieve table properties via hook
    alt Infinite Scroll Enabled
        VT->>ISB: Render infinite scroll body
        ISB->>FV: Use fixed virtual list to render rows
    else 
        VT->>VTBC: Render virtual table body component
        VTBC->>FV: Use fixed virtual list to render rows
    end
Loading

Possibly related PRs

Suggested labels

Enhancement, Task

Suggested reviewers

  • ApekshaBhosale
  • jacquesikot

Poem

In a world of tables, sleek and new,
Constants added, old code bid adieu.
Context now guides each row and cell,
Virtual or static, they all excel.
With a streamlined flow and cheerful cheer,
CodeRabbit Inc leads the charge this year!
🎉🚀

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added Query & Widgets Pod All issues related to Query, JS, Eval, and Widgets Table Widget V2 Issues related to Table Widget V2 Widgets & Accelerators Pod Issues related to widgets & Accelerators Widgets Product This label groups issues related to widgets skip-changelog Adding this label to a PR prevents it from being listed in the changelog labels Feb 19, 2025
@rahulbarwal rahulbarwal self-assigned this Feb 21, 2025
@rahulbarwal rahulbarwal marked this pull request as ready for review February 21, 2025 09:44
@rahulbarwal rahulbarwal added the ok-to-test Required label for CI label Feb 21, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (16)
app/client/src/widgets/TableWidgetV2/component/header/index.tsx (3)

13-49: Refactor for Enhanced Readability

The direct extraction of many properties from useAppsmithTable() can become unwieldy. Consider grouping related properties into sub-objects to improve clarity and reduce repetitive prop spreads throughout the code.


59-77: Check Scrolling Behavior

Wrapping with SimpleBar is a neat approach to manage scrolling. Validate that scroll events and styles are correctly handled in all browsers. A fallback for environments without custom scrollbar support could further improve UX.


78-112: Consider Bundling Props

BannerNActions receives numerous props, which might be streamlined using an object or a context. This can help reduce repetitive passing of props and improve maintainability.

app/client/src/widgets/TableWidgetV2/component/header/BannerNActions.tsx (2)

7-16: Leverage TypeScript Union Types

Explicitly defining a union type for scenarios like isAddRowInProgress can create clearer, narrower prop contracts. Consider applying such patterns to better communicate the intended usage.


18-34: Centralize Conditional Logic

Conditional rendering is handled cleanly. If more states and banner types emerge in the future, moving conditional logic into a dedicated helper function or a switch-based approach may improve scalability.

app/client/src/widgets/TableWidgetV2/component/cellComponents/HeaderCell.tsx (2)

177-178: Offset logic for sticky column with multi-row selection.
Ensure props.column.totalLeft is always a valid numeric value to avoid misaligned headers.


204-205: Optional chaining to handle freeze.
If handleColumnFreeze will always be defined from the hook, consider removing the guard.

🧰 Tools
🪛 Biome (1.9.4)

[error] 204-208: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

app/client/src/widgets/TableWidgetV2/component/Table.tsx (1)

133-136: Confirm behavior for out-of-range pageNo.
If props.pageNo exceeds pageCount, resetting to 0 may be unexpected. Consider clamping to the last page instead if that's the desired user experience.

app/client/src/widgets/TableWidgetV2/component/StaticTable/index.tsx (1)

8-8: Use a type alias instead of an empty interface.
Empty interfaces are equivalent to {}. Updating with a type alias improves clarity:

-interface StaticTableProps {}
+type StaticTableProps = Record<string, never>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 7-8: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

app/client/src/widgets/TableWidgetV2/component/VirtualTable/InifiniteScrollBody/index.tsx (1)

36-36: Extract magic number into a named constant.

The buffer size of 5 should be defined as a named constant to improve code maintainability and clarity.

+const ITEM_COUNT_BUFFER = 5;

-          itemCount={itemCount + 5}
+          itemCount={itemCount + ITEM_COUNT_BUFFER}
app/client/src/widgets/TableWidgetV2/component/TableContext.tsx (2)

76-84: Update error message to match hook name.

The error message refers to "useTable" but the hook is named "useAppsmithTable".

-    throw new Error("useTable must be used within a TableProvider");
+    throw new Error("useAppsmithTable must be used within a TableProvider");

54-65: Optimize memoization dependencies.

The scrollContainerStyles memo dependency on state.compactMode is unnecessary since tableSizes is already derived from it.

  }, [
    state.isHeaderVisible,
    state.height,
-   state.compactMode,
    state.width
  ]);
app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/Row.tsx (2)

67-99: Extract cell rendering logic to a separate component.

The cell rendering logic is complex and could benefit from being extracted into a separate component for better maintainability and potential reuse.

+ const TableCell = React.memo(({ cell, cellIndex, columns, multiRowSelection }) => {
+   const cellProperties = cell.getCellProps();
+   cellProperties["style"] = {
+     ...cellProperties.style,
+     left:
+       columns[cellIndex].sticky === StickyType.LEFT && multiRowSelection
+         ? cell.column.totalLeft + MULTISELECT_CHECKBOX_WIDTH
+         : cellProperties?.style?.left,
+   };
+   return (
+     <div
+       {...cellProperties}
+       className={/* ... existing className logic ... */}
+       data-colindex={cellIndex}
+       data-rowindex={props.index}
+       key={cellIndex}
+     >
+       {cell.render("Cell")}
+     </div>
+   );
+ });

32-38: Memoize row style computation.

The row style computation could be memoized to prevent unnecessary recalculations.

+ const rowStyle = React.useMemo(
+   () => ({
+     display: "flex",
+     ...(props.style || {}),
+   }),
+   [props.style]
+ );
  const rowProps = {
    ...props.row.getRowProps(),
-   style: {
-     display: "flex",
-     ...(props.style || {}),
-   },
+   style: rowStyle,
  };
app/client/src/widgets/TableWidgetV2/component/header/TableColumnHeader.tsx (1)

113-113: Add error boundary for empty rows rendering

Consider wrapping the empty rows rendering with an error boundary to gracefully handle potential rendering failures.

app/client/src/widgets/TableWidgetV2/component/cellComponents/EmptyCell.tsx (1)

127-154: Optimize sticky column calculations

Consider memoizing the sticky column calculations to prevent unnecessary recalculations during re-renders.

+const calculateLeftDistance = React.useMemo(() => {
   const leftColWidths = tableColumns
     .slice(0, colIndex)
     .map((col) => col.width);

   if (multiRowSelection) {
     return colIndex === 0
       ? MULTISELECT_CHECKBOX_WIDTH
       : sum(leftColWidths) + MULTISELECT_CHECKBOX_WIDTH;
   }
   return colIndex === 0 ? 0 : sum(leftColWidths);
+}, [colIndex, multiRowSelection, tableColumns]);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98457f9 and 6e90439.

📒 Files selected for processing (22)
  • app/client/src/widgets/TableWidgetV2/component/Constants.ts (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/StaticTable.tsx (0 hunks)
  • app/client/src/widgets/TableWidgetV2/component/StaticTable/StaticTableBody/index.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/StaticTable/index.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/Table.tsx (7 hunks)
  • app/client/src/widgets/TableWidgetV2/component/TableBody/index.tsx (0 hunks)
  • app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/Row.tsx (3 hunks)
  • app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/VirtualList.tsx (2 hunks)
  • app/client/src/widgets/TableWidgetV2/component/TableContext.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/VirtualTable.tsx (0 hunks)
  • app/client/src/widgets/TableWidgetV2/component/VirtualTable/InifiniteScrollBody/index.tsx (2 hunks)
  • app/client/src/widgets/TableWidgetV2/component/VirtualTable/VirtualTableBodyComponent.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/VirtualTable/VirtualTableInnerElement.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/VirtualTable/index.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/cellComponents/EmptyCell.tsx (2 hunks)
  • app/client/src/widgets/TableWidgetV2/component/cellComponents/HeaderCell.tsx (9 hunks)
  • app/client/src/widgets/TableWidgetV2/component/header/BannerNActions.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/header/TableColumnHeader.tsx (3 hunks)
  • app/client/src/widgets/TableWidgetV2/component/header/VirtualTableInnerElement.tsx (0 hunks)
  • app/client/src/widgets/TableWidgetV2/component/header/index.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/index.tsx (2 hunks)
  • app/client/src/widgets/TableWidgetV2/component/types.ts (1 hunks)
💤 Files with no reviewable changes (4)
  • app/client/src/widgets/TableWidgetV2/component/VirtualTable.tsx
  • app/client/src/widgets/TableWidgetV2/component/StaticTable.tsx
  • app/client/src/widgets/TableWidgetV2/component/TableBody/index.tsx
  • app/client/src/widgets/TableWidgetV2/component/header/VirtualTableInnerElement.tsx
✅ Files skipped from review due to trivial changes (1)
  • app/client/src/widgets/TableWidgetV2/component/Constants.ts
🧰 Additional context used
🪛 Biome (1.9.4)
app/client/src/widgets/TableWidgetV2/component/VirtualTable/index.tsx

[error] 8-9: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

app/client/src/widgets/TableWidgetV2/component/StaticTable/index.tsx

[error] 7-8: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: perform-test / rts-build / build
  • GitHub Check: perform-test / client-build / client-build
  • GitHub Check: perform-test / server-build / server-unit-tests
🔇 Additional comments (30)
app/client/src/widgets/TableWidgetV2/component/header/index.tsx (1)

51-56: Validate Memo Dependencies

Using React.useMemo here is optimal. However, ensure that all sources influencing columns are properly included in its dependency array. If columns is derived from dynamic data, confirm that the memo remains valid on each relevant update.

app/client/src/widgets/TableWidgetV2/component/header/BannerNActions.tsx (1)

1-5: Verify Import Paths

The new BannerNActions component correctly imports from actions and banner. Ensure that any rename or path relocations get updated consistently across the codebase.

app/client/src/widgets/TableWidgetV2/component/cellComponents/HeaderCell.tsx (11)

159-169: Great use of the central hook for table props.
This centralizes state effectively and simplifies prop management.


172-172: No issue with spreading header props.
This is a standard approach and looks good.


182-182: Confirm isResizingColumn type.
Ensure isResizingColumn is a ref to avoid runtime errors calling .current.


193-193: Validate negative index usage for sorting.
Check if the sortTableColumn(-1, ...) call gracefully handles "no sort" scenarios.


199-201: Readability of editable checks.
This chain of conditions is clear and concise.


274-276: Horizontal alignment logic is clear.
No issues in referencing columnProperties.horizontalAlignment.


286-286: Menu visibility condition.
The condition for hiding the menu is straightforward and looks correct.


296-306: Sorting actions on menu items.
Both ascending and descending sort calls appear consistent.


317-321: Freeze column menu items.
Conditional disabling and check icons are used effectively.

Also applies to: 329-333


347-347: Portal class referencing the widget ID.
This namespacing strategy is good for preventing clashes.


365-366: Resizer props integration.
The resizing logic is properly delegated to getResizerProps().

app/client/src/widgets/TableWidgetV2/component/Table.tsx (9)

1-3: Imports look good.
No issues noticed. The new references to Blueprint libraries, React Table, and related modules are appropriately declared.

Also applies to: 7-7, 9-15, 17-17, 21-21, 23-24, 27-27, 29-30


120-132: Check for zero or negative page sizes.
Consider verifying if props.pageSize can be zero or negative, which could lead to unexpected logic or infinite pageCount scenarios.


214-224: Confirm partial row selection toggle logic.
toggleAllRowSelect(!Boolean(rowSelectionState), page) also clears partial selections (state = 2). Double-check that this aligns with the intended tri-state selection behavior.

🧰 Tools
🪛 Biome (1.9.4)

[error] 219-219: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)


224-239: Header visibility logic is clear.
Memoizing the condition for showing the header based on search, filters, and other flags is straightforward and readable.


255-269: Good approach to determining virtualization.
Leveraging isInfiniteScrollEnabled or checking for HTML columns is a clear strategy for deciding between static rendering and virtual scrolling.


282-296: Proper centralization with TableProvider.
Handing off table-specific props and state to a provider nicely simplifies the rest of the component.


326-326: Conditional table header is well-structured.
Showing the header only when necessary avoids clutter.


338-338: Swapping between VirtualTable and StaticTable is neat.
This ternary-based approach cleanly handles different rendering modes.


342-342: No additional remarks.

app/client/src/widgets/TableWidgetV2/component/StaticTable/StaticTableBody/index.tsx (1)

1-21: StaticTableBodyComponent is straightforward.
Mapping over rows to render a Row for each entry, and rendering EmptyRows if pageSize exceeds the number of rows, is efficient and clear.

app/client/src/widgets/TableWidgetV2/component/StaticTable/index.tsx (1)

1-7: StaticTable implementation looks good.
Forwarding the ref to SimpleBar and composing column headers with the table body is well-structured and easy to follow.

Also applies to: 9-21

app/client/src/widgets/TableWidgetV2/component/VirtualTable/VirtualTableBodyComponent.tsx (1)

1-30: LGTM! Clean implementation with proper separation of concerns.

The component follows React best practices by using forwardRef and centralizing state management through the useAppsmithTable hook.

app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/VirtualList.tsx (1)

37-37:

❓ Verification inconclusive

Breaking Change: outerRef is now required.

Making outerRef required could break existing implementations that don't provide this prop. Ensure all consumers of this component are updated.


🏁 Script executed:

#!/bin/bash
# Find all usages of BaseVirtualListProps or VirtualList components
ast-grep --pattern 'type $_ = BaseVirtualListProps'
ast-grep --pattern 'const $_ = <(FixedVirtualList|FixedInfiniteVirtualList)'

Length of output: 76644


Action Required: Verify Consumers for outerRef Update

The change making outerRef: Ref<SimpleBar> required in VirtualList (line 37) is a breaking change that could impact any consumer not supplying this prop. Our shell searches did not reveal any clear usages of BaseVirtualListProps or the FixedVirtualList/FixedInfiniteVirtualList components, so we couldn’t confirm whether current consumers cover this new requirement. Please ensure that:

  • Every instance of VirtualList / its wrapped components is updated to pass a valid outerRef.
  • Manual verification is done for all consumers (particularly within TableWidgetV2) to prevent runtime errors.
app/client/src/widgets/TableWidgetV2/component/header/TableColumnHeader.tsx (2)

16-29: Well-structured state management using context!

The refactoring successfully centralizes state management by using the useAppsmithTable hook, which reduces prop drilling and improves code organization.


30-36:

❓ Verification inconclusive

Verify handling of zero totalColumnsWidth

While the memoization is correct, verify that the component handles cases where totalColumnsWidth is 0 appropriately.


🏁 Script executed:

#!/bin/bash
# Search for tests or handling of zero totalColumnsWidth
rg -A 5 "totalColumnsWidth.*[=><].*0" 

Length of output: 39


Verify zero totalColumnsWidth edge case handling

The memoization implementation is correct; however, no explicit tests or handling for when totalColumnsWidth is 0 were found in the repository. Please verify manually that when totalColumnsWidth is 0, the component computes headerWidth as expected (i.e., it should remain 0 rather than unexpectedly applying the multi-selection width). If this is an important edge case, consider adding a dedicated unit test to cover this behavior.

app/client/src/widgets/TableWidgetV2/component/cellComponents/EmptyCell.tsx (1)

23-32: Clean function signature refactoring!

The function has been successfully simplified by leveraging the context hook while maintaining its core functionality.

app/client/src/widgets/TableWidgetV2/component/index.tsx (1)

238-238: Good default value handling!

Adding a default value for compactMode ensures consistent behavior when the prop is not provided.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
app/client/src/widgets/TableWidgetV2/component/StaticTable/__tests__/StaticTable.test.tsx (2)

8-21: Consider adding error cases to SimpleBar mock.

The SimpleBar mock is well-structured but only handles the happy path. Consider adding test cases for error scenarios.

 jest.mock("simplebar-react", () => {
   return {
     __esModule: true,
     default: React.forwardRef<
       HTMLDivElement,
       { children: React.ReactNode; style?: React.CSSProperties }
     >((props, ref) => (
+      // Add error handling for invalid props
+      !props ? null : 
       <div className="simplebar-content-wrapper" ref={ref} style={props.style}>
         {props.children}
       </div>
     )),
   };
 });

55-62: Add test for table rendering with empty data.

The test suite covers basic rendering but misses edge cases. Consider adding a test for rendering with empty data.

it("renders correctly with empty data", () => {
  (useAppsmithTable as jest.Mock).mockReturnValue({
    scrollContainerStyles: { height: 0, width: 0 },
  });
  const ref = React.createRef<SimpleBar>();
  render(<StaticTable ref={ref} />);
  expect(screen.getByTestId("mock-table-header")).toBeInTheDocument();
  expect(screen.getByTestId("mock-table-body")).toBeInTheDocument();
});
app/client/src/widgets/TableWidgetV2/component/TableContext.test.tsx (1)

287-308: Enhance memoization test with multiple re-renders.

The current memoization test only checks a single re-render. Consider testing multiple re-renders and prop changes.

it("maintains memoization across multiple re-renders", () => {
  const { rerender } = render(
    <TableProvider {...mockTableProviderProps}>
      <TestParent />
    </TableProvider>
  );

  const firstText = screen.getByText(/.+/).textContent;

  // Multiple re-renders with same props
  for (let i = 0; i < 5; i++) {
    rerender(
      <TableProvider {...mockTableProviderProps}>
        <TestParent />
      </TableProvider>
    );
    expect(screen.getByText(/.+/).textContent).toBe(firstText);
  }

  // Re-render with different props
  rerender(
    <TableProvider {...{ ...mockTableProviderProps, width: 900 }}>
      <TestParent />
    </TableProvider>
  );
  expect(screen.getByText(/.+/).textContent).not.toBe(firstText);
});
app/client/src/widgets/TableWidgetV2/component/StaticTable/__tests__/StaticTableBody.test.tsx (1)

122-136: Enhance performance test with timing measurements.

The performance test verifies rendering of large datasets but doesn't measure actual performance metrics.

it("[Performance] should render large datasets within performance budget", () => {
  const largeDataSet = Array.from({ length: 1000 }, (_, index) =>
    createMockRow(index, index)
  );

  (useAppsmithTable as jest.Mock).mockReturnValue({
    ...mockTableContextState,
    pageSize: 1000,
    subPage: largeDataSet,
  } as unknown as TableContextState);

  const start = performance.now();
  const { getAllByTestId } = render(<StaticTableBodyComponent />);
  const end = performance.now();

  expect(getAllByTestId("mocked-row")).toHaveLength(1000);
  expect(end - start).toBeLessThan(100); // 100ms budget
});
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e90439 and 6b200f7.

📒 Files selected for processing (3)
  • app/client/src/widgets/TableWidgetV2/component/StaticTable/__tests__/StaticTable.test.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/StaticTable/__tests__/StaticTableBody.test.tsx (1 hunks)
  • app/client/src/widgets/TableWidgetV2/component/TableContext.test.tsx (1 hunks)
🔇 Additional comments (1)
app/client/src/widgets/TableWidgetV2/component/StaticTable/__tests__/StaticTableBody.test.tsx (1)

30-37: LGTM! Well-structured test helper function.

The createMockRow helper function is well-implemented and reusable across tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ok-to-test Required label for CI Query & Widgets Pod All issues related to Query, JS, Eval, and Widgets skip-changelog Adding this label to a PR prevents it from being listed in the changelog Table Widget V2 Issues related to Table Widget V2 Widgets & Accelerators Pod Issues related to widgets & Accelerators Widgets Product This label groups issues related to widgets
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor table widget code base for clarity
1 participant