2021-04-30 06:31:32 +00:00
import React , { useMemo , useState , useEffect } from 'react' ;
import {
useTable ,
useFilters ,
useSortBy ,
useGlobalFilter ,
useAsyncDebounce ,
usePagination ,
useBlockLayout ,
2021-04-30 08:10:57 +00:00
useResizeColumns
2021-04-30 06:31:32 +00:00
} from 'react-table' ;
2021-09-06 08:50:38 +00:00
import { resolveReferences , resolveWidgetFieldValue , validateWidget } from '@/_helpers/utils' ;
2021-04-24 16:32:14 +00:00
import SelectSearch , { fuzzySearch } from 'react-select-search' ;
2021-04-30 06:31:32 +00:00
import { useExportData } from 'react-table-plugins' ;
import Papa from 'papaparse' ;
2021-05-02 13:45:13 +00:00
import { Pagination } from './Pagination' ;
2021-05-09 07:26:54 +00:00
import { CustomSelect } from './CustomSelect' ;
2021-05-09 10:51:26 +00:00
import { Tags } from './Tags' ;
2021-08-02 04:46:59 +00:00
import { Radio } from './Radio' ;
2021-08-20 04:13:16 +00:00
import { Toggle } from './Toggle'
2021-08-25 16:37:29 +00:00
import { Datepicker } from './Datepicker' ;
2021-04-25 05:14:54 +00:00
2021-04-24 18:57:18 +00:00
var _ = require ( 'lodash' ) ;
2021-04-03 05:25:41 +00:00
2021-04-30 06:31:32 +00:00
export function Table ( {
id ,
width ,
height ,
component ,
onComponentClick ,
currentState = { components : { } } ,
onEvent ,
paramUpdated ,
changeCanDrag ,
onComponentOptionChanged ,
2021-07-03 14:17:47 +00:00
onComponentOptionsChanged ,
darkMode
2021-04-30 06:31:32 +00:00
} ) {
const color = component . definition . styles . textColor . value ;
const actions = component . definition . properties . actions || { value : [ ] } ;
2021-05-02 13:45:13 +00:00
const serverSidePaginationProperty = component . definition . properties . serverSidePagination ;
const serverSidePagination = serverSidePaginationProperty ? serverSidePaginationProperty . value : false ;
2021-04-30 06:31:32 +00:00
2021-06-01 11:24:37 +00:00
const serverSideSearchProperty = component . definition . properties . serverSideSearch ;
const serverSideSearch = serverSideSearchProperty ? serverSideSearchProperty . value : false ;
2021-08-23 11:30:33 +00:00
const displaySearchBoxProperty = component . definition . properties . displaySearchBox ;
const displaySearchBox = displaySearchBoxProperty ? displaySearchBoxProperty . value : true ;
2021-09-07 05:31:10 +00:00
const showDownloadButtonProperty = component . definition . properties . showDownloadButton ? . value ;
const showDownloadButton = resolveWidgetFieldValue ( showDownloadButtonProperty , currentState ) ? ? true ; // default is true for backward compatibility
const showFilterButtonProperty = component . definition . properties . showFilterButton ? . value ;
const showFilterButton = resolveWidgetFieldValue ( showFilterButtonProperty , currentState ) ? ? true ; // default is true for backward compatibility
2021-09-13 10:07:07 +00:00
const showBulkUpdateActionsProperty = component . definition . properties . showBulkUpdateActions ? . value ;
const showBulkUpdateActions = resolveWidgetFieldValue ( showBulkUpdateActionsProperty , currentState ) ? ? true ; // default is true for backward compatibility
2021-09-07 05:31:10 +00:00
const clientSidePaginationProperty = component . definition . properties . clientSidePagination ? . value ;
const clientSidePagination = resolveWidgetFieldValue ( clientSidePaginationProperty , currentState ) ? ? ! serverSidePagination ; // default is true for backward compatibility
2021-08-28 16:10:45 +00:00
const tableTypeProperty = component . definition . styles . tableType ;
let tableType = tableTypeProperty ? tableTypeProperty . value : 'table-bordered' ;
tableType = tableType === '' ? 'table-bordered' : tableType ;
2021-09-02 14:11:59 +00:00
const widgetVisibility = component . definition . styles ? . visibility ? . value ? ? true ;
const disabledState = component . definition . styles ? . disabledState ? . value ? ? false ;
const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue ( disabledState , currentState ) : disabledState ;
2021-08-30 11:43:05 +00:00
let parsedWidgetVisibility = widgetVisibility ;
try {
parsedWidgetVisibility = resolveReferences ( parsedWidgetVisibility , currentState , [ ] ) ;
} catch ( err ) { console . log ( err ) ; }
2021-04-30 06:31:32 +00:00
const [ loadingState , setLoadingState ] = useState ( false ) ;
useEffect ( ( ) => {
const loadingStateProperty = component . definition . properties . loadingState ;
if ( loadingStateProperty && currentState ) {
2021-04-30 08:10:57 +00:00
const newState = resolveReferences ( loadingStateProperty . value , currentState , false ) ;
2021-04-30 06:31:32 +00:00
setLoadingState ( newState ) ;
2021-04-08 07:49:38 +00:00
}
2021-04-30 06:31:32 +00:00
} , [ currentState ] ) ;
const [ componentState , setcomponentState ] = useState ( currentState . components [ component . component ] || { } ) ;
useEffect ( ( ) => {
setcomponentState ( currentState . components [ component . name ] || { } ) ;
} , [ currentState . components [ component . name ] ] ) ;
const [ isFiltersVisible , setFiltersVisibility ] = useState ( false ) ;
const [ filters , setFilters ] = useState ( [ ] ) ;
function showFilters ( ) {
setFiltersVisibility ( true ) ;
}
function hideFilters ( ) {
setFiltersVisibility ( false ) ;
}
function filterColumnChanged ( index , value ) {
const newFilters = filters ;
2021-04-30 08:10:57 +00:00
newFilters [ index ] . id = value ;
2021-04-30 06:31:32 +00:00
setFilters ( newFilters ) ;
2021-04-30 08:10:57 +00:00
setAllFilters ( newFilters . filter ( ( filter ) => filter . id !== '' ) ) ;
2021-04-30 06:31:32 +00:00
}
function filterOperationChanged ( index , value ) {
const newFilters = filters ;
2021-04-30 08:10:57 +00:00
newFilters [ index ] . value = {
... newFilters [ index ] . value ,
operation : value
2021-04-30 06:31:32 +00:00
} ;
setFilters ( newFilters ) ;
2021-04-30 08:10:57 +00:00
setAllFilters ( newFilters . filter ( ( filter ) => filter . id !== '' ) ) ;
2021-04-30 06:31:32 +00:00
}
function filterValueChanged ( index , value ) {
const newFilters = filters ;
2021-04-30 08:10:57 +00:00
newFilters [ index ] . value = {
... newFilters [ index ] . value ,
value : value
2021-04-30 06:31:32 +00:00
} ;
setFilters ( newFilters ) ;
2021-04-30 08:10:57 +00:00
setAllFilters ( newFilters . filter ( ( filter ) => filter . id !== '' ) ) ;
2021-04-30 06:31:32 +00:00
}
function addFilter ( ) {
setFilters ( [ ... filters , { id : '' , value : { operation : 'contains' , value : '' } } ] ) ;
}
function removeFilter ( index ) {
let newFilters = filters ;
newFilters . splice ( index , 1 ) ;
setFilters ( newFilters ) ;
setAllFilters ( newFilters ) ;
}
function clearFilters ( ) {
setFilters ( [ ] ) ;
setAllFilters ( [ ] ) ;
}
const defaultColumn = React . useMemo (
( ) => ( {
minWidth : 60 ,
2021-04-30 08:10:57 +00:00
width : 268
2021-04-30 06:31:32 +00:00
} ) ,
[ ]
) ;
const columnSizes = component . definition . properties . columnSizes || { } ;
function handleCellValueChange ( index , key , value , rowData ) {
const changeSet = componentState . changeSet ;
const dataUpdates = componentState . dataUpdates || [ ] ;
let obj = changeSet ? changeSet [ index ] || { } : { } ;
obj = _ . set ( obj , key , value ) ;
let newChangeset = {
... changeSet ,
[ index ] : {
2021-04-30 08:10:57 +00:00
... obj
}
2021-04-30 06:31:32 +00:00
} ;
obj = _ . set ( rowData , key , value ) ;
2021-08-02 14:35:21 +00:00
let newDataUpdates = {
... dataUpdates ,
[ index ] : { ... obj }
} ;
2021-04-30 06:31:32 +00:00
onComponentOptionsChanged ( component , [
[ 'dataUpdates' , newDataUpdates ] ,
2021-04-30 08:10:57 +00:00
[ 'changeSet' , newChangeset ]
2021-04-30 06:31:32 +00:00
] ) ;
}
2021-04-30 08:10:57 +00:00
function getExportFileBlob ( {
columns , data
} ) {
2021-04-30 06:31:32 +00:00
const headerNames = columns . map ( ( col ) => col . exportValue ) ;
const csvString = Papa . unparse ( { fields : headerNames , data } ) ;
return new Blob ( [ csvString ] , { type : 'text/csv' } ) ;
}
2021-05-02 13:45:13 +00:00
function onPageIndexChanged ( page ) {
onComponentOptionChanged ( component , 'pageIndex' , page ) . then ( ( ) => {
onEvent ( 'onPageChanged' , { component , data : { } } ) ;
} ) ;
}
2021-04-30 06:31:32 +00:00
function handleChangesSaved ( ) {
2021-04-30 08:10:57 +00:00
Object . keys ( changeSet ) . forEach ( ( key ) => {
2021-04-30 06:31:32 +00:00
tableData [ key ] = {
2021-04-30 08:10:57 +00:00
... _ . merge ( tableData [ key ] , changeSet [ key ] )
2021-04-30 06:31:32 +00:00
} ;
} ) ;
onComponentOptionChanged ( component , 'changeSet' , { } ) ;
onComponentOptionChanged ( component , 'dataUpdates' , [ ] ) ;
}
function handleChangesDiscarded ( ) {
onComponentOptionChanged ( component , 'changeSet' , { } ) ;
onComponentOptionChanged ( component , 'dataUpdates' , [ ] ) ;
}
function customFilter ( rows , columnIds , filterValue ) {
try {
if ( filterValue . operation === 'equals' ) {
return rows . filter ( ( row ) => row . values [ columnIds [ 0 ] ] === filterValue . value ) ;
}
2021-05-09 12:03:03 +00:00
if ( filterValue . operation === 'matches' ) {
return rows . filter ( ( row ) => row . values [ columnIds [ 0 ] ] . toString ( ) . toLowerCase ( ) . includes ( filterValue . value . toLowerCase ( ) ) ) ;
}
2021-04-30 06:31:32 +00:00
if ( filterValue . operation === 'gt' ) {
return rows . filter ( ( row ) => row . values [ columnIds [ 0 ] ] > filterValue . value ) ;
}
if ( filterValue . operation === 'lt' ) {
return rows . filter ( ( row ) => row . values [ columnIds [ 0 ] ] < filterValue . value ) ;
}
if ( filterValue . operation === 'gte' ) {
return rows . filter ( ( row ) => row . values [ columnIds [ 0 ] ] >= filterValue . value ) ;
}
if ( filterValue . operation === 'lte' ) {
return rows . filter ( ( row ) => row . values [ columnIds [ 0 ] ] <= filterValue . value ) ;
}
let value = filterValue . value ;
if ( typeof value === 'string' ) {
value = value . toLowerCase ( ) ;
}
return rows . filter ( ( row ) => {
let rowValue = row . values [ columnIds [ 0 ] ] ;
if ( typeof rowValue === 'string' ) {
rowValue = rowValue . toLowerCase ( ) ;
}
return rowValue . includes ( value ) ;
} ) ;
} catch {
return rows ;
}
}
2021-04-04 06:26:46 +00:00
2021-04-30 06:31:32 +00:00
const changeSet = componentState ? componentState . changeSet : { } ;
2021-04-09 04:56:17 +00:00
2021-04-30 06:31:32 +00:00
const columnData = component . definition . properties . columns . value . map ( ( column ) => {
2021-08-20 17:07:21 +00:00
const columnSize = columnSizes [ column . id ] || columnSizes [ column . name ] ;
2021-04-30 06:31:32 +00:00
const columnType = column . columnType ;
2021-04-09 04:56:17 +00:00
2021-04-30 06:31:32 +00:00
const columnOptions = { } ;
2021-08-02 04:46:59 +00:00
if ( columnType === 'dropdown' || columnType === 'multiselect' || columnType === 'badge' || columnType === 'badges' || columnType === 'radio' ) {
2021-04-30 08:10:57 +00:00
const values = resolveReferences ( column . values , currentState ) || [ ] ;
const labels = resolveReferences ( column . labels , currentState , [ ] ) || [ ] ;
2021-04-30 06:31:32 +00:00
2021-09-01 07:36:14 +00:00
if ( Array . isArray ( labels ) ) {
2021-04-30 08:10:57 +00:00
columnOptions . selectOptions = labels . map ( ( label , index ) => {
2021-04-30 06:31:32 +00:00
return { name : label , value : values [ index ] } ;
} ) ;
}
2021-04-03 05:25:41 +00:00
}
2021-08-25 16:37:29 +00:00
if ( columnType === 'datepicker' ) {
column . isTimeChecked = column . isTimeChecked ? column . isTimeChecked : false
column . dateFormat = column . dateFormat ? column . dateFormat : 'DD/MM/YYYY'
}
2021-04-03 05:25:41 +00:00
2021-05-10 10:52:35 +00:00
const width = columnSize || defaultColumn . width ;
2021-04-30 06:31:32 +00:00
return {
2021-08-19 05:02:46 +00:00
id : column . id ,
2021-04-30 06:31:32 +00:00
Header : column . name ,
accessor : column . key || column . name ,
filter : customFilter ,
2021-05-10 10:52:35 +00:00
width : width ,
2021-09-01 07:36:14 +00:00
columnOptions ,
2021-04-30 06:31:32 +00:00
Cell : function ( cell ) {
const rowChangeSet = changeSet ? changeSet [ cell . row . index ] : null ;
const cellValue = rowChangeSet ? rowChangeSet [ column . name ] || cell . value : cell . value ;
2021-09-01 16:03:17 +00:00
if ( columnType === 'string' || columnType === undefined || columnType === 'default' ) {
2021-09-02 06:16:26 +00:00
const textColor = resolveReferences ( column . textColor , currentState , { cellValue } ) ;
const cellStyles = {
color : textColor === undefined ? darkMode === true ? '#fff' : 'black' : textColor
}
2021-04-30 06:31:32 +00:00
if ( column . isEditable ) {
2021-09-06 08:50:38 +00:00
const validationData = validateWidget ( {
validationObject : {
regex : {
value : column . regex
} ,
minLength : {
value : column . minLength
} ,
maxLength : {
value : column . maxLength
} ,
customRule : {
value : column . customRule
}
} ,
widgetValue : cellValue ,
2021-09-06 14:32:09 +00:00
currentState ,
customResolveObjects : { cellValue }
2021-09-06 08:50:38 +00:00
} )
const { isValid , validationError } = validationData ;
2021-04-30 06:31:32 +00:00
return (
2021-09-06 08:50:38 +00:00
< div >
< input
type = "text"
style = { cellStyles }
onKeyDown = { ( e ) => {
if ( e . key === 'Enter' ) {
if ( e . target . defaultValue !== e . target . value ) {
handleCellValueChange ( cell . row . index , column . key || column . name , e . target . value , cell . row . original ) ;
}
}
} }
onBlur = { ( e ) => {
2021-09-01 16:10:45 +00:00
if ( e . target . defaultValue !== e . target . value ) {
handleCellValueChange ( cell . row . index , column . key || column . name , e . target . value , cell . row . original ) ;
}
2021-09-06 08:50:38 +00:00
} }
className = { ` form-control-plaintext form-control-plaintext-sm ${ ! isValid ? 'is-invalid' : '' } ` }
defaultValue = { cellValue }
/ >
< div class = "invalid-feedback" > { validationError } < / div >
< / div >
2021-04-30 06:31:32 +00:00
) ;
}
2021-09-02 06:16:26 +00:00
return < span style = { cellStyles } > { cellValue } < / span > ;
2021-05-10 10:52:35 +00:00
} if ( columnType === 'text' ) {
2021-05-10 11:24:55 +00:00
return < textarea
rows = "1"
className = "form-control-plaintext text-container text-muted"
readOnly = { ! column . isEditable }
style = { { maxWidth : width , minWidth : width - 10 } }
onBlur = { ( e ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , e . target . value , cell . row . original ) ;
} }
2021-06-14 05:15:35 +00:00
defaultValue = { cellValue }
2021-05-10 11:24:55 +00:00
>
< / textarea > ;
2021-04-30 08:10:57 +00:00
} if ( columnType === 'dropdown' ) {
2021-09-06 14:32:09 +00:00
const validationData = validateWidget ( {
validationObject : {
customRule : {
value : column . customRule
}
} ,
widgetValue : cellValue ,
currentState ,
customResolveObjects : { cellValue }
} )
const { isValid , validationError } = validationData ;
2021-04-30 06:31:32 +00:00
return (
< div >
< SelectSearch
2021-04-30 08:10:57 +00:00
options = { columnOptions . selectOptions }
2021-04-30 06:31:32 +00:00
value = { cellValue }
search = { true }
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
filterOptions = { fuzzySearch }
placeholder = "Select.."
/ >
2021-09-06 14:32:09 +00:00
< div className = { ` invalid-feedback ${ isValid ? '' : 'd-flex' } ` } > { validationError } < / div >
2021-04-30 06:31:32 +00:00
< / div >
) ;
2021-04-30 08:10:57 +00:00
} if ( columnType === 'multiselect' ) {
2021-04-30 06:31:32 +00:00
return (
< div >
< SelectSearch
printOptions = "on-focus"
multiple
search = { true }
placeholder = "Select.."
2021-04-30 08:10:57 +00:00
options = { columnOptions . selectOptions }
2021-04-30 06:31:32 +00:00
value = { cellValue }
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
/ >
< / div >
) ;
2021-05-09 07:26:54 +00:00
} if ( columnType === 'badge' ) {
return (
< div >
< CustomSelect
options = { columnOptions . selectOptions }
value = { cellValue }
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
/ >
< / div >
) ;
2021-05-09 08:06:08 +00:00
} if ( columnType === 'badges' ) {
return (
< div >
< CustomSelect
options = { columnOptions . selectOptions }
value = { cellValue }
multiple = { true }
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
/ >
< / div >
) ;
2021-05-09 10:51:26 +00:00
} if ( columnType === 'tags' ) {
return (
< div >
< Tags
value = { cellValue }
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
/ >
< / div >
) ;
2021-08-02 04:46:59 +00:00
} if ( columnType === 'radio' ) {
return (
< div >
< Radio
options = { columnOptions . selectOptions }
value = { cellValue }
readOnly = { ! column . isEditable }
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
2021-08-20 04:13:16 +00:00
/ >
< / div >
) ;
} if ( columnType === 'toggle' ) {
return (
< div >
< Toggle
value = { cellValue }
readOnly = { ! column . isEditable }
2021-08-28 15:27:10 +00:00
activeColor = { column . activeColor }
2021-08-20 04:13:16 +00:00
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
2021-08-02 04:46:59 +00:00
/ >
< / div >
) ;
2021-08-25 16:37:29 +00:00
} if ( columnType === 'datepicker' ) {
return (
< div >
< Datepicker
dateFormat = { column . dateFormat }
isTimeChecked = { column . isTimeChecked }
value = { cellValue }
readOnly = { column . isEditable }
onChange = { ( value ) => {
handleCellValueChange ( cell . row . index , column . key || column . name , value , cell . row . original ) ;
} }
/ >
< / div >
) ;
2021-04-30 06:31:32 +00:00
}
2021-04-30 08:10:57 +00:00
return cellValue || '' ;
}
2021-04-30 06:31:32 +00:00
} ;
} ) ;
let tableData = [ ] ;
if ( currentState ) {
2021-04-30 08:10:57 +00:00
tableData = resolveReferences ( component . definition . properties . data . value , currentState , [ ] ) ;
2021-04-30 06:31:32 +00:00
if ( ! Array . isArray ( tableData ) ) tableData = [ ] ;
console . log ( 'resolved param' , tableData ) ;
}
2021-04-30 08:10:57 +00:00
tableData = tableData || [ ] ;
2021-08-31 10:37:38 +00:00
const leftActions = ( ) => actions . value . filter ( action => action . position === 'left' )
const rightActions = ( ) => actions . value . filter ( action => [ undefined , 'right' ] . includes ( action . position ) )
const leftActionsCellData = leftActions ( ) . length > 0
? [
{
id : 'leftActions' ,
Header : 'Actions' ,
accessor : 'edit' ,
2021-09-01 02:55:46 +00:00
width : columnSizes . leftActions || defaultColumn . width ,
2021-08-31 10:37:38 +00:00
Cell : ( cell ) => {
return leftActions ( ) . map ( ( action ) => (
< button
key = { action . name }
className = "btn btn-sm m-1 btn-light"
style = { { background : action . backgroundColor , color : action . textColor } }
onClick = { ( e ) => {
e . stopPropagation ( ) ;
onEvent ( 'onTableActionButtonClicked' , { component , data : cell . row . original , action } ) ;
} }
>
{ action . buttonText }
< / button >
) ) ;
}
}
]
: [ ] ;
const rightActionsCellData = rightActions ( ) . length > 0
2021-04-30 08:10:57 +00:00
? [
{
2021-08-31 10:37:38 +00:00
id : 'rightActions' ,
2021-04-30 08:10:57 +00:00
Header : 'Actions' ,
accessor : 'edit' ,
2021-09-01 02:55:46 +00:00
width : columnSizes . rightActions || defaultColumn . width ,
2021-04-30 08:10:57 +00:00
Cell : ( cell ) => {
2021-08-31 10:37:38 +00:00
return rightActions ( ) . map ( ( action ) => (
2021-04-30 06:31:32 +00:00
< button
2021-04-30 08:10:57 +00:00
key = { action . name }
2021-04-30 06:31:32 +00:00
className = "btn btn-sm m-1 btn-light"
style = { { background : action . backgroundColor , color : action . textColor } }
onClick = { ( e ) => {
e . stopPropagation ( ) ;
onEvent ( 'onTableActionButtonClicked' , { component , data : cell . row . original , action } ) ;
} }
>
{ action . buttonText }
< / button >
2021-04-30 08:10:57 +00:00
) ) ;
}
}
]
: [ ] ;
2021-04-30 06:31:32 +00:00
2021-09-01 07:36:14 +00:00
const optionsData = columnData . map ( column => column . columnOptions ? . selectOptions ) ;
2021-04-30 06:31:32 +00:00
const columns = useMemo (
2021-08-31 10:37:38 +00:00
( ) => [ ... leftActionsCellData , ... columnData , ... rightActionsCellData ] ,
2021-08-29 06:15:57 +00:00
[ JSON . stringify ( columnData ) ,
2021-08-31 11:33:45 +00:00
leftActionsCellData . length ,
rightActionsCellData . length ,
2021-08-29 06:15:57 +00:00
componentState . changeSet ,
2021-09-01 07:36:14 +00:00
JSON . stringify ( optionsData ) ,
2021-08-29 06:15:57 +00:00
JSON . stringify ( component . definition . properties . columns )
] // Hack: need to fix
2021-04-30 06:31:32 +00:00
) ;
2021-09-01 16:43:13 +00:00
const data = useMemo ( ( ) => tableData , [ tableData . length , componentState . changeSet ] ) ;
2021-04-30 06:31:32 +00:00
const computedStyles = {
color ,
2021-04-30 08:10:57 +00:00
width : ` ${ width } px `
2021-04-30 06:31:32 +00:00
} ;
const {
getTableProps ,
getTableBodyProps ,
headerGroups ,
page ,
canPreviousPage ,
canNextPage ,
pageOptions ,
gotoPage ,
pageCount ,
nextPage ,
previousPage ,
setPageSize ,
state ,
2021-09-05 15:52:27 +00:00
rows ,
2021-04-30 06:31:32 +00:00
prepareRow ,
setAllFilters ,
preGlobalFilteredRows ,
setGlobalFilter ,
state : { pageIndex , pageSize } ,
2021-04-30 08:10:57 +00:00
exportData
2021-04-30 06:31:32 +00:00
} = useTable (
{
2021-09-21 11:22:39 +00:00
autoResetPage : false ,
2021-04-30 06:31:32 +00:00
columns ,
data ,
defaultColumn ,
2021-09-07 05:31:10 +00:00
initialState : { pageIndex : 0 , pageSize : - 1 } ,
2021-05-02 13:45:13 +00:00
pageCount : - 1 ,
manualPagination : false ,
2021-04-30 08:10:57 +00:00
getExportFileBlob
2021-04-09 04:56:17 +00:00
} ,
2021-04-30 06:31:32 +00:00
useFilters ,
useGlobalFilter ,
useSortBy ,
usePagination ,
useBlockLayout ,
useResizeColumns ,
useExportData
) ;
2021-09-07 05:31:10 +00:00
React . useEffect ( ( ) => {
if ( serverSidePagination || ! clientSidePagination ) {
setPageSize ( - 1 )
}
if ( ! serverSidePagination && clientSidePagination ) {
setPageSize ( 10 )
}
} , [ clientSidePagination , serverSidePagination ] )
2021-09-05 15:52:27 +00:00
useEffect ( ( ) => {
const pageData = page . map ( row => row . original ) ;
const currentData = rows . map ( row => row . original ) ; ;
onComponentOptionsChanged ( component , [
[ 'currentPageData' , pageData ] ,
[ 'currentData' , currentData ]
] ) ;
} , [ tableData . length , componentState . changeSet ] ) ;
2021-04-30 06:31:32 +00:00
useEffect ( ( ) => {
if ( ! state . columnResizing . isResizingColumn ) {
changeCanDrag ( true ) ;
2021-05-05 01:49:11 +00:00
paramUpdated ( id , 'columnSizes' , { ... columnSizes , ... state . columnResizing . columnWidths } ) ;
2021-04-30 06:31:32 +00:00
} else {
changeCanDrag ( false ) ;
}
2021-05-05 07:06:07 +00:00
} , [ state . columnResizing . isResizingColumn ] ) ;
2021-04-30 06:31:32 +00:00
2021-04-30 08:10:57 +00:00
function GlobalFilter ( ) {
2021-04-30 06:31:32 +00:00
const count = preGlobalFilteredRows . length ;
2021-04-30 08:10:57 +00:00
const [ value , setValue ] = React . useState ( state . globalFilter ) ;
const onChange = useAsyncDebounce ( ( filterValue ) => {
setGlobalFilter ( filterValue || undefined ) ;
2021-04-30 06:31:32 +00:00
} , 200 ) ;
2021-04-09 05:39:27 +00:00
2021-06-01 11:24:37 +00:00
const handleSearchTextChange = ( text ) => {
setValue ( text ) ;
onChange ( text ) ;
onComponentOptionChanged ( component , 'searchText' , text ) . then ( ( ) => {
if ( serverSideSearch === true ) {
onEvent ( 'onSearch' , { component , data : { } } ) ;
}
} ) ;
}
2021-04-21 07:21:26 +00:00
return (
2021-04-30 06:31:32 +00:00
< div className = "ms-2 d-inline-block" >
Search : { ' ' }
< input
2021-07-03 14:17:47 +00:00
className = "global-search-field"
2021-06-01 08:09:17 +00:00
defaultValue = { value || '' }
onBlur = { ( e ) => {
2021-06-01 11:24:37 +00:00
handleSearchTextChange ( e . target . value )
2021-04-30 06:31:32 +00:00
} }
2021-06-01 08:09:17 +00:00
onKeyDown = { ( e ) => {
if ( e . key === 'Enter' ) {
2021-06-01 11:24:37 +00:00
handleSearchTextChange ( e . target . value )
2021-06-01 08:09:17 +00:00
}
}
}
2021-04-30 06:31:32 +00:00
placeholder = { ` ${ count } records ` }
style = { {
2021-04-30 08:10:57 +00:00
border : '0'
2021-04-30 06:31:32 +00:00
} }
/ >
< / div >
) ;
}
return (
< div
2021-09-02 14:11:59 +00:00
data - disabled = { parsedDisabledState }
2021-07-03 14:17:47 +00:00
className = "card jet-table"
2021-08-30 11:43:05 +00:00
style = { { width : ` ${ width } px ` , height : ` ${ height } px ` , display : parsedWidgetVisibility ? '' : 'none' } }
2021-08-30 13:23:58 +00:00
onClick = { event => { event . stopPropagation ( ) ; onComponentClick ( id , component ) } }
2021-04-30 06:31:32 +00:00
>
2021-08-23 11:30:33 +00:00
{ /* Show top bar unless search box is disabled and server pagination is enabled */ }
2021-09-07 05:31:10 +00:00
{ displaySearchBox &&
2021-08-23 11:30:33 +00:00
< div className = "card-body border-bottom py-3 jet-data-table-header" >
< div className = "d-flex" >
{ displaySearchBox && < div className = "ms-auto text-muted" >
< GlobalFilter / >
< / div > }
2021-04-30 06:31:32 +00:00
< / div >
< / div >
2021-09-07 05:31:10 +00:00
}
2021-04-30 06:31:32 +00:00
< div className = "table-responsive jet-data-table" >
2021-08-28 16:10:45 +00:00
< table { ...getTableProps ( ) } className = { ` table table-vcenter table-nowrap ${ tableType } ` } style = { computedStyles } >
2021-04-30 06:31:32 +00:00
< thead >
{ headerGroups . map ( ( headerGroup ) => (
< tr { ...headerGroup.getHeaderGroupProps ( ) } tabIndex = "0" className = "tr" >
{ headerGroup . headers . map ( ( column ) => (
< th
{ ... column . getHeaderProps ( column . getSortByToggleProps ( ) ) }
className = { column . isSorted ? ( column . isSortedDesc ? 'sort-desc th' : 'sort-asc th' ) : 'th' }
>
{ column . render ( 'Header' ) }
< div
draggable = "true"
{ ... column . getResizerProps ( ) }
className = { ` resizer ${ column . isResizing ? 'isResizing' : '' } ` }
/ >
< / th >
) ) }
< / tr >
) ) }
< / thead >
2021-05-26 12:31:33 +00:00
{ ! loadingState && page . length === 0 &&
< center className = "w-100" > < div className = "py-5" > no data < / div > < / center >
}
2021-04-30 06:31:32 +00:00
{ ! loadingState && (
< tbody { ...getTableBodyProps ( ) } >
{ console . log ( 'page' , page ) }
2021-04-30 08:10:57 +00:00
{ page . map ( ( row ) => {
2021-04-30 06:31:32 +00:00
prepareRow ( row ) ;
return (
< tr
className = "table-row"
{ ... row . getRowProps ( ) }
onClick = { ( e ) => {
e . stopPropagation ( ) ;
onEvent ( 'onRowClicked' , { component , data : row . original } ) ;
} }
>
{ row . cells . map ( ( cell ) => {
let cellProps = cell . getCellProps ( ) ;
if ( componentState . changeSet ) {
if ( componentState . changeSet [ cell . row . index ] ) {
2021-08-20 12:19:46 +00:00
2021-09-02 06:16:26 +00:00
const currentColumn = columnData . find ( column => column . id === cell . column . id ) ;
2021-09-01 10:19:36 +00:00
2021-09-02 06:16:26 +00:00
if ( _ . get ( componentState . changeSet [ cell . row . index ] , currentColumn ? . accessor , undefined ) !== undefined ) {
2021-04-30 06:31:32 +00:00
console . log ( 'componentState.changeSet' , componentState . changeSet ) ;
2021-04-30 08:10:57 +00:00
cellProps . style . backgroundColor = '#ffffde' ;
2021-04-30 06:31:32 +00:00
}
}
}
return < td { ...cellProps } > { cell . render ( 'Cell' ) } < / td > ;
} ) }
< / tr >
) ;
} ) }
< / tbody >
) }
< / table >
{ loadingState === true && (
< div style = { { width : '100%' } } className = "p-2" >
2021-07-03 18:07:51 +00:00
< center >
< div className = "spinner-border mt-5" role = "status" > < / div >
< / center >
2021-04-30 06:31:32 +00:00
< / div >
) }
< / div >
2021-09-07 05:31:10 +00:00
{ ( clientSidePagination || serverSidePagination || Object . keys ( componentState . changeSet || { } ) . length > 0 || showFilterButton || showDownloadButton ) &&
< div className = "card-footer d-flex align-items-center jet-table-footer" >
< div className = "table-footer row" >
2021-04-30 06:31:32 +00:00
< div className = "col" >
2021-09-07 05:31:10 +00:00
{ ( clientSidePagination || serverSidePagination ) &&
< Pagination
lastActivePageIndex = { currentState . components [ component . name ] ? . pageIndex ? ? 1 }
serverSide = { serverSidePagination }
autoGotoPage = { gotoPage }
autoCanNextPage = { canNextPage }
autoPageCount = { pageCount }
autoPageOptions = { pageOptions }
onPageIndexChanged = { onPageIndexChanged }
/ >
}
2021-04-30 06:31:32 +00:00
< / div >
2021-09-13 10:07:07 +00:00
{ ( showBulkUpdateActions && Object . keys ( componentState . changeSet || { } ) . length > 0 ) && (
2021-09-07 05:31:10 +00:00
< div className = "col" >
< button
className = { ` btn btn-primary btn-sm ${ componentState . isSavingChanges ? 'btn-loading' : '' } ` }
onClick = { ( ) => onEvent ( 'onBulkUpdate' , { component } ) . then ( ( ) => {
handleChangesSaved ( ) ;
} )
}
>
Save Changes
< / button >
< button className = "btn btn-light btn-sm mx-2" onClick = { ( ) => handleChangesDiscarded ( ) } >
Discard changes
< / button >
< / div >
) }
< div className = "col-auto" >
{ showFilterButton &&
< span data - tip = "Filter data" className = "btn btn-light btn-sm p-1 mx-2" onClick = { ( ) => showFilters ( ) } >
< img src = "/assets/images/icons/filter.svg" width = "13" height = "13" / >
{ filters . length > 0 &&
< a className = "badge bg-azure" style = { { width : '4px' , height : '4px' , marginTop : '5px' } } > < / a >
}
< / span >
2021-05-15 07:13:53 +00:00
}
2021-09-07 05:31:10 +00:00
{ showDownloadButton &&
< span
data - tip = "Download as CSV"
className = "btn btn-light btn-sm p-1"
onClick = { ( ) => exportData ( 'csv' , true ) }
>
< img src = "/assets/images/icons/download.svg" width = "13" height = "13" / >
< / span >
}
< / div >
2021-04-30 06:31:32 +00:00
< / div >
< / div >
2021-09-07 05:31:10 +00:00
}
2021-04-30 06:31:32 +00:00
{ isFiltersVisible && (
< div className = "table-filters card" >
2021-04-30 08:10:57 +00:00
< div className = "card-header row" >
2021-04-30 06:31:32 +00:00
< div className = "col" >
2021-04-30 08:10:57 +00:00
< h4 className = "text-muted" > Filters < / h4 >
2021-04-30 06:31:32 +00:00
< / div >
< div className = "col-auto" >
< button onClick = { ( ) => hideFilters ( ) } className = "btn btn-light btn-sm" >
x
< / button >
< / div >
< / div >
< div className = "card-body" >
{ filters . map ( ( filter , index ) => (
< div className = "row mb-2" key = { index } >
< div className = "col p-2" style = { { maxWidth : '70px' } } >
< small > { index > 0 ? 'and' : 'where' } < / small >
< / div >
< div className = "col" >
< SelectSearch
options = { columnData . map ( ( column ) => {
2021-08-23 13:24:28 +00:00
return { name : column . Header , value : column . id } ;
2021-04-30 06:31:32 +00:00
} ) }
value = { filter . id }
search = { true }
onChange = { ( value ) => {
filterColumnChanged ( index , value ) ;
} }
filterOptions = { fuzzySearch }
placeholder = "Select.."
/ >
< / div >
< div className = "col" style = { { maxWidth : '180px' } } >
< SelectSearch
options = { [
{ name : 'contains' , value : 'contains' } ,
2021-05-09 12:03:03 +00:00
{ name : 'matches' , value : 'matches' } ,
2021-04-30 06:31:32 +00:00
{ name : 'equals' , value : 'equals' } ,
{ name : 'greater than' , value : 'gt' } ,
{ name : 'less than' , value : 'lt' } ,
{ name : 'greater than or equals' , value : 'gte' } ,
2021-04-30 08:10:57 +00:00
{ name : 'less than or equals' , value : 'lte' }
2021-04-30 06:31:32 +00:00
] }
value = { filter . value . operation }
search = { true }
onChange = { ( value ) => {
filterOperationChanged ( index , value ) ;
} }
filterOptions = { fuzzySearch }
placeholder = "Select.."
/ >
< / div >
< div className = "col" >
< input
type = "text"
value = { filter . value . value }
placeholder = "value"
className = "form-control"
onChange = { ( e ) => filterValueChanged ( index , e . target . value ) }
/ >
< / div >
< div className = "col-auto" >
< button onClick = { ( ) => removeFilter ( index ) } className = "btn btn-light btn-sm p-2 text-danger" >
x
< / button >
< / div >
< / div >
) ) }
2021-04-30 08:10:57 +00:00
{ filters . length === 0 && (
2021-04-30 06:31:32 +00:00
< div >
< center >
< span className = "text-muted" > no filters yet . < / span >
< / center >
< / div >
) }
< / div >
2021-04-30 08:10:57 +00:00
< div className = "card-footer" >
2021-04-30 06:31:32 +00:00
< button onClick = { addFilter } className = "btn btn-light btn-sm text-muted" >
+ add filter
< / button >
< button onClick = { ( ) => clearFilters ( ) } className = "btn btn-light btn-sm mx-2 text-muted" >
clear filters
< / button >
< / div >
< / div >
) }
< / div >
) ;
2021-04-12 13:35:48 +00:00
}