2020-07-14 07:55:46 +00:00
|
|
|
import React, { useEffect } from "react";
|
2020-06-03 10:50:10 +00:00
|
|
|
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
2020-08-10 11:16:13 +00:00
|
|
|
import Table from "components/designSystems/appsmith/Table";
|
2020-06-03 10:50:10 +00:00
|
|
|
import { RenderMode, RenderModes } from "constants/WidgetConstants";
|
2020-07-03 08:26:04 +00:00
|
|
|
import { debounce } from "lodash";
|
2020-08-10 11:16:13 +00:00
|
|
|
import { getMenuOptions } from "components/designSystems/appsmith/TableUtilities";
|
2020-07-20 06:04:05 +00:00
|
|
|
import {
|
2020-08-10 11:16:13 +00:00
|
|
|
ColumnTypes,
|
|
|
|
|
CompactMode,
|
|
|
|
|
ReactTableColumnProps,
|
|
|
|
|
ReactTableFilter,
|
|
|
|
|
} from "widgets/TableWidget";
|
2020-06-03 10:50:10 +00:00
|
|
|
|
|
|
|
|
export interface ColumnMenuOptionProps {
|
|
|
|
|
content: string | JSX.Element;
|
|
|
|
|
closeOnClick?: boolean;
|
|
|
|
|
isSelected?: boolean;
|
2020-07-14 07:55:46 +00:00
|
|
|
editColumnName?: boolean;
|
2020-06-03 10:50:10 +00:00
|
|
|
columnAccessor?: string;
|
|
|
|
|
id?: string;
|
|
|
|
|
category?: boolean;
|
|
|
|
|
options?: ColumnMenuSubOptionProps[];
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick?: (columnIndex: number, isSelected: boolean) => void;
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ColumnMenuSubOptionProps {
|
|
|
|
|
content: string;
|
|
|
|
|
isSelected: boolean;
|
|
|
|
|
closeOnClick: boolean;
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => void;
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface ReactTableComponentProps {
|
|
|
|
|
widgetId: string;
|
2020-07-20 06:04:05 +00:00
|
|
|
widgetName: string;
|
2020-07-03 08:26:04 +00:00
|
|
|
searchKey: string;
|
2020-06-03 10:50:10 +00:00
|
|
|
isDisabled?: boolean;
|
|
|
|
|
isVisible?: boolean;
|
2020-07-02 06:26:01 +00:00
|
|
|
isLoading: boolean;
|
2020-06-03 10:50:10 +00:00
|
|
|
renderMode: RenderMode;
|
|
|
|
|
width: number;
|
|
|
|
|
height: number;
|
|
|
|
|
pageSize: number;
|
|
|
|
|
tableData: object[];
|
|
|
|
|
columnOrder?: string[];
|
|
|
|
|
disableDrag: (disable: boolean) => void;
|
|
|
|
|
onRowClick: (rowData: object, rowIndex: number) => void;
|
2020-07-14 07:55:46 +00:00
|
|
|
onCommandClick: (dynamicTrigger: string, onComplete: () => void) => void;
|
2020-06-03 10:50:10 +00:00
|
|
|
updatePageNo: Function;
|
2020-07-03 08:26:04 +00:00
|
|
|
updateHiddenColumns: (hiddenColumns?: string[]) => void;
|
2020-08-10 06:45:31 +00:00
|
|
|
sortTableColumn: (column: string, asc: boolean) => void;
|
2020-06-03 10:50:10 +00:00
|
|
|
nextPageClick: Function;
|
|
|
|
|
prevPageClick: Function;
|
|
|
|
|
pageNo: number;
|
|
|
|
|
serverSidePaginationEnabled: boolean;
|
|
|
|
|
columnActions?: ColumnAction[];
|
|
|
|
|
selectedRowIndex: number;
|
|
|
|
|
hiddenColumns?: string[];
|
|
|
|
|
columnNameMap?: { [key: string]: string };
|
|
|
|
|
columnTypeMap?: {
|
|
|
|
|
[key: string]: {
|
|
|
|
|
type: string;
|
|
|
|
|
format: string;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
columnSizeMap?: { [key: string]: number };
|
|
|
|
|
updateColumnType: Function;
|
|
|
|
|
updateColumnName: Function;
|
|
|
|
|
handleResizeColumn: Function;
|
|
|
|
|
handleReorderColumn: Function;
|
2020-07-03 08:26:04 +00:00
|
|
|
searchTableData: (searchKey: any) => void;
|
2020-08-10 11:16:13 +00:00
|
|
|
filters?: ReactTableFilter[];
|
|
|
|
|
applyFilter: (filters: ReactTableFilter[]) => void;
|
2020-07-20 06:04:05 +00:00
|
|
|
columns: ReactTableColumnProps[];
|
2020-08-10 10:01:36 +00:00
|
|
|
compactMode?: CompactMode;
|
|
|
|
|
updateCompactMode: (compactMode: CompactMode) => void;
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const ReactTableComponent = (props: ReactTableComponentProps) => {
|
|
|
|
|
useEffect(() => {
|
2020-08-10 11:16:13 +00:00
|
|
|
let dragged = -1;
|
2020-07-14 07:55:46 +00:00
|
|
|
const headers = Array.prototype.slice.call(
|
|
|
|
|
document.querySelectorAll(`#table${props.widgetId} .draggable-header`),
|
|
|
|
|
);
|
|
|
|
|
headers.forEach((header, i) => {
|
|
|
|
|
header.setAttribute("draggable", true);
|
|
|
|
|
|
|
|
|
|
header.ondragstart = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
header.style =
|
|
|
|
|
"background: #efefef; border-radius: 4px; z-index: 100; width: 100%; text-overflow: none; overflow: none;";
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
dragged = i;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
header.ondrag = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
header.ondragend = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
header.style = "";
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setTimeout(() => (dragged = -1), 1000);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// the dropped header
|
|
|
|
|
header.ondragover = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
if (i !== dragged && dragged !== -1) {
|
|
|
|
|
if (dragged > i) {
|
|
|
|
|
header.parentElement.className = "th header-reorder highlight-left";
|
|
|
|
|
} else if (dragged < i) {
|
|
|
|
|
header.parentElement.className =
|
|
|
|
|
"th header-reorder highlight-right";
|
|
|
|
|
}
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
2020-07-14 07:55:46 +00:00
|
|
|
e.preventDefault();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
header.ondragenter = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
if (i !== dragged && dragged !== -1) {
|
|
|
|
|
if (dragged > i) {
|
|
|
|
|
header.parentElement.className = "th header-reorder highlight-left";
|
|
|
|
|
} else if (dragged < i) {
|
|
|
|
|
header.parentElement.className =
|
|
|
|
|
"th header-reorder highlight-right";
|
|
|
|
|
}
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
2020-07-14 07:55:46 +00:00
|
|
|
e.preventDefault();
|
|
|
|
|
};
|
2020-06-03 10:50:10 +00:00
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
header.ondragleave = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
header.parentElement.className = "th header-reorder";
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
header.ondrop = (e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
header.style = "";
|
|
|
|
|
header.parentElement.className = "th header-reorder";
|
|
|
|
|
if (i !== dragged && dragged !== -1) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
let columnOrder = props.columnOrder;
|
|
|
|
|
if (columnOrder === undefined) {
|
2020-07-20 06:04:05 +00:00
|
|
|
columnOrder = props.columns.map(item => item.accessor);
|
2020-07-14 07:55:46 +00:00
|
|
|
}
|
2020-07-20 06:04:05 +00:00
|
|
|
const draggedColumn = props.columns[dragged].accessor;
|
2020-07-14 07:55:46 +00:00
|
|
|
columnOrder.splice(dragged, 1);
|
|
|
|
|
columnOrder.splice(i, 0, draggedColumn);
|
|
|
|
|
props.handleReorderColumn(columnOrder);
|
|
|
|
|
} else {
|
|
|
|
|
dragged = -1;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const getColumnMenu = (columnIndex: number) => {
|
2020-07-20 06:04:05 +00:00
|
|
|
const column = props.columns[columnIndex];
|
2020-07-14 07:55:46 +00:00
|
|
|
const columnId = column.accessor;
|
|
|
|
|
const columnType =
|
|
|
|
|
props.columnTypeMap && props.columnTypeMap[columnId]
|
|
|
|
|
? props.columnTypeMap[columnId].type
|
|
|
|
|
: "";
|
|
|
|
|
const format =
|
|
|
|
|
props.columnTypeMap && props.columnTypeMap[columnId]
|
|
|
|
|
? props.columnTypeMap[columnId].format
|
|
|
|
|
: "";
|
2020-06-03 10:50:10 +00:00
|
|
|
const isColumnHidden = !!(
|
2020-07-14 07:55:46 +00:00
|
|
|
props.hiddenColumns && props.hiddenColumns.includes(columnId)
|
2020-06-03 10:50:10 +00:00
|
|
|
);
|
|
|
|
|
const columnMenuOptions: ColumnMenuOptionProps[] = getMenuOptions({
|
|
|
|
|
columnAccessor: columnId,
|
|
|
|
|
isColumnHidden,
|
|
|
|
|
columnType,
|
|
|
|
|
format,
|
2020-07-14 07:55:46 +00:00
|
|
|
hideColumn: hideColumn,
|
|
|
|
|
updateColumnType: updateColumnType,
|
|
|
|
|
handleUpdateCurrencySymbol: handleUpdateCurrencySymbol,
|
|
|
|
|
handleDateFormatUpdate: handleDateFormatUpdate,
|
2020-06-03 10:50:10 +00:00
|
|
|
});
|
|
|
|
|
return columnMenuOptions;
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const hideColumn = (columnIndex: number, isColumnHidden: boolean) => {
|
2020-07-20 06:04:05 +00:00
|
|
|
const column = props.columns[columnIndex];
|
2020-07-14 07:55:46 +00:00
|
|
|
let hiddenColumns = props.hiddenColumns || [];
|
2020-06-03 10:50:10 +00:00
|
|
|
if (!isColumnHidden) {
|
|
|
|
|
hiddenColumns.push(column.accessor);
|
2020-07-14 07:55:46 +00:00
|
|
|
const columnOrder = props.columnOrder || [];
|
2020-06-03 10:50:10 +00:00
|
|
|
if (columnOrder.includes(column.accessor)) {
|
|
|
|
|
columnOrder.splice(columnOrder.indexOf(column.accessor), 1);
|
2020-07-14 07:55:46 +00:00
|
|
|
props.handleReorderColumn(columnOrder);
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
hiddenColumns = hiddenColumns.filter(item => {
|
|
|
|
|
return item !== column.accessor;
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-07-14 07:55:46 +00:00
|
|
|
props.updateHiddenColumns(hiddenColumns);
|
2020-06-03 10:50:10 +00:00
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const updateColumnType = (columnIndex: number, columnType: string) => {
|
2020-07-20 06:04:05 +00:00
|
|
|
const column = props.columns[columnIndex];
|
2020-07-14 07:55:46 +00:00
|
|
|
const columnTypeMap = props.columnTypeMap || {};
|
2020-06-03 10:50:10 +00:00
|
|
|
columnTypeMap[column.accessor] = {
|
|
|
|
|
type: columnType,
|
|
|
|
|
format: "",
|
|
|
|
|
};
|
2020-07-14 07:55:46 +00:00
|
|
|
props.updateColumnType(columnTypeMap);
|
2020-06-03 10:50:10 +00:00
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const handleColumnNameUpdate = (columnIndex: number, columnName: string) => {
|
2020-07-20 06:04:05 +00:00
|
|
|
const column = props.columns[columnIndex];
|
2020-07-14 07:55:46 +00:00
|
|
|
const columnNameMap = props.columnNameMap || {};
|
2020-06-03 10:50:10 +00:00
|
|
|
columnNameMap[column.accessor] = columnName;
|
2020-07-14 07:55:46 +00:00
|
|
|
props.updateColumnName(columnNameMap);
|
2020-06-03 10:50:10 +00:00
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const handleUpdateCurrencySymbol = (
|
2020-06-22 08:25:03 +00:00
|
|
|
columnIndex: number,
|
|
|
|
|
currencySymbol: string,
|
|
|
|
|
) => {
|
2020-07-20 06:04:05 +00:00
|
|
|
const column = props.columns[columnIndex];
|
2020-07-14 07:55:46 +00:00
|
|
|
const columnTypeMap = props.columnTypeMap || {};
|
2020-06-03 10:50:10 +00:00
|
|
|
columnTypeMap[column.accessor] = {
|
|
|
|
|
type: "currency",
|
|
|
|
|
format: currencySymbol,
|
|
|
|
|
};
|
2020-07-14 07:55:46 +00:00
|
|
|
props.updateColumnType(columnTypeMap);
|
2020-06-03 10:50:10 +00:00
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const handleDateFormatUpdate = (columnIndex: number, dateFormat: string) => {
|
2020-07-20 06:04:05 +00:00
|
|
|
const column = props.columns[columnIndex];
|
2020-07-14 07:55:46 +00:00
|
|
|
const columnTypeMap = props.columnTypeMap || {};
|
2020-06-03 10:50:10 +00:00
|
|
|
columnTypeMap[column.accessor] = {
|
|
|
|
|
type: "date",
|
|
|
|
|
format: dateFormat,
|
|
|
|
|
};
|
2020-07-14 07:55:46 +00:00
|
|
|
props.updateColumnType(columnTypeMap);
|
2020-06-03 10:50:10 +00:00
|
|
|
};
|
|
|
|
|
|
2020-08-10 06:45:31 +00:00
|
|
|
const sortTableColumn = (columnIndex: number, asc: boolean) => {
|
|
|
|
|
const column = props.columns[columnIndex];
|
|
|
|
|
const columnType = column.metaProperties?.type || ColumnTypes.TEXT;
|
|
|
|
|
if (columnType !== ColumnTypes.IMAGE && columnType !== ColumnTypes.VIDEO) {
|
|
|
|
|
props.sortTableColumn(column.accessor, asc);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const handleResizeColumn = (columnIndex: number, columnWidth: string) => {
|
2020-07-20 06:04:05 +00:00
|
|
|
const column = props.columns[columnIndex];
|
2020-07-14 07:55:46 +00:00
|
|
|
const columnSizeMap = props.columnSizeMap || {};
|
2020-06-03 10:50:10 +00:00
|
|
|
const width = Number(columnWidth.split("px")[0]);
|
|
|
|
|
columnSizeMap[column.accessor] = width;
|
2020-07-14 07:55:46 +00:00
|
|
|
props.handleResizeColumn(columnSizeMap);
|
2020-06-03 10:50:10 +00:00
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
const selectTableRow = (
|
2020-06-03 10:50:10 +00:00
|
|
|
row: { original: object; index: number },
|
|
|
|
|
isSelected: boolean,
|
|
|
|
|
) => {
|
|
|
|
|
if (!isSelected) {
|
2020-07-14 07:55:46 +00:00
|
|
|
props.onRowClick(row.original, row.index);
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
return (
|
|
|
|
|
<Table
|
|
|
|
|
isLoading={props.isLoading}
|
|
|
|
|
width={props.width}
|
|
|
|
|
height={props.height}
|
|
|
|
|
pageSize={props.pageSize || 1}
|
|
|
|
|
widgetId={props.widgetId}
|
2020-07-20 06:04:05 +00:00
|
|
|
widgetName={props.widgetName}
|
2020-07-14 07:55:46 +00:00
|
|
|
searchKey={props.searchKey}
|
2020-07-20 06:04:05 +00:00
|
|
|
columns={props.columns}
|
2020-07-14 07:55:46 +00:00
|
|
|
hiddenColumns={props.hiddenColumns}
|
|
|
|
|
updateHiddenColumns={props.updateHiddenColumns}
|
|
|
|
|
data={props.tableData}
|
|
|
|
|
displayColumnActions={props.renderMode === RenderModes.CANVAS}
|
|
|
|
|
columnNameMap={props.columnNameMap}
|
|
|
|
|
getColumnMenu={getColumnMenu}
|
|
|
|
|
handleColumnNameUpdate={handleColumnNameUpdate}
|
|
|
|
|
handleResizeColumn={debounce(handleResizeColumn, 300)}
|
2020-08-10 06:45:31 +00:00
|
|
|
sortTableColumn={sortTableColumn}
|
2020-07-14 07:55:46 +00:00
|
|
|
selectTableRow={selectTableRow}
|
|
|
|
|
pageNo={props.pageNo - 1}
|
|
|
|
|
updatePageNo={props.updatePageNo}
|
2020-07-28 14:26:27 +00:00
|
|
|
columnActions={props.columnActions}
|
2020-07-14 07:55:46 +00:00
|
|
|
nextPageClick={() => {
|
|
|
|
|
props.nextPageClick();
|
|
|
|
|
}}
|
|
|
|
|
prevPageClick={() => {
|
|
|
|
|
props.prevPageClick();
|
|
|
|
|
}}
|
|
|
|
|
serverSidePaginationEnabled={props.serverSidePaginationEnabled}
|
|
|
|
|
selectedRowIndex={props.selectedRowIndex}
|
|
|
|
|
disableDrag={() => {
|
|
|
|
|
props.disableDrag(true);
|
|
|
|
|
}}
|
|
|
|
|
enableDrag={() => {
|
|
|
|
|
props.disableDrag(false);
|
|
|
|
|
}}
|
|
|
|
|
searchTableData={debounce(props.searchTableData, 500)}
|
2020-08-10 11:16:13 +00:00
|
|
|
filters={props.filters}
|
|
|
|
|
applyFilter={props.applyFilter}
|
2020-08-10 10:01:36 +00:00
|
|
|
compactMode={props.compactMode}
|
|
|
|
|
updateCompactMode={props.updateCompactMode}
|
2020-07-14 07:55:46 +00:00
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
};
|
2020-06-03 10:50:10 +00:00
|
|
|
|
|
|
|
|
export default ReactTableComponent;
|