feat: Update TableWidgetV2 to include customIsLoading property (#36857)
## Description <ins>Problem</ins> There are many problems with table loader logic, for which many users try to implement a modal for loader. These problems stem from dependency and delay on eval, discussed comprehensively in #12308 <ins>Solution</ins> This PR updates the TableWidgetV2 component to include a new property called `customIsLoading`. This property controls the loading state of the widget and is added to the TableWidgetProps interface. Additionally, the component's state is updated to include the `customIsLoading` property. The `contentConfig` file for the TableWidgetV2 is also modified to include the `customIsLoading` property with its corresponding label, control type, help text, and validation. These changes improve the flexibility and customization options of the TableWidgetV2 component. Fixes #12308 _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 <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/11456273525> > Commit: 1c6f4f9caabc3aa45ec3916e5ccb465d946ab0a1 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11456273525&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Table` > Spec: > <hr>Tue, 22 Oct 2024 09:17:37 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new feature flag for custom loading states in the table widget. - Added properties for managing custom loading behavior in the `TableWidgetV2`. - **Bug Fixes** - Enhanced loading state management to ensure accurate representation based on new properties. - **Tests** - Added unit tests for loading behavior in the `TableWidgetV2` component, covering default and custom loading scenarios. - **Documentation** - Updated help text for properties related to loading states to improve clarity. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
dc5fbed66b
commit
554ec58d40
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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"];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -226,6 +226,8 @@ class TableWidgetV2 extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
)
|
||||
? false
|
||||
: undefined,
|
||||
customIsLoading: false,
|
||||
customIsLoadingValue: "",
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1211,6 +1213,8 @@ class TableWidgetV2 extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
|
||||
getWidgetView() {
|
||||
const {
|
||||
customIsLoading,
|
||||
customIsLoadingValue,
|
||||
delimiter,
|
||||
filteredTableData = [],
|
||||
isVisibleDownload,
|
||||
|
|
@ -1266,7 +1270,11 @@ class TableWidgetV2 extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
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}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user