diff --git a/app/client/src/widgets/TableWidgetV2/component/cellComponents/HeaderCell.tsx b/app/client/src/widgets/TableWidgetV2/component/cellComponents/HeaderCell.tsx index e302dce660b6..9bc73b67ea40 100644 --- a/app/client/src/widgets/TableWidgetV2/component/cellComponents/HeaderCell.tsx +++ b/app/client/src/widgets/TableWidgetV2/component/cellComponents/HeaderCell.tsx @@ -160,6 +160,7 @@ const HeaderCellComponent = (props: HeaderProps) => { canFreezeColumn, editMode, handleColumnFreeze, + isInfiniteScrollEnabled, isResizingColumn, isSortable, multiRowSelection, @@ -193,7 +194,8 @@ const HeaderCellComponent = (props: HeaderProps) => { sortTableColumn(columnIndex, sortOrder); }; - const disableSort = editMode === false && isSortable === false; + const disableSort = + isInfiniteScrollEnabled || (editMode === false && isSortable === false); const isColumnEditable = props.column.columnProperties.isCellEditable && diff --git a/app/client/src/widgets/TableWidgetV2/widget/__tests__/propertyUtils.test.ts b/app/client/src/widgets/TableWidgetV2/widget/__tests__/propertyUtils.test.ts index fcb13bea2612..2d3eb8985b8f 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/__tests__/propertyUtils.test.ts +++ b/app/client/src/widgets/TableWidgetV2/widget/__tests__/propertyUtils.test.ts @@ -1,3 +1,4 @@ +import { updateAllowAddNewRowOnInfiniteScrollChange } from "../propertyUtils"; import { totalRecordsCountValidation, uniqueColumnNameValidation, @@ -9,6 +10,8 @@ import { updateCustomColumnAliasOnLabelChange, selectColumnOptionsValidation, allowedFirstDayOfWeekRange, + updateCellEditabilityOnInfiniteScrollChange, + updateSearchSortFilterOnInfiniteScrollChange, } from "../propertyUtils"; import _ from "lodash"; import type { ColumnTypes, TableWidgetProps } from "../../constants"; @@ -1049,3 +1052,195 @@ describe("allowedFirstDayOfWeekRange", () => { }); }); }); + +describe("Infinite Scroll Update Hooks - ", () => { + it("updateAllowAddNewRowOnInfiniteScrollChange - should disable/enable add new row when infinite scroll is toggled", () => { + const props = {} as TableWidgetProps; + + // When infinite scroll is enabled + expect( + updateAllowAddNewRowOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + true, + ), + ).toEqual([ + { + propertyPath: "allowAddNewRow", + propertyValue: false, + }, + ]); + + // When infinite scroll is disabled + expect( + updateAllowAddNewRowOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + false, + ), + ).toEqual([ + { + propertyPath: "allowAddNewRow", + propertyValue: true, + }, + ]); + + // When some other value is passed + expect( + updateAllowAddNewRowOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + "some-other-value", + ), + ).toBeUndefined(); + }); + + it("updateSearchSortFilterOnInfiniteScrollChange - should disable/enable search, filter, sort when infinite scroll is toggled", () => { + const props = {} as TableWidgetProps; + + // When infinite scroll is enabled + expect( + updateSearchSortFilterOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + true, + ), + ).toEqual([ + { + propertyPath: "isVisibleSearch", + propertyValue: false, + }, + { + propertyPath: "isVisibleFilters", + propertyValue: false, + }, + { + propertyPath: "isSortable", + propertyValue: false, + }, + ]); + + // When infinite scroll is disabled + expect( + updateSearchSortFilterOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + false, + ), + ).toEqual([ + { + propertyPath: "isVisibleFilters", + propertyValue: true, + }, + { + propertyPath: "isVisibleSearch", + propertyValue: true, + }, + { + propertyPath: "isSortable", + propertyValue: true, + }, + ]); + + // When some other value is passed + expect( + updateSearchSortFilterOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + "some-other-value", + ), + ).toBeUndefined(); + }); + + it("updateCellEditabilityOnInfiniteScrollChange - should disable cell editability when infinite scroll is enabled", () => { + // Setup mock primary columns + const props = { + primaryColumns: { + column1: { + id: "column1", + alias: "column1", + isEditable: true, + isCellEditable: true, + }, + column2: { + id: "column2", + alias: "column2", + isEditable: true, + isCellEditable: true, + }, + }, + } as unknown as TableWidgetProps; + + // When infinite scroll is enabled + expect( + updateCellEditabilityOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + true, + ), + ).toEqual([ + { + propertyPath: "primaryColumns.column1.isCellEditable", + propertyValue: false, + }, + { + propertyPath: "primaryColumns.column1.isEditable", + propertyValue: false, + }, + { + propertyPath: "primaryColumns.column2.isCellEditable", + propertyValue: false, + }, + { + propertyPath: "primaryColumns.column2.isEditable", + propertyValue: false, + }, + ]); + + // When infinite scroll is disabled + expect( + updateCellEditabilityOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + false, + ), + ).toEqual([ + { + propertyPath: "primaryColumns.column1.isCellEditable", + propertyValue: true, + }, + { + propertyPath: "primaryColumns.column1.isEditable", + propertyValue: true, + }, + { + propertyPath: "primaryColumns.column2.isCellEditable", + propertyValue: true, + }, + { + propertyPath: "primaryColumns.column2.isEditable", + propertyValue: true, + }, + ]); + + // Test with no primary columns + const propsWithoutColumns = {} as TableWidgetProps; + + expect( + updateCellEditabilityOnInfiniteScrollChange( + propsWithoutColumns, + "infiniteScrollEnabled", + true, + ), + ).toBeUndefined(); + + // When some other value is passed + expect( + updateCellEditabilityOnInfiniteScrollChange( + props, + "infiniteScrollEnabled", + "some-other-value", + ), + ).toBeUndefined(); + }); +}); diff --git a/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/__tests__/contentConfig.test.ts b/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/__tests__/contentConfig.test.ts new file mode 100644 index 000000000000..bcd33eaa7c58 --- /dev/null +++ b/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/__tests__/contentConfig.test.ts @@ -0,0 +1,114 @@ +import contentConfig from "../contentConfig"; +import type { TableWidgetProps } from "../../../constants"; +import type { PropertyPaneSectionConfig } from "constants/PropertyControlConstants"; + +describe("TableWidgetV2 contentConfig tests", () => { + it("should disable relevant sections when infinite scroll is enabled", () => { + const sectionsToCheck = ["Search & filters", "Sorting", "Adding a row"]; + + const disabledHelpText = + "This feature is disabled because infinite scroll is enabled"; + + sectionsToCheck.forEach((sectionName) => { + const section = contentConfig.find( + (section) => + (section as PropertyPaneSectionConfig).sectionName === sectionName, + ) as PropertyPaneSectionConfig & { dependencies: string[] }; + + expect(section).toBeDefined(); + + if (section) { + expect(typeof section.shouldDisableSection).toBe("function"); + expect(section.disabledHelpText).toBe(disabledHelpText); + expect(section.dependencies).toContain("infiniteScrollEnabled"); + + const enabledProps = { + infiniteScrollEnabled: true, + } as TableWidgetProps; + const disabledProps = { + infiniteScrollEnabled: false, + } as TableWidgetProps; + + expect(section.shouldDisableSection!(enabledProps, "")).toBe(true); + expect(section.shouldDisableSection!(disabledProps, "")).toBe(false); + } + }); + + const paginationSection = contentConfig.find( + (section) => + (section as PropertyPaneSectionConfig).sectionName === "Pagination", + ) as PropertyPaneSectionConfig; + + expect(paginationSection).toBeDefined(); + + if (paginationSection && paginationSection.children) { + const serverSidePagination = paginationSection.children.find( + (child) => + (child as PropertyPaneSectionConfig & { propertyName: string }) + .propertyName === "serverSidePaginationEnabled", + ) as PropertyPaneSectionConfig & { + propertyName: string; + shouldDisableSection: ( + props: TableWidgetProps, + propertyPath: string, + ) => boolean; + disabledHelpText: string; + dependencies: string[]; + }; + + expect(serverSidePagination).toBeDefined(); + + if (serverSidePagination) { + expect(typeof serverSidePagination.shouldDisableSection).toBe( + "function", + ); + expect(serverSidePagination.disabledHelpText).toBe(disabledHelpText); + expect(serverSidePagination.dependencies).toContain( + "infiniteScrollEnabled", + ); + + const enabledProps = { + infiniteScrollEnabled: true, + } as TableWidgetProps; + const disabledProps = { + infiniteScrollEnabled: false, + } as TableWidgetProps; + + expect( + serverSidePagination.shouldDisableSection(enabledProps, ""), + ).toBe(true); + expect( + serverSidePagination.shouldDisableSection(disabledProps, ""), + ).toBe(false); + } + } + }); + + it("should have proper update hooks for infiniteScrollEnabled property", () => { + const paginationSection = contentConfig.find( + (section) => + (section as PropertyPaneSectionConfig).sectionName === "Pagination", + ) as PropertyPaneSectionConfig; + + expect(paginationSection).toBeDefined(); + + if (paginationSection && paginationSection.children) { + const infiniteScrollProperty = paginationSection.children.find( + (child) => + (child as PropertyPaneSectionConfig & { propertyName: string }) + .propertyName === "infiniteScrollEnabled", + ) as PropertyPaneSectionConfig & { + propertyName: string; + updateHook: unknown; + dependencies: string[]; + }; + + expect(infiniteScrollProperty).toBeDefined(); + + if (infiniteScrollProperty) { + expect(infiniteScrollProperty.updateHook).toBeDefined(); + expect(infiniteScrollProperty.dependencies).toContain("primaryColumns"); + } + } + }); +}); diff --git a/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts b/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts index 6bbb90486aba..bf12ab66c6d8 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts +++ b/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts @@ -1,30 +1,38 @@ +import type { PropertyPaneConfig } from "constants/PropertyControlConstants"; +import { ValidationTypes } from "constants/WidgetValidation"; import { createMessage, TABLE_WIDGET_TOTAL_RECORD_TOOLTIP, } from "ee/constants/messages"; -import type { PropertyPaneConfig } from "constants/PropertyControlConstants"; -import { ValidationTypes } from "constants/WidgetValidation"; import { EvaluationSubstitutionType } from "ee/entities/DataTree/types"; import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType"; import type { TableWidgetProps } from "widgets/TableWidgetV2/constants"; +import { + INFINITE_SCROLL_ENABLED, + InlineEditingSaveOptions, +} from "widgets/TableWidgetV2/constants"; +import { composePropertyUpdateHook } from "widgets/WidgetUtils"; import { ALLOW_TABLE_WIDGET_SERVER_SIDE_FILTERING, CUSTOM_SORT_FUNCTION_ENABLED, } from "../../constants"; -import { InlineEditingSaveOptions } from "widgets/TableWidgetV2/constants"; -import { composePropertyUpdateHook } from "widgets/WidgetUtils"; +import Widget from "../index"; import { tableDataValidation, totalRecordsCountValidation, uniqueColumnNameValidation, + updateAllowAddNewRowOnInfiniteScrollChange, + updateCellEditabilityOnInfiniteScrollChange, updateColumnOrderHook, updateCustomColumnAliasOnLabelChange, updateInlineEditingOptionDropdownVisibilityHook, updateInlineEditingSaveOptionHook, + updateSearchSortFilterOnInfiniteScrollChange, } from "../propertyUtils"; import panelConfig from "./PanelConfig"; -import Widget from "../index"; -import { INFINITE_SCROLL_ENABLED } from "../../constants"; + +const INFINITE_SCROLL_DISABLED_HELP_TEXT = + "This feature is disabled because infinite scroll is enabled"; export default [ { @@ -165,8 +173,6 @@ export default [ isBindProperty: true, isTriggerProperty: false, validation: { type: ValidationTypes.BOOLEAN }, - hidden: (props: TableWidgetProps) => props.infiniteScrollEnabled, - dependencies: ["infiniteScrollEnabled"], }, { helpText: @@ -176,6 +182,10 @@ export default [ controlType: "SWITCH", isBindProperty: false, isTriggerProperty: false, + shouldDisableSection: (props: TableWidgetProps) => + props.infiniteScrollEnabled, + disabledHelpText: INFINITE_SCROLL_DISABLED_HELP_TEXT, + dependencies: ["infiniteScrollEnabled"], }, { helpText: @@ -185,6 +195,12 @@ export default [ controlType: "SWITCH", isBindProperty: false, isTriggerProperty: false, + updateHook: composePropertyUpdateHook([ + updateAllowAddNewRowOnInfiniteScrollChange, + updateCellEditabilityOnInfiniteScrollChange, + updateSearchSortFilterOnInfiniteScrollChange, + ]), + dependencies: ["primaryColumns"], hidden: () => !Widget.getFeatureFlag(INFINITE_SCROLL_ENABLED), }, { @@ -236,6 +252,10 @@ export default [ }, { sectionName: "Search & filters", + shouldDisableSection: (props: TableWidgetProps) => + props.infiniteScrollEnabled, + disabledHelpText: INFINITE_SCROLL_DISABLED_HELP_TEXT, + dependencies: ["infiniteScrollEnabled"], children: [ { propertyName: "isVisibleSearch", @@ -385,6 +405,10 @@ export default [ }, { sectionName: "Sorting", + shouldDisableSection: (props: TableWidgetProps) => + props.infiniteScrollEnabled, + disabledHelpText: INFINITE_SCROLL_DISABLED_HELP_TEXT, + dependencies: ["infiniteScrollEnabled"], children: [ { helpText: "Controls sorting in View Mode", @@ -438,6 +462,10 @@ export default [ { sectionName: "Adding a row", + shouldDisableSection: (props: TableWidgetProps) => + props.infiniteScrollEnabled, + disabledHelpText: INFINITE_SCROLL_DISABLED_HELP_TEXT, + dependencies: ["infiniteScrollEnabled"], children: [ { propertyName: "allowAddNewRow", diff --git a/app/client/src/widgets/TableWidgetV2/widget/propertyUtils.ts b/app/client/src/widgets/TableWidgetV2/widget/propertyUtils.ts index df960d6d7d83..58f38a7f31f3 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/propertyUtils.ts +++ b/app/client/src/widgets/TableWidgetV2/widget/propertyUtils.ts @@ -1447,3 +1447,112 @@ export function colorForEachRowValidation( return generateResponseAndReturn(false, DEFAULT_MESSAGE); } + +// Infinite scroll not supported for add new row yet +export const updateAllowAddNewRowOnInfiniteScrollChange = ( + props: TableWidgetProps, + propertyPath: string, + propertyValue: unknown, +): Array<{ propertyPath: string; propertyValue: unknown }> | undefined => { + if (propertyValue === true) { + return [ + { + propertyPath: "allowAddNewRow", + propertyValue: false, + }, + ]; + } else if (propertyValue === false) { + return [ + { + propertyPath: "allowAddNewRow", + propertyValue: true, + }, + ]; + } + + return; +}; + +// Infinite scroll not supported for search, sort and filters yet +export const updateSearchSortFilterOnInfiniteScrollChange = ( + props: TableWidgetProps, + propertyPath: string, + propertyValue: unknown, +): Array<{ propertyPath: string; propertyValue: unknown }> | undefined => { + if (propertyValue === true) { + return [ + { + propertyPath: "isVisibleSearch", + propertyValue: false, + }, + { + propertyPath: "isVisibleFilters", + propertyValue: false, + }, + { + propertyPath: "isSortable", + propertyValue: false, + }, + ]; + } else if (propertyValue === false) { + return [ + { + propertyPath: "isVisibleFilters", + propertyValue: true, + }, + { + propertyPath: "isVisibleSearch", + propertyValue: true, + }, + { + propertyPath: "isSortable", + propertyValue: true, + }, + ]; + } + + return; +}; + +// Disable cell editability when infinite scroll is enabled +export const updateCellEditabilityOnInfiniteScrollChange = ( + props: TableWidgetProps, + propertyPath: string, + propertyValue: unknown, +): Array<{ propertyPath: string; propertyValue: unknown }> | undefined => { + if (!props.primaryColumns) return; + + const updates: Array<{ propertyPath: string; propertyValue: unknown }> = []; + + if (propertyValue === true) { + Object.entries(props.primaryColumns).forEach(([, column]) => { + const columnName = column.alias; + + updates.push({ + propertyPath: `primaryColumns.${columnName}.isCellEditable`, + propertyValue: false, + }); + + updates.push({ + propertyPath: `primaryColumns.${columnName}.isEditable`, + propertyValue: false, + }); + }); + } else if (propertyValue === false) { + Object.entries(props.primaryColumns).forEach(([, column]) => { + const columnName = column.alias; + + updates.push({ + propertyPath: `primaryColumns.${columnName}.isCellEditable`, + propertyValue: true, + }); + + updates.push({ + propertyPath: `primaryColumns.${columnName}.isEditable`, + propertyValue: true, + }); + }); + } + + return updates.length > 0 ? updates : undefined; +};