Merge branch 'fix/react-table-widget' into 'release'
Fix/react table widget See merge request theappsmith/internal-tools-client!599
This commit is contained in:
commit
3b729bc470
|
|
@ -30,7 +30,9 @@ describe("Text-Table Binding Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Text-Table Binding Functionality For Email", function() {
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.isSelectRow(2);
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.testJsontext("text", "{{Table1.selectedRow.email}}");
|
||||
|
|
@ -50,19 +52,21 @@ describe("Text-Table Binding Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Text-Table Binding Functionality For Total Length", function() {
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.pageNo(1);
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.pageNo();
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.testJsontext("text", "{{Table1.pageSize}}");
|
||||
cy.get(commonlocators.TableRow)
|
||||
.find("tr")
|
||||
.find(".tr")
|
||||
.then(listing => {
|
||||
const listingCount = listing.length.toString();
|
||||
cy.get(commonlocators.TextInside).should("have.text", listingCount);
|
||||
cy.PublishtheApp();
|
||||
cy.pageNo(1);
|
||||
cy.pageNo();
|
||||
cy.get(publish.tableLength)
|
||||
.find("tr")
|
||||
.find(".tr")
|
||||
.then(listing => {
|
||||
const listingCountP = listing.length.toString();
|
||||
cy.get(commonlocators.TextInside).should(
|
||||
|
|
@ -73,7 +77,9 @@ describe("Text-Table Binding Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Text-Table Binding Functionality For Username", function() {
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
/**
|
||||
* @param(Index) Provide index value to select the row.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -19,16 +19,16 @@ describe("Table Widget Functionality", function() {
|
|||
cy.widgetText("Table1", widgetsPage.tableWidget, commonlocators.tableInner);
|
||||
cy.testJsontext("tabledata", JSON.stringify(this.data.TableInput));
|
||||
cy.wait("@updateLayout");
|
||||
cy.ExportVerify(commonlocators.pdfSupport, "PDF Export");
|
||||
cy.ExportVerify(commonlocators.ExcelSupport, "Excel Export");
|
||||
cy.ExportVerify(commonlocators.csvSupport, "CSV Export");
|
||||
// cy.ExportVerify(commonlocators.pdfSupport, "PDF Export");
|
||||
// cy.ExportVerify(commonlocators.ExcelSupport, "Excel Export");
|
||||
// cy.ExportVerify(commonlocators.csvSupport, "CSV Export");
|
||||
cy.get(widgetsPage.ColumnAction).click({ force: true });
|
||||
cy.readTabledata("1", "5").then(tabData => {
|
||||
const tabValue = tabData;
|
||||
expect(tabValue).to.be.equal("Action");
|
||||
cy.log("the value is" + tabValue);
|
||||
});
|
||||
cy.pageNo(2).should("be.visible");
|
||||
// cy.readTabledata("1", "5").then(tabData => {
|
||||
// const tabValue = tabData;
|
||||
// expect(tabValue).to.be.equal("Action");
|
||||
// cy.log("the value is" + tabValue);
|
||||
// });
|
||||
cy.pageNo();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
cy.get(widgetsPage.tableOnRowSelected)
|
||||
.get(commonlocators.dropdownSelectButton)
|
||||
|
|
@ -56,31 +56,33 @@ describe("Table Widget Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Table Widget Functionality To Verify The PageNo", function() {
|
||||
cy.pageNo(2).should("be.visible");
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
it("Table Widget Functionality To Verify The Extension Support", function() {
|
||||
cy.openPropertyPane("tablewidget");
|
||||
cy.togglebar(commonlocators.pdfSupport);
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.tableWidget + " " + "button").should(
|
||||
"contain",
|
||||
"PDF Export",
|
||||
);
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
cy.togglebarDisable(commonlocators.pdfSupport);
|
||||
cy.togglebar(commonlocators.ExcelSupport);
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.tableWidget + " " + "button").should(
|
||||
"not.contain",
|
||||
"PDF Export",
|
||||
);
|
||||
cy.get(publish.tableWidget + " " + "button").should(
|
||||
"contain",
|
||||
"Excel Export",
|
||||
);
|
||||
cy.pageNo();
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
});
|
||||
// it("Table Widget Functionality To Verify The Extension Support", function() {
|
||||
// cy.openPropertyPane("tablewidget");
|
||||
// cy.togglebar(commonlocators.pdfSupport);
|
||||
// cy.PublishtheApp();
|
||||
// cy.get(publish.tableWidget + " " + "button").should(
|
||||
// "contain",
|
||||
// "PDF Export",
|
||||
// );
|
||||
// cy.get(publish.backToEditor).click();
|
||||
// cy.openPropertyPane("tablewidget");
|
||||
// cy.togglebarDisable(commonlocators.pdfSupport);
|
||||
// cy.togglebar(commonlocators.ExcelSupport);
|
||||
// cy.PublishtheApp();
|
||||
// cy.get(publish.tableWidget + " " + "button").should(
|
||||
// "not.contain",
|
||||
// "PDF Export",
|
||||
// );
|
||||
// cy.get(publish.tableWidget + " " + "button").should(
|
||||
// "contain",
|
||||
// "Excel Export",
|
||||
// );
|
||||
// });
|
||||
});
|
||||
Cypress.on("test:after:run", attributes => {
|
||||
/* eslint-disable no-console */
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
"editWidgetName": ".bp3-editable-text",
|
||||
"dropDownIcon": ".t--property-control-textstyle span.bp3-icon-chevron-down",
|
||||
"onDateSelectedField": ".t--property-control-ondateselected",
|
||||
"TableRow": ".t--draggable-tablewidget .e-gridcontent.e-lib.e-droppable",
|
||||
"TableRow": ".t--draggable-tablewidget .tbody",
|
||||
"Disablejs": ".t--property-control-disabled",
|
||||
"requiredjs": ".t--property-control-required",
|
||||
"horizontalScroll": ".t--property-control-allowhorizontalscroll input",
|
||||
|
|
@ -45,8 +45,8 @@
|
|||
"disabledBtn": " button[disabled='disabled']",
|
||||
"inputField": " .bp3-input",
|
||||
"csvSupport": ".t--property-control-csvexport input",
|
||||
"backToEditor": ".bp3-icon.bp3-icon-chevron-left + span.bp3-button-text",
|
||||
"backToEditor": ".t--back-to-editor",
|
||||
"enableSearchLocCheckbox": ".t--property-control-enablesearchlocation input",
|
||||
"enablePickLocCheckbox": ".t--property-control-enablepicklocation input",
|
||||
"enableCreateMarkerCheckbox": ".t--property-control-createnewmarker input"
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"textWidget": ".t--widget-textwidget",
|
||||
"richTextEditorWidget": ".t--widget-richtexteditorwidget",
|
||||
"datepickerWidget": ".t--widget-datepickerwidget",
|
||||
"backToEditor": ".bp3-icon.bp3-icon-chevron-left + span.bp3-button-text",
|
||||
"backToEditor": ".t--back-to-editor",
|
||||
"inputWidget": ".t--widget-inputwidget",
|
||||
"checkboxWidget": ".t--widget-checkboxwidget",
|
||||
"radioWidget": ".t--widget-radiogroupwidget",
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
"horizontalTab": ".t--widget-chartwidget g[class*='-scrollContainer'] rect",
|
||||
"tableWidget": ".t--widget-tablewidget",
|
||||
"mapWidget": ".t--widget-mapwidget",
|
||||
"tableLength": ".t--widget-tablewidget .e-gridcontent.e-lib.e-droppable",
|
||||
"tableLength": ".t--widget-tablewidget .tbody",
|
||||
"mapSearch": ".t--widget-mapwidget input",
|
||||
"pickMyLocation": ".t--widget-mapwidget div[title='Pick My Location']"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -918,16 +918,13 @@ Cypress.Commands.add("createApi", (url, parameters) => {
|
|||
|
||||
Cypress.Commands.add("isSelectRow", index => {
|
||||
cy.get(
|
||||
'.e-gridcontent.e-lib.e-droppable td[index="' +
|
||||
index +
|
||||
'"][aria-colindex="' +
|
||||
index +
|
||||
'"]',
|
||||
'.tbody .td[data-rowindex="' + index + '"][data-colindex="' + 0 + '"]',
|
||||
).click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("readTabledata", (rowNum, colNum) => {
|
||||
const selector = `.t--draggable-tablewidget .e-gridcontent.e-lib.e-droppable td[index=${rowNum}][aria-colindex=${colNum}]`;
|
||||
// const selector = `.t--draggable-tablewidget .e-gridcontent.e-lib.e-droppable td[index=${rowNum}][aria-colindex=${colNum}]`;
|
||||
const selector = `.t--draggable-tablewidget .tbody .td[data-rowindex=${rowNum}][data-colindex=${colNum}] div`;
|
||||
const tabVal = cy.get(selector).invoke("text");
|
||||
return tabVal;
|
||||
});
|
||||
|
|
@ -948,10 +945,9 @@ Cypress.Commands.add("setDate", (date, dateFormate) => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("pageNo", index => {
|
||||
cy.get(".e-pagercontainer a")
|
||||
.eq(index)
|
||||
.click({ force: true })
|
||||
.should("be.visible");
|
||||
cy.get(".page-item")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("pageNoValidate", index => {
|
||||
|
|
@ -1052,7 +1048,8 @@ Cypress.Commands.add("ExportVerify", (togglecss, name) => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("readTabledataPublish", (rowNum, colNum) => {
|
||||
const selector = `.t--widget-tablewidget .e-gridcontent.e-lib.e-droppable td[index=${rowNum}][aria-colindex=${colNum}]`;
|
||||
// const selector = `.t--widget-tablewidget .e-gridcontent.e-lib.e-droppable td[index=${rowNum}][aria-colindex=${colNum}]`;
|
||||
const selector = `.t--widget-tablewidget .tbody .td[data-rowindex=${rowNum}][data-colindex=${colNum}] div`;
|
||||
const tabVal = cy.get(selector).invoke("text");
|
||||
return tabVal;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
"@types/react-instantsearch-dom": "^6.3.0",
|
||||
"@types/react-redux": "^7.0.1",
|
||||
"@types/react-router-dom": "^5.1.2",
|
||||
"@types/react-table": "^7.0.13",
|
||||
"@types/styled-components": "^4.1.8",
|
||||
"@types/tinycolor2": "^1.4.2",
|
||||
"@uppy/core": "^1.8.2",
|
||||
|
|
@ -90,6 +91,7 @@
|
|||
"react-scripts": "^3.3.0",
|
||||
"react-select": "^3.0.8",
|
||||
"react-spring": "^8.0.27",
|
||||
"react-table": "^7.0.0",
|
||||
"react-tabs": "^3.0.0",
|
||||
"react-toastify": "^5.5.0",
|
||||
"react-transition-group": "^4.3.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,483 @@
|
|||
import React from "react";
|
||||
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
||||
import Table from "./Table";
|
||||
import { RenderMode, RenderModes } from "constants/WidgetConstants";
|
||||
import _ from "lodash";
|
||||
import { getMenuOptions, renderActions, renderCell } from "./TableUtilities";
|
||||
|
||||
interface ReactTableComponentState {
|
||||
trigger: number;
|
||||
columnIndex: number;
|
||||
pageSize: number;
|
||||
action: string;
|
||||
columnName: string;
|
||||
}
|
||||
|
||||
export interface ReactTableColumnProps {
|
||||
Header: string;
|
||||
accessor: string;
|
||||
width: number;
|
||||
minWidth: number;
|
||||
draggable: boolean;
|
||||
isHidden?: boolean;
|
||||
Cell: (props: any) => JSX.Element;
|
||||
}
|
||||
|
||||
export interface ColumnMenuOptionProps {
|
||||
content: string | JSX.Element;
|
||||
closeOnClick?: boolean;
|
||||
isSelected?: boolean;
|
||||
columnAccessor?: string;
|
||||
id?: string;
|
||||
category?: boolean;
|
||||
options?: ColumnMenuSubOptionProps[];
|
||||
onClick?: (isSelected: boolean) => void;
|
||||
}
|
||||
|
||||
export interface ColumnMenuSubOptionProps {
|
||||
content: string;
|
||||
isSelected: boolean;
|
||||
closeOnClick: boolean;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
interface ReactTableComponentProps {
|
||||
widgetId: string;
|
||||
isDisabled?: boolean;
|
||||
isVisible?: boolean;
|
||||
renderMode: RenderMode;
|
||||
width: number;
|
||||
height: number;
|
||||
pageSize: number;
|
||||
tableData: object[];
|
||||
columnOrder?: string[];
|
||||
disableDrag: (disable: boolean) => void;
|
||||
onRowClick: (rowData: object, rowIndex: number) => void;
|
||||
onCommandClick: (dynamicTrigger: string) => void;
|
||||
updatePageNo: Function;
|
||||
updateHiddenColumns: Function;
|
||||
resetSelectedRowIndex: Function;
|
||||
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;
|
||||
}
|
||||
|
||||
export class ReactTableComponent extends React.Component<
|
||||
ReactTableComponentProps,
|
||||
ReactTableComponentState
|
||||
> {
|
||||
private dragged = -1;
|
||||
constructor(props: ReactTableComponentProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
trigger: 0,
|
||||
columnIndex: -1,
|
||||
action: "",
|
||||
columnName: "",
|
||||
pageSize: props.pageSize,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mountEvents();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: ReactTableComponentProps) {
|
||||
if (this.props.pageSize !== prevProps.pageSize) {
|
||||
this.setState({ pageSize: this.props.pageSize });
|
||||
}
|
||||
this.mountEvents();
|
||||
}
|
||||
|
||||
mountEvents() {
|
||||
const headers = Array.prototype.slice.call(
|
||||
document.querySelectorAll(
|
||||
`#table${this.props.widgetId} .draggable-header`,
|
||||
),
|
||||
);
|
||||
const columns = this.getTableColumns();
|
||||
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();
|
||||
this.dragged = i;
|
||||
};
|
||||
|
||||
header.ondrag = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
header.ondragend = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
header.style = "";
|
||||
e.stopPropagation();
|
||||
setTimeout(() => (this.dragged = -1), 1000);
|
||||
};
|
||||
|
||||
// the dropped header
|
||||
header.ondragover = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
if (i !== this.dragged && this.dragged !== -1) {
|
||||
if (this.dragged > i) {
|
||||
header.parentElement.className = "th header-reorder highlight-left";
|
||||
} else if (this.dragged < i) {
|
||||
header.parentElement.className =
|
||||
"th header-reorder highlight-right";
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
header.ondragenter = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
if (i !== this.dragged && this.dragged !== -1) {
|
||||
if (this.dragged > i) {
|
||||
header.parentElement.className = "th header-reorder highlight-left";
|
||||
} else if (this.dragged < i) {
|
||||
header.parentElement.className =
|
||||
"th header-reorder highlight-right";
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
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 !== this.dragged && this.dragged !== -1) {
|
||||
e.preventDefault();
|
||||
let columnOrder = this.props.columnOrder;
|
||||
if (columnOrder === undefined) {
|
||||
columnOrder = this.props.tableData.length
|
||||
? Object.keys(this.props.tableData[0])
|
||||
: [];
|
||||
}
|
||||
const draggedColumn = columns[this.dragged].accessor;
|
||||
columnOrder.splice(this.dragged, 1);
|
||||
columnOrder.splice(i, 0, draggedColumn);
|
||||
this.props.handleReorderColumn(columnOrder);
|
||||
this.setState({ trigger: Math.random() });
|
||||
} else {
|
||||
this.dragged = -1;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getTableColumns = () => {
|
||||
const tableData: object[] = this.props.tableData;
|
||||
let columns: ReactTableColumnProps[] = [];
|
||||
const hiddenColumns: ReactTableColumnProps[] = [];
|
||||
if (tableData.length) {
|
||||
const row = tableData[0];
|
||||
for (const i in row) {
|
||||
const columnName: string =
|
||||
this.props.columnNameMap && this.props.columnNameMap[i]
|
||||
? this.props.columnNameMap[i]
|
||||
: i;
|
||||
const columnType: { type: string; format?: string } =
|
||||
this.props.columnTypeMap && this.props.columnTypeMap[i]
|
||||
? this.props.columnTypeMap[i]
|
||||
: { type: "text" };
|
||||
const columnSize: number =
|
||||
this.props.columnSizeMap && this.props.columnSizeMap[i]
|
||||
? this.props.columnSizeMap[i]
|
||||
: 150;
|
||||
const isHidden =
|
||||
!!this.props.hiddenColumns && this.props.hiddenColumns.includes(i);
|
||||
const columnData = {
|
||||
Header: columnName,
|
||||
accessor: i,
|
||||
width: columnSize,
|
||||
minWidth: 60,
|
||||
draggable: true,
|
||||
isHidden: false,
|
||||
Cell: (props: any) => {
|
||||
return renderCell(
|
||||
props.cell.value,
|
||||
columnType.type,
|
||||
isHidden,
|
||||
columnType.format,
|
||||
);
|
||||
},
|
||||
};
|
||||
if (isHidden) {
|
||||
columnData.isHidden = true;
|
||||
hiddenColumns.push(columnData);
|
||||
} else {
|
||||
columns.push(columnData);
|
||||
}
|
||||
}
|
||||
columns = this.reorderColumns(columns);
|
||||
if (this.props.columnActions?.length) {
|
||||
columns.push({
|
||||
Header: "Actions",
|
||||
accessor: "actions",
|
||||
width: 150,
|
||||
minWidth: 60,
|
||||
draggable: true,
|
||||
Cell: () => {
|
||||
return renderActions({
|
||||
columnActions: this.props.columnActions,
|
||||
onCommandClick: this.props.onCommandClick,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
hiddenColumns.length &&
|
||||
this.props.renderMode === RenderModes.CANVAS
|
||||
) {
|
||||
columns = columns.concat(hiddenColumns);
|
||||
}
|
||||
}
|
||||
return columns;
|
||||
};
|
||||
|
||||
reorderColumns = (columns: ReactTableColumnProps[]) => {
|
||||
const columnOrder = this.props.columnOrder || [];
|
||||
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;
|
||||
};
|
||||
|
||||
showMenu = (columnIndex: number) => {
|
||||
this.setState({ columnIndex: columnIndex, action: "" });
|
||||
};
|
||||
|
||||
getColumnMenu = () => {
|
||||
const { columnIndex } = this.state;
|
||||
let columnType = "";
|
||||
let columnId = "";
|
||||
let format = "";
|
||||
if (columnIndex !== -1) {
|
||||
const columns = this.getTableColumns();
|
||||
const column = columns[columnIndex];
|
||||
columnId = column.accessor;
|
||||
columnType =
|
||||
this.props.columnTypeMap && this.props.columnTypeMap[columnId]
|
||||
? this.props.columnTypeMap[columnId].type
|
||||
: "";
|
||||
format =
|
||||
this.props.columnTypeMap && this.props.columnTypeMap[columnId]
|
||||
? this.props.columnTypeMap[columnId].format
|
||||
: "";
|
||||
}
|
||||
const isColumnHidden = !!(
|
||||
this.props.hiddenColumns && this.props.hiddenColumns.includes(columnId)
|
||||
);
|
||||
const columnMenuOptions: ColumnMenuOptionProps[] = getMenuOptions({
|
||||
columnAccessor: columnId,
|
||||
isColumnHidden,
|
||||
columnType,
|
||||
format,
|
||||
hideColumn: this.hideColumn,
|
||||
updateColumnType: this.updateColumnType,
|
||||
handleUpdateCurrencySymbol: this.handleUpdateCurrencySymbol,
|
||||
handleDateFormatUpdate: this.handleDateFormatUpdate,
|
||||
updateAction: (action: string) => this.setState({ action: action }),
|
||||
});
|
||||
return columnMenuOptions;
|
||||
};
|
||||
|
||||
hideColumn = (isColumnHidden: boolean) => {
|
||||
const columns = this.getTableColumns();
|
||||
const columnIndex = this.state.columnIndex;
|
||||
const column = columns[columnIndex];
|
||||
let hiddenColumns = this.props.hiddenColumns || [];
|
||||
if (!isColumnHidden) {
|
||||
hiddenColumns.push(column.accessor);
|
||||
const columnOrder = this.props.columnOrder || [];
|
||||
if (columnOrder.includes(column.accessor)) {
|
||||
columnOrder.splice(columnOrder.indexOf(column.accessor), 1);
|
||||
this.props.handleReorderColumn(columnOrder);
|
||||
}
|
||||
} else {
|
||||
hiddenColumns = hiddenColumns.filter(item => {
|
||||
return item !== column.accessor;
|
||||
});
|
||||
}
|
||||
this.props.updateHiddenColumns(hiddenColumns);
|
||||
this.setState({ columnIndex: -1 });
|
||||
};
|
||||
|
||||
updateColumnType = (columnType: string) => {
|
||||
const columns = this.getTableColumns();
|
||||
const columnIndex = this.state.columnIndex;
|
||||
const column = columns[columnIndex];
|
||||
const columnTypeMap = this.props.columnTypeMap || {};
|
||||
columnTypeMap[column.accessor] = {
|
||||
type: columnType,
|
||||
format: "",
|
||||
};
|
||||
this.props.updateColumnType(columnTypeMap);
|
||||
this.setState({ action: "", columnIndex: -1 });
|
||||
};
|
||||
|
||||
onColumnNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ columnName: event.target.value });
|
||||
};
|
||||
|
||||
onKeyPress = (key: string) => {
|
||||
if (key === "Enter") {
|
||||
this.handleColumnNameUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
handleColumnNameUpdate = () => {
|
||||
const columns = this.getTableColumns();
|
||||
const columnIndex = this.state.columnIndex;
|
||||
const columnName = this.state.columnName;
|
||||
const column = columns[columnIndex];
|
||||
const columnNameMap = this.props.columnNameMap || {};
|
||||
columnNameMap[column.accessor] = columnName;
|
||||
this.props.updateColumnName(columnNameMap);
|
||||
this.setState({
|
||||
columnIndex: -1,
|
||||
columnName: "",
|
||||
action: "",
|
||||
});
|
||||
};
|
||||
|
||||
handleUpdateCurrencySymbol = (currencySymbol: string) => {
|
||||
const columns = this.getTableColumns();
|
||||
const columnIndex = this.state.columnIndex;
|
||||
const column = columns[columnIndex];
|
||||
const columnTypeMap = this.props.columnTypeMap || {};
|
||||
columnTypeMap[column.accessor] = {
|
||||
type: "currency",
|
||||
format: currencySymbol,
|
||||
};
|
||||
this.props.updateColumnType(columnTypeMap);
|
||||
this.setState({
|
||||
columnIndex: -1,
|
||||
action: "",
|
||||
});
|
||||
};
|
||||
|
||||
handleDateFormatUpdate = (dateFormat: string) => {
|
||||
const columns = this.getTableColumns();
|
||||
const columnIndex = this.state.columnIndex;
|
||||
const column = columns[columnIndex];
|
||||
const columnTypeMap = this.props.columnTypeMap || {};
|
||||
columnTypeMap[column.accessor] = {
|
||||
type: "date",
|
||||
format: dateFormat,
|
||||
};
|
||||
this.props.updateColumnType(columnTypeMap);
|
||||
this.setState({
|
||||
columnIndex: -1,
|
||||
action: "",
|
||||
});
|
||||
};
|
||||
|
||||
handleResizeColumn = (columnIndex: number, columnWidth: string) => {
|
||||
const columns = this.getTableColumns();
|
||||
const column = columns[columnIndex];
|
||||
const columnSizeMap = this.props.columnSizeMap || {};
|
||||
const width = Number(columnWidth.split("px")[0]);
|
||||
columnSizeMap[column.accessor] = width;
|
||||
this.props.handleResizeColumn(columnSizeMap);
|
||||
};
|
||||
|
||||
selectTableRow = (
|
||||
row: { original: object; index: number },
|
||||
isSelected: boolean,
|
||||
) => {
|
||||
if (!isSelected) {
|
||||
this.props.onRowClick(row.original, row.index);
|
||||
} else {
|
||||
this.props.resetSelectedRowIndex();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const columns = this.getTableColumns();
|
||||
return (
|
||||
<Table
|
||||
width={this.props.width}
|
||||
height={this.props.height}
|
||||
pageSize={this.state.pageSize || 1}
|
||||
widgetId={this.props.widgetId}
|
||||
columns={columns}
|
||||
data={this.props.tableData}
|
||||
showMenu={this.showMenu}
|
||||
displayColumnActions={this.props.renderMode === RenderModes.CANVAS}
|
||||
columnNameMap={this.props.columnNameMap}
|
||||
columnMenuOptions={this.getColumnMenu()}
|
||||
columnIndex={this.state.columnIndex}
|
||||
columnAction={this.state.action}
|
||||
onColumnNameChange={this.onColumnNameChange}
|
||||
handleColumnNameUpdate={this.handleColumnNameUpdate}
|
||||
handleResizeColumn={_.debounce(this.handleResizeColumn, 300)}
|
||||
selectTableRow={this.selectTableRow}
|
||||
pageNo={this.props.pageNo - 1}
|
||||
updatePageNo={this.props.updatePageNo}
|
||||
nextPageClick={() => {
|
||||
this.props.nextPageClick();
|
||||
}}
|
||||
prevPageClick={() => {
|
||||
this.props.prevPageClick();
|
||||
}}
|
||||
onKeyPress={this.onKeyPress}
|
||||
serverSidePaginationEnabled={this.props.serverSidePaginationEnabled}
|
||||
selectedRowIndex={this.props.selectedRowIndex}
|
||||
disableDrag={() => {
|
||||
this.props.disableDrag(true);
|
||||
}}
|
||||
enableDrag={() => {
|
||||
this.props.disableDrag(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ReactTableComponent;
|
||||
274
app/client/src/components/designSystems/appsmith/Table.tsx
Normal file
274
app/client/src/components/designSystems/appsmith/Table.tsx
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
import React from "react";
|
||||
import {
|
||||
useTable,
|
||||
usePagination,
|
||||
useFlexLayout,
|
||||
useResizeColumns,
|
||||
useRowSelect,
|
||||
} from "react-table";
|
||||
import { Icon, InputGroup } from "@blueprintjs/core";
|
||||
import {
|
||||
TableWrapper,
|
||||
PaginationWrapper,
|
||||
PaginationItemWrapper,
|
||||
} from "./TableStyledWrappers";
|
||||
import {
|
||||
ReactTableColumnProps,
|
||||
ColumnMenuOptionProps,
|
||||
} from "./ReactTableComponent";
|
||||
import { TableColumnMenuPopup } from "./TableColumnMenu";
|
||||
|
||||
interface TableProps {
|
||||
width: number;
|
||||
height: number;
|
||||
pageSize: number;
|
||||
widgetId: string;
|
||||
columns: ReactTableColumnProps[];
|
||||
data: object[];
|
||||
showMenu: (columnIndex: number) => void;
|
||||
displayColumnActions: boolean;
|
||||
columnNameMap?: { [key: string]: string };
|
||||
columnMenuOptions: ColumnMenuOptionProps[];
|
||||
columnIndex: number;
|
||||
columnAction: string;
|
||||
onColumnNameChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
handleColumnNameUpdate: () => void;
|
||||
handleResizeColumn: Function;
|
||||
selectTableRow: (
|
||||
row: { original: object; index: number },
|
||||
isSelected: boolean,
|
||||
) => void;
|
||||
pageNo: number;
|
||||
updatePageNo: Function;
|
||||
nextPageClick: () => void;
|
||||
prevPageClick: () => void;
|
||||
onKeyPress: (key: string) => void;
|
||||
serverSidePaginationEnabled: boolean;
|
||||
selectedRowIndex: number;
|
||||
disableDrag: () => void;
|
||||
enableDrag: () => void;
|
||||
}
|
||||
|
||||
export const Table = (props: TableProps) => {
|
||||
const { data, columns } = props;
|
||||
const defaultColumn = React.useMemo(
|
||||
() => ({
|
||||
minWidth: 30,
|
||||
width: 150,
|
||||
maxWidth: 400,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
const pageCount = Math.ceil(data.length / props.pageSize);
|
||||
const currentPageIndex = props.pageNo < pageCount ? props.pageNo : 0;
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
prepareRow,
|
||||
page,
|
||||
pageOptions,
|
||||
} = useTable(
|
||||
{
|
||||
columns,
|
||||
data,
|
||||
defaultColumn,
|
||||
initialState: {
|
||||
pageIndex: currentPageIndex,
|
||||
pageSize: props.pageSize,
|
||||
},
|
||||
manualPagination: true,
|
||||
pageCount,
|
||||
},
|
||||
useFlexLayout,
|
||||
useResizeColumns,
|
||||
usePagination,
|
||||
useRowSelect,
|
||||
);
|
||||
let startIndex = currentPageIndex * props.pageSize;
|
||||
let endIndex = startIndex + props.pageSize;
|
||||
if (props.serverSidePaginationEnabled) {
|
||||
startIndex = 0;
|
||||
endIndex = data.length;
|
||||
}
|
||||
const subPage = page.slice(startIndex, endIndex);
|
||||
const selectedRowIndex = props.selectedRowIndex;
|
||||
return (
|
||||
<TableWrapper
|
||||
width={props.width}
|
||||
height={props.height}
|
||||
id={`table${props.widgetId}`}
|
||||
>
|
||||
<div className="tableWrap">
|
||||
<div {...getTableProps()} className="table">
|
||||
<div onMouseOver={props.disableDrag} onMouseLeave={props.enableDrag}>
|
||||
{headerGroups.map((headerGroup: any, index: number) => (
|
||||
<div
|
||||
key={index}
|
||||
{...headerGroup.getHeaderGroupProps()}
|
||||
className="tr"
|
||||
>
|
||||
{headerGroup.headers.map((column: any, columnIndex: number) => {
|
||||
if (column.isResizing) {
|
||||
props.handleResizeColumn(
|
||||
columnIndex,
|
||||
column.getHeaderProps().style.width,
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key={columnIndex}
|
||||
{...column.getHeaderProps()}
|
||||
className="th header-reorder"
|
||||
>
|
||||
{props.columnIndex === columnIndex &&
|
||||
props.columnAction === "rename_column" && (
|
||||
<InputGroup
|
||||
placeholder="Enter Column Name"
|
||||
onChange={props.onColumnNameChange}
|
||||
onKeyPress={event => props.onKeyPress(event.key)}
|
||||
type="text"
|
||||
defaultValue={
|
||||
props.columnNameMap &&
|
||||
props.columnNameMap[column.id]
|
||||
? props.columnNameMap[column.id]
|
||||
: column.id
|
||||
}
|
||||
className="input-group"
|
||||
onBlur={() => props.handleColumnNameUpdate()}
|
||||
/>
|
||||
)}
|
||||
{(props.columnIndex !== columnIndex ||
|
||||
(props.columnIndex === columnIndex &&
|
||||
"rename_column" !== props.columnAction)) && (
|
||||
<div
|
||||
className={
|
||||
!column.isHidden
|
||||
? "draggable-header"
|
||||
: "hidden-header"
|
||||
}
|
||||
>
|
||||
{column.render("Header")}
|
||||
</div>
|
||||
)}
|
||||
{props.displayColumnActions && (
|
||||
<div className="column-menu">
|
||||
<TableColumnMenuPopup
|
||||
showMenu={props.showMenu}
|
||||
columnMenuOptions={props.columnMenuOptions}
|
||||
columnIndex={columnIndex}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
{...column.getResizerProps()}
|
||||
className={`resizer ${
|
||||
column.isResizing ? "isResizing" : ""
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div {...getTableBodyProps()} className="tbody">
|
||||
{subPage.map((row, index) => {
|
||||
prepareRow(row);
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
{...row.getRowProps()}
|
||||
className={
|
||||
"tr" +
|
||||
`${row.index === selectedRowIndex ? " selected-row" : ""}`
|
||||
}
|
||||
onClick={() => {
|
||||
row.toggleRowSelected();
|
||||
props.selectTableRow(row, row.index === selectedRowIndex);
|
||||
}}
|
||||
>
|
||||
{row.cells.map((cell, cellIndex) => {
|
||||
return (
|
||||
<div
|
||||
key={cellIndex}
|
||||
{...cell.getCellProps()}
|
||||
className="td"
|
||||
data-rowindex={index}
|
||||
data-colindex={cellIndex}
|
||||
>
|
||||
{cell.render("Cell")}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{props.serverSidePaginationEnabled && (
|
||||
<PaginationWrapper>
|
||||
<PaginationItemWrapper
|
||||
disabled={false}
|
||||
onClick={() => {
|
||||
props.prevPageClick();
|
||||
}}
|
||||
>
|
||||
<Icon icon="chevron-left" iconSize={16} color="#A1ACB3" />
|
||||
</PaginationItemWrapper>
|
||||
<PaginationItemWrapper selected className="page-item">
|
||||
{props.pageNo + 1}
|
||||
</PaginationItemWrapper>
|
||||
<PaginationItemWrapper
|
||||
disabled={false}
|
||||
onClick={() => {
|
||||
props.nextPageClick();
|
||||
}}
|
||||
>
|
||||
<Icon icon="chevron-right" iconSize={16} color="#A1ACB3" />
|
||||
</PaginationItemWrapper>
|
||||
</PaginationWrapper>
|
||||
)}
|
||||
{!props.serverSidePaginationEnabled && (
|
||||
<PaginationWrapper>
|
||||
<PaginationItemWrapper
|
||||
disabled={currentPageIndex === 0}
|
||||
onClick={() => {
|
||||
const pageNo = currentPageIndex > 0 ? currentPageIndex - 1 : 0;
|
||||
props.updatePageNo(pageNo + 1);
|
||||
}}
|
||||
>
|
||||
<Icon icon="chevron-left" iconSize={16} color="#A1ACB3" />
|
||||
</PaginationItemWrapper>
|
||||
{pageOptions.map((pageNumber: number, index: number) => {
|
||||
return (
|
||||
<PaginationItemWrapper
|
||||
key={index}
|
||||
selected={pageNumber === currentPageIndex}
|
||||
onClick={() => {
|
||||
props.updatePageNo(pageNumber + 1);
|
||||
}}
|
||||
className="page-item"
|
||||
>
|
||||
{index + 1}
|
||||
</PaginationItemWrapper>
|
||||
);
|
||||
})}
|
||||
<PaginationItemWrapper
|
||||
disabled={currentPageIndex === pageCount - 1}
|
||||
onClick={() => {
|
||||
const pageNo =
|
||||
currentPageIndex < pageCount - 1 ? currentPageIndex + 1 : 0;
|
||||
props.updatePageNo(pageNo + 1);
|
||||
}}
|
||||
>
|
||||
<Icon icon="chevron-right" iconSize={16} color="#A1ACB3" />
|
||||
</PaginationItemWrapper>
|
||||
</PaginationWrapper>
|
||||
)}
|
||||
</TableWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Table;
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
import React from "react";
|
||||
import {
|
||||
Popover,
|
||||
Classes,
|
||||
PopoverInteractionKind,
|
||||
Icon,
|
||||
Position,
|
||||
} from "@blueprintjs/core";
|
||||
import {
|
||||
DropDownWrapper,
|
||||
OptionWrapper,
|
||||
IconOptionWrapper,
|
||||
} from "./TableStyledWrappers";
|
||||
import {
|
||||
ColumnMenuSubOptionProps,
|
||||
ColumnMenuOptionProps,
|
||||
} from "./ReactTableComponent";
|
||||
|
||||
interface TableColumnMenuPopup {
|
||||
showMenu: (index: number) => void;
|
||||
columnIndex: number;
|
||||
columnMenuOptions: ColumnMenuOptionProps[];
|
||||
}
|
||||
|
||||
export const TableColumnMenuPopup = (props: TableColumnMenuPopup) => {
|
||||
return (
|
||||
<Popover
|
||||
minimal
|
||||
usePortal
|
||||
enforceFocus={false}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
position={Position.BOTTOM}
|
||||
>
|
||||
<Icon
|
||||
icon="more"
|
||||
iconSize={12}
|
||||
color="#A1ACB3"
|
||||
onClick={e => {
|
||||
props.showMenu(props.columnIndex);
|
||||
}}
|
||||
/>
|
||||
<DropDownWrapper>
|
||||
{props.columnMenuOptions.map(
|
||||
(option: ColumnMenuOptionProps, index: number) => (
|
||||
<OptionWrapper
|
||||
key={index}
|
||||
onClick={() => {
|
||||
if (option.onClick) {
|
||||
option.onClick(!!option.isSelected);
|
||||
}
|
||||
}}
|
||||
className={
|
||||
option.closeOnClick
|
||||
? Classes.POPOVER_DISMISS
|
||||
: option.category
|
||||
? "non-selectable"
|
||||
: ""
|
||||
}
|
||||
selected={!!option.isSelected}
|
||||
>
|
||||
{!option.options && <div>{option.content}</div>}
|
||||
{option.options && (
|
||||
<Popover
|
||||
minimal
|
||||
usePortal
|
||||
enforceFocus={false}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
position={Position.BOTTOM_RIGHT}
|
||||
className="column-type"
|
||||
>
|
||||
<IconOptionWrapper>{option.content}</IconOptionWrapper>
|
||||
<DropDownWrapper>
|
||||
{option.options.map(
|
||||
(item: ColumnMenuSubOptionProps, itemIndex: number) => (
|
||||
<OptionWrapper
|
||||
key={itemIndex}
|
||||
onClick={item.onClick}
|
||||
className={
|
||||
item.closeOnClick ? Classes.POPOVER_DISMISS : ""
|
||||
}
|
||||
selected={!!item.isSelected}
|
||||
>
|
||||
{item.content}
|
||||
</OptionWrapper>
|
||||
),
|
||||
)}
|
||||
</DropDownWrapper>
|
||||
</Popover>
|
||||
)}
|
||||
</OptionWrapper>
|
||||
),
|
||||
)}
|
||||
</DropDownWrapper>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
import styled from "styled-components";
|
||||
import { Colors } from "constants/Colors";
|
||||
|
||||
export const TableWrapper = styled.div<{ width: number; height: number }>`
|
||||
width: ${props => props.width - 5}px;
|
||||
height: ${props => props.height - 5}px;
|
||||
background: white;
|
||||
border: 1px solid ${Colors.GEYSER_LIGHT};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
.tableWrap {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
border-bottom: 1px solid ${Colors.GEYSER_LIGHT};
|
||||
}
|
||||
.table {
|
||||
border-spacing: 0;
|
||||
color: ${Colors.BLUE_BAYOUX};
|
||||
position: relative;
|
||||
.thead {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.tbody {
|
||||
overflow: scroll;
|
||||
height: ${props => props.height - 5 - 102}px;
|
||||
}
|
||||
.tr {
|
||||
:last-child {
|
||||
.td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
:nth-child(even) {
|
||||
background: ${Colors.ATHENS_GRAY_DARKER};
|
||||
}
|
||||
&.selected-row {
|
||||
background: ${Colors.ATHENS_GRAY};
|
||||
}
|
||||
&:hover {
|
||||
background: ${Colors.ATHENS_GRAY};
|
||||
}
|
||||
}
|
||||
.th,
|
||||
.td {
|
||||
margin: 0;
|
||||
padding: 9px 10px;
|
||||
border-bottom: 1px solid ${Colors.GEYSER_LIGHT};
|
||||
border-right: 1px solid ${Colors.GEYSER_LIGHT};
|
||||
position: relative;
|
||||
:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
.resizer {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translateX(50%);
|
||||
z-index: 1;
|
||||
${"" /* prevents from scrolling while dragging on touch devices */}
|
||||
touch-action:none;
|
||||
&.isResizing {
|
||||
cursor: isResizing;
|
||||
}
|
||||
}
|
||||
}
|
||||
.th {
|
||||
padding: 0 10px 0 0;
|
||||
height: 52px;
|
||||
line-height: 52px;
|
||||
background: ${Colors.ATHENS_GRAY_DARKER};
|
||||
}
|
||||
.td {
|
||||
height: 52px;
|
||||
line-height: 52px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
.draggable-header,
|
||||
.hidden-header {
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: ${Colors.OXFORD_BLUE};
|
||||
font-weight: 500;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.draggable-header {
|
||||
cursor: pointer;
|
||||
&.reorder-line {
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.hidden-header {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.column-menu {
|
||||
cursor: pointer;
|
||||
height: 52px;
|
||||
line-height: 52px;
|
||||
}
|
||||
.th {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
&.highlight-left {
|
||||
border-left: 2px solid ${Colors.GREEN};
|
||||
}
|
||||
&.highlight-right {
|
||||
border-right: 2px solid ${Colors.GREEN};
|
||||
}
|
||||
}
|
||||
.input-group {
|
||||
height: 52px;
|
||||
line-height: 52px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const DropDownWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: white;
|
||||
z-index: 1;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid ${Colors.ATHENS_GRAY};
|
||||
box-shadow: 0px 2px 4px rgba(67, 70, 74, 0.14);
|
||||
`;
|
||||
|
||||
export const OptionWrapper = styled.div<{ selected: boolean }>`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
color: ${props => (props.selected ? Colors.WHITE : Colors.OXFORD_BLUE)};
|
||||
font-size: 14px;
|
||||
min-width: 200px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
margin: 3px 0;
|
||||
background: ${props => (props.selected ? Colors.GREEN : Colors.WHITE)};
|
||||
&:hover {
|
||||
background: ${props => (props.selected ? Colors.GREEN : Colors.POLAR)};
|
||||
}
|
||||
.column-type {
|
||||
width: 100%;
|
||||
}
|
||||
&.non-selectable {
|
||||
color: ${Colors.GRAY};
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export const IconOptionWrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
export const PaginationWrapper = styled.div`
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const PaginationItemWrapper = styled.div<{
|
||||
disabled?: boolean;
|
||||
selected?: boolean;
|
||||
}>`
|
||||
background: ${props => (props.disabled ? Colors.ATHENS_GRAY : Colors.WHITE)};
|
||||
border: 1px solid
|
||||
${props => (props.selected ? Colors.GREEN : Colors.GEYSER_LIGHT)};
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 0 0 8px;
|
||||
pointer-events: ${props => props.disabled && "none"};
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
border-color: ${Colors.GREEN};
|
||||
}
|
||||
`;
|
||||
|
||||
export const MenuColumnWrapper = styled.div<{ selected: boolean }>`
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
background: ${props => props.selected && Colors.GREEN};
|
||||
position: relative;
|
||||
.title {
|
||||
color: ${props => (props.selected ? Colors.WHITE : Colors.OXFORD_BLUE)};
|
||||
margin-left: 10px;
|
||||
}
|
||||
.sub-menu {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ActionWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px 5px 0 0;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
height: 32px;
|
||||
color: ${Colors.WHITE};
|
||||
background: ${Colors.GREEN};
|
||||
border-radius: 4px;
|
||||
letter-spacing: -0.03em;
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
export const CellWrapper = styled.div<{ isHidden: boolean }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: normal;
|
||||
opacity: ${props => (props.isHidden ? "0.6" : "1")};
|
||||
.image-cell {
|
||||
width: 40px;
|
||||
height: 32px;
|
||||
margin: 0 5px 0 0;
|
||||
border-radius: 4px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
video {
|
||||
border-radius: 4px;
|
||||
}
|
||||
`;
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
import React from "react";
|
||||
import { Icon } from "@blueprintjs/core";
|
||||
import moment from "moment-timezone";
|
||||
import {
|
||||
MenuColumnWrapper,
|
||||
CellWrapper,
|
||||
ActionWrapper,
|
||||
} from "./TableStyledWrappers";
|
||||
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
||||
import { ColumnMenuOptionProps } from "./ReactTableComponent";
|
||||
|
||||
interface MenuOptionProps {
|
||||
columnAccessor?: string;
|
||||
isColumnHidden: boolean;
|
||||
columnType: string;
|
||||
format?: string;
|
||||
hideColumn: (isColumnHidden: boolean) => void;
|
||||
updateAction: (action: string) => void;
|
||||
updateColumnType: (columnType: string) => void;
|
||||
handleUpdateCurrencySymbol: (currencySymbol: string) => void;
|
||||
handleDateFormatUpdate: (dateFormat: string) => void;
|
||||
}
|
||||
|
||||
export const getMenuOptions = (props: MenuOptionProps) => {
|
||||
const basicOptions: ColumnMenuOptionProps[] = [
|
||||
{
|
||||
content: "Rename a Column",
|
||||
closeOnClick: true,
|
||||
id: "rename_column",
|
||||
onClick: () => {
|
||||
props.updateAction("rename_column");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: props.isColumnHidden ? "Show Column" : "Hide Column",
|
||||
closeOnClick: true,
|
||||
id: "hide_column",
|
||||
onClick: () => {
|
||||
props.hideColumn(props.isColumnHidden);
|
||||
},
|
||||
},
|
||||
];
|
||||
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 === "image"}>
|
||||
<Icon
|
||||
icon="media"
|
||||
iconSize={12}
|
||||
color={props.columnType === "image" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
<div className="title">Image</div>
|
||||
</MenuColumnWrapper>
|
||||
),
|
||||
closeOnClick: true,
|
||||
isSelected: props.columnType === "image",
|
||||
onClick: (isSelected: boolean) => {
|
||||
if (isSelected) {
|
||||
props.updateColumnType("");
|
||||
} else {
|
||||
props.updateColumnType("image");
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
content: (
|
||||
<MenuColumnWrapper selected={props.columnType === "video"}>
|
||||
<Icon
|
||||
icon="video"
|
||||
iconSize={12}
|
||||
color={props.columnType === "video" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
<div className="title">Video</div>
|
||||
</MenuColumnWrapper>
|
||||
),
|
||||
isSelected: props.columnType === "video",
|
||||
closeOnClick: true,
|
||||
onClick: (isSelected: boolean) => {
|
||||
if (isSelected) {
|
||||
props.updateColumnType("");
|
||||
} else {
|
||||
props.updateColumnType("video");
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
content: (
|
||||
<MenuColumnWrapper selected={props.columnType === "text"}>
|
||||
<Icon
|
||||
icon="label"
|
||||
iconSize={12}
|
||||
color={props.columnType === "text" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
<div className="title">Text</div>
|
||||
</MenuColumnWrapper>
|
||||
),
|
||||
closeOnClick: true,
|
||||
isSelected: props.columnType === "text",
|
||||
onClick: (isSelected: boolean) => {
|
||||
if (isSelected) {
|
||||
props.updateColumnType("");
|
||||
} else {
|
||||
props.updateColumnType("text");
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
content: (
|
||||
<MenuColumnWrapper selected={props.columnType === "currency"}>
|
||||
<Icon
|
||||
icon="dollar"
|
||||
iconSize={12}
|
||||
color={props.columnType === "currency" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
<div className="title">Currency</div>
|
||||
<Icon
|
||||
className="sub-menu"
|
||||
icon="chevron-right"
|
||||
iconSize={16}
|
||||
color={props.columnType === "currency" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
</MenuColumnWrapper>
|
||||
),
|
||||
closeOnClick: false,
|
||||
isSelected: props.columnType === "currency",
|
||||
options: [
|
||||
{
|
||||
content: "USD - $",
|
||||
isSelected: props.format === "$",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleUpdateCurrencySymbol("$");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "INR - ₹",
|
||||
isSelected: props.format === "₹",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleUpdateCurrencySymbol("₹");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "GBP - £",
|
||||
isSelected: props.format === "£",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleUpdateCurrencySymbol("£");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "AUD - A$",
|
||||
isSelected: props.format === "A$",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleUpdateCurrencySymbol("A$");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "EUR - €",
|
||||
isSelected: props.format === "€",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleUpdateCurrencySymbol("€");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "SGD - S$",
|
||||
isSelected: props.format === "S$",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleUpdateCurrencySymbol("S$");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "CAD - C$",
|
||||
isSelected: props.format === "C$",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleUpdateCurrencySymbol("C$");
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
content: (
|
||||
<MenuColumnWrapper selected={props.columnType === "date"}>
|
||||
<Icon
|
||||
icon="calendar"
|
||||
iconSize={12}
|
||||
color={props.columnType === "date" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
<div className="title">Date</div>
|
||||
<Icon
|
||||
className="sub-menu"
|
||||
icon="chevron-right"
|
||||
iconSize={16}
|
||||
color={props.columnType === "date" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
</MenuColumnWrapper>
|
||||
),
|
||||
closeOnClick: false,
|
||||
isSelected: props.columnType === "date",
|
||||
options: [
|
||||
{
|
||||
content: "MM-DD-YY",
|
||||
isSelected: props.format === "MM-DD-YY",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleDateFormatUpdate("MM-DD-YY");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "DD-MM-YY",
|
||||
isSelected: props.format === "DD-MM-YY",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleDateFormatUpdate("DD-MM-YY");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "DD/MM/YY",
|
||||
isSelected: props.format === "DD/MM/YY",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleDateFormatUpdate("DD/MM/YY");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "MM/DD/YY",
|
||||
isSelected: props.format === "MM/DD/YY",
|
||||
closeOnClick: true,
|
||||
onClick: () => {
|
||||
props.handleDateFormatUpdate("MM/DD/YY");
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
content: (
|
||||
<MenuColumnWrapper selected={props.columnType === "time"}>
|
||||
<Icon
|
||||
icon="time"
|
||||
iconSize={12}
|
||||
color={props.columnType === "time" ? "#ffffff" : "#2E3D49"}
|
||||
/>
|
||||
<div className="title">Time</div>
|
||||
</MenuColumnWrapper>
|
||||
),
|
||||
closeOnClick: true,
|
||||
isSelected: props.columnType === "time",
|
||||
onClick: (isSelected: boolean) => {
|
||||
if (isSelected) {
|
||||
props.updateColumnType("");
|
||||
} else {
|
||||
props.updateColumnType("time");
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
return columnMenuOptions;
|
||||
};
|
||||
|
||||
export const renderCell = (
|
||||
value: any,
|
||||
columnType: string,
|
||||
isHidden: boolean,
|
||||
format?: string,
|
||||
) => {
|
||||
if (!value) {
|
||||
return <div></div>;
|
||||
}
|
||||
switch (columnType) {
|
||||
case "image":
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>
|
||||
{value
|
||||
.toString()
|
||||
.split(",")
|
||||
.map((item: string, index: number) => {
|
||||
if (item.match(/\.(jpeg|jpg|gif|png)$/)) {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="image-cell"
|
||||
style={{ backgroundImage: `url("${item}")` }}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <div>Invalid Image</div>;
|
||||
}
|
||||
})}
|
||||
</CellWrapper>
|
||||
);
|
||||
case "video":
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>
|
||||
<video width="56" height="32" autoPlay={false}>
|
||||
<source src={`${value}`} type="video/mp4" />
|
||||
</video>
|
||||
</CellWrapper>
|
||||
);
|
||||
case "currency":
|
||||
if (!isNaN(value)) {
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>{`${format}${value}`}</CellWrapper>
|
||||
);
|
||||
} else {
|
||||
return <CellWrapper isHidden={isHidden}>Invalid Value</CellWrapper>;
|
||||
}
|
||||
case "date":
|
||||
let isValidDate = true;
|
||||
if (isNaN(value)) {
|
||||
const dateTime = Date.parse(value);
|
||||
if (isNaN(dateTime)) {
|
||||
isValidDate = false;
|
||||
}
|
||||
}
|
||||
if (isValidDate) {
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>
|
||||
{moment(value).format(format)}
|
||||
</CellWrapper>
|
||||
);
|
||||
} else {
|
||||
return <CellWrapper isHidden={isHidden}>Invalid Date</CellWrapper>;
|
||||
}
|
||||
case "time":
|
||||
let isValidTime = true;
|
||||
if (isNaN(value)) {
|
||||
const time = Date.parse(value);
|
||||
if (isNaN(time)) {
|
||||
isValidTime = false;
|
||||
}
|
||||
}
|
||||
if (isValidTime) {
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>
|
||||
{moment(value).format("HH:mm")}
|
||||
</CellWrapper>
|
||||
);
|
||||
} else {
|
||||
return <CellWrapper isHidden={isHidden}>Invalid Time</CellWrapper>;
|
||||
}
|
||||
case "text":
|
||||
return <CellWrapper isHidden={isHidden}>{value}</CellWrapper>;
|
||||
default:
|
||||
return <CellWrapper isHidden={isHidden}>{value}</CellWrapper>;
|
||||
}
|
||||
};
|
||||
|
||||
interface RenderActionProps {
|
||||
columnActions?: ColumnAction[];
|
||||
onCommandClick: (dynamicTrigger: string) => void;
|
||||
}
|
||||
|
||||
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 (
|
||||
<ActionWrapper
|
||||
key={index}
|
||||
onClick={() => {
|
||||
props.onCommandClick(action.dynamicTrigger);
|
||||
}}
|
||||
>
|
||||
{action.label}
|
||||
</ActionWrapper>
|
||||
);
|
||||
})}
|
||||
</CellWrapper>
|
||||
);
|
||||
};
|
||||
|
|
@ -45,6 +45,8 @@ export const Colors: Record<string, string> = {
|
|||
BLUE_CHARCOAL: "#23292E",
|
||||
TROUT: "#4C565E",
|
||||
JAFFA_DARK: "#EF7541",
|
||||
GRAY: "#828282",
|
||||
ATHENS_GRAY_DARKER: "#F8F9FA",
|
||||
};
|
||||
|
||||
export type Color = typeof Colors[keyof typeof Colors];
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export const AppViewerHeader = (props: AppViewerHeaderProps) => {
|
|||
<HeaderWrapper>
|
||||
{props.url && (
|
||||
<Button
|
||||
className="t--back-to-editor"
|
||||
href={props.url}
|
||||
intent="primary"
|
||||
icon="chevron-left"
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export type CustomizedDropdownProps = {
|
|||
openOnHover?: boolean;
|
||||
};
|
||||
|
||||
const getIcon = (icon?: string, intent?: Intent) => {
|
||||
export const getIcon = (icon?: string, intent?: Intent) => {
|
||||
if (icon) {
|
||||
if (MenuIcons[icon]) {
|
||||
return MenuIcons[icon]({
|
||||
|
|
@ -68,7 +68,7 @@ const getIcon = (icon?: string, intent?: Intent) => {
|
|||
}
|
||||
};
|
||||
|
||||
const getContentSection = (section: CustomizedDropdownOptionSection) => {
|
||||
export const getContentSection = (section: CustomizedDropdownOptionSection) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{section.options &&
|
||||
|
|
|
|||
|
|
@ -248,11 +248,19 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
parsed,
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Table Data`,
|
||||
};
|
||||
} else if (!_.every(parsed, datum => _.isObject(datum))) {
|
||||
} else if (
|
||||
!_.every(parsed, datum => {
|
||||
return (
|
||||
_.isObject(datum) &&
|
||||
Object.keys(datum).filter(key => _.isString(key) && key.length === 0)
|
||||
.length === 0
|
||||
);
|
||||
})
|
||||
) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: [],
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Table Data`,
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: [{ "key1" : "val1", "key2" : "val2" }, { "key1" : "val3", "key2" : "val4" }]`,
|
||||
};
|
||||
}
|
||||
return { isValid, parsed };
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
|||
import { WidgetType } from "constants/WidgetConstants";
|
||||
import { EventType } from "constants/ActionConstants";
|
||||
import { forIn } from "lodash";
|
||||
import ReactTableComponent from "components/designSystems/appsmith/ReactTableComponent";
|
||||
|
||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||
import {
|
||||
|
|
@ -105,11 +106,70 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
this.props.tableData.length === 0 ? 2 : TABLE_HEADER_HEIGHT;
|
||||
const tableContentHeight =
|
||||
componentHeight - TABLE_FOOTER_HEIGHT - tableHeaderHeight - exportHeight;
|
||||
const pageSize = Math.floor(tableContentHeight / ROW_HEIGHT);
|
||||
// Use below code to calculate page size for old table component
|
||||
// const pageSize = Math.floor(tableContentHeight / ROW_HEIGHT);
|
||||
const pageSize = Math.floor((componentHeight - 104) / 52);
|
||||
|
||||
if (pageSize !== this.props.pageSize) {
|
||||
super.updateWidgetMetaProperty("pageSize", pageSize);
|
||||
}
|
||||
|
||||
// /*
|
||||
return (
|
||||
<Suspense fallback={<Skeleton />}>
|
||||
<ReactTableComponent
|
||||
height={componentHeight}
|
||||
width={componentWidth}
|
||||
tableData={tableData}
|
||||
widgetId={this.props.widgetId}
|
||||
renderMode={this.props.renderMode}
|
||||
hiddenColumns={hiddenColumns}
|
||||
columnActions={this.props.columnActions}
|
||||
columnNameMap={this.props.columnNameMap}
|
||||
columnTypeMap={this.props.columnTypeMap}
|
||||
columnOrder={this.props.columnOrder}
|
||||
pageSize={pageSize}
|
||||
onCommandClick={this.onCommandClick}
|
||||
selectedRowIndex={
|
||||
this.props.selectedRowIndex === undefined
|
||||
? -1
|
||||
: this.props.selectedRowIndex
|
||||
}
|
||||
serverSidePaginationEnabled={serverSidePaginationEnabled}
|
||||
onRowClick={this.handleRowClick}
|
||||
pageNo={pageNo}
|
||||
nextPageClick={this.handleNextPageClick}
|
||||
prevPageClick={this.handlePrevPageClick}
|
||||
updatePageNo={(pageNo: number) => {
|
||||
super.updateWidgetMetaProperty("pageNo", pageNo);
|
||||
}}
|
||||
updateHiddenColumns={(hiddenColumns?: string[]) => {
|
||||
super.updateWidgetProperty("hiddenColumns", hiddenColumns);
|
||||
}}
|
||||
updateColumnType={(columnTypeMap: {
|
||||
[key: string]: { type: string; format: string };
|
||||
}) => {
|
||||
super.updateWidgetProperty("columnTypeMap", columnTypeMap);
|
||||
}}
|
||||
updateColumnName={(columnNameMap: { [key: string]: string }) => {
|
||||
super.updateWidgetProperty("columnNameMap", columnNameMap);
|
||||
}}
|
||||
handleResizeColumn={(columnSizeMap: { [key: string]: number }) => {
|
||||
super.updateWidgetProperty("columnSizeMap", columnSizeMap);
|
||||
}}
|
||||
handleReorderColumn={(columnOrder: string[]) => {
|
||||
super.updateWidgetProperty("columnOrder", columnOrder);
|
||||
}}
|
||||
columnSizeMap={this.props.columnSizeMap}
|
||||
resetSelectedRowIndex={this.resetSelectedRowIndex}
|
||||
disableDrag={(disable: boolean) => {
|
||||
this.disableDrag(disable);
|
||||
}}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
// */
|
||||
/*
|
||||
return (
|
||||
<Suspense fallback={<Skeleton />}>
|
||||
<TableComponent
|
||||
|
|
@ -144,10 +204,11 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
/>
|
||||
</Suspense>
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
updateHiddenColumns = (hiddenColumns?: string[]) => {
|
||||
this.updateWidgetProperty("hiddenColumns", hiddenColumns);
|
||||
super.updateWidgetProperty("hiddenColumns", hiddenColumns);
|
||||
};
|
||||
|
||||
onCommandClick = (action: string) => {
|
||||
|
|
@ -225,6 +286,10 @@ export interface TableWidgetProps extends WidgetProps {
|
|||
columnActions?: ColumnAction[];
|
||||
serverSidePaginationEnabled?: boolean;
|
||||
hiddenColumns?: string[];
|
||||
columnOrder?: string[];
|
||||
columnNameMap?: { [key: string]: string };
|
||||
columnTypeMap?: { [key: string]: { type: string; format: string } };
|
||||
columnSizeMap?: { [key: string]: number };
|
||||
}
|
||||
|
||||
export default TableWidget;
|
||||
|
|
|
|||
120
app/client/typings/react-table-config/index.d.ts
vendored
Normal file
120
app/client/typings/react-table-config/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
import {
|
||||
UseColumnOrderInstanceProps,
|
||||
UseColumnOrderState,
|
||||
UseExpandedHooks,
|
||||
UseExpandedInstanceProps,
|
||||
UseExpandedOptions,
|
||||
UseExpandedRowProps,
|
||||
UseExpandedState,
|
||||
UseFiltersColumnOptions,
|
||||
UseFiltersColumnProps,
|
||||
UseFiltersInstanceProps,
|
||||
UseFiltersOptions,
|
||||
UseFiltersState,
|
||||
UseGlobalFiltersColumnOptions,
|
||||
UseGlobalFiltersInstanceProps,
|
||||
UseGlobalFiltersOptions,
|
||||
UseGlobalFiltersState,
|
||||
UseGroupByCellProps,
|
||||
UseGroupByColumnOptions,
|
||||
UseGroupByColumnProps,
|
||||
UseGroupByHooks,
|
||||
UseGroupByInstanceProps,
|
||||
UseGroupByOptions,
|
||||
UseGroupByRowProps,
|
||||
UseGroupByState,
|
||||
UsePaginationInstanceProps,
|
||||
UsePaginationOptions,
|
||||
UsePaginationState,
|
||||
UseResizeColumnsColumnOptions,
|
||||
UseResizeColumnsColumnProps,
|
||||
UseResizeColumnsOptions,
|
||||
UseResizeColumnsState,
|
||||
UseRowSelectHooks,
|
||||
UseRowSelectInstanceProps,
|
||||
UseRowSelectOptions,
|
||||
UseRowSelectRowProps,
|
||||
UseRowSelectState,
|
||||
UseRowStateCellProps,
|
||||
UseRowStateInstanceProps,
|
||||
UseRowStateOptions,
|
||||
UseRowStateRowProps,
|
||||
UseRowStateState,
|
||||
UseSortByColumnOptions,
|
||||
UseSortByColumnProps,
|
||||
UseSortByHooks,
|
||||
UseSortByInstanceProps,
|
||||
UseSortByOptions,
|
||||
UseSortByState,
|
||||
} from "react-table";
|
||||
|
||||
declare module "react-table" {
|
||||
// take this file as-is, or comment out the sections that don't apply to your plugin configuration
|
||||
|
||||
export interface TableOptions<D extends object>
|
||||
extends UseExpandedOptions<D>,
|
||||
UseFiltersOptions<D>,
|
||||
UseGlobalFiltersOptions<D>,
|
||||
UseGroupByOptions<D>,
|
||||
UsePaginationOptions<D>,
|
||||
UseResizeColumnsOptions<D>,
|
||||
UseRowSelectOptions<D>,
|
||||
UseRowStateOptions<D>,
|
||||
UseSortByOptions<D>,
|
||||
// note that having Record here allows you to add anything to the options, this matches the spirit of the
|
||||
// underlying js library, but might be cleaner if it's replaced by a more specific type that matches your
|
||||
// feature set, this is a safe default.
|
||||
Record<string, any> {}
|
||||
|
||||
export interface Hooks<D extends object = {}>
|
||||
extends UseExpandedHooks<D>,
|
||||
UseGroupByHooks<D>,
|
||||
UseRowSelectHooks<D>,
|
||||
UseSortByHooks<D> {}
|
||||
|
||||
export interface TableInstance<D extends object = {}>
|
||||
extends UseColumnOrderInstanceProps<D>,
|
||||
UseExpandedInstanceProps<D>,
|
||||
UseFiltersInstanceProps<D>,
|
||||
UseGlobalFiltersInstanceProps<D>,
|
||||
UseGroupByInstanceProps<D>,
|
||||
UsePaginationInstanceProps<D>,
|
||||
UseRowSelectInstanceProps<D>,
|
||||
UseRowStateInstanceProps<D>,
|
||||
UseSortByInstanceProps<D> {}
|
||||
|
||||
export interface TableState<D extends object = {}>
|
||||
extends UseColumnOrderState<D>,
|
||||
UseExpandedState<D>,
|
||||
UseFiltersState<D>,
|
||||
UseGlobalFiltersState<D>,
|
||||
UseGroupByState<D>,
|
||||
UsePaginationState<D>,
|
||||
UseResizeColumnsState<D>,
|
||||
UseRowSelectState<D>,
|
||||
UseRowStateState<D>,
|
||||
UseSortByState<D> {}
|
||||
|
||||
export interface Column<D extends object = {}>
|
||||
extends UseFiltersColumnOptions<D>,
|
||||
UseGlobalFiltersColumnOptions<D>,
|
||||
UseGroupByColumnOptions<D>,
|
||||
UseResizeColumnsColumnOptions<D>,
|
||||
UseSortByColumnOptions<D> {}
|
||||
|
||||
export interface ColumnInstance<D extends object = {}>
|
||||
extends UseFiltersColumnProps<D>,
|
||||
UseGroupByColumnProps<D>,
|
||||
UseResizeColumnsColumnProps<D>,
|
||||
UseSortByColumnProps<D> {}
|
||||
|
||||
export interface Cell<D extends object = {}>
|
||||
extends UseGroupByCellProps<D>,
|
||||
UseRowStateCellProps<D> {}
|
||||
|
||||
export interface Row<D extends object = {}>
|
||||
extends UseExpandedRowProps<D>,
|
||||
UseGroupByRowProps<D>,
|
||||
UseRowSelectRowProps<D>,
|
||||
UseRowStateRowProps<D> {}
|
||||
}
|
||||
|
|
@ -2978,6 +2978,12 @@
|
|||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-table@^7.0.13":
|
||||
version "7.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-table/-/react-table-7.0.13.tgz#4c6879b1e93b918b86144206356dff31e2cd2c0b"
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-tabs@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-tabs/-/react-tabs-2.3.1.tgz#62d3322667ac228c4d0f9f36ac9f86988c0b3971"
|
||||
|
|
@ -9549,7 +9555,6 @@ loglevel@^1.6.6:
|
|||
loglevel@^1.6.7:
|
||||
version "1.6.7"
|
||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.7.tgz#b3e034233188c68b889f5b862415306f565e2c56"
|
||||
integrity sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A==
|
||||
|
||||
loglevelnext@^1.0.1:
|
||||
version "1.0.5"
|
||||
|
|
@ -12561,6 +12566,10 @@ react-syntax-highlighter@^11.0.2:
|
|||
prismjs "^1.8.4"
|
||||
refractor "^2.4.1"
|
||||
|
||||
react-table@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0.tgz#3297e454cbffe916626b184f5394d7e7e098fa36"
|
||||
|
||||
react-tabs@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.1.0.tgz#ecc50f034c1d6da2606fab9293055bbc861b382e"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user