PromucFlow_constructor/app/client/src/widgets/TableWidget/index.tsx
Vicky Bansal cb1604905e
Table sort column APIs (#6068)
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
2021-08-25 18:50:06 +05:30

971 lines
32 KiB
TypeScript

import React, { lazy, Suspense } from "react";
import log from "loglevel";
import moment from "moment";
import {
isNumber,
isString,
isNil,
isEqual,
xor,
without,
isBoolean,
} from "lodash";
import * as Sentry from "@sentry/react";
import BaseWidget, { WidgetState } from "../BaseWidget";
import { RenderModes, WidgetType } from "constants/WidgetConstants";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import {
getDefaultColumnProperties,
getTableStyles,
renderCell,
renderDropdown,
renderActions,
} from "components/designSystems/appsmith/TableComponent/TableUtilities";
import { getAllTableColumnKeys } from "components/designSystems/appsmith/TableComponent/TableHelpers";
import Skeleton from "components/utils/Skeleton";
import { noop, retryPromise } from "utils/AppsmithUtils";
import withMeta from "../MetaHOC";
import { getDynamicBindings } from "utils/DynamicBindingUtils";
import {
OperatorTypes,
ReactTableFilter,
} from "components/designSystems/appsmith/TableComponent/Constants";
import { TableWidgetProps } from "./TableWidgetConstants";
import derivedProperties from "./parseDerivedProperties";
import {
ColumnProperties,
CellLayoutProperties,
ReactTableColumnProps,
ColumnTypes,
CompactModeTypes,
CompactMode,
SortOrderTypes,
} from "components/designSystems/appsmith/TableComponent/Constants";
import tablePropertyPaneConfig from "./TablePropertyPaneConfig";
import { BatchPropertyUpdatePayload } from "actions/controlActions";
import { isArray } from "lodash";
const ReactTableComponent = lazy(() =>
retryPromise(() =>
import("components/designSystems/appsmith/TableComponent"),
),
);
class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return tablePropertyPaneConfig;
}
static getMetaPropertiesMap(): Record<string, any> {
return {
pageNo: 1,
selectedRowIndex: undefined,
selectedRowIndices: undefined,
searchText: undefined,
// The following meta property is used for rendering the table.
filters: [],
sortOrder: {
column: "",
order: null,
},
};
}
static getDerivedPropertiesMap() {
return {
selectedRow: `{{(()=>{${derivedProperties.getSelectedRow}})()}}`,
selectedRows: `{{(()=>{${derivedProperties.getSelectedRows}})()}}`,
pageSize: `{{(()=>{${derivedProperties.getPageSize}})()}}`,
triggerRowSelection: "{{!!this.onRowSelected}}",
sanitizedTableData: `{{(()=>{${derivedProperties.getSanitizedTableData}})()}}`,
tableColumns: `{{(()=>{${derivedProperties.getTableColumns}})()}}`,
filteredTableData: `{{(()=>{ ${derivedProperties.getFilteredTableData}})()}}`,
};
}
static getDefaultPropertiesMap(): Record<string, string> {
return {
searchText: "defaultSearchText",
selectedRowIndex: "defaultSelectedRow",
selectedRowIndices: "defaultSelectedRow",
};
}
getPropertyValue = (value: any, index: number, preserveCase = false) => {
if (isBoolean(value)) {
return value;
}
if (Array.isArray(value) && isBoolean(value[index])) {
return value[index];
}
if (value && Array.isArray(value) && value[index]) {
return preserveCase
? value[index].toString()
: value[index].toString().toUpperCase();
} else if (value) {
return preserveCase ? value.toString() : value.toString().toUpperCase();
} else {
return value;
}
};
getCellProperties = (
columnProperties: ColumnProperties,
rowIndex: number,
) => {
const cellProperties: CellLayoutProperties = {
horizontalAlignment: this.getPropertyValue(
columnProperties.horizontalAlignment,
rowIndex,
),
verticalAlignment: this.getPropertyValue(
columnProperties.verticalAlignment,
rowIndex,
),
cellBackground: this.getPropertyValue(
columnProperties.cellBackground,
rowIndex,
),
buttonStyle: this.getPropertyValue(
columnProperties.buttonStyle,
rowIndex,
),
buttonLabelColor: this.getPropertyValue(
columnProperties.buttonLabelColor,
rowIndex,
),
buttonLabel: this.getPropertyValue(
columnProperties.buttonLabel,
rowIndex,
true,
),
textSize: this.getPropertyValue(columnProperties.textSize, rowIndex),
textColor: this.getPropertyValue(columnProperties.textColor, rowIndex),
fontStyle: this.getPropertyValue(columnProperties.fontStyle, rowIndex), //Fix this
isVisible: this.getPropertyValue(columnProperties.isVisible, rowIndex),
isDisabled: this.getPropertyValue(columnProperties.isDisabled, rowIndex),
isCellVisible: this.getPropertyValue(
columnProperties.isCellVisible,
rowIndex,
),
displayText: this.getPropertyValue(
columnProperties.displayText,
rowIndex,
true,
),
};
return cellProperties;
};
getTableColumns = () => {
let columns: ReactTableColumnProps[] = [];
const hiddenColumns: ReactTableColumnProps[] = [];
const { columnSizeMap } = this.props;
const { componentWidth } = this.getComponentDimensions();
let totalColumnSizes = 0;
const defaultColumnWidth = 150;
const allColumnProperties = this.props.tableColumns || [];
for (let index = 0; index < allColumnProperties.length; index++) {
const isAllCellVisible: boolean | boolean[] =
allColumnProperties[index].isCellVisible;
const columnProperties = allColumnProperties[index];
const isHidden = !columnProperties.isVisible;
const accessor = columnProperties.id;
const columnData = {
Header: columnProperties.label,
accessor: accessor,
width:
columnSizeMap && columnSizeMap[accessor]
? columnSizeMap[accessor]
: defaultColumnWidth,
minWidth: 60,
draggable: true,
isHidden: false,
isAscOrder: columnProperties.isAscOrder,
isDerived: columnProperties.isDerived,
metaProperties: {
isHidden: isHidden,
type: columnProperties.columnType,
format: columnProperties?.outputFormat || "",
inputFormat: columnProperties?.inputFormat || "",
},
columnProperties: columnProperties,
Cell: (props: any) => {
let rowIndex: number = props.cell.row.index;
const data = this.props.filteredTableData[rowIndex];
if (data && data.__originalIndex__) rowIndex = data.__originalIndex__;
const cellProperties = this.getCellProperties(
columnProperties,
rowIndex,
);
if (columnProperties.columnType === "button") {
const buttonProps = {
isSelected: !!props.row.isSelected,
onCommandClick: (action: string, onComplete: () => void) =>
this.onCommandClick(rowIndex, action, onComplete),
backgroundColor: cellProperties.buttonStyle || "rgb(3, 179, 101)",
buttonLabelColor: cellProperties.buttonLabelColor || "#FFFFFF",
isDisabled: cellProperties.isDisabled || false,
isCellVisible: cellProperties.isCellVisible ?? true,
columnActions: [
{
id: columnProperties.id,
label: cellProperties.buttonLabel || "Action",
dynamicTrigger: columnProperties.onClick || "",
},
],
};
return renderActions(buttonProps, isHidden, cellProperties);
} else if (columnProperties.columnType === "dropdown") {
let options = [];
try {
options = JSON.parse(columnProperties.dropdownOptions || "");
} catch (e) {}
return renderDropdown({
options: options,
onItemSelect: this.onItemSelect,
isCellVisible: cellProperties.isCellVisible ?? true,
onOptionChange: columnProperties.onOptionChange || "",
selectedIndex: isNumber(props.cell.value)
? props.cell.value
: undefined,
});
} else if (columnProperties.columnType === "image") {
const isSelected = !!props.row.isSelected;
const isCellVisible = cellProperties.isCellVisible ?? true;
const onClick = columnProperties.onClick
? () =>
this.onCommandClick(rowIndex, columnProperties.onClick, noop)
: noop;
return renderCell(
props.cell.value,
columnProperties.columnType,
isHidden,
cellProperties,
componentWidth,
isCellVisible,
onClick,
isSelected,
);
} else {
const isCellVisible = cellProperties.isCellVisible ?? true;
return renderCell(
props.cell.value,
columnProperties.columnType,
isHidden,
cellProperties,
componentWidth,
isCellVisible,
);
}
},
};
// Hide Column when All cells are hidden
if (
(isBoolean(isAllCellVisible) && !isAllCellVisible) ||
(isArray(isAllCellVisible) &&
isAllCellVisible.every((v) => v === false)) ||
isHidden
) {
columnData.isHidden = true;
hiddenColumns.push(columnData);
} else {
totalColumnSizes += columnData.width;
columns.push(columnData);
}
}
if (totalColumnSizes < componentWidth) {
const lastColumnIndex = columns.length - 1;
let remainingColumnsSize = 0;
for (let i = 0; i < columns.length - 1; i++) {
remainingColumnsSize += columns[i].width || defaultColumnWidth;
}
if (columns[lastColumnIndex]) {
columns[lastColumnIndex].width =
componentWidth - remainingColumnsSize < defaultColumnWidth
? defaultColumnWidth
: componentWidth - remainingColumnsSize; //Min remaining width to be defaultColumnWidth
}
}
if (hiddenColumns.length && this.props.renderMode === RenderModes.CANVAS) {
columns = columns.concat(hiddenColumns);
}
return columns.filter((column: ReactTableColumnProps) => column.accessor);
};
transformData = (
tableData: Array<Record<string, unknown>>,
columns: ReactTableColumnProps[],
) => {
const updatedTableData = [];
// For each row in the tableData (filteredTableData)
for (let row = 0; row < tableData.length; row++) {
// Get the row object
const data: { [key: string]: any } = tableData[row];
if (data) {
const tableRow: { [key: string]: any } = {};
// For each column in the expected columns of the table
for (let colIndex = 0; colIndex < columns.length; colIndex++) {
// Get the column properties
const column = columns[colIndex];
const { accessor } = column;
let value = data[accessor];
if (column.metaProperties) {
const type = column.metaProperties.type;
switch (type) {
case ColumnTypes.DATE:
let isValidDate = true;
let outputFormat = Array.isArray(column.metaProperties.format)
? column.metaProperties.format[row]
: column.metaProperties.format;
let inputFormat;
try {
const type = Array.isArray(column.metaProperties.inputFormat)
? column.metaProperties.inputFormat[row]
: column.metaProperties.inputFormat;
if (type !== "Epoch" && type !== "Milliseconds") {
inputFormat = type;
moment(value, inputFormat);
} else if (!isNumber(value)) {
isValidDate = false;
}
} catch (e) {
isValidDate = false;
}
if (isValidDate) {
try {
if (outputFormat === "SAME_AS_INPUT") {
outputFormat = inputFormat;
}
if (column.metaProperties.inputFormat === "Milliseconds") {
value = Number(value);
} else if (column.metaProperties.inputFormat === "Epoch") {
value = 1000 * Number(value);
}
tableRow[accessor] = moment(value, inputFormat).format(
outputFormat,
);
} catch (e) {
log.debug("Unable to parse Date:", { e });
tableRow[accessor] = "";
}
} else if (value) {
tableRow[accessor] = "Invalid Value";
} else {
tableRow[accessor] = "";
}
break;
default:
const data =
isString(value) || isNumber(value)
? value
: isNil(value)
? ""
: JSON.stringify(value);
tableRow[accessor] = data;
break;
}
}
}
updatedTableData.push(tableRow);
}
}
return updatedTableData;
};
getParsedComputedValues = (value: string | Array<unknown>) => {
let computedValues: Array<unknown> = [];
if (isString(value)) {
try {
computedValues = JSON.parse(value);
} catch (e) {
log.debug("Error parsing column value: ", value);
}
} else if (Array.isArray(value)) {
computedValues = value;
} else {
log.debug("Error parsing column values:", value);
}
return computedValues;
};
getEmptyRow = () => {
const columnKeys: string[] = getAllTableColumnKeys(
this.props.sanitizedTableData,
);
const selectedRow: { [key: string]: any } = {};
for (let i = 0; i < columnKeys.length; i++) {
selectedRow[columnKeys[i]] = "";
}
return selectedRow;
};
getDerivedColumns = (
derivedColumns: Record<string, ColumnProperties>,
tableColumnCount: number,
) => {
if (!derivedColumns) return [];
//update index property of all columns in new derived columns
return (
Object.keys(derivedColumns)?.map((columnId: string, index: number) => {
return {
...derivedColumns[columnId],
index: index + tableColumnCount,
};
}) || []
);
};
createTablePrimaryColumns = ():
| Record<string, ColumnProperties>
| undefined => {
const {
sanitizedTableData = [],
primaryColumns = {},
columnNameMap = {},
columnTypeMap = {},
derivedColumns = {},
hiddenColumns = [],
migrated,
} = this.props;
// Bail out if the data doesn't exist.
// This is a temporary measure,
// to solve for the scenario where the column properties are getting reset
// Repurcussion: The primary columns control will never go into the "no data" state.
if (isString(sanitizedTableData) || sanitizedTableData.length === 0) return;
const previousColumnIds = Object.keys(primaryColumns);
const tableColumns: Record<string, ColumnProperties> = {};
//Get table level styles
const tableStyles = getTableStyles(this.props);
const columnKeys: string[] = getAllTableColumnKeys(sanitizedTableData);
// Generate default column properties for all columns
// But donot replace existing columns with the same id
for (let index = 0; index < columnKeys.length; index++) {
const i = columnKeys[index];
const prevIndex = previousColumnIds.indexOf(i);
if (prevIndex > -1) {
// we found an existing property with the same column id use the previous properties
tableColumns[i] = primaryColumns[i];
} else {
const columnProperties = getDefaultColumnProperties(
i,
index,
this.props.widgetName,
);
if (migrated === false) {
// Update column names using the names from the table before migration
if ((columnNameMap as Record<string, string>)[i]) {
columnProperties.label = columnNameMap[i];
}
// Update column types using types from the table before migration
if (
(columnTypeMap as Record<
string,
{ type: ColumnTypes; inputFormat?: string; format?: string }
>)[i]
) {
columnProperties.columnType = columnTypeMap[i].type;
columnProperties.inputFormat = columnTypeMap[i].inputFormat;
columnProperties.outputFormat = columnTypeMap[i].format;
}
// Hide columns which were hidden in the table before migration
if (hiddenColumns.indexOf(i) > -1) {
columnProperties.isVisible = false;
}
}
//add column properties along with table level styles
tableColumns[columnProperties.id] = {
...columnProperties,
...tableStyles,
};
}
}
// Get derived columns
const updatedDerivedColumns = this.getDerivedColumns(
derivedColumns,
Object.keys(tableColumns).length,
);
//add derived columns to primary columns
updatedDerivedColumns.forEach((derivedColumn: ColumnProperties) => {
tableColumns[derivedColumn.id] = derivedColumn;
});
const newColumnIds = Object.keys(tableColumns);
if (xor(previousColumnIds, newColumnIds).length > 0) return tableColumns;
else return;
};
updateColumnProperties = (
tableColumns?: Record<string, ColumnProperties>,
) => {
const { primaryColumns = {} } = this.props;
const { columnOrder, migrated } = this.props;
if (tableColumns) {
const previousColumnIds = Object.keys(primaryColumns);
const newColumnIds = Object.keys(tableColumns);
if (xor(previousColumnIds, newColumnIds).length > 0) {
const columnIdsToAdd = without(newColumnIds, ...previousColumnIds);
const propertiesToAdd: Record<string, unknown> = {};
columnIdsToAdd.forEach((id: string) => {
Object.entries(tableColumns[id]).forEach(([key, value]) => {
propertiesToAdd[`primaryColumns.${id}.${key}`] = value;
});
});
// If new columnOrders have different values from the original columnOrders
if (xor(newColumnIds, columnOrder).length > 0) {
propertiesToAdd["columnOrder"] = newColumnIds;
}
const pathsToDelete: string[] = [];
if (migrated === false) {
propertiesToAdd["migrated"] = true;
}
const propertiesToUpdate: BatchPropertyUpdatePayload = {
modify: propertiesToAdd,
};
const columnsIdsToDelete = without(previousColumnIds, ...newColumnIds);
if (columnsIdsToDelete.length > 0) {
columnsIdsToDelete.forEach((id: string) => {
pathsToDelete.push(`primaryColumns.${id}`);
});
propertiesToUpdate.remove = pathsToDelete;
}
super.batchUpdateWidgetProperty(propertiesToUpdate);
}
}
};
componentDidMount() {
const { sanitizedTableData } = this.props;
let newPrimaryColumns;
// When we have tableData, the primaryColumns order is unlikely to change
// When we don't have tableData primaryColumns will not be available, so let's let it be.
if (Array.isArray(sanitizedTableData) && sanitizedTableData.length > 0) {
newPrimaryColumns = this.createTablePrimaryColumns();
if (newPrimaryColumns) this.updateColumnProperties(newPrimaryColumns);
}
}
componentDidUpdate(prevProps: TableWidgetProps) {
const { primaryColumns = {} } = this.props;
// Bail out if santizedTableData is a string. This signifies an error in evaluations
// Since, it is an error in evaluations, we should not attempt to process the data
if (isString(this.props.sanitizedTableData)) return;
// Check if data is modifed by comparing the stringified versions of the previous and next tableData
const tableDataModified =
JSON.stringify(this.props.sanitizedTableData) !==
JSON.stringify(prevProps.sanitizedTableData);
if (tableDataModified) {
this.updateSelectedRowIndex();
}
// 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
const defaultFilter = [
{
column: "",
operator: OperatorTypes.OR,
value: "",
condition: "",
},
];
this.applyFilters(defaultFilter);
// Get columns keys from this.props.tableData
const columnIds: string[] = getAllTableColumnKeys(this.props.tableData);
// Get column keys from columns except for derivedColumns
const primaryColumnIds = Object.keys(primaryColumns).filter(
(id: string) => {
return !primaryColumns[id].isDerived; // Filter out the derived columns
},
);
// If the keys which exist in the tableData are different from the ones available in primaryColumns
if (xor(columnIds, primaryColumnIds).length > 0) {
const newTableColumns = this.createTablePrimaryColumns(); // This updates the widget
this.updateColumnProperties(newTableColumns);
}
}
if (!this.props.pageNo) this.props.updateWidgetMetaProperty("pageNo", 1);
// If the user has switched the mutiple row selection feature
if (this.props.multiRowSelection !== prevProps.multiRowSelection) {
// It is switched ON:
if (this.props.multiRowSelection) {
// Use the selectedRowIndex if available as default selected index
const selectedRowIndices = this.props.selectedRowIndex
? [this.props.selectedRowIndex]
: []; // Else use an empty array
this.props.updateWidgetMetaProperty(
"selectedRowIndices",
selectedRowIndices,
);
this.props.updateWidgetMetaProperty("selectedRowIndex", -1);
} else {
this.props.updateWidgetMetaProperty("selectedRowIndices", []);
}
}
// If the user changed the defaultSelectedRow(s)
if (!isEqual(this.props.defaultSelectedRow, prevProps.defaultSelectedRow)) {
//Runs only when defaultSelectedRow is changed from property pane
this.updateSelectedRowIndex();
}
if (this.props.pageSize !== prevProps.pageSize) {
if (this.props.onPageSizeChange) {
super.executeAction({
triggerPropertyName: "onPageSizeChange",
dynamicString: this.props.onPageSizeChange,
event: {
type: EventType.ON_PAGE_SIZE_CHANGE,
},
});
}
}
}
updateSelectedRowIndex = () => {
if (!this.props.multiRowSelection) {
const selectedRowIndex = isNumber(this.props.defaultSelectedRow)
? this.props.defaultSelectedRow
: -1;
this.props.updateWidgetMetaProperty("selectedRowIndex", selectedRowIndex);
} else {
const selectedRowIndices = Array.isArray(this.props.defaultSelectedRow)
? this.props.defaultSelectedRow
: [];
this.props.updateWidgetMetaProperty(
"selectedRowIndices",
selectedRowIndices,
);
}
};
getSelectedRowIndices = () => {
let selectedRowIndices: number[] | undefined = this.props
.selectedRowIndices;
if (!this.props.multiRowSelection) selectedRowIndices = undefined;
else {
if (!Array.isArray(selectedRowIndices)) {
if (Number.isInteger(selectedRowIndices))
selectedRowIndices = [selectedRowIndices];
else selectedRowIndices = [];
}
}
return selectedRowIndices;
};
applyFilters = (filters: ReactTableFilter[]) => {
this.resetSelectedRowIndex();
this.props.updateWidgetMetaProperty("filters", filters);
};
toggleDrag = (disable: boolean) => {
this.disableDrag(disable);
};
getPageView() {
const {
delimiter,
pageSize,
filteredTableData = [],
isVisibleCompactMode,
isVisibleDownload,
isVisibleFilters,
isVisiblePagination,
isVisibleSearch,
} = this.props;
const tableColumns = this.getTableColumns() || [];
const transformedData = this.transformData(filteredTableData, tableColumns);
const { componentHeight, componentWidth } = this.getComponentDimensions();
const isVisibleHeaderOptions =
isVisibleCompactMode ||
isVisibleDownload ||
isVisibleFilters ||
isVisiblePagination ||
isVisibleSearch;
return (
<Suspense fallback={<Skeleton />}>
<ReactTableComponent
applyFilter={this.applyFilters}
columnSizeMap={this.props.columnSizeMap}
columns={tableColumns}
compactMode={this.props.compactMode || CompactModeTypes.DEFAULT}
delimiter={delimiter}
disableDrag={this.toggleDrag}
editMode={this.props.renderMode === RenderModes.CANVAS}
filters={this.props.filters}
handleReorderColumn={this.handleReorderColumn}
handleResizeColumn={this.handleResizeColumn}
height={componentHeight}
isLoading={this.props.isLoading}
isVisibleCompactMode={isVisibleCompactMode}
isVisibleDownload={isVisibleDownload}
isVisibleFilters={isVisibleFilters}
isVisiblePagination={isVisiblePagination}
isVisibleSearch={isVisibleSearch}
multiRowSelection={this.props.multiRowSelection}
nextPageClick={this.handleNextPageClick}
onCommandClick={this.onCommandClick}
onRowClick={this.handleRowClick}
pageNo={this.props.pageNo}
pageSize={
isVisibleHeaderOptions ? Math.max(1, pageSize) : pageSize + 1
}
prevPageClick={this.handlePrevPageClick}
searchKey={this.props.searchText}
searchTableData={this.handleSearchTable}
selectAllRow={this.handleAllRowSelect}
selectedRowIndex={
this.props.selectedRowIndex === undefined
? -1
: this.props.selectedRowIndex
}
selectedRowIndices={this.getSelectedRowIndices()}
serverSidePaginationEnabled={!!this.props.serverSidePaginationEnabled}
sortTableColumn={this.handleColumnSorting}
tableData={transformedData}
triggerRowSelection={this.props.triggerRowSelection}
unSelectAllRow={this.resetSelectedRowIndex}
updateCompactMode={this.handleCompactModeChange}
updatePageNo={this.updatePageNumber}
widgetId={this.props.widgetId}
widgetName={this.props.widgetName}
width={componentWidth}
/>
</Suspense>
);
}
handleCompactModeChange = (compactMode: CompactMode) => {
if (this.props.renderMode === RenderModes.CANVAS) {
super.updateWidgetProperty("compactMode", compactMode);
} else {
this.props.updateWidgetMetaProperty("compactMode", compactMode);
}
};
handleReorderColumn = (columnOrder: string[]) => {
if (this.props.renderMode === RenderModes.CANVAS) {
super.updateWidgetProperty("columnOrder", columnOrder);
} else this.props.updateWidgetMetaProperty("columnOrder", columnOrder);
};
handleColumnSorting = (column: string, asc: boolean) => {
this.resetSelectedRowIndex();
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 }) => {
if (this.props.renderMode === RenderModes.CANVAS) {
super.updateWidgetProperty("columnSizeMap", columnSizeMap);
} else {
this.props.updateWidgetMetaProperty("columnSizeMap", columnSizeMap);
}
};
handleSearchTable = (searchKey: any) => {
const { onSearchTextChanged } = this.props;
this.resetSelectedRowIndex();
this.props.updateWidgetMetaProperty("pageNo", 1);
this.props.updateWidgetMetaProperty("searchText", searchKey, {
triggerPropertyName: "onSearchTextChanged",
dynamicString: onSearchTextChanged,
event: {
type: EventType.ON_SEARCH,
},
});
};
onCommandClick = (
rowIndex: number,
action: string,
onComplete: () => void,
) => {
try {
const rowData = [this.props.filteredTableData[rowIndex]];
const { jsSnippets } = getDynamicBindings(action);
const modifiedAction = jsSnippets.reduce((prev: string, next: string) => {
return prev + `{{(currentRow) => { ${next} }}} `;
}, "");
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: modifiedAction,
event: {
type: EventType.ON_CLICK,
callback: onComplete,
},
responseData: rowData,
});
} catch (error) {
log.debug("Error parsing row action", error);
}
};
onItemSelect = (action: string) => {
super.executeAction({
dynamicString: action,
event: {
type: EventType.ON_OPTION_CHANGE,
},
});
};
handleAllRowSelect = (pageData: Record<string, unknown>[]) => {
if (this.props.multiRowSelection) {
const selectedRowIndices = pageData.map(
(row: Record<string, unknown>) => row.index,
);
this.props.updateWidgetMetaProperty(
"selectedRowIndices",
selectedRowIndices,
);
}
};
handleRowClick = (rowData: Record<string, unknown>, index: number) => {
if (this.props.multiRowSelection) {
const selectedRowIndices = this.props.selectedRowIndices
? [...this.props.selectedRowIndices]
: [];
if (selectedRowIndices.includes(index)) {
const rowIndex = selectedRowIndices.indexOf(index);
selectedRowIndices.splice(rowIndex, 1);
} else {
selectedRowIndices.push(index);
}
this.props.updateWidgetMetaProperty(
"selectedRowIndices",
selectedRowIndices,
);
} else {
const selectedRowIndex = isNumber(this.props.selectedRowIndex)
? this.props.selectedRowIndex
: -1;
if (selectedRowIndex !== index) {
this.props.updateWidgetMetaProperty("selectedRowIndex", index, {
triggerPropertyName: "onRowSelected",
dynamicString: this.props.onRowSelected,
event: {
type: EventType.ON_ROW_SELECTED,
},
});
}
}
};
updatePageNumber = (pageNo: number, event?: EventType) => {
if (event) {
this.props.updateWidgetMetaProperty("pageNo", pageNo, {
triggerPropertyName: "onPageChange",
dynamicString: this.props.onPageChange,
event: {
type: event,
},
});
} else {
this.props.updateWidgetMetaProperty("pageNo", pageNo);
}
if (this.props.onPageChange) {
this.resetSelectedRowIndex();
}
};
handleNextPageClick = () => {
let pageNo = this.props.pageNo || 1;
pageNo = pageNo + 1;
this.props.updateWidgetMetaProperty("pageNo", pageNo, {
triggerPropertyName: "onPageChange",
dynamicString: this.props.onPageChange,
event: {
type: EventType.ON_NEXT_PAGE,
},
});
if (this.props.onPageChange) {
this.resetSelectedRowIndex();
}
};
resetSelectedRowIndex = () => {
if (!this.props.multiRowSelection) {
const selectedRowIndex = isNumber(this.props.defaultSelectedRow)
? this.props.defaultSelectedRow
: -1;
this.props.updateWidgetMetaProperty("selectedRowIndex", selectedRowIndex);
} else {
const selectedRowIndices = Array.isArray(this.props.defaultSelectedRow)
? this.props.defaultSelectedRow
: [];
this.props.updateWidgetMetaProperty(
"selectedRowIndices",
selectedRowIndices,
);
}
};
handlePrevPageClick = () => {
let pageNo = this.props.pageNo || 1;
pageNo = pageNo - 1;
if (pageNo >= 1) {
this.props.updateWidgetMetaProperty("pageNo", pageNo, {
triggerPropertyName: "onPageChange",
dynamicString: this.props.onPageChange,
event: {
type: EventType.ON_PREV_PAGE,
},
});
if (this.props.onPageChange) {
this.resetSelectedRowIndex();
}
}
};
getWidgetType(): WidgetType {
return "TABLE_WIDGET";
}
}
export default TableWidget;
export const ProfiledTableWidget = Sentry.withProfiler(withMeta(TableWidget));