mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
Use react-table for rendering tables
This commit is contained in:
parent
d53393b73c
commit
b22386b1b0
3 changed files with 239 additions and 73 deletions
|
|
@ -1,89 +1,168 @@
|
|||
import React from 'react';
|
||||
import React, { useMemo, useState, useEffect } from "react";
|
||||
import { useTable, useFilters } from "react-table";
|
||||
import { resolve, findProp } from '@/_helpers/utils';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
export const Table = function Table({ id, component, onComponentClick, currentState, onEvent }) {
|
||||
export function Table({ id, component, onComponentClick, currentState, onEvent }) {
|
||||
|
||||
const backgroundColor = component.definition.styles.backgroundColor.value;
|
||||
const color = component.definition.styles.textColor.value;
|
||||
const actions = component.definition.properties.actions || { value: []};
|
||||
|
||||
let loadingState = false;
|
||||
const loadingStateProperty = component.definition.properties.loadingState;
|
||||
if(loadingStateProperty && currentState) {
|
||||
loadingState = resolve(loadingStateProperty.value, currentState);
|
||||
}
|
||||
|
||||
const [filterInput, setFilterInput] = useState("");
|
||||
|
||||
const handleFilterChange = e => {
|
||||
const value = e.target.value || undefined;
|
||||
setFilter("name", value);
|
||||
setFilterInput(value);
|
||||
};
|
||||
|
||||
const backgroundColor = component.definition.styles.backgroundColor.value;
|
||||
const color = component.definition.styles.textColor.value;
|
||||
const columns = component.definition.properties.columns.value;
|
||||
const actions = component.definition.properties.actions || { value: []};
|
||||
const columnData = component.definition.properties.columns.value.map((column) => {
|
||||
return { Header: column.name, accessor: column.key || column.name }
|
||||
})
|
||||
|
||||
const loadingStateProperty = component.definition.properties.loadingState;
|
||||
|
||||
let loadingState = false;
|
||||
if(loadingStateProperty && currentState) {
|
||||
loadingState = resolve(loadingStateProperty.value, currentState);
|
||||
}
|
||||
|
||||
console.log('currentState', currentState);
|
||||
|
||||
let data = []
|
||||
let tableData = []
|
||||
if(currentState) {
|
||||
data = resolve(component.definition.properties.data.value, currentState, []);
|
||||
console.log('resolved param', data);
|
||||
}
|
||||
|
||||
function findColumnValue(row, column) {
|
||||
if(column.key) {
|
||||
return findProp(row, column.key);
|
||||
} else {
|
||||
return findProp(row, column.name);
|
||||
}
|
||||
tableData = resolve(component.definition.properties.data.value, currentState, []);
|
||||
console.log('resolved param', tableData);
|
||||
}
|
||||
|
||||
// Quick fix, need to remove later
|
||||
data = data ? data : [];
|
||||
tableData = tableData ? tableData : [];
|
||||
|
||||
const computedStyles = {
|
||||
|
||||
const columns = useMemo(
|
||||
() =>
|
||||
[
|
||||
...columnData,
|
||||
{
|
||||
id: 'actions',
|
||||
Header: 'Actions',
|
||||
accessor: 'edit',
|
||||
Cell: (cell) => {
|
||||
return actions.value.map((action) =>
|
||||
<button
|
||||
className="btn btn-sm m-1 btn-light"
|
||||
onClick={(e) => { e.stopPropagation(); onEvent('onTableActionButtonClicked', { component, data: cell.row.original, action }); }}
|
||||
>
|
||||
{action.buttonText}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const data = useMemo(
|
||||
() =>
|
||||
tableData,
|
||||
[tableData.length]
|
||||
);
|
||||
|
||||
const computedStyles = {
|
||||
backgroundColor,
|
||||
color
|
||||
color,
|
||||
width: '700px'
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="table-responsive table-bordered" style={{...computedStyles, width: '700px'}} onClick={() => onComponentClick(id, component) }>
|
||||
<table
|
||||
class="table table-vcenter table-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.map((column) => <th>{column.name}</th>)}
|
||||
{actions.value.length > 0 &&
|
||||
<th>Actions</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
rows,
|
||||
prepareRow,
|
||||
setFilter
|
||||
} = useTable( {
|
||||
columns,
|
||||
data
|
||||
},
|
||||
useFilters,
|
||||
);
|
||||
|
||||
{data.map((row =>
|
||||
<tr onClick={(e) => { e.stopPropagation(); onEvent('onRowClicked', { component, data: row }); }}>
|
||||
{columns.map((column) => <td>{findColumnValue(row, column)}</td>)}
|
||||
|
||||
{actions.value.length > 0 &&
|
||||
<td>
|
||||
{actions.value.map((action) => (
|
||||
<button
|
||||
class="btn btn-sm m-1 btn-light"
|
||||
onClick={(e) => { e.stopPropagation(); onEvent('onTableActionButtonClicked', { component, data: row, action }); }}
|
||||
>
|
||||
{action.buttonText}
|
||||
</button>
|
||||
))}
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
{/* <div className="table-footer p-2">
|
||||
Records 1-10 of 242
|
||||
</div> */}
|
||||
</table>
|
||||
|
||||
{loadingState &&
|
||||
return (
|
||||
<div class="card" style={{width: '702px'}} onClick={() => onComponentClick(id, component) }>
|
||||
<div class="card-body border-bottom py-3">
|
||||
<div class="d-flex">
|
||||
<div class="text-muted">
|
||||
Show
|
||||
<div class="mx-2 d-inline-block">
|
||||
<input type="text" class="form-control form-control-sm" value="8" size="3" aria-label="Invoices count"/>
|
||||
</div>
|
||||
entries
|
||||
</div>
|
||||
<div class="ms-auto text-muted">
|
||||
Search:
|
||||
<div class="ms-2 d-inline-block">
|
||||
<input
|
||||
className="form-control form-control-sm"
|
||||
value={filterInput}
|
||||
onChange={handleFilterChange}
|
||||
placeholder={"Search name"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table {...getTableProps()} class="table table-vcenter table-nowrap table-bordered" style={computedStyles}>
|
||||
<thead>
|
||||
{headerGroups.map(headerGroup => (
|
||||
<tr {...headerGroup.getHeaderGroupProps()}>
|
||||
{headerGroup.headers.map(column => (
|
||||
<th {...column.getHeaderProps()}>{column.render("Header")}</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody {...getTableBodyProps()}>
|
||||
{rows.map((row, i) => {
|
||||
prepareRow(row);
|
||||
return (
|
||||
<tr {...row.getRowProps()} onClick={(e) => { e.stopPropagation(); onEvent('onRowClicked', { component, data: row.original }); }}>
|
||||
{row.cells.map(cell => {
|
||||
return <td {...cell.getCellProps()}>{cell.render("Cell")}</td>;
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
{loadingState &&
|
||||
<div style={{width: '100%'}} className="p-5">
|
||||
<Skeleton count={5}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
<div class="card-footer d-flex align-items-center">
|
||||
<p class="m-0 text-muted">Showing <span>1</span> to <span>8</span> of <span>16</span> entries</p>
|
||||
<ul class="pagination m-0 ms-auto">
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><polyline points="15 6 9 12 15 18"></polyline></svg>
|
||||
prev
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item"><a class="page-link" href="#">1</a></li>
|
||||
<li class="page-item active"><a class="page-link" href="#">2</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">3</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">4</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">5</a></li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><polyline points="9 6 15 12 9 18"></polyline></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
89
frontend/src/Editor/Components/Tables.jsx
Normal file
89
frontend/src/Editor/Components/Tables.jsx
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import React from 'react';
|
||||
import { resolve, findProp } from '@/_helpers/utils';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
export const Table = function Table({ id, component, onComponentClick, currentState, onEvent }) {
|
||||
|
||||
const backgroundColor = component.definition.styles.backgroundColor.value;
|
||||
const color = component.definition.styles.textColor.value;
|
||||
const columns = component.definition.properties.columns.value;
|
||||
const actions = component.definition.properties.actions || { value: []};
|
||||
|
||||
const loadingStateProperty = component.definition.properties.loadingState;
|
||||
|
||||
let loadingState = false;
|
||||
if(loadingStateProperty && currentState) {
|
||||
loadingState = resolve(loadingStateProperty.value, currentState);
|
||||
}
|
||||
|
||||
console.log('currentState', currentState);
|
||||
|
||||
let data = []
|
||||
if(currentState) {
|
||||
data = resolve(component.definition.properties.data.value, currentState, []);
|
||||
console.log('resolved param', data);
|
||||
}
|
||||
|
||||
function findColumnValue(row, column) {
|
||||
if(column.key) {
|
||||
return findProp(row, column.key);
|
||||
} else {
|
||||
return findProp(row, column.name);
|
||||
}
|
||||
}
|
||||
|
||||
// Quick fix, need to remove later
|
||||
data = data ? data : [];
|
||||
|
||||
const computedStyles = {
|
||||
backgroundColor,
|
||||
color
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="table-responsive table-bordered" style={{...computedStyles, width: '700px'}} onClick={() => onComponentClick(id, component) }>
|
||||
<table
|
||||
class="table table-vcenter table-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.map((column) => <th>{column.name}</th>)}
|
||||
{actions.value.length > 0 &&
|
||||
<th>Actions</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
{data.map((row =>
|
||||
<tr onClick={(e) => { e.stopPropagation(); onEvent('onRowClicked', { component, data: row }); }}>
|
||||
{columns.map((column) => <td>{findColumnValue(row, column)}</td>)}
|
||||
|
||||
{actions.value.length > 0 &&
|
||||
<td>
|
||||
{actions.value.map((action) => (
|
||||
<button
|
||||
class="btn btn-sm m-1 btn-light"
|
||||
onClick={(e) => { e.stopPropagation(); onEvent('onTableActionButtonClicked', { component, data: row, action }); }}
|
||||
>
|
||||
{action.buttonText}
|
||||
</button>
|
||||
))}
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
{/* <div className="table-footer p-2">
|
||||
Records 1-10 of 242
|
||||
</div> */}
|
||||
</table>
|
||||
|
||||
{loadingState &&
|
||||
<div style={{width: '100%'}} className="p-5">
|
||||
<Skeleton count={5}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -51,7 +51,6 @@ export const componentTypes = [
|
|||
'onRowClicked'
|
||||
],
|
||||
styles: {
|
||||
backgroundColor: { type: 'color'},
|
||||
textColor: { type: 'color'}
|
||||
},
|
||||
definition: {
|
||||
|
|
@ -73,7 +72,6 @@ export const componentTypes = [
|
|||
}
|
||||
},
|
||||
styles: {
|
||||
backgroundColor: { value: '' },
|
||||
textColor: { value: '' }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue