feat: Row selection in Table widget using Primary Column (#8156)
This commit is contained in:
parent
4889098888
commit
3ac913a12c
|
|
@ -1,70 +1,66 @@
|
|||
{
|
||||
"dsl": {
|
||||
"widgetName": "MainContainer",
|
||||
"backgroundColor": "none",
|
||||
"rightColumn": 1080,
|
||||
"snapColumns": 64,
|
||||
"detachFromLayout": true,
|
||||
"widgetId": "0",
|
||||
"topRow": 0,
|
||||
"bottomRow": 840,
|
||||
"containerStyle": "none",
|
||||
"snapRows": 129,
|
||||
"parentRowSpace": 1,
|
||||
"type": "CANVAS_WIDGET",
|
||||
"canExtend": true,
|
||||
"version": 42,
|
||||
"minHeight": 820,
|
||||
"parentColumnSpace": 1,
|
||||
"dynamicBindingPathList": [],
|
||||
"leftColumn": 0,
|
||||
"children": [
|
||||
{
|
||||
"widgetName": "Button1",
|
||||
"buttonColor": "#03B365",
|
||||
"displayName": "Button",
|
||||
"iconSVG": "/static/media/icon.cca02633.svg",
|
||||
"topRow": 17,
|
||||
"bottomRow": 21,
|
||||
"parentRowSpace": 10,
|
||||
"type": "BUTTON_WIDGET",
|
||||
"hideCard": false,
|
||||
"parentColumnSpace": 16.6875,
|
||||
"dynamicTriggerPathList": [],
|
||||
"leftColumn": 12,
|
||||
"dynamicBindingPathList": [
|
||||
{
|
||||
"key": "text"
|
||||
},
|
||||
{
|
||||
"key": "isVisible"
|
||||
},
|
||||
{
|
||||
"key": "isDisabled"
|
||||
}
|
||||
],
|
||||
"text": "{{Nodata}}",
|
||||
"isDisabled": "{{lintError}}",
|
||||
"key": "miv4p1z4sm",
|
||||
"rightColumn": 28,
|
||||
"isDefaultClickDisabled": true,
|
||||
"widgetId": "nzf2tet2bn",
|
||||
"recaptchaV2": false,
|
||||
"isVisible": "{{error}}",
|
||||
"version": 1,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"buttonVariant": "PRIMARY",
|
||||
"dynamicPropertyPathList": [
|
||||
{
|
||||
"key": "isDisabled"
|
||||
},
|
||||
{
|
||||
"key": "isVisible"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"dsl": {
|
||||
"widgetName": "MainContainer",
|
||||
"backgroundColor": "none",
|
||||
"rightColumn": 1080,
|
||||
"snapColumns": 64,
|
||||
"detachFromLayout": true,
|
||||
"widgetId": "0",
|
||||
"topRow": 0,
|
||||
"bottomRow": 840,
|
||||
"containerStyle": "none",
|
||||
"snapRows": 129,
|
||||
"parentRowSpace": 1,
|
||||
"type": "CANVAS_WIDGET",
|
||||
"canExtend": true,
|
||||
"version": 42,
|
||||
"minHeight": 820,
|
||||
"parentColumnSpace": 1,
|
||||
"dynamicBindingPathList": [],
|
||||
"leftColumn": 0,
|
||||
"children": [{
|
||||
"widgetName": "Button1",
|
||||
"buttonColor": "#03B365",
|
||||
"displayName": "Button",
|
||||
"iconSVG": "/static/media/icon.cca02633.svg",
|
||||
"topRow": 17,
|
||||
"bottomRow": 21,
|
||||
"parentRowSpace": 10,
|
||||
"type": "BUTTON_WIDGET",
|
||||
"hideCard": false,
|
||||
"parentColumnSpace": 16.6875,
|
||||
"dynamicTriggerPathList": [],
|
||||
"leftColumn": 12,
|
||||
"dynamicBindingPathList": [{
|
||||
"key": "text"
|
||||
},
|
||||
{
|
||||
"key": "isVisible"
|
||||
},
|
||||
{
|
||||
"key": "isDisabled"
|
||||
}
|
||||
],
|
||||
"text": "{{Nodata}}",
|
||||
"isDisabled": "{{lintError}}",
|
||||
"key": "miv4p1z4sm",
|
||||
"rightColumn": 28,
|
||||
"isDefaultClickDisabled": true,
|
||||
"widgetId": "nzf2tet2bn",
|
||||
"recaptchaV2": false,
|
||||
"isVisible": "{{error}}",
|
||||
"version": 1,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"buttonVariant": "PRIMARY",
|
||||
"dynamicPropertyPathList": [{
|
||||
"key": "isDisabled"
|
||||
},
|
||||
{
|
||||
"key": "isVisible"
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
158
app/client/cypress/fixtures/multiSelectedRowUpdationDsl.json
Normal file
158
app/client/cypress/fixtures/multiSelectedRowUpdationDsl.json
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
{
|
||||
|
||||
"dsl": {
|
||||
"widgetName": "MainContainer",
|
||||
"backgroundColor": "none",
|
||||
"rightColumn": 966,
|
||||
"snapColumns": 64,
|
||||
"detachFromLayout": true,
|
||||
"widgetId": "0",
|
||||
"topRow": 0,
|
||||
"bottomRow": 730,
|
||||
"containerStyle": "none",
|
||||
"snapRows": 125,
|
||||
"parentRowSpace": 1,
|
||||
"type": "CANVAS_WIDGET",
|
||||
"canExtend": true,
|
||||
"version": 44,
|
||||
"minHeight": 710,
|
||||
"parentColumnSpace": 1,
|
||||
"dynamicBindingPathList": [],
|
||||
"leftColumn": 0,
|
||||
"children": [{
|
||||
"widgetName": "Button1",
|
||||
"onClick": "{{storeValue('data',[\n{\n \"data\": 1,\n},\n{\n\t\"data\": 2,\n},\n{\n\t\"data\": 3,\n}\n])}}",
|
||||
"buttonColor": "#03B365",
|
||||
"dynamicPropertyPathList": [{
|
||||
"key": "onClick"
|
||||
}],
|
||||
"displayName": "Button",
|
||||
"iconSVG": "/static/media/icon.f8a91627.svg",
|
||||
"topRow": 6,
|
||||
"bottomRow": 10,
|
||||
"parentRowSpace": 10,
|
||||
"type": "BUTTON_WIDGET",
|
||||
"hideCard": false,
|
||||
"parentColumnSpace": 14.90625,
|
||||
"dynamicTriggerPathList": [{
|
||||
"key": "onClick"
|
||||
}],
|
||||
"leftColumn": 42,
|
||||
"dynamicBindingPathList": [],
|
||||
"text": "Initial Data Set",
|
||||
"isDisabled": false,
|
||||
"key": "7939wnll69",
|
||||
"rightColumn": 58,
|
||||
"isDefaultClickDisabled": true,
|
||||
"widgetId": "20w01zcnlb",
|
||||
"recaptchaV2": false,
|
||||
"isVisible": true,
|
||||
"version": 1,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"buttonVariant": "PRIMARY"
|
||||
}, {
|
||||
"widgetName": "Button2",
|
||||
"onClick": "{{storeValue('data',[\n{\n \"data\": 1,\n},\n{\n\t\"data\": 4,\n},\n{\n\t\"data\": 3,\n}\n])}}",
|
||||
"buttonColor": "#03B365",
|
||||
"dynamicPropertyPathList": [{
|
||||
"key": "onClick"
|
||||
}],
|
||||
"displayName": "Button",
|
||||
"iconSVG": "/static/media/icon.f8a91627.svg",
|
||||
"topRow": 16,
|
||||
"bottomRow": 20,
|
||||
"parentRowSpace": 10,
|
||||
"type": "BUTTON_WIDGET",
|
||||
"hideCard": false,
|
||||
"parentColumnSpace": 14.90625,
|
||||
"dynamicTriggerPathList": [{
|
||||
"key": "onClick"
|
||||
}],
|
||||
"leftColumn": 43,
|
||||
"dynamicBindingPathList": [],
|
||||
"text": "Submit",
|
||||
"isDisabled": false,
|
||||
"key": "7939wnll69",
|
||||
"rightColumn": 59,
|
||||
"isDefaultClickDisabled": true,
|
||||
"widgetId": "71erdenmmv",
|
||||
"recaptchaV2": false,
|
||||
"isVisible": true,
|
||||
"version": 1,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"buttonVariant": "PRIMARY"
|
||||
}, {
|
||||
"multiRowSelection": true,
|
||||
"widgetName": "Table1",
|
||||
"defaultPageSize": 0,
|
||||
"columnOrder": ["data"],
|
||||
"isVisibleDownload": true,
|
||||
"dynamicPropertyPathList": [],
|
||||
"displayName": "Table",
|
||||
"iconSVG": "/static/media/icon.75823c5c.svg",
|
||||
"topRow": 19,
|
||||
"bottomRow": 47,
|
||||
"parentRowSpace": 10,
|
||||
"type": "TABLE_WIDGET",
|
||||
"defaultSelectedRow": "",
|
||||
"hideCard": false,
|
||||
"parentColumnSpace": 14.90625,
|
||||
"dynamicTriggerPathList": [],
|
||||
"dynamicBindingPathList": [{
|
||||
"key": "tableData"
|
||||
}, {
|
||||
"key": "primaryColumns.data.computedValue"
|
||||
}],
|
||||
"leftColumn": 2,
|
||||
"primaryColumns": {
|
||||
"data": {
|
||||
"index": 0,
|
||||
"width": 150,
|
||||
"id": "data",
|
||||
"horizontalAlignment": "LEFT",
|
||||
"verticalAlignment": "CENTER",
|
||||
"columnType": "text",
|
||||
"textSize": "PARAGRAPH",
|
||||
"enableFilter": true,
|
||||
"enableSort": true,
|
||||
"isVisible": true,
|
||||
"isDisabled": false,
|
||||
"isCellVisible": true,
|
||||
"isDerived": false,
|
||||
"label": "data",
|
||||
"computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.data))}}"
|
||||
}
|
||||
},
|
||||
"delimiter": ",",
|
||||
"key": "toz7v2e4xk",
|
||||
"derivedColumns": {},
|
||||
"rightColumn": 32,
|
||||
"textSize": "PARAGRAPH",
|
||||
"widgetId": "qs7595pbv3",
|
||||
"isVisibleFilters": true,
|
||||
"tableData": "{{appsmith.store.data}}",
|
||||
"isVisible": true,
|
||||
"label": "Data",
|
||||
"searchKey": "",
|
||||
"version": 3,
|
||||
"totalRecordsCount": 0,
|
||||
"parentId": "0",
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"horizontalAlignment": "LEFT",
|
||||
"isVisibleSearch": true,
|
||||
"isVisiblePagination": true,
|
||||
"primaryColumnId": "data",
|
||||
"verticalAlignment": "CENTER",
|
||||
"columnSizeMap": {
|
||||
"task": 245,
|
||||
"step": 62,
|
||||
"status": 75
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
const widgetsPage = require("../../../../locators/Widgets.json");
|
||||
const dsl = require("../../../../fixtures/multiSelectedRowUpdationDsl.json");
|
||||
|
||||
/*
|
||||
Selected row stays selected after data updation
|
||||
if the primary column value isn't updated.
|
||||
*/
|
||||
describe("Table Widget row multi select validation", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
|
||||
it("Test multi select column shows when enableMultirowselection is true", function() {
|
||||
cy.get(widgetsPage.buttonWidget)
|
||||
.first()
|
||||
.click();
|
||||
cy.wait(1000);
|
||||
cy.get(".t--table-multiselect")
|
||||
.first()
|
||||
.click();
|
||||
cy.get(widgetsPage.buttonWidget)
|
||||
.last()
|
||||
.click();
|
||||
cy.get(".tbody .tr")
|
||||
.first()
|
||||
.should("have.class", "selected-row");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
import React from "react";
|
||||
import BaseControl, { ControlProps } from "./BaseControl";
|
||||
import { ColumnProperties } from "widgets/TableWidget/component/Constants";
|
||||
import { StyledDropDown, StyledDropDownContainer } from "./StyledControls";
|
||||
import { DropdownOption } from "components/ads/Dropdown";
|
||||
|
||||
class PrimaryColumnDropdownControl extends BaseControl<ControlProps> {
|
||||
render() {
|
||||
// Get columns from widget properties
|
||||
const columns: Record<string, ColumnProperties> = this.props
|
||||
.widgetProperties.primaryColumns;
|
||||
const options: any[] = [];
|
||||
|
||||
for (const i in columns) {
|
||||
options.push({
|
||||
label: columns[i].label,
|
||||
id: columns[i].id,
|
||||
value: i,
|
||||
});
|
||||
}
|
||||
|
||||
let defaultSelected: DropdownOption = {
|
||||
label: "No selection.",
|
||||
value: undefined,
|
||||
};
|
||||
|
||||
const selected: DropdownOption = options.find(
|
||||
(option) => option.value === this.props.propertyValue,
|
||||
);
|
||||
|
||||
if (selected) {
|
||||
defaultSelected = selected;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledDropDownContainer>
|
||||
<StyledDropDown
|
||||
onSelect={this.onItemSelect}
|
||||
options={options}
|
||||
selected={defaultSelected}
|
||||
showLabelOnly
|
||||
width="100%"
|
||||
/>
|
||||
</StyledDropDownContainer>
|
||||
);
|
||||
}
|
||||
|
||||
onItemSelect = (value?: string): void => {
|
||||
if (value) {
|
||||
this.updateProperty(this.props.propertyName, value);
|
||||
}
|
||||
};
|
||||
|
||||
static getControlType() {
|
||||
return "PRIMARY_COLUMNS_DROPDOWN";
|
||||
}
|
||||
}
|
||||
|
||||
export interface PrimaryColumnDropdownControlProps extends ControlProps {
|
||||
propertyValue: string;
|
||||
}
|
||||
|
||||
export default PrimaryColumnDropdownControl;
|
||||
|
|
@ -27,6 +27,9 @@ import TabControl from "components/propertyControls/TabControl";
|
|||
import ActionSelectorControl from "components/propertyControls/ActionSelectorControl";
|
||||
import ColumnActionSelectorControl from "components/propertyControls/ColumnActionSelectorControl";
|
||||
import PrimaryColumnsControl from "components/propertyControls/PrimaryColumnsControl";
|
||||
import PrimaryColumnDropdownControl, {
|
||||
PrimaryColumnDropdownControlProps,
|
||||
} from "components/propertyControls/PrimaryColumnDropdownControl";
|
||||
import ColorPickerControl, {
|
||||
ColorPickerControlProps,
|
||||
} from "components/propertyControls/ColorPickerControl";
|
||||
|
|
@ -67,6 +70,7 @@ export const PropertyControls = {
|
|||
TabControl,
|
||||
ColorPickerControl,
|
||||
PrimaryColumnsControl,
|
||||
PrimaryColumnDropdownControl,
|
||||
IconTabControl,
|
||||
ButtonTabControl,
|
||||
ComputeTablePropertyControl,
|
||||
|
|
@ -91,7 +95,8 @@ export type PropertyControlPropsType =
|
|||
| ButtonTabControlProps
|
||||
| StepControlProps
|
||||
| ColorPickerControlProps
|
||||
| ComputeTablePropertyControlProps;
|
||||
| ComputeTablePropertyControlProps
|
||||
| PrimaryColumnDropdownControlProps;
|
||||
|
||||
export const getPropertyControlTypes = (): { [key: string]: string } => {
|
||||
const _types: { [key: string]: string } = {};
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ describe("getAllPathsFromPropertyConfig", () => {
|
|||
defaultSelectedRow: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
isSortable: EvaluationSubstitutionType.TEMPLATE,
|
||||
primaryColumnId: EvaluationSubstitutionType.TEMPLATE,
|
||||
compactMode: EvaluationSubstitutionType.TEMPLATE,
|
||||
delimiter: EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.computedValue":
|
||||
|
|
@ -205,6 +206,9 @@ describe("getAllPathsFromPropertyConfig", () => {
|
|||
default: true,
|
||||
},
|
||||
},
|
||||
primaryColumnId: {
|
||||
type: "TEXT",
|
||||
},
|
||||
tableData: {
|
||||
type: "OBJECT_ARRAY",
|
||||
params: {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export interface TableWidgetProps extends WidgetProps, WithMeta, TableStyles {
|
|||
filters?: ReactTableFilter[];
|
||||
compactMode?: CompactMode;
|
||||
isSortable?: boolean;
|
||||
primaryColumnId?: string;
|
||||
primaryColumns: Record<string, ColumnProperties>;
|
||||
derivedColumns: Record<string, ColumnProperties>;
|
||||
sortOrder: {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export default {
|
|||
getSelectedRows: (props, moment, _) => {
|
||||
const selectedRowIndices = Array.isArray(props.selectedRowIndices)
|
||||
? props.selectedRowIndices
|
||||
: [props.selectedRowIndices];
|
||||
: [];
|
||||
const filteredTableData =
|
||||
props.filteredTableData || props.sanitizedTableData || [];
|
||||
|
||||
|
|
@ -264,6 +264,9 @@ export default {
|
|||
derivedTableData = derivedTableData.map((item, index) => ({
|
||||
...item,
|
||||
__originalIndex__: index,
|
||||
__primaryKey__: props.primaryColumnId
|
||||
? item[props.primaryColumnId]
|
||||
: undefined,
|
||||
}));
|
||||
const columns = props.tableColumns;
|
||||
const sortedColumn = props.sortOrder.column;
|
||||
|
|
|
|||
|
|
@ -531,8 +531,20 @@ describe("Validates Derived Properties", () => {
|
|||
],
|
||||
};
|
||||
const expected = [
|
||||
{ id: 234, name: "Jane Doe", extra: "Extra2", __originalIndex__: 1 },
|
||||
{ id: 123, name: "John Doe", extra: "Extra1", __originalIndex__: 0 },
|
||||
{
|
||||
id: 234,
|
||||
name: "Jane Doe",
|
||||
extra: "Extra2",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 123,
|
||||
name: "John Doe",
|
||||
extra: "Extra1",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
let result = getFilteredTableData(input, moment, _);
|
||||
|
|
@ -678,9 +690,27 @@ describe("Validates Derived Properties", () => {
|
|||
],
|
||||
};
|
||||
const expected = [
|
||||
{ id: 1234, name: "Jim Doe", extra: "", __originalIndex__: 0 },
|
||||
{ id: 234, name: "Jane Doe", extra: "Extra2", __originalIndex__: 2 },
|
||||
{ id: 123, name: "John Doe", extra: "Extra1", __originalIndex__: 1 },
|
||||
{
|
||||
id: 1234,
|
||||
name: "Jim Doe",
|
||||
extra: "",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 234,
|
||||
name: "Jane Doe",
|
||||
extra: "Extra2",
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 123,
|
||||
name: "John Doe",
|
||||
extra: "Extra1",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
let result = getFilteredTableData(input, moment, _);
|
||||
|
|
@ -812,10 +842,34 @@ describe("Validates Derived Properties", () => {
|
|||
],
|
||||
};
|
||||
const expected = [
|
||||
{ id: 2345, name: "Jane Doeson", age: 30, __originalIndex__: 3 },
|
||||
{ id: 1234, name: "Jim Doe", age: 28, __originalIndex__: 0 },
|
||||
{ id: 234, name: "Jane Doe", age: 22, __originalIndex__: 2 },
|
||||
{ id: 123, name: "John Doe", age: null, __originalIndex__: 1 },
|
||||
{
|
||||
id: 2345,
|
||||
name: "Jane Doeson",
|
||||
age: 30,
|
||||
__originalIndex__: 3,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 1234,
|
||||
name: "Jim Doe",
|
||||
age: 28,
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 234,
|
||||
name: "Jane Doe",
|
||||
age: 22,
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 123,
|
||||
name: "John Doe",
|
||||
age: null,
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
let result = getFilteredTableData(input, moment, _);
|
||||
|
|
@ -947,10 +1001,34 @@ describe("Validates Derived Properties", () => {
|
|||
],
|
||||
};
|
||||
const expected = [
|
||||
{ id: 1234, name: "Jim Doe", age: 28, __originalIndex__: 0 },
|
||||
{ id: 2345, name: "Jane Doeson", age: 30, __originalIndex__: 3 },
|
||||
{ id: 234, name: "Jane Doe", age: 22, __originalIndex__: 2 },
|
||||
{ id: 123, name: "", age: null, __originalIndex__: 1 },
|
||||
{
|
||||
id: 1234,
|
||||
name: "Jim Doe",
|
||||
age: 28,
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 2345,
|
||||
name: "Jane Doeson",
|
||||
age: 30,
|
||||
__originalIndex__: 3,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 234,
|
||||
name: "Jane Doe",
|
||||
age: 22,
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
{
|
||||
id: 123,
|
||||
name: "",
|
||||
age: null,
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
let result = getFilteredTableData(input, moment, _);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import { getDynamicBindings } from "utils/DynamicBindingUtils";
|
|||
import { ReactTableFilter, OperatorTypes } from "../component/Constants";
|
||||
import { TableWidgetProps } from "../constants";
|
||||
import derivedProperties from "./parseDerivedProperties";
|
||||
import { selectRowIndex, selectRowIndices } from "./utilities";
|
||||
|
||||
import {
|
||||
ColumnProperties,
|
||||
|
|
@ -572,14 +573,26 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
JSON.stringify(prevProps.sanitizedTableData);
|
||||
|
||||
if (tableDataModified) {
|
||||
this.updateSelectedRowIndex();
|
||||
this.updateMetaRowData(
|
||||
prevProps.filteredTableData,
|
||||
this.props.filteredTableData,
|
||||
);
|
||||
this.props.updateWidgetMetaProperty("triggeredRowIndex", undefined);
|
||||
}
|
||||
|
||||
// If the user has changed the tableData OR
|
||||
// The binding has returned a new value
|
||||
if (tableDataModified && this.props.renderMode === RenderModes.CANVAS) {
|
||||
// Set filter to default
|
||||
this.applyFilters(defaultFilter);
|
||||
const defaultFilter = [
|
||||
{
|
||||
column: "",
|
||||
operator: OperatorTypes.OR,
|
||||
value: "",
|
||||
condition: "",
|
||||
},
|
||||
];
|
||||
this.props.updateWidgetMetaProperty("filters", defaultFilter);
|
||||
// Get columns keys from this.props.tableData
|
||||
const columnIds: string[] = getAllTableColumnKeys(this.props.tableData);
|
||||
// Get column keys from columns except for derivedColumns
|
||||
|
|
@ -684,6 +697,34 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
}
|
||||
};
|
||||
|
||||
updateMetaRowData = (
|
||||
oldTableData: Array<Record<string, unknown>>,
|
||||
newTableData: Array<Record<string, unknown>>,
|
||||
) => {
|
||||
if (!this.props.multiRowSelection) {
|
||||
const selectedRowIndex = selectRowIndex(
|
||||
oldTableData,
|
||||
newTableData,
|
||||
this.props.defaultSelectedRow,
|
||||
this.props.selectedRowIndex,
|
||||
this.props.primaryColumnId,
|
||||
);
|
||||
this.props.updateWidgetMetaProperty("selectedRowIndex", selectedRowIndex);
|
||||
} else {
|
||||
const selectedRowIndices = selectRowIndices(
|
||||
oldTableData,
|
||||
newTableData,
|
||||
this.props.defaultSelectedRow,
|
||||
this.props.selectedRowIndices,
|
||||
this.props.primaryColumnId,
|
||||
);
|
||||
this.props.updateWidgetMetaProperty(
|
||||
"selectedRowIndices",
|
||||
selectedRowIndices,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
getSelectedRowIndices = () => {
|
||||
let selectedRowIndices: number[] | undefined = this.props
|
||||
.selectedRowIndices;
|
||||
|
|
|
|||
|
|
@ -1330,6 +1330,17 @@ export default [
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
helpText:
|
||||
"Assigns a unique column which helps maintain selectedRows and triggeredRows based on value",
|
||||
propertyName: "primaryColumnId",
|
||||
dependencies: ["primaryColumns"],
|
||||
label: "Primary key column",
|
||||
controlType: "PRIMARY_COLUMNS_DROPDOWN",
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
validation: { type: ValidationTypes.TEXT },
|
||||
},
|
||||
{
|
||||
propertyName: "defaultSearchText",
|
||||
label: "Default Search Text",
|
||||
|
|
|
|||
239
app/client/src/widgets/TableWidget/widget/utilities.test.ts
Normal file
239
app/client/src/widgets/TableWidget/widget/utilities.test.ts
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
import {
|
||||
getOriginalRowIndex,
|
||||
selectRowIndex,
|
||||
selectRowIndices,
|
||||
} from "./utilities";
|
||||
|
||||
describe("getOriginalRowIndex", () => {
|
||||
it("With no previous data ", () => {
|
||||
const oldTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: " a fetch_users wih the Mock DB",
|
||||
status: "--",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: " a fetch_users wih the Mock DB",
|
||||
status: "--",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
},
|
||||
];
|
||||
const newTableData: Record<string, unknown>[] = [];
|
||||
const selectedRowIndex = 1;
|
||||
const result = getOriginalRowIndex(
|
||||
oldTableData,
|
||||
newTableData,
|
||||
selectedRowIndex,
|
||||
);
|
||||
const expected = undefined;
|
||||
expect(result).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it("With no new data", () => {
|
||||
const oldTableData: Record<string, unknown>[] = [];
|
||||
const newTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: " a fetch_users wih the Mock DB",
|
||||
status: "--",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: " a fetch_users wih the Mock DB",
|
||||
status: "--",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
},
|
||||
];
|
||||
|
||||
const selectedRowIndex = 1;
|
||||
const result = getOriginalRowIndex(
|
||||
oldTableData,
|
||||
newTableData,
|
||||
selectedRowIndex,
|
||||
);
|
||||
const expected = undefined;
|
||||
expect(result).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it("With no selectedRowIndex", () => {
|
||||
const oldTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: "1",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: "",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: "2",
|
||||
},
|
||||
];
|
||||
const newTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: " a fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: "1",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: "",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: "2",
|
||||
},
|
||||
];
|
||||
const result = getOriginalRowIndex(oldTableData, newTableData, undefined);
|
||||
const expected = undefined;
|
||||
expect(result).toStrictEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("selectRowIndex", () => {
|
||||
it("With new Data", () => {
|
||||
const oldTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: "1",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: "",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: "2",
|
||||
},
|
||||
];
|
||||
const newTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: " a fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: "1",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: "",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: "2",
|
||||
},
|
||||
];
|
||||
const selectedRowIndexProp = 0;
|
||||
const defaultSelectedRow = 0;
|
||||
const result = selectRowIndex(
|
||||
oldTableData,
|
||||
newTableData,
|
||||
defaultSelectedRow,
|
||||
selectedRowIndexProp,
|
||||
"step",
|
||||
);
|
||||
expect(result).toStrictEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("selectRowIndices", () => {
|
||||
it("With no selected index", () => {
|
||||
const oldTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: "1",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: "",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: "2",
|
||||
},
|
||||
];
|
||||
const newTableData = [
|
||||
{
|
||||
step: "#1",
|
||||
task: " a fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 0,
|
||||
__primaryKey__: "1",
|
||||
},
|
||||
{
|
||||
step: "#2",
|
||||
task: "fetch_users with the Mock DB",
|
||||
status: "--",
|
||||
__originalIndex__: 1,
|
||||
__primaryKey__: "",
|
||||
},
|
||||
{
|
||||
step: "#3",
|
||||
task: "Bind the query => fetch_users.data",
|
||||
status: "--",
|
||||
__originalIndex__: 2,
|
||||
__primaryKey__: "2",
|
||||
},
|
||||
];
|
||||
const defaultSelectedRow = [0];
|
||||
const result = selectRowIndices(
|
||||
oldTableData,
|
||||
newTableData,
|
||||
defaultSelectedRow,
|
||||
[],
|
||||
undefined,
|
||||
);
|
||||
expect(result).toEqual([0]);
|
||||
});
|
||||
});
|
||||
69
app/client/src/widgets/TableWidget/widget/utilities.ts
Normal file
69
app/client/src/widgets/TableWidget/widget/utilities.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { isNumber } from "lodash";
|
||||
|
||||
export const getOriginalRowIndex = (
|
||||
oldTableData: Array<Record<string, unknown>>,
|
||||
newTableData: Array<Record<string, unknown>>,
|
||||
selectedRowIndex: number | undefined,
|
||||
) => {
|
||||
const primaryKey =
|
||||
selectedRowIndex !== undefined &&
|
||||
oldTableData[selectedRowIndex] &&
|
||||
oldTableData[selectedRowIndex].__primaryKey__
|
||||
? oldTableData[selectedRowIndex].__primaryKey__
|
||||
: null;
|
||||
if (primaryKey) {
|
||||
const selectedRow = newTableData.find(
|
||||
(item) => item.__primaryKey__ === primaryKey,
|
||||
);
|
||||
if (selectedRow) {
|
||||
return selectedRow.__originalIndex__ as number;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const selectRowIndex = (
|
||||
oldTableData: Array<Record<string, unknown>>,
|
||||
newTableData: Array<Record<string, unknown>>,
|
||||
defaultSelectedRow: string | number | number[] | undefined,
|
||||
selectedRowIndexProp: number | undefined,
|
||||
primaryColumnId: string | undefined,
|
||||
) => {
|
||||
let selectedRowIndex = isNumber(defaultSelectedRow) ? defaultSelectedRow : -1;
|
||||
if (
|
||||
selectedRowIndexProp !== -1 &&
|
||||
selectedRowIndexProp !== undefined &&
|
||||
primaryColumnId
|
||||
) {
|
||||
const rowIndex = getOriginalRowIndex(
|
||||
oldTableData,
|
||||
newTableData,
|
||||
selectedRowIndexProp,
|
||||
);
|
||||
if (rowIndex !== undefined) {
|
||||
selectedRowIndex = rowIndex;
|
||||
}
|
||||
}
|
||||
return selectedRowIndex;
|
||||
};
|
||||
|
||||
export const selectRowIndices = (
|
||||
oldTableData: Array<Record<string, unknown>>,
|
||||
newTableData: Array<Record<string, unknown>>,
|
||||
defaultSelectedRow: string | number | number[] | undefined,
|
||||
selectedRowIndicesProp: number[] | undefined,
|
||||
primaryColumnId: string | undefined,
|
||||
) => {
|
||||
const rowIndices: number[] =
|
||||
Array.isArray(selectedRowIndicesProp) && primaryColumnId
|
||||
? selectedRowIndicesProp
|
||||
: Array.isArray(defaultSelectedRow)
|
||||
? defaultSelectedRow
|
||||
: [];
|
||||
const selectedRowIndices = rowIndices
|
||||
.map((index: number) => {
|
||||
const rowIndex = getOriginalRowIndex(oldTableData, newTableData, index);
|
||||
return rowIndex;
|
||||
})
|
||||
.filter((index) => index !== undefined);
|
||||
return selectedRowIndices;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user