2020-07-14 07:55:46 +00:00
|
|
|
import React, { useState } from "react";
|
|
|
|
|
import { Icon, InputGroup } from "@blueprintjs/core";
|
2020-06-03 10:50:10 +00:00
|
|
|
import {
|
|
|
|
|
MenuColumnWrapper,
|
|
|
|
|
CellWrapper,
|
|
|
|
|
ActionWrapper,
|
2020-08-10 06:45:31 +00:00
|
|
|
SortIconWrapper,
|
2020-06-03 10:50:10 +00:00
|
|
|
} from "./TableStyledWrappers";
|
|
|
|
|
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
2020-08-10 11:16:13 +00:00
|
|
|
import { ColumnMenuOptionProps } from "components/designSystems/appsmith/ReactTableComponent";
|
2020-07-20 06:04:05 +00:00
|
|
|
import {
|
|
|
|
|
ReactTableColumnProps,
|
|
|
|
|
ColumnTypes,
|
2020-08-10 11:16:13 +00:00
|
|
|
Condition,
|
|
|
|
|
} from "widgets/TableWidget";
|
2020-07-20 06:04:05 +00:00
|
|
|
import { isString, isNumber } from "lodash";
|
2020-06-22 13:46:19 +00:00
|
|
|
import VideoComponent from "components/designSystems/appsmith/VideoComponent";
|
2020-07-14 07:55:46 +00:00
|
|
|
import Button from "components/editorComponents/Button";
|
2020-07-03 08:32:21 +00:00
|
|
|
import AutoToolTipComponent from "components/designSystems/appsmith/AutoToolTipComponent";
|
2020-07-14 07:55:46 +00:00
|
|
|
import TableColumnMenuPopup from "./TableColumnMenu";
|
2020-08-10 06:45:31 +00:00
|
|
|
import { ControlIcons } from "icons/ControlIcons";
|
|
|
|
|
import { AnyStyledComponent } from "styled-components";
|
|
|
|
|
import styled from "constants/DefaultTheme";
|
2020-07-20 06:04:05 +00:00
|
|
|
import { Colors } from "constants/Colors";
|
2020-08-10 11:16:13 +00:00
|
|
|
import moment from "moment";
|
2020-06-03 10:50:10 +00:00
|
|
|
|
|
|
|
|
interface MenuOptionProps {
|
|
|
|
|
columnAccessor?: string;
|
|
|
|
|
isColumnHidden: boolean;
|
|
|
|
|
columnType: string;
|
|
|
|
|
format?: string;
|
2020-06-22 08:25:03 +00:00
|
|
|
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",
|
2020-07-14 07:55:46 +00:00
|
|
|
editColumnName: true,
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: props.isColumnHidden ? "Show Column" : "Hide Column",
|
|
|
|
|
closeOnClick: true,
|
|
|
|
|
id: "hide_column",
|
2020-06-22 08:25:03 +00:00
|
|
|
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: (
|
2020-07-20 06:04:05 +00:00
|
|
|
<MenuColumnWrapper selected={props.columnType === ColumnTypes.IMAGE}>
|
2020-06-03 10:50:10 +00:00
|
|
|
<Icon
|
|
|
|
|
icon="media"
|
|
|
|
|
iconSize={12}
|
2020-07-20 06:04:05 +00:00
|
|
|
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,
|
2020-07-20 06:04:05 +00:00
|
|
|
isSelected: props.columnType === ColumnTypes.IMAGE,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number, isSelected: boolean) => {
|
2020-06-03 10:50:10 +00:00
|
|
|
if (isSelected) {
|
2020-06-22 08:25:03 +00:00
|
|
|
props.updateColumnType(columnIndex, "");
|
2020-06-03 10:50:10 +00:00
|
|
|
} else {
|
2020-07-20 06:04:05 +00:00
|
|
|
props.updateColumnType(columnIndex, ColumnTypes.IMAGE);
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: (
|
2020-07-20 06:04:05 +00:00
|
|
|
<MenuColumnWrapper selected={props.columnType === ColumnTypes.VIDEO}>
|
2020-06-03 10:50:10 +00:00
|
|
|
<Icon
|
|
|
|
|
icon="video"
|
|
|
|
|
iconSize={12}
|
2020-07-20 06:04:05 +00:00
|
|
|
color={
|
|
|
|
|
props.columnType === ColumnTypes.VIDEO
|
|
|
|
|
? Colors.WHITE
|
|
|
|
|
: Colors.OXFORD_BLUE
|
|
|
|
|
}
|
2020-06-03 10:50:10 +00:00
|
|
|
/>
|
|
|
|
|
<div className="title">Video</div>
|
|
|
|
|
</MenuColumnWrapper>
|
|
|
|
|
),
|
2020-07-20 06:04:05 +00:00
|
|
|
isSelected: props.columnType === ColumnTypes.VIDEO,
|
2020-06-03 10:50:10 +00:00
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number, isSelected: boolean) => {
|
2020-06-03 10:50:10 +00:00
|
|
|
if (isSelected) {
|
2020-06-22 08:25:03 +00:00
|
|
|
props.updateColumnType(columnIndex, "");
|
2020-06-03 10:50:10 +00:00
|
|
|
} else {
|
2020-07-20 06:04:05 +00:00
|
|
|
props.updateColumnType(columnIndex, ColumnTypes.VIDEO);
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: (
|
2020-07-20 06:04:05 +00:00
|
|
|
<MenuColumnWrapper selected={props.columnType === ColumnTypes.TEXT}>
|
2020-06-03 10:50:10 +00:00
|
|
|
<Icon
|
|
|
|
|
icon="label"
|
|
|
|
|
iconSize={12}
|
2020-07-20 06:04:05 +00:00
|
|
|
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,
|
2020-07-20 06:04:05 +00:00
|
|
|
isSelected: props.columnType === ColumnTypes.TEXT,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number, isSelected: boolean) => {
|
2020-06-03 10:50:10 +00:00
|
|
|
if (isSelected) {
|
2020-06-22 08:25:03 +00:00
|
|
|
props.updateColumnType(columnIndex, "");
|
2020-06-03 10:50:10 +00:00
|
|
|
} else {
|
2020-07-20 06:04:05 +00:00
|
|
|
props.updateColumnType(columnIndex, ColumnTypes.TEXT);
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: (
|
2020-07-20 06:04:05 +00:00
|
|
|
<MenuColumnWrapper selected={props.columnType === ColumnTypes.CURRENCY}>
|
2020-06-03 10:50:10 +00:00
|
|
|
<Icon
|
|
|
|
|
icon="dollar"
|
|
|
|
|
iconSize={12}
|
2020-07-20 06:04:05 +00:00
|
|
|
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}
|
2020-07-20 06:04:05 +00:00
|
|
|
color={
|
|
|
|
|
props.columnType === ColumnTypes.CURRENCY
|
|
|
|
|
? Colors.WHITE
|
|
|
|
|
: Colors.OXFORD_BLUE
|
|
|
|
|
}
|
2020-06-03 10:50:10 +00:00
|
|
|
/>
|
|
|
|
|
</MenuColumnWrapper>
|
|
|
|
|
),
|
|
|
|
|
closeOnClick: false,
|
2020-07-20 06:04:05 +00:00
|
|
|
isSelected: props.columnType === ColumnTypes.CURRENCY,
|
2020-06-03 10:50:10 +00:00
|
|
|
options: [
|
|
|
|
|
{
|
|
|
|
|
content: "USD - $",
|
|
|
|
|
isSelected: props.format === "$",
|
|
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleUpdateCurrencySymbol(columnIndex, "$");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: "INR - ₹",
|
|
|
|
|
isSelected: props.format === "₹",
|
|
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleUpdateCurrencySymbol(columnIndex, "₹");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: "GBP - £",
|
|
|
|
|
isSelected: props.format === "£",
|
|
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleUpdateCurrencySymbol(columnIndex, "£");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: "AUD - A$",
|
|
|
|
|
isSelected: props.format === "A$",
|
|
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleUpdateCurrencySymbol(columnIndex, "A$");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: "EUR - €",
|
|
|
|
|
isSelected: props.format === "€",
|
|
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleUpdateCurrencySymbol(columnIndex, "€");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: "SGD - S$",
|
|
|
|
|
isSelected: props.format === "S$",
|
|
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleUpdateCurrencySymbol(columnIndex, "S$");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: "CAD - C$",
|
|
|
|
|
isSelected: props.format === "C$",
|
|
|
|
|
closeOnClick: true,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleUpdateCurrencySymbol(columnIndex, "C$");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: (
|
2020-07-20 06:04:05 +00:00
|
|
|
<MenuColumnWrapper selected={props.columnType === ColumnTypes.DATE}>
|
2020-06-03 10:50:10 +00:00
|
|
|
<Icon
|
|
|
|
|
icon="calendar"
|
|
|
|
|
iconSize={12}
|
2020-07-20 06:04:05 +00:00
|
|
|
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}
|
2020-07-20 06:04:05 +00:00
|
|
|
color={
|
|
|
|
|
props.columnType === ColumnTypes.DATE
|
|
|
|
|
? Colors.WHITE
|
|
|
|
|
: Colors.OXFORD_BLUE
|
|
|
|
|
}
|
2020-06-03 10:50:10 +00:00
|
|
|
/>
|
|
|
|
|
</MenuColumnWrapper>
|
|
|
|
|
),
|
|
|
|
|
closeOnClick: false,
|
2020-07-20 06:04:05 +00:00
|
|
|
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,
|
2020-06-22 08:25:03 +00:00
|
|
|
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,
|
2020-06-22 08:25:03 +00:00
|
|
|
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,
|
2020-06-22 08:25:03 +00:00
|
|
|
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,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number) => {
|
|
|
|
|
props.handleDateFormatUpdate(columnIndex, "MM/DD/YY");
|
2020-06-03 10:50:10 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
content: (
|
2020-07-20 06:04:05 +00:00
|
|
|
<MenuColumnWrapper selected={props.columnType === ColumnTypes.TIME}>
|
2020-06-03 10:50:10 +00:00
|
|
|
<Icon
|
|
|
|
|
icon="time"
|
|
|
|
|
iconSize={12}
|
2020-07-20 06:04:05 +00:00
|
|
|
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,
|
2020-07-20 06:04:05 +00:00
|
|
|
isSelected: props.columnType === ColumnTypes.TIME,
|
2020-06-22 08:25:03 +00:00
|
|
|
onClick: (columnIndex: number, isSelected: boolean) => {
|
2020-06-03 10:50:10 +00:00
|
|
|
if (isSelected) {
|
2020-06-22 08:25:03 +00:00
|
|
|
props.updateColumnType(columnIndex, "");
|
2020-06-03 10:50:10 +00:00
|
|
|
} else {
|
2020-07-20 06:04:05 +00:00
|
|
|
props.updateColumnType(columnIndex, ColumnTypes.TIME);
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
2020-08-10 06:45:31 +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) {
|
2020-07-20 06:04:05 +00:00
|
|
|
case ColumnTypes.IMAGE:
|
2020-08-10 10:01:36 +00:00
|
|
|
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>
|
|
|
|
|
);
|
|
|
|
|
}
|
2020-06-18 11:23:11 +00:00
|
|
|
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) => {
|
2020-06-18 11:23:11 +00:00
|
|
|
if (imageRegex.test(item)) {
|
2020-06-03 10:50:10 +00:00
|
|
|
return (
|
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>
|
|
|
|
|
);
|
2020-07-20 06:04:05 +00:00
|
|
|
case ColumnTypes.VIDEO:
|
2020-08-10 11:16:13 +00:00
|
|
|
const youtubeRegex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=|\?v=)([^#&?]*).*/;
|
2020-08-10 10:01:36 +00:00
|
|
|
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:
|
2020-07-20 06:04:05 +00:00
|
|
|
const data =
|
2020-07-24 13:58:28 +00:00
|
|
|
isString(value) || isNumber(value)
|
|
|
|
|
? value.toString()
|
|
|
|
|
: JSON.stringify(value);
|
2020-07-03 08:32:21 +00:00
|
|
|
return (
|
2020-07-24 13:58:28 +00:00
|
|
|
<AutoToolTipComponent title={data} isHidden={isHidden}>
|
2020-07-03 08:32:21 +00:00
|
|
|
{data}
|
|
|
|
|
</AutoToolTipComponent>
|
|
|
|
|
);
|
2020-06-03 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
interface RenderActionProps {
|
2020-07-28 14:26:27 +00:00
|
|
|
isSelected: boolean;
|
2020-06-03 10:50:10 +00:00
|
|
|
columnActions?: ColumnAction[];
|
2020-07-14 07:55:46 +00:00
|
|
|
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 (
|
2020-07-14 07:55:46 +00:00
|
|
|
<TableAction
|
2020-06-03 10:50:10 +00:00
|
|
|
key={index}
|
2020-07-14 07:55:46 +00:00
|
|
|
action={action}
|
2020-07-28 14:26:27 +00:00
|
|
|
isSelected={props.isSelected}
|
2020-07-14 07:55:46 +00:00
|
|
|
onCommandClick={props.onCommandClick}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</CellWrapper>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const TableAction = (props: {
|
2020-07-28 14:26:27 +00:00
|
|
|
isSelected: boolean;
|
2020-07-14 07:55:46 +00:00
|
|
|
action: ColumnAction;
|
|
|
|
|
onCommandClick: (dynamicTrigger: string, onComplete: () => void) => void;
|
|
|
|
|
}) => {
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const onComplete = () => {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
};
|
|
|
|
|
return (
|
2020-07-28 14:26:27 +00:00
|
|
|
<ActionWrapper
|
|
|
|
|
onClick={e => {
|
|
|
|
|
if (props.isSelected) {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
2020-07-14 07:55:46 +00:00
|
|
|
<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,
|
2020-07-16 10:39:07 +00:00
|
|
|
page: any,
|
|
|
|
|
prepareRow: any,
|
2020-07-14 07:55:46 +00:00
|
|
|
) => {
|
|
|
|
|
const rows: string[] = new Array(rowCount).fill("");
|
2020-07-16 10:39:07 +00:00
|
|
|
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>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-07-14 07:55:46 +00:00
|
|
|
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
|
|
|
}}
|
|
|
|
|
>
|
2020-07-14 07:55:46 +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
|
|
|
);
|
|
|
|
|
})}
|
2020-07-14 07:55:46 +00:00
|
|
|
</React.Fragment>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2020-08-10 06:45:31 +00:00
|
|
|
const SortIcon = styled(ControlIcons.SORT_CONTROL as AnyStyledComponent)`
|
|
|
|
|
padding: 0;
|
|
|
|
|
position: relative;
|
|
|
|
|
top: 3px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
svg {
|
|
|
|
|
path {
|
|
|
|
|
fill: ${props => props.theme.colors.secondary};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
`;
|
|
|
|
|
|
2020-07-14 07:55:46 +00:00
|
|
|
export const TableHeaderCell = (props: {
|
|
|
|
|
columnName: string;
|
|
|
|
|
columnIndex: number;
|
|
|
|
|
isHidden: boolean;
|
2020-08-10 06:45:31 +00:00
|
|
|
isAscOrder?: boolean;
|
2020-07-14 07:55:46 +00:00
|
|
|
displayColumnActions: boolean;
|
|
|
|
|
handleColumnNameUpdate: (columnIndex: number, name: string) => void;
|
|
|
|
|
getColumnMenu: (columnIndex: number) => ColumnMenuOptionProps[];
|
2020-08-10 06:45:31 +00:00
|
|
|
sortTableColumn: (columnIndex: number, asc: boolean) => void;
|
2020-07-14 07:55:46 +00:00
|
|
|
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);
|
|
|
|
|
};
|
2020-08-13 06:45:28 +00:00
|
|
|
const handleSortColumn = () => {
|
2020-08-10 06:45:31 +00:00
|
|
|
props.sortTableColumn(
|
|
|
|
|
props.columnIndex,
|
|
|
|
|
props.isAscOrder === undefined ? true : !props.isAscOrder,
|
|
|
|
|
);
|
|
|
|
|
};
|
2020-07-14 07:55:46 +00:00
|
|
|
if (column.isResizing) {
|
|
|
|
|
props.handleResizeColumn(
|
|
|
|
|
props.columnIndex,
|
|
|
|
|
column.getHeaderProps().style.width,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return (
|
2020-08-10 06:45:31 +00:00
|
|
|
<div
|
|
|
|
|
{...column.getHeaderProps()}
|
|
|
|
|
className="th header-reorder"
|
2020-08-13 06:45:28 +00:00
|
|
|
onClick={handleSortColumn}
|
2020-08-10 06:45:31 +00:00
|
|
|
>
|
|
|
|
|
{props.isAscOrder !== undefined ? (
|
|
|
|
|
<SortIconWrapper rotate={!props.isAscOrder}>
|
|
|
|
|
<SortIcon height={16} width={16} />
|
|
|
|
|
</SortIconWrapper>
|
|
|
|
|
) : null}
|
2020-07-14 07:55:46 +00:00
|
|
|
{renameColumn && (
|
|
|
|
|
<RenameColumn
|
|
|
|
|
value={props.columnName}
|
|
|
|
|
handleSave={handleSaveColumnName}
|
|
|
|
|
columnIndex={props.columnIndex}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{!renameColumn && (
|
2020-08-10 06:45:31 +00:00
|
|
|
<div
|
|
|
|
|
className={
|
|
|
|
|
!props.isHidden
|
|
|
|
|
? `draggable-header ${
|
|
|
|
|
props.isAscOrder !== undefined ? "sorted" : ""
|
|
|
|
|
}`
|
|
|
|
|
: "hidden-header"
|
|
|
|
|
}
|
|
|
|
|
>
|
2020-07-14 07:55:46 +00:00
|
|
|
{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
|
|
|
);
|
|
|
|
|
};
|
2020-07-20 06:04:05 +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;
|
|
|
|
|
};
|
2020-08-10 11:16:13 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|