fix: Add ability to set the number of rows(page size) for WDS table widget (#31941)

Fixes #30561 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Enhanced feature flag functionality for improved widget deployment
control.
- Added a configurable `pageSize` property to WDSTableWidget for
customizing displayed rows.

- **Refactor**
- Streamlined table scrolling by removing `SimpleBar` and adjusting
container styles.
- Improved table structure and styling for enhanced performance and user
experience.
  - Updated height calculation logic for better data display.

- **Bug Fixes**
- Resolved issue with inaccurate evaluation of feature flags to ensure
all users access latest features.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro-2.local>
Co-authored-by: Nikhil Nandagopal <nikhil.nandagopal@gmail.com>
This commit is contained in:
Pawan Kumar 2024-03-21 20:51:04 +05:30 committed by GitHub
parent 613547b43d
commit f60b65b919
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 219 additions and 324 deletions

View File

@ -5,7 +5,6 @@ import type {
Row as ReactTableRowType,
} from "react-table";
import type { ReactElementType } from "react-window";
import SimpleBar from "simplebar-react";
import "simplebar-react/dist/simplebar.min.css";
import type { ReactTableColumnProps, TableSizes } from "./Constants";
import { MULTISELECT_CHECKBOX_WIDTH, TABLE_SCROLLBAR_WIDTH } from "./Constants";
@ -37,14 +36,13 @@ type StaticTableProps = TableColumnHeaderProps & {
isAddRowInProgress: boolean;
headerProps?: TableColumnHeaderProps | Record<string, never>;
totalColumnsWidth?: number;
scrollContainerStyles: any;
useVirtual: boolean;
tableBodyRef?: React.MutableRefObject<HTMLDivElement | null>;
};
const StaticTable = (props: StaticTableProps, ref: React.Ref<SimpleBar>) => {
const StaticTable = (props: StaticTableProps) => {
return (
<SimpleBar ref={ref} style={props.scrollContainerStyles}>
<>
<TableColumnHeader
accentColor={props.accentColor}
borderRadius={props.borderRadius}
@ -77,7 +75,7 @@ const StaticTable = (props: StaticTableProps, ref: React.Ref<SimpleBar>) => {
borderRadius={props.borderRadius}
columns={props.columns}
getTableBodyProps={props.getTableBodyProps}
height={props.height}
height={props.pageSize * props.tableSizes.ROW_HEIGHT}
isAddRowInProgress={props.isAddRowInProgress}
multiRowSelection={!!props.multiRowSelection}
pageSize={props.pageSize}
@ -91,7 +89,7 @@ const StaticTable = (props: StaticTableProps, ref: React.Ref<SimpleBar>) => {
useVirtual={props.useVirtual}
width={props.width - TABLE_SCROLLBAR_WIDTH / 2}
/>
</SimpleBar>
</>
);
};

View File

@ -28,7 +28,6 @@ import {
import { Colors } from "constants/Colors";
import type { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { EditableCell, TableVariant } from "../constants";
import SimpleBar from "simplebar-react";
import "simplebar-react/dist/simplebar.min.css";
import { createGlobalStyle } from "styled-components";
import { Classes as PopOver2Classes } from "@blueprintjs/popover2";
@ -335,63 +334,56 @@ export function Table(props: TableProps) {
widgetId={props.widgetId}
/>
{isHeaderVisible && (
<SimpleBar
<Flex
gap="spacing-1"
padding="spacing-1"
style={{
maxHeight: tableSizes.TABLE_HEADER_HEIGHT,
borderBottom: "var(--border-width-1) solid var(--color-bd)",
}}
>
<Flex
gap="spacing-1"
minWidth="910px"
padding="spacing-1"
style={{
borderBottom: "var(--border-width-1) solid var(--color-bd)",
}}
>
<TableHeader
allowAddNewRow={props.allowAddNewRow}
applyFilter={props.applyFilter}
columns={tableHeadercolumns}
currentPageIndex={currentPageIndex}
delimiter={props.delimiter}
disableAddNewRow={!!props.editableCell?.column}
disabledAddNewRowSave={props.disabledAddNewRowSave}
filters={props.filters}
isAddRowInProgress={props.isAddRowInProgress}
isVisibleDownload={props.isVisibleDownload}
isVisibleFilters={props.isVisibleFilters}
isVisiblePagination={props.isVisiblePagination}
isVisibleSearch={props.isVisibleSearch}
nextPageClick={props.nextPageClick}
onAddNewRow={props.onAddNewRow}
onAddNewRowAction={props.onAddNewRowAction}
pageCount={pageCount}
pageNo={props.pageNo}
pageOptions={pageOptions}
prevPageClick={props.prevPageClick}
searchKey={props.searchKey}
searchTableData={props.searchTableData}
serverSidePaginationEnabled={props.serverSidePaginationEnabled}
tableColumns={columns}
tableData={data}
tableSizes={tableSizes}
totalRecordsCount={props.totalRecordsCount}
updatePageNo={props.updatePageNo}
widgetId={props.widgetId}
widgetName={props.widgetName}
width={props.width}
/>
</Flex>
</SimpleBar>
<TableHeader
allowAddNewRow={props.allowAddNewRow}
applyFilter={props.applyFilter}
columns={tableHeadercolumns}
currentPageIndex={currentPageIndex}
delimiter={props.delimiter}
disableAddNewRow={!!props.editableCell?.column}
disabledAddNewRowSave={props.disabledAddNewRowSave}
filters={props.filters}
isAddRowInProgress={props.isAddRowInProgress}
isVisibleDownload={props.isVisibleDownload}
isVisibleFilters={props.isVisibleFilters}
isVisiblePagination={props.isVisiblePagination}
isVisibleSearch={props.isVisibleSearch}
nextPageClick={props.nextPageClick}
onAddNewRow={props.onAddNewRow}
onAddNewRowAction={props.onAddNewRowAction}
pageCount={pageCount}
pageNo={props.pageNo}
pageOptions={pageOptions}
prevPageClick={props.prevPageClick}
searchKey={props.searchKey}
searchTableData={props.searchTableData}
serverSidePaginationEnabled={props.serverSidePaginationEnabled}
tableColumns={columns}
tableData={data}
tableSizes={tableSizes}
totalRecordsCount={props.totalRecordsCount}
updatePageNo={props.updatePageNo}
widgetId={props.widgetId}
widgetName={props.widgetName}
width={props.width}
/>
</Flex>
)}
<div
className={
className={`tableWrap ${
props.isLoading
? Classes.SKELETON
: shouldUseVirtual
? "tableWrap virtual"
: "tableWrap"
}
? " virtual"
: ""
}`}
>
<div {...getTableProps()} className="table column-freeze">
{!shouldUseVirtual && (
@ -417,7 +409,6 @@ export function Table(props: TableProps) {
prepareRow={prepareRow}
primaryColumnId={props.primaryColumnId}
rowSelectionState={rowSelectionState}
scrollContainerStyles={scrollContainerStyles}
selectTableRow={props.selectTableRow}
selectedRowIndex={props.selectedRowIndex}
selectedRowIndices={props.selectedRowIndices}

View File

@ -1,5 +1,4 @@
import type { Ref } from "react";
import React from "react";
import React, { useLayoutEffect } from "react";
import type {
Row as ReactTableRowType,
TableBodyPropGetter,
@ -7,11 +6,9 @@ import type {
} from "react-table";
import type { ListChildComponentProps, ReactElementType } from "react-window";
import { FixedSizeList, areEqual } from "react-window";
import { WIDGET_PADDING } from "constants/WidgetConstants";
import { EmptyRows, EmptyRow, Row } from "./Row";
import type { ReactTableColumnProps, TableSizes } from "../Constants";
import type { HeaderComponentProps } from "../Table";
import type SimpleBar from "simplebar-react";
export type BodyContextType = {
accentColor: string;
@ -81,36 +78,53 @@ interface BodyPropsType {
innerElementType?: ReactElementType;
}
const TableVirtualBodyComponent = React.forwardRef(
(props: BodyPropsType, ref: Ref<SimpleBar>) => {
return (
<div className="simplebar-content-wrapper">
<FixedSizeList
className="virtual-list simplebar-content"
height={
props.height -
props.tableSizes.TABLE_HEADER_HEIGHT -
2 * WIDGET_PADDING
}
innerElementType={props.innerElementType}
itemCount={Math.max(props.rows.length, props.pageSize)}
itemData={props.rows}
itemSize={
props.tableSizes.ROW_HEIGHT + props.tableSizes.ROW_VIRTUAL_OFFSET
}
outerRef={ref}
width={`calc(100% + ${2 * WIDGET_PADDING}px)`}
>
{rowRenderer}
</FixedSizeList>
</div>
);
},
);
const TableVirtualBodyComponent = (props: BodyPropsType) => {
const ref = React.useRef<HTMLDivElement>(null);
const [horizontalScrollbarHeight, setHorizontalScrollbarHeight] =
React.useState(0);
useLayoutEffect(() => {
if (ref.current) {
const horizontalScrollbar = ref.current;
if (horizontalScrollbar) {
setHorizontalScrollbarHeight(
horizontalScrollbar.offsetHeight - horizontalScrollbar.clientHeight,
);
}
}
}, [ref.current]);
return (
<FixedSizeList
data-virtual-list=""
height={
props.height +
props.tableSizes.COLUMN_HEADER_HEIGHT +
horizontalScrollbarHeight
}
innerElementType={props.innerElementType}
itemCount={Math.max(props.rows.length, props.pageSize)}
itemData={props.rows}
itemSize={props.tableSizes.ROW_HEIGHT}
outerRef={ref}
style={{
overflow: "auto",
scrollbarColor: "initial",
}}
width="100cqw"
>
{rowRenderer}
</FixedSizeList>
);
};
const TableBodyComponent = (props: BodyPropsType) => {
return (
<div {...props.getTableBodyProps()} className="tbody body">
<div
{...props.getTableBodyProps()}
className="tbody body"
style={{ height: props.height }}
>
{props.rows.map((row, index) => {
return <Row index={index} key={index} row={row} />;
})}
@ -121,86 +135,78 @@ const TableBodyComponent = (props: BodyPropsType) => {
);
};
export const TableBody = React.forwardRef(
(
props: BodyPropsType & BodyContextType & { useVirtual: boolean },
ref: Ref<SimpleBar>,
) => {
const {
accentColor,
borderRadius,
canFreezeColumn,
columns,
disableDrag,
editMode,
enableDrag,
handleAllRowSelectClick,
handleColumnFreeze,
handleReorderColumn,
headerGroups,
isAddRowInProgress,
isResizingColumn,
isSortable,
multiRowSelection,
prepareRow,
primaryColumnId,
rows,
rowSelectionState,
selectedRowIndex,
selectedRowIndices,
selectTableRow,
sortTableColumn,
subPage,
useVirtual,
widgetId,
width,
...restOfProps
} = props;
export const TableBody = (
props: BodyPropsType & BodyContextType & { useVirtual: boolean },
) => {
const {
accentColor,
borderRadius,
canFreezeColumn,
columns,
disableDrag,
editMode,
enableDrag,
handleAllRowSelectClick,
handleColumnFreeze,
handleReorderColumn,
headerGroups,
isAddRowInProgress,
isResizingColumn,
isSortable,
multiRowSelection,
prepareRow,
primaryColumnId,
rows,
rowSelectionState,
selectedRowIndex,
selectedRowIndices,
selectTableRow,
sortTableColumn,
subPage,
useVirtual,
widgetId,
width,
...restOfProps
} = props;
return (
<BodyContext.Provider
value={{
accentColor,
canFreezeColumn,
disableDrag,
editMode,
enableDrag,
handleAllRowSelectClick,
handleColumnFreeze,
handleReorderColumn,
headerGroups,
isResizingColumn,
isSortable,
rowSelectionState,
sortTableColumn,
subPage,
widgetId,
isAddRowInProgress,
borderRadius,
multiRowSelection,
prepareRow,
primaryColumnId,
selectedRowIndex,
selectedRowIndices,
selectTableRow,
columns,
width,
rows,
getTableBodyProps: props.getTableBodyProps,
totalColumnsWidth: props.totalColumnsWidth,
}}
>
{useVirtual ? (
<TableVirtualBodyComponent
ref={ref}
rows={rows}
width={width}
{...restOfProps}
/>
) : (
<TableBodyComponent rows={rows} {...restOfProps} />
)}
</BodyContext.Provider>
);
},
);
return (
<BodyContext.Provider
value={{
accentColor,
canFreezeColumn,
disableDrag,
editMode,
enableDrag,
handleAllRowSelectClick,
handleColumnFreeze,
handleReorderColumn,
headerGroups,
isResizingColumn,
isSortable,
rowSelectionState,
sortTableColumn,
subPage,
widgetId,
isAddRowInProgress,
borderRadius,
multiRowSelection,
prepareRow,
primaryColumnId,
selectedRowIndex,
selectedRowIndices,
selectTableRow,
columns,
width,
rows,
getTableBodyProps: props.getTableBodyProps,
totalColumnsWidth: props.totalColumnsWidth,
}}
>
{useVirtual ? (
<TableVirtualBodyComponent rows={rows} width={width} {...restOfProps} />
) : (
<TableBodyComponent rows={rows} {...restOfProps} />
)}
</BodyContext.Provider>
);
};

View File

@ -15,12 +15,10 @@ import {
TABLE_SIZES,
ImageSizes,
MULTISELECT_CHECKBOX_WIDTH,
TABLE_SCROLLBAR_HEIGHT,
TABLE_SCROLLBAR_WIDTH,
} from "./Constants";
import type { Color } from "constants/Colors";
import { Colors } from "constants/Colors";
import { hideScrollbar, invisible } from "constants/DefaultTheme";
import { invisible } from "constants/DefaultTheme";
import { lightenColor, darkenColor } from "widgets/WidgetUtils";
import { FontStyleTypes } from "constants/WidgetConstants";
import { Classes } from "@blueprintjs/core";
@ -63,34 +61,7 @@ export const TableWrapper = styled.div<{
overflow: hidden;
/* wriiten exclusively for safari */
position: sticky;
.simplebar-track {
opacity: 0.7;
&.simplebar-horizontal {
height: ${TABLE_SCROLLBAR_HEIGHT}px;
.simplebar-scrollbar {
height: 5px;
}
&.simplebar-hover {
height: 10px;
& .simplebar-scrollbar {
height: 8px;
}
}
}
&.simplebar-vertical {
direction: rtl;
top: ${(props) => props.tableSizes.TABLE_HEADER_HEIGHT - 10}px;
width: ${TABLE_SCROLLBAR_WIDTH}px;
&.simplebar-hover {
width: 10px;
& .simplebar-scrollbar {
width: 11px;
}
}
}
position: sticky;
}
.tableWrap {
height: 100%;
@ -98,8 +69,11 @@ export const TableWrapper = styled.div<{
position: relative;
width: 100%;
overflow: auto hidden;
scrollbar-color: initial;
container-type: inline-size;
&.virtual {
${hideScrollbar};
overflow: hidden;
}
}
.table {
@ -108,8 +82,7 @@ export const TableWrapper = styled.div<{
position: relative;
display: table;
width: 100%;
${hideScrollbar};
.tbody {
tab .tbody {
height: fit-content;
width: fit-content;
}
@ -204,10 +177,6 @@ export const TableWrapper = styled.div<{
}
}
.virtual-list {
${hideScrollbar};
}
.column-freeze {
.body {
position: relative;
@ -263,10 +232,6 @@ export const TableWrapper = styled.div<{
}
}
.tbody .tr:last-child .td {
border-bottom: none;
}
.draggable-header,
.hidden-header {
width: 100%;

View File

@ -4,8 +4,6 @@ import type {
TableBodyProps,
Row as ReactTableRowType,
} from "react-table";
import SimpleBar from "simplebar-react";
import "simplebar-react/dist/simplebar.min.css";
import type { ReactTableColumnProps, TableSizes } from "./Constants";
import type { TableColumnHeaderProps } from "./header/TableColumnHeader";
import VirtualTableInnerElement from "./header/VirtualTableInnerElement";
@ -37,47 +35,42 @@ type VirtualTableProps = TableColumnHeaderProps & {
useVirtual: boolean;
};
const VirtualTable = (props: VirtualTableProps, ref: React.Ref<SimpleBar>) => {
const VirtualTable = (props: VirtualTableProps) => {
return (
<SimpleBar ref={ref} style={props.scrollContainerStyles}>
{({ scrollableNodeRef }) => (
<TableBody
accentColor={props.accentColor}
borderRadius={props.borderRadius}
canFreezeColumn={props.canFreezeColumn}
columns={props.columns}
disableDrag={props.disableDrag}
editMode={props.editMode}
enableDrag={props.enableDrag}
getTableBodyProps={props.getTableBodyProps}
handleAllRowSelectClick={props.handleAllRowSelectClick}
handleColumnFreeze={props.handleColumnFreeze}
handleReorderColumn={props.handleReorderColumn}
headerGroups={props.headerGroups}
height={props.height}
innerElementType={VirtualTableInnerElement}
isAddRowInProgress={props.isAddRowInProgress}
isResizingColumn={props.isResizingColumn}
isSortable={props.isSortable}
multiRowSelection={!!props.multiRowSelection}
pageSize={props.pageSize}
prepareRow={props.prepareRow}
primaryColumnId={props.primaryColumnId}
ref={scrollableNodeRef}
rowSelectionState={props.rowSelectionState}
rows={props.subPage}
selectTableRow={props.selectTableRow}
selectedRowIndex={props.selectedRowIndex}
selectedRowIndices={props.selectedRowIndices}
sortTableColumn={props.sortTableColumn}
tableSizes={props.tableSizes}
totalColumnsWidth={props?.totalColumnsWidth}
useVirtual={props.useVirtual}
widgetId={props.widgetId}
width={props.width}
/>
)}
</SimpleBar>
<TableBody
accentColor={props.accentColor}
borderRadius={props.borderRadius}
canFreezeColumn={props.canFreezeColumn}
columns={props.columns}
disableDrag={props.disableDrag}
editMode={props.editMode}
enableDrag={props.enableDrag}
getTableBodyProps={props.getTableBodyProps}
handleAllRowSelectClick={props.handleAllRowSelectClick}
handleColumnFreeze={props.handleColumnFreeze}
handleReorderColumn={props.handleReorderColumn}
headerGroups={props.headerGroups}
height={props.pageSize * props.tableSizes.ROW_HEIGHT}
innerElementType={VirtualTableInnerElement}
isAddRowInProgress={props.isAddRowInProgress}
isResizingColumn={props.isResizingColumn}
isSortable={props.isSortable}
multiRowSelection={!!props.multiRowSelection}
pageSize={props.pageSize}
prepareRow={props.prepareRow}
primaryColumnId={props.primaryColumnId}
rowSelectionState={props.rowSelectionState}
rows={props.subPage}
selectTableRow={props.selectTableRow}
selectedRowIndex={props.selectedRowIndex}
selectedRowIndices={props.selectedRowIndices}
sortTableColumn={props.sortTableColumn}
tableSizes={props.tableSizes}
totalColumnsWidth={props?.totalColumnsWidth}
useVirtual={props.useVirtual}
widgetId={props.widgetId}
width={props.width}
/>
);
};

View File

@ -35,4 +35,5 @@ export const defaultsConfig = {
delimiter: ",",
version: 2,
inlineEditingSaveOption: InlineEditingSaveOptions.ROW_LEVEL,
pageSize: 8,
} as unknown as WidgetDefaultProps;

View File

@ -146,6 +146,17 @@ export const contentConfig = [
{
sectionName: "Pagination",
children: [
{
propertyName: "pageSize",
helpText: "Number of rows to be displayed at a time",
label: "Page size",
controlType: "NUMERIC_INPUT",
isJSConvertible: true,
defaultValue: 10,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.NUMBER },
},
{
propertyName: "isVisiblePagination",
helpText: "Toggle visibility of the pagination",

View File

@ -2,35 +2,6 @@ import { ValidationTypes } from "constants/WidgetValidation";
import { updateColumnStyles } from "../../widget/propertyUtils";
export const styleConfig = [
{
sectionName: "General",
children: [
{
propertyName: "compactMode",
helpText: "Selects row height",
label: "Default row height",
controlType: "ICON_TABS",
fullWidth: true,
defaultValue: "DEFAULT",
isBindProperty: true,
isTriggerProperty: false,
options: [
{
label: "Short",
value: "SHORT",
},
{
label: "Default",
value: "DEFAULT",
},
{
label: "Tall",
value: "TALL",
},
],
},
],
},
{
sectionName: "Text formatting",
children: [

View File

@ -150,46 +150,6 @@ export default {
return indices.map((index) => _.omit(rows[index], keysToBeOmitted));
},
//
getPageSize: (props, moment, _) => {
const TABLE_SIZES = {
DEFAULT: {
COLUMN_HEADER_HEIGHT: 32,
TABLE_HEADER_HEIGHT: 38,
ROW_HEIGHT: 40,
ROW_FONT_SIZE: 14,
VERTICAL_PADDING: 6,
EDIT_ICON_TOP: 10,
},
SHORT: {
COLUMN_HEADER_HEIGHT: 32,
TABLE_HEADER_HEIGHT: 38,
ROW_HEIGHT: 30,
ROW_FONT_SIZE: 12,
VERTICAL_PADDING: 0,
EDIT_ICON_TOP: 5,
},
TALL: {
COLUMN_HEADER_HEIGHT: 32,
TABLE_HEADER_HEIGHT: 38,
ROW_HEIGHT: 60,
ROW_FONT_SIZE: 18,
VERTICAL_PADDING: 16,
EDIT_ICON_TOP: 21,
},
};
const compactMode = props.compactMode || "DEFAULT";
const componentHeight = 300;
const tableSizes = TABLE_SIZES[compactMode];
let pageSize =
(componentHeight -
tableSizes.TABLE_HEADER_HEIGHT -
tableSizes.COLUMN_HEADER_HEIGHT) /
tableSizes.ROW_HEIGHT;
return pageSize % 1 > 0.3 ? Math.ceil(pageSize) : Math.floor(pageSize);
},
//
getProcessedTableData: (props, moment, _) => {
let data;

View File

@ -221,7 +221,6 @@ export class WDSTableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
selectedRow: `{{(()=>{${derivedProperties.getSelectedRow}})()}}`,
triggeredRow: `{{(()=>{${derivedProperties.getTriggeredRow}})()}}`,
selectedRows: `{{(()=>{${derivedProperties.getSelectedRows}})()}}`,
pageSize: `{{(()=>{${derivedProperties.getPageSize}})()}}`,
triggerRowSelection: "{{!!this.onRowSelected}}",
processedTableData: `{{(()=>{${derivedProperties.getProcessedTableData}})()}}`,
orderedTableColumns: `{{(()=>{${derivedProperties.getOrderedTableColumns}})()}}`,