PromucFlow_constructor/app/client/src/components/designSystems/appsmith/TableUtilities.tsx

834 lines
24 KiB
TypeScript
Raw Normal View History

import React, { useState } from "react";
import { Icon, InputGroup } from "@blueprintjs/core";
2020-06-03 10:50:10 +00:00
import {
MenuColumnWrapper,
CellWrapper,
ActionWrapper,
SortIconWrapper,
2020-06-03 10:50:10 +00:00
} from "./TableStyledWrappers";
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
import { ColumnMenuOptionProps } from "components/designSystems/appsmith/ReactTableComponent";
import {
ReactTableColumnProps,
ColumnTypes,
Condition,
} from "widgets/TableWidget";
import { isString, isNumber } from "lodash";
2020-06-22 13:46:19 +00:00
import VideoComponent from "components/designSystems/appsmith/VideoComponent";
import Button from "components/editorComponents/Button";
import AutoToolTipComponent from "components/designSystems/appsmith/AutoToolTipComponent";
import TableColumnMenuPopup from "./TableColumnMenu";
import { ControlIcons } from "icons/ControlIcons";
import { AnyStyledComponent } from "styled-components";
import styled from "constants/DefaultTheme";
import { Colors } from "constants/Colors";
import moment from "moment";
2020-06-03 10:50:10 +00:00
interface MenuOptionProps {
columnAccessor?: string;
isColumnHidden: boolean;
columnType: string;
format?: string;
hideColumn: (columnIndex: number, isColumnHidden: boolean) => void;
updateColumnType: (columnIndex: number, columnType: string) => void;
handleUpdateCurrencySymbol: (
columnIndex: number,
currencySymbol: string,
) => void;
handleDateFormatUpdate: (columnIndex: number, dateFormat: string) => void;
2020-06-03 10:50:10 +00:00
}
export const getMenuOptions = (props: MenuOptionProps) => {
const basicOptions: ColumnMenuOptionProps[] = [
{
content: "Rename a Column",
closeOnClick: true,
id: "rename_column",
editColumnName: true,
2020-06-03 10:50:10 +00:00
},
{
content: props.isColumnHidden ? "Show Column" : "Hide Column",
closeOnClick: true,
id: "hide_column",
onClick: (columnIndex: number) => {
props.hideColumn(columnIndex, props.isColumnHidden);
2020-06-03 10:50:10 +00:00
},
},
];
if (props.columnAccessor && props.columnAccessor === "actions") {
return basicOptions;
}
const columnMenuOptions: ColumnMenuOptionProps[] = [
...basicOptions,
{
content: "Select a Data Type",
id: "change_column_type",
category: true,
},
{
content: (
<MenuColumnWrapper selected={props.columnType === ColumnTypes.IMAGE}>
2020-06-03 10:50:10 +00:00
<Icon
icon="media"
iconSize={12}
color={
props.columnType === ColumnTypes.IMAGE
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
<div className="title">Image</div>
</MenuColumnWrapper>
),
closeOnClick: true,
isSelected: props.columnType === ColumnTypes.IMAGE,
onClick: (columnIndex: number, isSelected: boolean) => {
2020-06-03 10:50:10 +00:00
if (isSelected) {
props.updateColumnType(columnIndex, "");
2020-06-03 10:50:10 +00:00
} else {
props.updateColumnType(columnIndex, ColumnTypes.IMAGE);
2020-06-03 10:50:10 +00:00
}
},
},
{
content: (
<MenuColumnWrapper selected={props.columnType === ColumnTypes.VIDEO}>
2020-06-03 10:50:10 +00:00
<Icon
icon="video"
iconSize={12}
color={
props.columnType === ColumnTypes.VIDEO
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
<div className="title">Video</div>
</MenuColumnWrapper>
),
isSelected: props.columnType === ColumnTypes.VIDEO,
2020-06-03 10:50:10 +00:00
closeOnClick: true,
onClick: (columnIndex: number, isSelected: boolean) => {
2020-06-03 10:50:10 +00:00
if (isSelected) {
props.updateColumnType(columnIndex, "");
2020-06-03 10:50:10 +00:00
} else {
props.updateColumnType(columnIndex, ColumnTypes.VIDEO);
2020-06-03 10:50:10 +00:00
}
},
},
{
content: (
<MenuColumnWrapper selected={props.columnType === ColumnTypes.TEXT}>
2020-06-03 10:50:10 +00:00
<Icon
icon="label"
iconSize={12}
color={
props.columnType === ColumnTypes.TEXT
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
<div className="title">Text</div>
</MenuColumnWrapper>
),
closeOnClick: true,
isSelected: props.columnType === ColumnTypes.TEXT,
onClick: (columnIndex: number, isSelected: boolean) => {
2020-06-03 10:50:10 +00:00
if (isSelected) {
props.updateColumnType(columnIndex, "");
2020-06-03 10:50:10 +00:00
} else {
props.updateColumnType(columnIndex, ColumnTypes.TEXT);
2020-06-03 10:50:10 +00:00
}
},
},
{
content: (
<MenuColumnWrapper selected={props.columnType === ColumnTypes.CURRENCY}>
2020-06-03 10:50:10 +00:00
<Icon
icon="dollar"
iconSize={12}
color={
props.columnType === ColumnTypes.CURRENCY
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
<div className="title">Currency</div>
<Icon
className="sub-menu"
icon="chevron-right"
iconSize={16}
color={
props.columnType === ColumnTypes.CURRENCY
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
</MenuColumnWrapper>
),
closeOnClick: false,
isSelected: props.columnType === ColumnTypes.CURRENCY,
2020-06-03 10:50:10 +00:00
options: [
{
content: "USD - $",
isSelected: props.format === "$",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleUpdateCurrencySymbol(columnIndex, "$");
2020-06-03 10:50:10 +00:00
},
},
{
content: "INR - ₹",
isSelected: props.format === "₹",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleUpdateCurrencySymbol(columnIndex, "₹");
2020-06-03 10:50:10 +00:00
},
},
{
content: "GBP - £",
isSelected: props.format === "£",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleUpdateCurrencySymbol(columnIndex, "£");
2020-06-03 10:50:10 +00:00
},
},
{
content: "AUD - A$",
isSelected: props.format === "A$",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleUpdateCurrencySymbol(columnIndex, "A$");
2020-06-03 10:50:10 +00:00
},
},
{
content: "EUR - €",
isSelected: props.format === "€",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleUpdateCurrencySymbol(columnIndex, "€");
2020-06-03 10:50:10 +00:00
},
},
{
content: "SGD - S$",
isSelected: props.format === "S$",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleUpdateCurrencySymbol(columnIndex, "S$");
2020-06-03 10:50:10 +00:00
},
},
{
content: "CAD - C$",
isSelected: props.format === "C$",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleUpdateCurrencySymbol(columnIndex, "C$");
2020-06-03 10:50:10 +00:00
},
},
],
},
{
content: (
<MenuColumnWrapper selected={props.columnType === ColumnTypes.DATE}>
2020-06-03 10:50:10 +00:00
<Icon
icon="calendar"
iconSize={12}
color={
props.columnType === ColumnTypes.DATE
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
<div className="title">Date</div>
<Icon
className="sub-menu"
icon="chevron-right"
iconSize={16}
color={
props.columnType === ColumnTypes.DATE
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
</MenuColumnWrapper>
),
closeOnClick: false,
isSelected: props.columnType === ColumnTypes.DATE,
2020-06-03 10:50:10 +00:00
options: [
{
content: "MM-DD-YY",
isSelected: props.format === "MM-DD-YY",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleDateFormatUpdate(columnIndex, "MM-DD-YY");
2020-06-03 10:50:10 +00:00
},
},
{
content: "DD-MM-YY",
isSelected: props.format === "DD-MM-YY",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleDateFormatUpdate(columnIndex, "DD-MM-YY");
2020-06-03 10:50:10 +00:00
},
},
{
content: "DD/MM/YY",
isSelected: props.format === "DD/MM/YY",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleDateFormatUpdate(columnIndex, "DD/MM/YY");
2020-06-03 10:50:10 +00:00
},
},
{
content: "MM/DD/YY",
isSelected: props.format === "MM/DD/YY",
closeOnClick: true,
onClick: (columnIndex: number) => {
props.handleDateFormatUpdate(columnIndex, "MM/DD/YY");
2020-06-03 10:50:10 +00:00
},
},
],
},
{
content: (
<MenuColumnWrapper selected={props.columnType === ColumnTypes.TIME}>
2020-06-03 10:50:10 +00:00
<Icon
icon="time"
iconSize={12}
color={
props.columnType === ColumnTypes.TIME
? Colors.WHITE
: Colors.OXFORD_BLUE
}
2020-06-03 10:50:10 +00:00
/>
<div className="title">Time</div>
</MenuColumnWrapper>
),
closeOnClick: true,
isSelected: props.columnType === ColumnTypes.TIME,
onClick: (columnIndex: number, isSelected: boolean) => {
2020-06-03 10:50:10 +00:00
if (isSelected) {
props.updateColumnType(columnIndex, "");
2020-06-03 10:50:10 +00:00
} else {
props.updateColumnType(columnIndex, ColumnTypes.TIME);
2020-06-03 10:50:10 +00:00
}
},
},
{
content: (
<MenuColumnWrapper selected={props.columnType === ColumnTypes.NUMBER}>
<Icon
icon="numerical"
iconSize={12}
color={
props.columnType === ColumnTypes.NUMBER
? Colors.WHITE
: Colors.OXFORD_BLUE
}
/>
<div className="title">Number</div>
</MenuColumnWrapper>
),
closeOnClick: true,
isSelected: props.columnType === ColumnTypes.NUMBER,
onClick: (columnIndex: number, isSelected: boolean) => {
if (isSelected) {
props.updateColumnType(columnIndex, "");
} else {
props.updateColumnType(columnIndex, ColumnTypes.NUMBER);
}
},
},
2020-06-03 10:50:10 +00:00
];
return columnMenuOptions;
};
export const renderCell = (
value: any,
columnType: string,
isHidden: boolean,
) => {
switch (columnType) {
case ColumnTypes.IMAGE:
if (!value) {
return <CellWrapper isHidden={isHidden}></CellWrapper>;
} else if (!isString(value)) {
2020-06-16 07:37:39 +00:00
return (
<CellWrapper isHidden={isHidden}>
<div>Invalid Image </div>
</CellWrapper>
);
}
const imageRegex = /(http(s?):)([/|.|\w|\s|-])*\.(?:jpeg|jpg|gif|png)??(?:&?[^=&]*=[^=&]*)*/;
2020-06-03 10:50:10 +00:00
return (
<CellWrapper isHidden={isHidden}>
{value
.toString()
.split(",")
.map((item: string, index: number) => {
if (imageRegex.test(item)) {
2020-06-03 10:50:10 +00:00
return (
Fix-Open image in new tab on clicking it in table widget. (#119) * Added Button component in Table widget for actions * Action button state loading added for Table widget * Action button font-weight made as normal * Created header for common functionalities in Table Widget * Client side searching added in Table Widget. Action created for server side searching also. * Columns visibility feature initial commit * Column visibility list added in Table Widget * Changed pagination designs in accordance with new layout. This enable user to jump page as well. * Using colors values from constants * Table widget pagination, numeric input page number clamped between 1 and total pages * Adding tool tip to truncated values in table widget. Added AutoToolTipComponent that adds tooltip when text is truncated. * Table data download changes. Added downlaod icon and button to table widget. * Table data download changes * Table button loading state fixed. Table code refactored, rendering from props instead of state in ReactTableComponent * Table widget action button alignment fixed * Handled actions column changes * added proper keys to useMemo for react table widget * Download table data as CSV implemented * table data download, unused code removed * Code refactors and added dependency map with meta props and table data for computing columns * Table UI breakages on scroll and empty cells fixed * Handled empty rows in table widget * Fixed last row cut issue * Code review changes * Code review changes * Added table widget component heights as enum * code review changes * Search component in Table widget updated with support for clearing data, renamed properties * Opening image in new tab on clicking in table widget * Fixed table craching due to empty data filtering * Empty extra space on loading removed in table widget * Removed stopping of event propagation on table widget action button click * Table header UI overflow fixed * Clearing selected row on searching data in table widget * fix for cypress test Co-authored-by: Arpit Mohan <me@arpitmohan.com>
2020-07-24 10:32:31 +00:00
<a
onClick={e => e.stopPropagation()}
target="_blank"
rel="noopener noreferrer"
href={item}
>
<div
key={index}
className="image-cell"
style={{ backgroundImage: `url("${item}")` }}
/>
</a>
2020-06-03 10:50:10 +00:00
);
} else {
return <div>Invalid Image</div>;
}
})}
</CellWrapper>
);
case ColumnTypes.VIDEO:
const youtubeRegex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=|\?v=)([^#&?]*).*/;
if (!value) {
return <CellWrapper isHidden={isHidden}></CellWrapper>;
} else if (isString(value) && youtubeRegex.test(value)) {
2020-06-16 07:37:39 +00:00
return (
<CellWrapper isHidden={isHidden} className="video-cell">
2020-06-22 13:46:19 +00:00
<VideoComponent url={value} />
2020-06-16 07:37:39 +00:00
</CellWrapper>
);
} else {
return (
<CellWrapper isHidden={isHidden}>Invalid Video Link</CellWrapper>
);
}
2020-06-03 10:50:10 +00:00
default:
const data =
Fix-Search component in Table widget updated with support for clearing search data (#96) * Added Button component in Table widget for actions * Action button state loading added for Table widget * Action button font-weight made as normal * Created header for common functionalities in Table Widget * Client side searching added in Table Widget. Action created for server side searching also. * Columns visibility feature initial commit * Column visibility list added in Table Widget * Changed pagination designs in accordance with new layout. This enable user to jump page as well. * Using colors values from constants * Table widget pagination, numeric input page number clamped between 1 and total pages * Adding tool tip to truncated values in table widget. Added AutoToolTipComponent that adds tooltip when text is truncated. * Table data download changes. Added downlaod icon and button to table widget. * Table data download changes * Table button loading state fixed. Table code refactored, rendering from props instead of state in ReactTableComponent * Table widget action button alignment fixed * Handled actions column changes * added proper keys to useMemo for react table widget * Download table data as CSV implemented * table data download, unused code removed * Code refactors and added dependency map with meta props and table data for computing columns * Table UI breakages on scroll and empty cells fixed * Handled empty rows in table widget * Fixed last row cut issue * Code review changes * Code review changes * Added table widget component heights as enum * code review changes * Search component in Table widget updated with support for clearing data, renamed properties * Opening image in new tab on clicking in table widget * Fixed table craching due to empty data filtering * Empty extra space on loading removed in table widget * Removed stopping of event propagation on table widget action button click * Fixing for test cases * Table header UI overflow fixed * Clearing selected row on searching data in table widget * fix for cypress test * Table crash issue fix * searchKeyword renamed to searchText. searchText added to entity definitions Co-authored-by: Arpit Mohan <me@arpitmohan.com>
2020-07-24 13:58:28 +00:00
isString(value) || isNumber(value)
? value.toString()
: JSON.stringify(value);
return (
Fix-Search component in Table widget updated with support for clearing search data (#96) * Added Button component in Table widget for actions * Action button state loading added for Table widget * Action button font-weight made as normal * Created header for common functionalities in Table Widget * Client side searching added in Table Widget. Action created for server side searching also. * Columns visibility feature initial commit * Column visibility list added in Table Widget * Changed pagination designs in accordance with new layout. This enable user to jump page as well. * Using colors values from constants * Table widget pagination, numeric input page number clamped between 1 and total pages * Adding tool tip to truncated values in table widget. Added AutoToolTipComponent that adds tooltip when text is truncated. * Table data download changes. Added downlaod icon and button to table widget. * Table data download changes * Table button loading state fixed. Table code refactored, rendering from props instead of state in ReactTableComponent * Table widget action button alignment fixed * Handled actions column changes * added proper keys to useMemo for react table widget * Download table data as CSV implemented * table data download, unused code removed * Code refactors and added dependency map with meta props and table data for computing columns * Table UI breakages on scroll and empty cells fixed * Handled empty rows in table widget * Fixed last row cut issue * Code review changes * Code review changes * Added table widget component heights as enum * code review changes * Search component in Table widget updated with support for clearing data, renamed properties * Opening image in new tab on clicking in table widget * Fixed table craching due to empty data filtering * Empty extra space on loading removed in table widget * Removed stopping of event propagation on table widget action button click * Fixing for test cases * Table header UI overflow fixed * Clearing selected row on searching data in table widget * fix for cypress test * Table crash issue fix * searchKeyword renamed to searchText. searchText added to entity definitions Co-authored-by: Arpit Mohan <me@arpitmohan.com>
2020-07-24 13:58:28 +00:00
<AutoToolTipComponent title={data} isHidden={isHidden}>
{data}
</AutoToolTipComponent>
);
2020-06-03 10:50:10 +00:00
}
};
interface RenderActionProps {
isSelected: boolean;
2020-06-03 10:50:10 +00:00
columnActions?: ColumnAction[];
onCommandClick: (dynamicTrigger: string, onComplete: () => void) => void;
2020-06-03 10:50:10 +00:00
}
export const renderActions = (props: RenderActionProps) => {
if (!props.columnActions) return <CellWrapper isHidden={false}></CellWrapper>;
return (
<CellWrapper isHidden={false}>
{props.columnActions.map((action: ColumnAction, index: number) => {
return (
<TableAction
2020-06-03 10:50:10 +00:00
key={index}
action={action}
isSelected={props.isSelected}
onCommandClick={props.onCommandClick}
/>
);
})}
</CellWrapper>
);
};
const TableAction = (props: {
isSelected: boolean;
action: ColumnAction;
onCommandClick: (dynamicTrigger: string, onComplete: () => void) => void;
}) => {
const [loading, setLoading] = useState(false);
const onComplete = () => {
setLoading(false);
};
return (
<ActionWrapper
onClick={e => {
if (props.isSelected) {
e.stopPropagation();
}
}}
>
<Button
loading={loading}
onClick={() => {
setLoading(true);
props.onCommandClick(props.action.dynamicTrigger, onComplete);
}}
text={props.action.label}
intent="primary"
filled
size="small"
/>
</ActionWrapper>
);
};
const RenameColumn = (props: {
value: any;
columnIndex: number;
handleSave: (columnIndex: number, value: any) => void;
}) => {
const [columnName, updateColumnName] = useState(props.value);
const onKeyPress = (key: string) => {
if (key === "Enter") {
props.handleSave(props.columnIndex, columnName);
}
};
const onColumnNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
updateColumnName(event.target.value);
};
const handleColumnNameUpdate = () => {
props.handleSave(props.columnIndex, columnName);
};
return (
<InputGroup
autoFocus
type="text"
className="input-group"
placeholder="Enter Column Name"
defaultValue={columnName}
onChange={onColumnNameChange}
onKeyPress={e => onKeyPress(e.key)}
onBlur={e => handleColumnNameUpdate()}
/>
);
};
export const renderEmptyRows = (
rowCount: number,
columns: any,
tableWidth: number,
page: any,
prepareRow: any,
) => {
const rows: string[] = new Array(rowCount).fill("");
if (page.length) {
const row = page[0];
return rows.map((item: string, index: number) => {
prepareRow(row);
return (
<div {...row.getRowProps()} className="tr" key={index}>
{row.cells.map((cell: any, cellIndex: number) => {
return (
<div {...cell.getCellProps()} className="td" key={cellIndex} />
);
})}
</div>
);
});
}
const tableColumns = columns.length
? columns
: new Array(3).fill({ width: tableWidth / 3, isHidden: false });
return (
<React.Fragment>
{rows.map((row: string, index: number) => {
return (
<div
className="tr"
key={index}
style={{
display: "flex",
flex: "1 0 auto",
2020-06-03 10:50:10 +00:00
}}
>
{tableColumns.map((column: any, colIndex: number) => {
return (
<div
key={colIndex}
className="td"
style={{
width: column.width + "px",
boxSizing: "border-box",
flex: `${column.width} 0 auto`,
}}
/>
);
})}
</div>
2020-06-03 10:50:10 +00:00
);
})}
</React.Fragment>
);
};
const SortIcon = styled(ControlIcons.SORT_CONTROL as AnyStyledComponent)`
padding: 0;
position: relative;
top: 3px;
cursor: pointer;
svg {
path {
fill: ${props => props.theme.colors.secondary};
}
}
`;
export const TableHeaderCell = (props: {
columnName: string;
columnIndex: number;
isHidden: boolean;
isAscOrder?: boolean;
displayColumnActions: boolean;
handleColumnNameUpdate: (columnIndex: number, name: string) => void;
getColumnMenu: (columnIndex: number) => ColumnMenuOptionProps[];
sortTableColumn: (columnIndex: number, asc: boolean) => void;
handleResizeColumn: Function;
column: any;
}) => {
const { column } = props;
const [renameColumn, toggleRenameColumn] = React.useState(false);
const handleSaveColumnName = (columnIndex: number, columName: string) => {
props.handleColumnNameUpdate(columnIndex, columName);
toggleRenameColumn(false);
};
const handleSortColumn = () => {
props.sortTableColumn(
props.columnIndex,
props.isAscOrder === undefined ? true : !props.isAscOrder,
);
};
if (column.isResizing) {
props.handleResizeColumn(
props.columnIndex,
column.getHeaderProps().style.width,
);
}
return (
<div
{...column.getHeaderProps()}
className="th header-reorder"
onClick={handleSortColumn}
>
{props.isAscOrder !== undefined ? (
<SortIconWrapper rotate={!props.isAscOrder}>
<SortIcon height={16} width={16} />
</SortIconWrapper>
) : null}
{renameColumn && (
<RenameColumn
value={props.columnName}
handleSave={handleSaveColumnName}
columnIndex={props.columnIndex}
/>
)}
{!renameColumn && (
<div
className={
!props.isHidden
? `draggable-header ${
props.isAscOrder !== undefined ? "sorted" : ""
}`
: "hidden-header"
}
>
{column.render("Header")}
</div>
)}
{props.displayColumnActions && (
<div className="column-menu">
<TableColumnMenuPopup
getColumnMenu={props.getColumnMenu}
columnIndex={props.columnIndex}
editColumnName={() => toggleRenameColumn(true)}
/>
</div>
)}
<div
{...column.getResizerProps()}
className={`resizer ${column.isResizing ? "isResizing" : ""}`}
/>
</div>
2020-06-03 10:50:10 +00:00
);
};
export const getAllTableColumnKeys = (tableData: object[]) => {
const columnKeys: string[] = [];
for (let i = 0, tableRowCount = tableData.length; i < tableRowCount; i++) {
const row = tableData[i];
for (const key in row) {
if (!columnKeys.includes(key)) {
columnKeys.push(key);
}
}
}
return columnKeys;
};
export const reorderColumns = (
columns: ReactTableColumnProps[],
columnOrder: string[],
) => {
const reorderedColumns = [];
const reorderedFlagMap: { [key: string]: boolean } = {};
for (let index = 0; index < columns.length; index++) {
const accessor = columnOrder[index];
if (accessor) {
const column = columns.filter((col: ReactTableColumnProps) => {
return col.accessor === accessor;
});
if (column.length && !reorderedFlagMap[column[0].accessor]) {
reorderedColumns.push(column[0]);
reorderedFlagMap[column[0].accessor] = true;
} else if (!reorderedFlagMap[columns[index].accessor]) {
reorderedColumns.push(columns[index]);
reorderedFlagMap[columns[index].accessor] = true;
}
} else if (!reorderedFlagMap[columns[index].accessor]) {
reorderedColumns.push(columns[index]);
reorderedFlagMap[columns[index].accessor] = true;
}
}
if (reorderedColumns.length < columns.length) {
for (let index = 0; index < columns.length; index++) {
if (!reorderedFlagMap[columns[index].accessor]) {
reorderedColumns.push(columns[index]);
reorderedFlagMap[columns[index].accessor] = true;
}
}
}
return reorderedColumns;
};
export function sortTableFunction(
tableData: object[],
columns: ReactTableColumnProps[],
sortedColumn: string,
sortOrder: boolean,
) {
const columnType =
columns.find(
(column: ReactTableColumnProps) => column.accessor === sortedColumn,
)?.metaProperties?.type || ColumnTypes.TEXT;
return tableData.sort(
(a: { [key: string]: any }, b: { [key: string]: any }) => {
if (a[sortedColumn] !== undefined && b[sortedColumn] !== undefined) {
switch (columnType) {
case ColumnTypes.CURRENCY:
case ColumnTypes.NUMBER:
return sortOrder
? Number(a[sortedColumn]) > Number(b[sortedColumn])
? 1
: -1
: Number(b[sortedColumn]) > Number(a[sortedColumn])
? 1
: -1;
case ColumnTypes.DATE:
return sortOrder
? moment(a[sortedColumn]).isAfter(b[sortedColumn])
? 1
: -1
: moment(b[sortedColumn]).isAfter(a[sortedColumn])
? 1
: -1;
default:
return sortOrder
? a[sortedColumn].toString().toUpperCase() >
b[sortedColumn].toString().toUpperCase()
? 1
: -1
: b[sortedColumn].toString().toUpperCase() >
a[sortedColumn].toString().toUpperCase()
? 1
: -1;
}
} else {
return sortOrder ? 1 : 0;
}
},
);
}
export const ConditionFunctions: {
[key: string]: (a: any, b: any) => boolean;
} = {
isExactly: (a: any, b: any) => {
return a === b;
},
empty: (a: any) => {
return a === "" || a === undefined || a === null;
},
notEmpty: (a: any) => {
return a !== "" && a !== undefined && a !== null;
},
notEqualTo: (a: any, b: any) => {
return a !== b;
},
lessThan: (a: any, b: any) => {
const numericB = Number(b);
const numericA = Number(a);
return numericA < numericB;
},
lessThanEqualTo: (a: any, b: any) => {
const numericB = Number(b);
const numericA = Number(a);
return numericA <= numericB;
},
greaterThan: (a: any, b: any) => {
const numericB = Number(b);
const numericA = Number(a);
return numericA > numericB;
},
greaterThanEqualTo: (a: any, b: any) => {
const numericB = Number(b);
const numericA = Number(a);
return numericA >= numericB;
},
contains: (a: any, b: any) => {
if (isString(a) && isString(b)) {
return a.includes(b);
}
return false;
},
doesNotContain: (a: any, b: any) => {
if (isString(a) && isString(b)) {
return !a.includes(b);
}
return false;
},
startsWith: (a: any, b: any) => {
if (isString(a) && isString(b)) {
return a.indexOf(b) === 0;
}
return false;
},
endsWith: (a: any, b: any) => {
if (isString(a) && isString(b)) {
return a.length === a.indexOf(b) + b.length;
}
return false;
},
is: (a: any, b: any) => {
return moment(a).isSame(moment(b), "d");
},
isNot: (a: any, b: any) => {
return !moment(a).isSame(moment(b), "d");
},
isAfter: (a: any, b: any) => {
return !moment(a).isAfter(moment(b), "d");
},
isBefore: (a: any, b: any) => {
return !moment(a).isBefore(moment(b), "d");
},
};
export function compare(a: any, b: any, condition: Condition) {
let result = true;
try {
const conditionFunction = ConditionFunctions[condition];
if (conditionFunction) {
result = conditionFunction(a, b);
}
} catch (e) {
console.error(e);
}
return result;
}