From cb1604905e8914df74abfe69ac8b2a189eb3cc59 Mon Sep 17 00:00:00 2001 From: Vicky Bansal <67091118+vicky-primathon@users.noreply.github.com> Date: Wed, 25 Aug 2021 18:50:06 +0530 Subject: [PATCH] Table sort column APIs (#6068) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User now should have access to the table sort column if any through the `{{table.sortOrder}}` API. This will return an object when sort is active > {column: string, order: enum|‘asc’|'desc'}. There should also be a `onSort` action available which can trigger an Event --- app/client/cypress/fixtures/testdata.json | 1 + .../Bind_InputWidget_Table_Sorting_spec.js | 28 ++++++++++++++++ .../Table_Widget_Copy_Paste_spec.js | 2 +- .../Entity_Explorer_Multiple_Widgets_spec.js | 2 +- .../appsmith/TableComponent/Constants.ts | 5 +++ .../ActionConstants.tsx | 1 + app/client/src/entities/Widget/utils.test.ts | 1 + .../utils/autocomplete/EntityDefinitions.ts | 4 +++ .../TableWidget/TablePropertyPaneConfig.ts | 9 ++++++ .../TableWidget/TableWidgetConstants.ts | 6 ++-- app/client/src/widgets/TableWidget/derived.js | 12 +++---- .../src/widgets/TableWidget/derived.test.js | 32 +++++++++++++------ app/client/src/widgets/TableWidget/index.tsx | 30 ++++++++++++----- 13 files changed, 104 insertions(+), 29 deletions(-) diff --git a/app/client/cypress/fixtures/testdata.json b/app/client/cypress/fixtures/testdata.json index f449eeeb45..890e541768 100644 --- a/app/client/cypress/fixtures/testdata.json +++ b/app/client/cypress/fixtures/testdata.json @@ -46,6 +46,7 @@ "apiMultipartBodyType": "multi-part", "defaultMoustacheData": "{{Input1.text", "defaultInputWidget": "{{Table1.selectedRow.id", + "sortedColumn": "{{Table1.sortOrder.column", "deafultDropDownWidget": [ { "label": "{{Table1.selectedRow.email}}", diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Bind_InputWidget_Table_Sorting_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Bind_InputWidget_Table_Sorting_spec.js index 5413f82f83..27d16cbb8d 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Bind_InputWidget_Table_Sorting_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Bind_InputWidget_Table_Sorting_spec.js @@ -50,4 +50,32 @@ describe("Binding the Table and input Widget", function() { .should("contain", tabValue); }); }); + + it("validation of column id displayed in input widgets based on sorted column", function() { + cy.SearchEntityandOpen("Input1"); + cy.get(".t--property-control-defaulttext .CodeMirror textarea") + .first() + .focus() + .type("{ctrl}{shift}{downarrow}") + .then(($cm) => { + if ($cm.val() !== "") { + cy.get(".t--property-control-defaulttext .CodeMirror textarea") + .first() + .clear({ + force: true, + }); + } + }); + cy.get(widgetsPage.defaultInput).type(testdata.sortedColumn); + cy.get(commonlocators.editPropCrossButton).click({ force: true }); + cy.wait("@updateLayout").should( + "have.nested.property", + "response.body.responseMeta.status", + 200, + ); + cy.get(publish.inputWidget + " " + "input") + .first() + .invoke("attr", "value") + .should("contain", "id"); + }); }); diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_Widget_Copy_Paste_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_Widget_Copy_Paste_spec.js index 9f8b41073a..70734365ee 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_Widget_Copy_Paste_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_Widget_Copy_Paste_spec.js @@ -42,7 +42,7 @@ describe("Test Suite to validate copy/paste table Widget", function() { .last() .click(); cy.get(apiwidget.propertyList).then(function($lis) { - expect($lis).to.have.length(8); + expect($lis).to.have.length(9); expect($lis.eq(0)).to.contain("{{Table1Copy.selectedRow}}"); expect($lis.eq(1)).to.contain("{{Table1Copy.selectedRows}}"); }); diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ExplorerTests/Entity_Explorer_Multiple_Widgets_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ExplorerTests/Entity_Explorer_Multiple_Widgets_spec.js index 4eda944815..44df894d66 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ExplorerTests/Entity_Explorer_Multiple_Widgets_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ExplorerTests/Entity_Explorer_Multiple_Widgets_spec.js @@ -38,7 +38,7 @@ describe("Entity explorer tests related to widgets and validation", function() { .last() .click({ force: true }); cy.get(apiwidget.propertyList).then(function($lis) { - expect($lis).to.have.length(8); + expect($lis).to.have.length(9); expect($lis.eq(0)).to.contain("{{Table1.selectedRow}}"); expect($lis.eq(1)).to.contain("{{Table1.selectedRows}}"); expect($lis.eq(2)).to.contain("{{Table1.selectedRowIndex}}"); diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts b/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts index 2cd81dc336..b065168689 100644 --- a/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts +++ b/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts @@ -62,6 +62,11 @@ export enum OperatorTypes { AND = "AND", } +export enum SortOrderTypes { + asc = "asc", + desc = "desc", +} + export interface TableStyles { cellBackground?: string; textColor?: string; diff --git a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx index 9ee33d1c37..c991a5b83b 100644 --- a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx +++ b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx @@ -77,6 +77,7 @@ export enum EventType { ON_RATE_CHANGED = "ON_RATE_CHANGED", ON_IFRAME_URL_CHANGED = "ON_IFRAME_URL_CHANGED", ON_IFRAME_MESSAGE_RECEIVED = "ON_IFRAME_MESSAGE_RECEIVED", + ON_SORT = "ON_SORT", ON_CHECKBOX_GROUP_SELECTION_CHANGE = "ON_CHECKBOX_GROUP_SELECTION_CHANGE", } diff --git a/app/client/src/entities/Widget/utils.test.ts b/app/client/src/entities/Widget/utils.test.ts index 5a47e11894..156505fd20 100644 --- a/app/client/src/entities/Widget/utils.test.ts +++ b/app/client/src/entities/Widget/utils.test.ts @@ -175,6 +175,7 @@ describe("getAllPathsFromPropertyConfig", () => { onRowSelected: true, onPageChange: true, onSearchTextChanged: true, + onSort: true, onPageSizeChange: true, "primaryColumns.status.onClick": true, }, diff --git a/app/client/src/utils/autocomplete/EntityDefinitions.ts b/app/client/src/utils/autocomplete/EntityDefinitions.ts index 8664528976..8b21301ca0 100644 --- a/app/client/src/utils/autocomplete/EntityDefinitions.ts +++ b/app/client/src/utils/autocomplete/EntityDefinitions.ts @@ -70,6 +70,10 @@ export const entityDefinitions = { pageSize: "number", isVisible: isVisible, searchText: "string", + sortOrder: { + column: "string", + order: ["asc", "desc"], + }, }), VIDEO_WIDGET: { "!doc": diff --git a/app/client/src/widgets/TableWidget/TablePropertyPaneConfig.ts b/app/client/src/widgets/TableWidget/TablePropertyPaneConfig.ts index 4e27882fe8..c706e05928 100644 --- a/app/client/src/widgets/TableWidget/TablePropertyPaneConfig.ts +++ b/app/client/src/widgets/TableWidget/TablePropertyPaneConfig.ts @@ -963,6 +963,15 @@ export default [ isBindProperty: true, isTriggerProperty: true, }, + { + helpText: "Triggers an action when a table column is sorted", + propertyName: "onSort", + label: "onSort", + controlType: "ACTION_SELECTOR", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: true, + }, ], }, { diff --git a/app/client/src/widgets/TableWidget/TableWidgetConstants.ts b/app/client/src/widgets/TableWidget/TableWidgetConstants.ts index 4eb11adafc..d60b6f4425 100644 --- a/app/client/src/widgets/TableWidget/TableWidgetConstants.ts +++ b/app/client/src/widgets/TableWidget/TableWidgetConstants.ts @@ -3,6 +3,7 @@ import { CompactMode, ReactTableFilter, TableStyles, + SortOrderTypes, } from "components/designSystems/appsmith/TableComponent/Constants"; import { WidgetProps } from "widgets/BaseWidget"; import { WithMeta } from "widgets/MetaHOC"; @@ -19,6 +20,7 @@ export interface TableWidgetProps extends WidgetProps, WithMeta, TableStyles { pageSize: number; onRowSelected?: string; onSearchTextChanged: string; + onSort: string; selectedRowIndex?: number; selectedRowIndices: number[]; serverSidePaginationEnabled?: boolean; @@ -34,9 +36,9 @@ export interface TableWidgetProps extends WidgetProps, WithMeta, TableStyles { compactMode?: CompactMode; primaryColumns: Record; derivedColumns: Record; - sortedColumn?: { + sortOrder: { column: string; - asc: boolean; + order: SortOrderTypes | null; }; } diff --git a/app/client/src/widgets/TableWidget/derived.js b/app/client/src/widgets/TableWidget/derived.js index 99b5f090b5..7176dd4146 100644 --- a/app/client/src/widgets/TableWidget/derived.js +++ b/app/client/src/widgets/TableWidget/derived.js @@ -144,8 +144,8 @@ export default { .filter(Boolean); idsNotToShow.forEach((id) => delete allColumns[id]); } - const sortColumn = props.sortedColumn?.column; - const sortOrder = props.sortedColumn?.asc; + const sortColumn = props.sortOrder.column; + const sortOrder = props.sortOrder.order === "asc" ? true : false; if ( props.columnOrder && Array.isArray(props.columnOrder) && @@ -230,13 +230,11 @@ export default { ...item, __originalIndex__: index, })); - const columns = props.tableColumns; - + const sortedColumn = props.sortOrder.column; let sortedTableData; - if (props.sortedColumn) { - const sortedColumn = props.sortedColumn.column; - const sortOrder = props.sortedColumn.asc; + if (sortedColumn) { + const sortOrder = props.sortOrder.order === "asc" ? true : false; const column = columns.find((column) => column.id === sortedColumn); const columnType = column && column.columnType ? column.columnType : "text"; diff --git a/app/client/src/widgets/TableWidget/derived.test.js b/app/client/src/widgets/TableWidget/derived.test.js index 9427b2baba..d8ea3bb4d0 100644 --- a/app/client/src/widgets/TableWidget/derived.test.js +++ b/app/client/src/widgets/TableWidget/derived.test.js @@ -6,7 +6,10 @@ describe("Validates Derived Properties", () => { const { getTableColumns } = derivedProperty; const input = { sanitizedTableData: [], - sortedColumn: undefined, + sortOrder: { + column: "", + order: null, + }, columnOrder: ["id", "another"], }; const expected = []; @@ -14,7 +17,16 @@ describe("Validates Derived Properties", () => { let result = getTableColumns(input, moment, _); expect(result).toStrictEqual(expected); - let result = getTableColumns({}, moment, _); + let result = getTableColumns( + { + sortOrder: { + column: "", + order: null, + }, + }, + moment, + _, + ); expect(result).toStrictEqual(expected); }); @@ -25,7 +37,7 @@ describe("Validates Derived Properties", () => { { id: 123, name: "John Doe" }, { id: 234, name: "Jane Doe" }, ], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], }; const expected = [ @@ -77,7 +89,7 @@ describe("Validates Derived Properties", () => { { id: 123, name: "John Doe" }, { id: 234, name: "Jane Doe" }, ], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], primaryColumns: { id: { @@ -168,7 +180,7 @@ describe("Validates Derived Properties", () => { { id: 123, name: "John Doe" }, { id: 234, name: "Jane Doe" }, ], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], primaryColumns: { id: { @@ -276,7 +288,7 @@ describe("Validates Derived Properties", () => { { id: 123, name: "John Doe" }, { id: 234, name: "Jane Doe" }, ], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], primaryColumns: { id: { @@ -403,7 +415,7 @@ describe("Validates Derived Properties", () => { { id: 123, name: "John Doe" }, { id: 234, name: "Jane Doe" }, ], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], primaryColumns: { id: { @@ -531,7 +543,7 @@ describe("Validates Derived Properties", () => { const { getFilteredTableData } = derivedProperty; const input = { sanitizedTableData: [], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], primaryColumns: {}, columns: [], @@ -550,7 +562,7 @@ describe("Validates Derived Properties", () => { { id: 123, name: "John Doe" }, { id: 234, name: "Jane Doe" }, ], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], primaryColumns: { id: { @@ -691,7 +703,7 @@ describe("Validates Derived Properties", () => { operator: "OR", }, ], - sortedColumn: { column: "id", asc: false }, + sortOrder: { column: "id", order: "desc" }, columnOrder: ["name", "id"], primaryColumns: { id: { diff --git a/app/client/src/widgets/TableWidget/index.tsx b/app/client/src/widgets/TableWidget/index.tsx index 694c02732b..7f439a1f89 100644 --- a/app/client/src/widgets/TableWidget/index.tsx +++ b/app/client/src/widgets/TableWidget/index.tsx @@ -41,6 +41,7 @@ import { ColumnTypes, CompactModeTypes, CompactMode, + SortOrderTypes, } from "components/designSystems/appsmith/TableComponent/Constants"; import tablePropertyPaneConfig from "./TablePropertyPaneConfig"; import { BatchPropertyUpdatePayload } from "actions/controlActions"; @@ -65,6 +66,10 @@ class TableWidget extends BaseWidget { searchText: undefined, // The following meta property is used for rendering the table. filters: [], + sortOrder: { + column: "", + order: null, + }, }; } @@ -771,14 +776,23 @@ class TableWidget extends BaseWidget { handleColumnSorting = (column: string, asc: boolean) => { this.resetSelectedRowIndex(); - if (column === "") { - this.props.updateWidgetMetaProperty("sortedColumn", undefined); - } else { - this.props.updateWidgetMetaProperty("sortedColumn", { - column: column, - asc: asc, - }); - } + const sortOrderProps = + column === "" + ? { + column: "", + order: null, + } + : { + column: column, + order: asc ? SortOrderTypes.asc : SortOrderTypes.desc, + }; + this.props.updateWidgetMetaProperty("sortOrder", sortOrderProps, { + triggerPropertyName: "onSort", + dynamicString: this.props.onSort, + event: { + type: EventType.ON_SORT, + }, + }); }; handleResizeColumn = (columnSizeMap: { [key: string]: number }) => {