diff --git a/app/client/src/ce/entities/FeatureFlag.ts b/app/client/src/ce/entities/FeatureFlag.ts index 5b3919ce5dba..1f59947f117f 100644 --- a/app/client/src/ce/entities/FeatureFlag.ts +++ b/app/client/src/ce/entities/FeatureFlag.ts @@ -39,6 +39,8 @@ export const FEATURE_FLAG = { release_anvil_toggle_enabled: "release_anvil_toggle_enabled", release_git_persist_branch_enabled: "release_git_persist_branch_enabled", release_ide_animations_enabled: "release_ide_animations_enabled", + release_table_custom_loading_state_enabled: + "release_table_custom_loading_state_enabled", } as const; export type FeatureFlag = keyof typeof FEATURE_FLAG; @@ -74,6 +76,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = { release_anvil_toggle_enabled: false, release_git_persist_branch_enabled: false, release_ide_animations_enabled: false, + release_table_custom_loading_state_enabled: false, }; export const AB_TESTING_EVENT_KEYS = { diff --git a/app/client/src/widgets/TableWidgetV2/constants.ts b/app/client/src/widgets/TableWidgetV2/constants.ts index 8fb0e8605aad..c88992218216 100644 --- a/app/client/src/widgets/TableWidgetV2/constants.ts +++ b/app/client/src/widgets/TableWidgetV2/constants.ts @@ -109,6 +109,8 @@ export interface TableWidgetProps firstEditableColumnIdByOrder: string; enableServerSideFiltering: boolean; onTableFilterUpdate: string; + customIsLoading: boolean; + customIsLoadingValue: boolean; } export enum TableVariantTypes { @@ -237,3 +239,6 @@ export const DEFAULT_COLUMN_NAME = "Table Column"; export const ALLOW_TABLE_WIDGET_SERVER_SIDE_FILTERING = FEATURE_FLAG["release_table_serverside_filtering_enabled"]; + +export const CUSTOM_LOADING_STATE_ENABLED = + FEATURE_FLAG["release_table_custom_loading_state_enabled"]; diff --git a/app/client/src/widgets/TableWidgetV2/widget/TableRendered.test.ts b/app/client/src/widgets/TableWidgetV2/widget/TableRendered.test.ts new file mode 100644 index 000000000000..fcd4e4a1dfe0 --- /dev/null +++ b/app/client/src/widgets/TableWidgetV2/widget/TableRendered.test.ts @@ -0,0 +1,181 @@ +import { ResponsiveBehavior } from "layoutSystems/common/utils/constants"; +import TableWidgetV2 from "."; +import type { TableWidgetProps } from "../constants"; + +describe("TableWidgetV2 getWidgetView", () => { + const tableWidgetProps: TableWidgetProps = { + customIsLoading: false, + customIsLoadingValue: false, + delimiter: ",", + filteredTableData: [], + isVisibleDownload: true, + isVisibleFilters: true, + isVisiblePagination: true, + isVisibleSearch: true, + pageSize: 10, + primaryColumns: {}, + totalRecordsCount: 100, + accentColor: "#000000", + borderColor: "#000000", + borderRadius: "40px", + borderWidth: "1px", + boxShadow: "none", + canFreezeColumn: true, + columnWidthMap: {}, + compactMode: "DEFAULT", + filters: [], + isAddRowInProgress: false, + isEditableCellsValid: {}, + isLoading: false, + isSortable: true, + multiRowSelection: false, + pageNo: 1, + renderMode: "CANVAS", + searchText: "", + selectedRowIndex: -1, + selectedRowIndices: [], + serverSidePaginationEnabled: false, + tableData: [], + widgetId: "widgetId", + widgetName: "TableWidget", + componentWidth: 800, + componentHeight: 600, + onPageChange: "", + onSearchTextChanged: "", + onSort: "", + onRowSelected: "", + onAddNewRowSave: "", + onAddNewRowDiscard: "", + onBulkSave: "", + onBulkDiscard: "", + onPageSizeChange: "", + commitBatchMetaUpdates: jest.fn(), + pushBatchMetaUpdates: jest.fn(), + updateWidgetMetaProperty: jest.fn(), + updateWidgetProperty: "", + updateOneClickBindingOptionsVisibility: "", + // Added missing properties + primaryColumnId: "", + columnOrder: [], + derivedColumns: {}, + dynamicPropertyPathList: [], + dynamicTriggerPathList: [], + dynamicBindingPathList: [], + childStylesheet: {}, + isVisible: true, + version: 1, + parentColumnSpace: 1, + parentRowSpace: 1, + leftColumn: 0, + rightColumn: 0, + topRow: 0, + bottomRow: 0, + parentId: "", + responsiveBehavior: ResponsiveBehavior.Hug, + minWidth: 0, + minHeight: 0, + isDisabled: false, + animateLoading: false, + primaryColor: "", + backgroundColor: "", + textColor: "", + fontFamily: "", + fontSize: "", + fontStyle: "", + textAlign: "", + textDecoration: "", + textTransform: "", + letterSpacing: "", + lineHeight: "", + whiteSpace: "", + overflow: "", + textOverflow: "", + wordBreak: "", + wordWrap: "", + cursor: "", + zIndex: 0, + pristine: true, + label: "TableWidget", + defaultSearchText: "", + sortOrder: { column: "", order: null }, + transientTableData: { data: { name: "name" } }, + newRow: {}, + firstEditableColumnIdByOrder: "", + enableServerSideFiltering: false, + onTableFilterUpdate: "", + type: "", + allowAddNewRow: false, + defaultNewRow: {}, + frozenColumnIndices: { a: 1 }, + }; + + describe("TableWidgetV2 loading checks", () => { + describe("When custom loading logic is not provided", () => { + it("Should not be loading with built-in property isLoading is set to false", () => { + const tableWidget = new TableWidgetV2(tableWidgetProps); + const widgetView = tableWidget.getWidgetView(); + + expect(widgetView.props.children.props.isLoading).toBe(false); + }); + it("Should be loading with built-in property isLoading is set to true", () => { + const tableWidget = new TableWidgetV2({ + ...tableWidgetProps, + isLoading: true, + }); + const widgetView = tableWidget.getWidgetView(); + + expect(widgetView.props.children.props.isLoading).toBe(true); + }); + }); + describe("When custom loading logic is provided", () => { + describe("When isLoading is false", () => { + it("Should not be loading with isLoading: false, customIsLoading: true and customIsLoadingTrue: true", () => { + const tableWidget = new TableWidgetV2({ + ...tableWidgetProps, + customIsLoading: true, + customIsLoadingValue: false, + isLoading: false, + }); + const widgetView = tableWidget.getWidgetView(); + + expect(widgetView.props.children.props.isLoading).toBe(false); + }); + it("Should be loading with customIsLoading set to true and customIsLoadingTrue set to true", () => { + const tableWidget = new TableWidgetV2({ + ...tableWidgetProps, + customIsLoading: true, + customIsLoadingValue: true, + isLoading: false, + }); + const widgetView = tableWidget.getWidgetView(); + + expect(widgetView.props.children.props.isLoading).toBe(true); + }); + }); + describe("When isLoading is true", () => { + it("Should be loading with customIsLoading set to true and customIsLoadingTrue set to false", () => { + const tableWidget = new TableWidgetV2({ + ...tableWidgetProps, + customIsLoading: true, + customIsLoadingValue: false, + isLoading: true, + }); + const widgetView = tableWidget.getWidgetView(); + + expect(widgetView.props.children.props.isLoading).toBe(true); + }); + it("Should be loading with customIsLoading set to true and customIsLoadingTrue set to true, even if in built loading is false", () => { + const tableWidget = new TableWidgetV2({ + ...tableWidgetProps, + customIsLoading: true, + customIsLoadingValue: true, + isLoading: true, + }); + const widgetView = tableWidget.getWidgetView(); + + expect(widgetView.props.children.props.isLoading).toBe(true); + }); + }); + }); + }); +}); diff --git a/app/client/src/widgets/TableWidgetV2/widget/index.tsx b/app/client/src/widgets/TableWidgetV2/widget/index.tsx index b83902333947..4d8e31b3e57b 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/TableWidgetV2/widget/index.tsx @@ -226,6 +226,8 @@ class TableWidgetV2 extends BaseWidget { ) ? false : undefined, + customIsLoading: false, + customIsLoadingValue: "", }; } @@ -1211,6 +1213,8 @@ class TableWidgetV2 extends BaseWidget { getWidgetView() { const { + customIsLoading, + customIsLoadingValue, delimiter, filteredTableData = [], isVisibleDownload, @@ -1266,7 +1270,11 @@ class TableWidgetV2 extends BaseWidget { height={componentHeight} isAddRowInProgress={this.props.isAddRowInProgress} isEditableCellsValid={this.props.isEditableCellsValid} - isLoading={this.props.isLoading} + isLoading={ + customIsLoading + ? customIsLoadingValue || this.props.isLoading + : this.props.isLoading + } isSortable={this.props.isSortable ?? true} isVisibleDownload={isVisibleDownload} isVisibleFilters={isVisibleFilters} diff --git a/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts b/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts index a3570b99228a..580daa70f83f 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts +++ b/app/client/src/widgets/TableWidgetV2/widget/propertyConfig/contentConfig.ts @@ -7,7 +7,10 @@ import { ValidationTypes } from "constants/WidgetValidation"; import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory"; import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType"; import type { TableWidgetProps } from "widgets/TableWidgetV2/constants"; -import { ALLOW_TABLE_WIDGET_SERVER_SIDE_FILTERING } from "../../constants"; +import { + ALLOW_TABLE_WIDGET_SERVER_SIDE_FILTERING, + CUSTOM_LOADING_STATE_ENABLED, +} from "../../constants"; import { InlineEditingSaveOptions } from "widgets/TableWidgetV2/constants"; import { composePropertyUpdateHook } from "widgets/WidgetUtils"; import { @@ -494,13 +497,35 @@ export default [ propertyName: "animateLoading", label: "Animate loading", controlType: "SWITCH", - helpText: "Controls the loading of the widget", + helpText: "Controls the animation loading of the widget", defaultValue: true, isJSConvertible: true, isBindProperty: true, isTriggerProperty: false, validation: { type: ValidationTypes.BOOLEAN }, }, + { + propertyName: "customIsLoading", + label: `Custom loading state`, + controlType: "SWITCH", + helpText: "Defines a custom value for the loading state", + defaultValue: false, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.BOOLEAN }, + hidden: () => !Widget.getFeatureFlag(CUSTOM_LOADING_STATE_ENABLED), + }, + { + propertyName: "customIsLoadingValue", + label: "isLoading value", + controlType: "INPUT_TEXT", + defaultValue: "", + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.BOOLEAN }, + hidden: (props: TableWidgetProps) => !props.customIsLoading, + dependencies: ["customIsLoading"], + }, { propertyName: "isVisibleDownload", helpText: "Toggle visibility of the data download",