@digifi-los/reactapp
Version:
1,192 lines (1,167 loc) • 65.2 kB
JavaScript
import React, { Component, /*PropTypes,*/ } from 'react';
import { Link, } from 'react-router';
import * as rb from 're-bulma';
import { Dropdown, Progress, Checkbox, Tab } from 'semantic-ui-react';
import moment from 'moment';
import numeral from 'numeral';
import utilities from '../../util';
import qs from 'querystring';
import debounce from 'debounce';
import { flatten, } from 'flat';
import { getRenderedComponent, } from '../AppLayoutMap';
import FileReaderInput from 'react-file-reader-input';
import path from 'path';
import RACodeMirror from '../RACodeMirror';
import ResponsiveDatalist from '../ResponsiveDatalist';
import { filterQuerySelectOptions, propTypes, defaultProps, getOptionsHeaders, getHeadersFromRows, excludeEmptyHeaders, getFilterOptions, defaultNewRowData, filterQuerySelectOptionsMap, getFilterSortableOption, } from './TableHelpers';
const filterLabelStyleProps = {
alignItems: 'center',
display: 'flex',
flex: 1,
height: '100%',
};
class ResponsiveTable extends Component {
constructor(props) {
super(props);
// console.debug('this.props.getState()',this.props.getState());
let rows = props.rows || [];
rows = (rows.documents) ? rows.documents : rows;
let headers = ((!props.headers || !props.headers.length) && rows[ 0 ]) ?
getHeadersFromRows({
rows: props.rows,
sortable: props.sortable,
excludeEmptyHeaders: props.excludeEmptyHeaders,
}) :
props.headers;
headers = getOptionsHeaders(props, headers);
headers = excludeEmptyHeaders({
headers,
excludeEmptyHeaders: props.excludeEmptyHeaders,
});
if (props.flattenRowData) {
rows = rows.map(row => Object.assign({}, row, flatten(row, props.flattenRowDataOptions)));
}
this.filterSelectOptions = getFilterOptions({ rows, headers, filters: this.props.filterSelectOptions, simpleSearchFilter: this.props.simpleSearchFilter, });
this.sortableSelctOptions = getFilterSortableOption({ headers, });
this.state = {
headers: headers,
rows: rows,
hasPagination: props.hasPagination,
simplePagination: props.simplePagination,
hasHeader: props.hasHeader,
hasFooter: props.hasFooter,
limit: props.limit,
currentPage: props.currentPage,
numItems: props.numItems || rows.length,
numPages: Math.ceil(props.numItems / props.limit),
numButtons: props.numButtons,
isLoading: false,
sortProp: this.props.searchField || '_id',
sortOrder: 'desc',
filterRowData: [],
filterRowNewData: defaultNewRowData,
newRowData: {},
selectedRowData: {},
selectedRowIndex: {},
filterButtons: [],
headerFilters: {},
showFilterSearch: props.showFilterSearch,
disableSort: props.disableSort,
// usingFiltersInSearch: props.usingFiltersInSearch,
};
this.searchFunction = debounce(this.updateTableData, 200);
this.getRenderedComponent = getRenderedComponent.bind(this);
this.addRow = this.updateByAddRow.bind(this);
this.replaceRows = this.updateByReplacingRows.bind(this);
this.addingRows = this.updateByAddingRows.bind(this);
this.selectRow = this.updateSelectedRow.bind(this);
this.deleteRow = this.updateByDeleteRow.bind(this);
this.moveRowDown = this.updateByMoveRowDown.bind(this);
this.moveRowUp = this.updateByMoveRowUp.bind(this);
this.updateNewRowText = this.updateNewRowDataText.bind(this);
this.updateInlineRowText = this.updateInlineRowDataText.bind(this);
this.updateRadioGroup = this.updateRadioGroupData.bind(this);
this.getFooterAddRow = this.updateGetFooterAddRow.bind(this);
this.removeFilterRow = this.removeFilterByDeleteRow.bind(this);
this.addFilterRow = this.addFilterByAddRow.bind(this);
this.updateNewFilterRowText = this.updateNewFilterRowDataText.bind(this);
}
componentWillReceiveProps(nextProps) {
let rows = nextProps.rows || [];
let headers = ((!nextProps.headers || !nextProps.headers.length) && rows[ 0 ]) ?
getHeadersFromRows({
rows,
sortable: nextProps.sortable,
excludeEmptyHeaders: nextProps.excludeEmptyHeaders,
}) :
nextProps.headers;
headers = getOptionsHeaders(nextProps);
headers = excludeEmptyHeaders({
headers,
excludeEmptyHeaders: nextProps.excludeEmptyHeaders,
});
if (nextProps.flattenRowData) {
rows = (rows || []).map(row => Object.assign({}, row, flatten(row, nextProps.flattenRowDataOptions)));
}
// console.debug('nextProps.limit', nextProps.limit);
// console.debug('this.state.limit', this.state.limit);
this.setState({
headers: headers,
rows: rows,
hasPagination: nextProps.hasPagination,
hasHeader: nextProps.hasHeader,
hasFooter: nextProps.hasFooter,
limit: nextProps.limit,
currentPage: nextProps.currentPage,
numItems: nextProps.numItems,
numPages: Math.ceil(nextProps.numItems / nextProps.limit),
numButtons: nextProps.numButtons,
});
}
updateSelectedRow(options) {
// console.debug({ options });
this.updateTableData(options);
}
updateByReplacingRows(newrows) {
this.updateTableData({ rows: newrows.concat([]), clearNewRowData: true, });
}
updateByAddingRows(newrows) {
let rows = this.state.rows.concat(newrows || []);
this.updateTableData({ rows, clearNewRowData: true, });
}
updateByAddRow() {
let rows = this.state.rows.concat([]);
let newRow = Object.assign({}, this.state.newRowData);
rows.splice(rows.length, 0, newRow);
// console.debug({ rowIndex, rows, deletedRow }, this.state.rows);
// this.props.onChange({ rows, });
this.updateTableData({ rows, clearNewRowData: true, });
}
updateByDeleteRow(rowIndex) {
let rows = this.state.rows.concat([]);
rows.splice(rowIndex, 1);
// console.debug({ rowIndex, rows }, this.state.rows);
// this.props.onChange({ rows, });
this.updateTableData({ rows, });
}
updateByMoveRowUp(rowIndex) {
let rows = this.state.rows.concat([]);
let deletedRow = rows.splice(rowIndex, 1)[ 0 ];
rows.splice(rowIndex - 1, 0, deletedRow);
// console.debug({ rowIndex, rows, deletedRow }, this.state.rows);
// this.props.onChange({ rows, });
this.updateTableData({ rows, });
}
updateByMoveRowDown(rowIndex) {
let rows = this.state.rows.concat([]);
let deletedRow = rows.splice(rowIndex, 1)[ 0 ];
rows.splice(rowIndex + 1, 0, deletedRow);
// console.debug({ rowIndex, rows, deletedRow }, this.state.rows);
// this.props.onChange({ rows, });
this.updateTableData({ rows, });
}
updateNewRowDataText(options) {
let { name, text, } = options;
let updatedStateProp = {
newRowData: Object.assign({},
this.state.newRowData, {
[ name ]: text,
}),
};
this.props.headers.forEach(header => {
if (header.sortid !== name && header.formtype && header.defaultValue && !updatedStateProp.newRowData[ header.sortid ]) {
updatedStateProp.newRowData[ header.sortid ] = header.defaultValue;
}
});
// console.debug({ updatedStateProp, options });
this.setState(updatedStateProp);
}
updateInlineRowDataText(options) {
let { name, text, rowIndex, } = options;
let rows = this.state.rows.concat([]);
rows[ rowIndex ][ name ] = text;
// console.debug({ rowIndex, rows, deletedRow }, this.state.rows);
// this.props.onChange({ rows, });
this.updateTableData({ rows, });
}
updateRadioGroupData(options) {
let { name, rowIndex, } = options;
let rows = this.state.rows.concat([]);
rows.forEach(row => {
row[ name ] = false;
})
rows[ rowIndex ][ name ] = true;
this.updateTableData({ rows, });
}
handleFileUpload(type) {
return (e, results) => {
let updatefunction = (type === 'replace') ?
this.replaceRows :
this.addingRows;
try {
console.debug({ e, results, });
results.forEach(result => {
const [ e, file, ] = result;
if (path.extname(file.name) === '.csv') {
} else {
let newRows = JSON.parse(e.target.result);
updatefunction(newRows);
}
});
} catch (e) {
this.props.errorNotification(e);
}
};
}
removeFilterByDeleteRow(rowIndex) {
let rows = this.state.filterRowData.concat([]);
rows.splice(rowIndex, 1);
this.setState({ filterRowData: rows, }, () => {
this.updateTableData({});
});
}
addFilterByAddRow() {
let rows = this.state.filterRowData.concat([]);
let newRow = Object.assign({}, this.state.filterRowNewData);
rows.splice(rows.length, 0, newRow);
if (newRow.property === '__property__') {
this.props.createNotification({ text: 'Please select a property', type: 'error', timed: 5000, });
} else if (newRow.filter_value === '__filter__') {
this.props.createNotification({ text: 'Please select a filter', type: 'error', timed: 5000, });
} else {
// console.debug('addFilterByAddRow', { rows });
this.setState({ filterRowData: rows, filterRowNewData: defaultNewRowData, }, () => {
this.updateTableData({});
});
}
}
updateNewFilterRowDataText(options) {
let { name, text, } = options;
let updatedStateProp = {
filterRowNewData: Object.assign({},
this.state.filterRowNewData, {
[ name ]: text,
}),
};
// console.debug({ updatedStateProp, options });
this.setState(updatedStateProp);
}
updateTableData(options) {
let updatedState = {};
let newSortOptions = {};
if (options.clearNewRowData) {
updatedState.newRowData = {};
}
if (typeof options.selectedRowIndex !== undefined) {
updatedState.selectedRowIndex = options.selectedRowIndex;
}
if (typeof options.selectedRowData !== undefined) {
updatedState.selectedRowData = options.selectedRowData;
}
if (!this.props.baseUrl) {
// console.debug({options})
updatedState.rows = (typeof options.rows !== 'undefined') ? options.rows : this.props.rows;
// console.debug({ updatedState, });
if (options.sort) {
newSortOptions.sortProp = options.sort;
if (this.state.sortProp === options.sort) {
newSortOptions.sortOrder = (this.state.sortOrder !== 'desc') ? 'desc' : 'asc';
} else {
newSortOptions.sortOrder = 'desc';
}
updatedState.rows = updatedState.rows.sort(utilities.sortObject(newSortOptions.sortOrder, options.sort));
updatedState.sortOrder = newSortOptions.sortOrder;
updatedState.sortProp = options.sort;
} else if (this.props.turnOffTableSort) {
updatedState.rows = updatedState.rows;
} else if ((this.state.sortOrder || this.state.sortProp) && !this.state.disableSort) {
newSortOptions.sortProp = this.state.sortProp;
newSortOptions.sortOrder = (this.state.sortOrder === 'desc' || this.state.sortOrder === '-') ? 'desc' : 'asc';
updatedState.rows = updatedState.rows.sort(utilities.sortObject(newSortOptions.sortOrder, newSortOptions.sortProp));
}
if (this.props.tableSearch && this.state.filterRowData && this.state.filterRowData.length) {
let filteredRows = [];
updatedState.rows.forEach(row => {
this.state.filterRowData.forEach(filter => {
if (row[ filter.property ]) {
switch (filter.filter_value) {
case 'like':
case 'in':
if (row[ filter.property ].indexOf(filter.value) !== -1) filteredRows.push(row);
break;
case 'not':
if (row[ filter.property ] !== filter.value) filteredRows.push(row);
break;
case 'not-like':
case 'not-in':
if (row[ filter.property ].indexOf(filter.value) === -1) filteredRows.push(row);
break;
case 'lt':
if (row[ filter.property ] < filter.value) filteredRows.push(row);
break;
case 'lte':
if (row[ filter.property ] <= filter.value) filteredRows.push(row);
break;
case 'gt':
if (row[ filter.property ] > filter.value) filteredRows.push(row);
break;
case 'gte':
if (row[ filter.property ] >= filter.value) filteredRows.push(row);
break;
case 'exists':
if (typeof row[ filter.property ] !== 'undefined') filteredRows.push(row);
break;
case 'size':
if (row[ filter.property ].length > filter.value) filteredRows.push(row);
break;
case 'is-date':
if (moment(row[ filter.property ]).isSame(filter.value)) filteredRows.push(row);
break;
case 'lte-date':
if (moment(row[ filter.property ]).isSameOrBefore(filter.value)) filteredRows.push(row);
break;
case 'lt-date':
if (moment(row[ filter.property ]).isBefore(filter.value)) filteredRows.push(row);
break;
case 'gte-date':
if (moment(row[ filter.property ]).isSameOrAfter(filter.value)) filteredRows.push(row);
break;
case 'gt-date':
if (moment(row[ filter.property ]).isAfter(filter.value)) filteredRows.push(row);
break;
case 'is':
default:
if (row[ filter.property ] === filter.value) filteredRows.push(row);
break;
}
}
});
// row[ this.props.searchField ].indexOf(options.search) !== -1
});
updatedState.rows = filteredRows;
// console.debug('updatedState.rows', updatedState.rows, { filteredRows, });
}
if (this.props.tableSearch && this.props.searchField && options.search) {
updatedState.rows = (updatedState.rows || this.props.rows).filter(row => {
return row[ this.props.searchField ] && row[ this.props.searchField ].indexOf(options.search) !== -1
});
}
updatedState.numPages = Math.ceil(updatedState.rows.length / this.state.limit);
updatedState.limit = this.state.limit;
updatedState.currentPage = (typeof options.pagenum !== 'undefined') ?
options.pagenum :
(this.state.currentPage && this.state.currentPage <= updatedState.numPages) ?
this.state.currentPage :
1;
updatedState.isLoading = false;
if (this.props.tableForm) {
// console.debug('before', {updatedState})
this.props.onChange(updatedState);
}
// else {
this.setState(updatedState);
// }
} else {
if (options.sort) {
newSortOptions.sortProp = options.sort;
if (this.state.sortProp === options.sort) {
newSortOptions.sortOrder = (this.state.sortOrder === '') ? '-' : '';
} else {
newSortOptions.sortOrder = '';
}
} else if (this.props.turnOffTableSort) {
updatedState.rows = updatedState.rows;
} else if (this.state.sortOrder || this.state.sortProp) {
newSortOptions.sortProp = this.state.sortProp;
newSortOptions.sortOrder = (this.state.sortOrder === 'desc' || this.state.sortOrder === '-') ? '-' : '';
}
if (options.pagenum < 1) {
options.pagenum = 1;
}
let headerFilterQueries = [];
if (this.props.filterSearch && this.props.simpleSearchFilter && this.props.useHeaderFilters && this.props.filterButtons) {
this.props.filterButtons.forEach(headerFilter => {
if (this.state.headerFilters[ headerFilter.headername ] !== undefined) {
if (headerFilter.multiple) {
headerFilterQueries.push(`${headerFilter.headername}=${this.state.headerFilters[ headerFilter.headername ].join(',')}`);
} else {
headerFilterQueries.push(`${headerFilter.headername}=${this.state.headerFilters[ headerFilter.headername ]}`);
}
}
});
}
this.setState({ isLoading: true, });
let stateProps = this.props.getState();
let fetchURL = `${stateProps.settings.basename}${this.props.baseUrl}&${qs.stringify({
limit: this.state.limit || this.props.limit,
sort: (newSortOptions.sortProp)
? `${newSortOptions.sortOrder}${newSortOptions.sortProp}`
: undefined,
fq: (this.state.filterRowData && this.state.filterRowData.length)
? this.state.filterRowData.map(frd => {
return `${frd.property}|||${frd.filter_value}|||${frd.value}`;
})
: undefined,
headerFilters: headerFilterQueries,
query: options.search,
allowSpecialCharacters: true,
pagenum: options.pagenum || 1,
})}`;
// console.debug('this.state.filterRowData', this.state.filterRowData, { options, fetchURL, });
let headers = Object.assign({
'x-access-token': stateProps.user.jwt_token,
}, stateProps.settings.userprofile.options.headers);
utilities.fetchComponent(fetchURL, { headers, })()
.then(response => {
// let usingResponsePages = false;
// console.debug('this.props.dataMap',this.props.dataMap)
// console.log({ response })
if (response.data && response.result && response.status) {
// console.log('USE DATA FROM RESPONSE', response.data)
// console.log('this.props.dataMap',this.props.dataMap)
response = response.data;
}
this.props.dataMap.forEach(data => {
if (data.key === 'rows') {
let rows = response[ data.value ] || [];
rows = (rows.documents) ? rows.documents : rows;
// console.log({ rows });
if (this.props.flattenRowData) {
updatedState[ data.key ] = rows.map(row => Object.assign({}, row, flatten(row, this.props.flattenRowDataOptions)));
}
} else {
// if (data.key === 'numPages') {
// usingResponsePages = true;
// }
updatedState[ data.key ] = response[ data.value ];
}
});
updatedState.numPages = Math.ceil(updatedState.numItems / this.state.limit);
updatedState.limit = this.state.limit;
updatedState.currentPage = (typeof options.pagenum !== 'undefined') ? options.pagenum : this.props.currentPage;
updatedState.isLoading = false;
if (options.sort) {
updatedState.sortOrder = newSortOptions.sortOrder;
updatedState.sortProp = options.sort;
}
// console.log({ updatedState });
if (this.props.tableForm) {
this.props.onChange(updatedState);
}
this.setState(updatedState);
}, e => {
this.props.errorNotification(e);
});
}
}
formatValue(inputs) {
let { value, row, options, header, uniqueFormOptions, } = inputs;
try {
// console.debug({ value, row, options, header, });
// console.debug(options.rowIndex,this.state.selectedRowIndex)
let returnValue = value;
if (header && header.stringify) {
value = JSON.stringify(value, null, 2);
returnValue = JSON.stringify(value, null, 2);
}
if (header && header.tostring) {
value = value.toString();
returnValue = value.toString();
}
if (header && header.customCellLayout) {
header.customCellLayout.props = Object.assign({}, header.customCellLayout.props, { cell: value, row });
return this.getRenderedComponent(header.customCellLayout);
}
if (header && header.tagifyArray) {
return value.map((val, kv) => (
<rb.Tag {...header.tagProps} key={kv}>{
(header.tagifyValue) ? val[ header.tagifyValue ].toString() : val.toString()}
</rb.Tag>))
}
else if (header && header.selectedOptionRowHeader) {
return <input type="radio" checked={(options.rowIndex === this.state.selectedRowIndex) ? true : false} />;
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'code') {
let CodeMirrorProps = Object.assign({}, {
codeMirrorProps: {
lineNumbers: true,
value: value, //formElement.value || this.state[ formElement.name ] || getPropertyAttribute({ element:formElement, property:this.state, });
//value: this.state[ formElement.name ] || formElement.value,
style: {
minHeight: 200,
},
lineWrapping: true,
onChange: function (text) {
// console.log({ newvalue });
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateInlineRowText({ name, text, rowIndex, });
}.bind(this),
},
}, header.CodeMirrorProps);
let codeProps = Object.assign({
wrapperProps: {
style: {
overflow: 'auto',
backgroundColor: 'white',
border: '1px solid #d3d6db',
borderRadius: 3,
height: 'auto',
boxShadow: 'inset 0 1px 2px rgba(17,17,17,.1)',
},
},
}, header.codeProps);
return <RACodeMirror
{...CodeMirrorProps}
{...codeProps}
/>;
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'textarea') {
return <rb.Textarea
{...header.textareaProps}
value={value}
onChange={(event) => {
let text = event.target.value;
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateInlineRowText({ name, text, rowIndex, });
}}
>{value}</rb.Textarea>;
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'text') {
return <rb.Input
value={value}
readOnly={header.readOnly ? true : false}
{...header.inputProps}
onChange={(event) => {
let text = event.target.value;
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateInlineRowText({ name, text, rowIndex, });
}}
>{value}</rb.Input>;
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'select') {
let selectOptions = uniqueFormOptions
? header.formoptions[ options.rowIndex ] || []
: header.formoptions || [];
return <rb.Select
value={value}
{...header.selectProps}
onChange={(event) => {
let text = event.target.value;
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateInlineRowText({ name, text, rowIndex, });
}}>
{selectOptions.map((opt, k) => {
return <option key={k} disabled={opt.disabled} value={opt.value}>{opt.label || opt.value}</option>;
})}
</rb.Select>
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'dropdown') {
let selectOptions = uniqueFormOptions
? header.formoptions[ options.rowIndex ] || []
: header.formoptions || [];
return <Dropdown
fluid
selection
value={value}
{...header.dropdownProps}
onChange={(event, { value }) => {
let text = value;
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateInlineRowText({ name, text, rowIndex, });
}}
options={selectOptions.map((opt, k) => {
return { key: k, disabled: opt.disabled, value: opt.value, text: (opt.label) ? opt.label : opt.value, };
})}
>
</Dropdown>
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'datalist') {
let rowdata = Array.isArray(this.props.__tableOptions[ header.sortid ][ options.rowIndex ]) ? this.props.__tableOptions[ header.sortid ][ options.rowIndex ]
: Array.isArray(this.props.__tableOptions[ header.sortid ]) ? this.props.__tableOptions[ header.sortid ]
: [];
return <ResponsiveDatalist
value={value}
{...header.datalistProps}
datalistdata={rowdata}
onChange={(event) => {
let text = event;
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateInlineRowText({ name, text, rowIndex, });
}}
>
</ResponsiveDatalist>
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'checkbox') {
let rowProps = (header.useRowProps && row.rowProps && row.rowProps[ header.sortid ]) ? Object.assign({}, row.rowProps[ header.sortid ]) : {};
let customCallbackfunction = () => { };
if (header.customOnChange) {
if (header.customOnChange.indexOf('func:this.props') !== -1) {
customCallbackfunction = this.props[header.customOnChange.replace('func:this.props.', '')];
} else if (header.customOnChange.indexOf('func:window') !== -1 && typeof window[header.customOnChange.replace('func:window.', '')] === 'function') {
customCallbackfunction = window[header.customOnChange.replace('func:window.', '')].bind(this);
}
}
let customOnChangeProps = Object.assign({}, header.customOnChangeProps, { onclickPropObject: row });
let checkboxLabel = (header.passProps && header.passProps.checkboxLabel) ? header.passProps.checkboxLabel : '';
return <Checkbox {...header.passProps} {...rowProps}
name={header.sortid}
checked={value ? true : false}
value={value}
label={(typeof checkboxLabel === 'object') ? this.getRenderedComponent(checkboxLabel) : checkboxLabel}
onChange={(event, { value }) => {
let text = !value;
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateInlineRowText({ name, text, rowIndex, });
customCallbackfunction(customOnChangeProps)
}}
>
</Checkbox>
} else if (this.props.useInputRows && header && header.formtype && header.formtype === 'radio') {
return <Checkbox {...header.passProps}
radio={true}
name={header.sortid}
value={value}
checked={value ? true : false}
onChange={(event, { value }) => {
if (!value) {
let name = header.sortid;
let rowIndex = options.rowIndex;
this.updateRadioGroup({ name, rowIndex, });
}
}}
>
</Checkbox>
} else if (typeof options.idx !== 'undefined' && typeof returnValue === 'string' && returnValue.indexOf('--idx--') !== -1) {
returnValue = returnValue.replace('--idx--', options.idx);
}
if (typeof options.idx !== 'undefined' && typeof returnValue === 'string' && returnValue.indexOf('--idx-ctr--') !== -1) {
returnValue = returnValue.replace('--idx-ctr--', (options.idx + 1));
}
if (options.momentFromNow) {
returnValue = moment(value).fromNow();
} else if (options.momentFormat) {
returnValue = moment(value).format(options.momentFormat);
} else if (options.numeralFormat) {
returnValue = numeral(value).format(options.numeralFormat);
} else if (header && header.wrapPreOutput) {
returnValue = <pre {...header.wrapPreOutputProps}>{value}</pre>;
} else if (options.icon && value) {
// console.debug({value})
if (typeof value !== 'string' && Array.isArray(value)) {
let icons = value.map((val, i) => <rb.Icon key={i + Math.random()} {...options.iconProps} icon={val} />);
return icons;
} else {
return <rb.Icon {...options.iconProps} icon={value} />;
}
} else if (options.image && value) {
if (typeof value !== 'string' && Array.isArray(value)) {
let images = value.map((val, i) => <rb.Image key={i} {...options.imageProps} src={val} />);
return { images, };
} else {
return <rb.Image {...options.imageProps} src={value} />;
}
}
if (typeof returnValue === 'undefined' || (returnValue === null && this.props.suppressNullValues)) {
return '';
// } else if (typeof returnValue !== 'object') {
// return JSON.stringify(returnValue);
} else if (returnValue === null) {
return 'null';
} else if (typeof returnValue === 'object' && !Array.isArray(returnValue)) {
return this.getRenderedComponent(returnValue);
} else {
return returnValue.toString();
}
} catch (e) {
console.log({ value, row, options, header, }, e);
return 'invalid';
}
}
getHeaderLinkURL(link, row) {
let returnLink = link.baseUrl;
if (link.params && link.params.length > 0) {
link.params.forEach((param) => {
returnLink = returnLink.replace(param.key, row[ param.val ]);
});
}
return returnLink;
}
updateGetFooterAddRow(header) {
if (header.selectedOptionRowHeader) return null;
switch (header.formtype) {
case 'select':
return (<rb.Select
{...header.footerFormElementPassProps}
value={this.state.newRowData[ header.sortid ] || header.defaultValue}
onChange={(event) => {
let text = event.target.value;
let name = header.sortid;
this.updateNewRowText({ name, text, });
}}>
{header.formoptions.map((opt, k) => {
return <option key={k} disabled={opt.disabled} value={opt.value}>{opt.label || opt.value}</option>;
})}
</rb.Select>);
// break;
case 'textarea':
return (<rb.Textarea
{...header.footerFormElementPassProps}
value={this.state.newRowData[ header.sortid ] || ''}
onChange={(event) => {
let text = event.target.value;
let name = header.sortid;
this.updateNewRowText({ name, text, });
}}>
</rb.Textarea>);
// break;
case 'code':
var CodeMirrorProps = Object.assign({}, {
codeMirrorProps: {
lineNumbers: true,
value: this.state.newRowData[ header.sortid ] || '', //formElement.value || this.state[ formElement.name ] || getPropertyAttribute({ element:formElement, property:this.state, });
//value: this.state[ formElement.name ] || formElement.value,
style: {
minHeight: 200,
},
lineWrapping: true,
onChange: function (text) {
// console.log({ newvalue });
let name = header.sortid;
this.updateNewRowText({ name, text, });
}.bind(this),
},
}, header.CodeMirrorProps);
var codeProps = Object.assign({
wrapperProps: {
style: {
overflow: 'auto',
backgroundColor: 'white',
border: '1px solid #d3d6db',
borderRadius: 3,
height: 'auto',
boxShadow: 'inset 0 1px 2px rgba(17,17,17,.1)',
},
},
}, header.codeProps);
return (<RACodeMirror
{...CodeMirrorProps}
{...codeProps}
/>);
case 'text':
default:
return (<rb.Input
{...header.footerFormElementPassProps}
value={this.state.newRowData[ header.sortid ] || ''}
onChange={(event) => {
let text = event.target.value;
let name = header.sortid;
this.updateNewRowText({ name, text, });
}}>
</rb.Input>);
// break;
}
}
toggleAdvancedSearchFilters() {
this.setState({ showFilterSearch: !this.state.showFilterSearch, });
// showFilterSearch:false,
// usingFiltersInSearch: false,
// showFilterSearch: props.showFilterSearch,
// usingFiltersInSearch: props.usingFiltersInSearch
}
render() {
// console.debug('render this.state', this.state);
let maxFormRowLength = 0;
let calcStartIndex = ((this.state.currentPage - 1) * this.state.limit);
let startIndex = (!this.props.baseUrl)
? calcStartIndex
: (this.searchInputTextVal && !this.props.calculatePagination)
? this.state.limit * (this.state.currentPage - 1)
: 0;
let endIndex = (!this.props.baseUrl)
? ((this.state.limit * this.state.currentPage))
: (this.searchInputTextVal && !this.props.calculatePagination)
? this.state.limit * (this.state.currentPage)
: this.state.limit;
let displayRows = this.state.rows.slice(startIndex, endIndex);
let mergedCustomLayout = (this.props.customLayout && displayRows && displayRows.length)
? (<div style={
Object.assign({
flexDirection: 'rows',
display: 'flex',
},
this.props.customLayoutStyle)
}>{displayRows.map(row => {
let mergedLayout = Object.assign({}, this.props.customLayout, {
props: Object.assign({},
this.props.customLayout.props,
row,
{ row },
{
__ra_rt_link: (this.props.customLayout.link) ? this.getHeaderLinkURL(this.props.customLayout.link, row) : undefined,
}),
});
// console.debug({ mergedLayout });
return this.getRenderedComponent(mergedLayout);
})}</div>)
: null;
const { numPages, currentPage, } = this.state;
const pageButtons = [];
const lastIndex = numPages - 1;
let start = currentPage - 2;
let end = currentPage;
if (start < 0) {
end += -start;
start = 0;
}
if (end > lastIndex) {
if (start > 0) {
start -= (end - lastIndex);
if (start < 0) {
start = 0;
}
}
end = lastIndex;
}
if (start > 0) {
pageButtons.push((
<li key={0}>
<rb.PageButton isActive={currentPage === 1}
onClick={() => this.updateTableData({ pagenum: 1, })}
>1
</rb.PageButton>
</li>
));
pageButtons.push(<li key="dot-before">...</li>);
}
for (let index = start; index <= end; index += 1) {
const inActive = ((index + 1) !== currentPage);
if (inActive) {
pageButtons.push((
<li key={index}>
<rb.PageButton
onClick={() => this.updateTableData({ pagenum: (index + 1), })}
>{index + 1}</rb.PageButton>
</li>
));
} else {
pageButtons.push((
<li key={index}>
<rb.PageButton color="isPrimary" isActive
onClick={() => this.updateTableData({ pagenum: (index + 1), })}>
{index + 1}
</rb.PageButton>
</li>
));
}
}
if (end < lastIndex) {
pageButtons.push(<li key="dot-after">...</li>);
pageButtons.push((
<li key={lastIndex}>
<rb.PageButton onClick={() => this.updateTableData({ pagenum: (lastIndex + 1), })}>
{lastIndex + 1}
</rb.PageButton>
</li>
));
}
const footer = (this.state.simplePagination)
? (
<rb.Pagination>
{(this.state.currentPage < 2)
? (<rb.Button icon="fa fa-angle-left" state="isDisabled"></rb.Button>)
: (<rb.Button icon="fa fa-angle-left" onClick={() => this.updateTableData({ pagenum: (this.state.currentPage - 1), search: this.searchInputTextVal, })}></rb.Button>)}
<span style={{ margin: '0 20px' }}>Page {this.state.currentPage} of {this.state.numPages}</span>
{(this.state.currentPage >= this.state.numPages)
? (<rb.Button icon="fa fa-angle-right" state="isDisabled"></rb.Button>)
: (<rb.Button icon="fa fa-angle-right" onClick={() => this.updateTableData({ pagenum: (this.state.currentPage + 1), search: this.searchInputTextVal, })}></rb.Button>)}
</rb.Pagination>
)
: (
<rb.Pagination>
{(this.state.currentPage < 2)
? (<rb.Button state="isDisabled"> Previous </rb.Button>)
: (<rb.PageButton onClick={() => this.updateTableData({ pagenum: (this.state.currentPage - 1), })}>Previous</rb.PageButton>)}
<ul>
{pageButtons}
</ul>
{(this.state.currentPage >= this.state.numPages)
? (<rb.Button state="isDisabled"> Next </rb.Button>)
: (<rb.PageButton onClick={() => this.updateTableData({ pagenum: (this.state.currentPage + 1), })}>Next</rb.PageButton>)}
</rb.Pagination>);
var fbts = <a />;
if (this.props.filterSearch) {
fbts = <rb.Button
style={(this.state.showFilterSearch)
? { background: '#69707a', color: '#f5f7fa', borderColor: 'transparent', }
: (this.state.filterRowData.length > 0)
? { background: '#222324', color: 'white', borderColor: 'transparent', }
: undefined}
{...this.props.filterButtonProps}
onClick={() => {
this.toggleAdvancedSearchFilters();
}}
>Advanced</rb.Button>;
}
let tableBody = displayRows.map((row, rowIndex) => (
<rb.Tr key={`row${rowIndex}`} className={(this.props.selectEntireRow && rowIndex === this.state.selectedRowIndex) ? '__selected' : undefined} >
{this.state.headers.map((header, colIndex) => {
// console.debug({header});
if (header.link) {
let rowProps = (this.props.useRowProps && row.rowProps) ? row.rowProps : {};
return (
<rb.Td key={`row${rowIndex}col${colIndex}`} {...header.columnProps} {...rowProps}>
<Link {...header.linkProps} to={this.getHeaderLinkURL(header.link, row)}>{
this.formatValue({
value: (typeof row[ header.sortid ] !== 'undefined')
? row[ header.sortid ]
: header.value,
row,
options: {
idx: rowIndex + calcStartIndex,
momentFormat: header.momentFormat,
numeralFormat: header.numeralFormat,
image: header.image,
imageProps: header.imageProps,
icon: header.icon,
iconProps: header.iconProps,
},
})
}</Link>
</rb.Td>
);
} else if (header.formRowButtons) {
// console.debug({ row, header, });
//http://htmlarrows.com/arrows/
let buttonCell = (
<rb.Td key={`row${rowIndex}col${colIndex}`} style={{ textAlign: 'right', }} {...header.columnProps}>
{(header.buttons && header.buttons.length) ?
header.buttons.map(button => {
return this.getRenderedComponent(Object.assign({
component: 'ResponsiveButton',
props: Object.assign({
onclickPropObject: row,
buttonProps: {},
}, button.passProps),
children: this.formatValue({
value: (typeof row[ header.sortid ] !== 'undefined')
? row[ header.sortid ]
: header.value,
row,
options: {
idx: rowIndex + calcStartIndex,
momentFormat: header.momentFormat,
image: header.image,
imageProps: header.imageProps,
icon: header.icon,
iconProps: header.iconProps,
},
}) || '',
}, button));
}) : null
// Object.assign
}
{
(rowIndex !== 0 && this.props.useUpArrowButton)
? <rb.Button {...this.props.formRowUpButton} onClick={() => {
this.moveRowUp(rowIndex);
}}>{(this.props.formRowUpButtonLabel) ? this.props.formRowUpButtonLabel : '⇧'}</rb.Button>
: null
}
{(rowIndex < this.state.rows.length - 1 && this.props.useDownArrowButton)
? <rb.Button {...this.props.formRowDownButton} onClick={() => {
this.moveRowDown(rowIndex);
}}>{(this.props.formRowDownButtonLabel) ? this.props.formRowDownButtonLabel : '⇩'}</rb.Button>
: null
}
<rb.Button {...this.props.formRowDeleteButton} onClick={() => {
this.deleteRow(rowIndex);
}}>{(this.props.formRowDeleteButtonLabel) ? this.props.formRowDeleteButtonLabel : '⤫'}</rb.Button>
</rb.Td>
);
let currentButtonLength = buttonCell.props.children.filter(Boolean).length;
maxFormRowLength = (currentButtonLength > maxFormRowLength) ? currentButtonLength : maxFormRowLength;
return buttonCell;
} else if (header.buttons && header.buttons.length) {
// console.debug({ row, header, });
return (
<rb.Td key={`row${rowIndex}col${colIndex}`} {...header.columnProps}>
{
header.buttons.map((button, idx) => {
return this.getRenderedComponent(Object.assign({
component: 'ResponsiveButton',
props: Object.assign({
onclickPropObject: row,
buttonProps: {},
}, button.passProps, (this.props.useRowProps && row.rowProps && row.rowProps.buttons && row.rowProps.buttons[ idx ]) ? row.rowProps.buttons[ idx ] : {}),
children: this.formatValue({
value: (typeof row[ header.sortid ] !== 'undefined')
? row[ header.sortid ]
: header.value,
row,
options: {
idx: rowIndex + calcStartIndex,
momentFormat: header.momentFormat,
image: header.image,
imageProps: header.imageProps,
icon: header.icon,
iconProps: header.iconProps,
},
}) || '',
}, button));
})
// Object.assign
}
</rb.Td>
);
} else if (header.progressBar) {
let progress = typeof header.progressBar.progress === 'boolean'
? header.progressBar.progress
: true;
let indicating = (header.progressBar.indicating || header.progressBar.indicating === undefined) && row.progressBar.progress < 100
? true
: false;
let label = row.progressBar.label
? row.progressBar.label
: null;
let success = row.progressBar && row.progressBar.state === 'success'
? true
: null;
let warning = row.progressBar && row.progressBar.state === 'warning'
? true
: null;
let error = row.progressBar && row.progressBar.state === 'error'
? true
: null;
let disabled = row.progressBar && row.progressBar.state === 'disabled'
? true
: null;
let style = row.progressBar && row.progressBar.style
? row.progressBar.style
: {};
return (
<rb.Td key={`row${rowIndex}col${colIndex}`} {...header.columnProps} onClick={() => {
if (this.props.selectEntireRow) {
this.selectRow({
selectedRowData: row,
selectedRowIndex: rowIndex,
});
}
// console.debug({ event, rowIndex, row, });
}}>
<Progress percent={row.progressBar.progress} indicating={indicating} progress={progress} success={success} warning={warning} error={error} disabled={disabled} style={style}>{label}</Progress>
</rb.Td>
);
} else {
let rowProps = (this.props.useRowProps && row.rowProps) ? row.rowProps : {};
return (
<rb.Td key={`row${rowIndex}col${colIndex}`} {...header.columnProps} {...rowProps} onClick={() => {
if (this.props.selectEntireRow) {
this.selectRow({
selectedRowData: row,
selectedRowIndex: rowIndex,
});
}
// console.debug({ event, rowIndex });
}}>
{
this.formatValue.call(this, {
value: (typeof row[ header.sortid ] !== 'undefined')
? row[ header.sortid ]
: header.value,
row,
options: {
rowIndex: rowIndex,
idx: rowIndex + calcStartIndex,
momentFormat: header.momentFormat,
numeralFormat: header.numeralFormat,
image: header.image,
imageProps: header.imageProps,
icon: header.icon,
iconProps: header.iconProps,
},
header,
uniqueFormOptions: this.props.uniqueFormOptions,
})
}
</rb.Td>
);
// return (
// <rb.Td>{(row[ header.sortid ] && header.momentFormat)
// ? moment(row[header.sortid]).format(header.momentFormat)
// :row[ header.sortid ]}</rb.Td>
// );
}
})}
</rb.Tr>
));
let filterButtons = [];
if (this.props.tableSearch && this.props.simpleSearchFilter && this.props.useHeaderFilters && this.props.filterButtons) {
let filterOnChange = function (event, newvalue) {
let newState = Object.assign({}, this.state.headerFilters, { [ newvalue.headername ]: newvalue.value, });
this.setState({ headerFilters: newState }, () => {
this.updateTableData({ search: this.searchInputTextVal, });
});
};
let tabFilterOnChange = function (event, newvalue) {
let newValueState = newvalue.panes[newvalue.activeIndex];
let newState = Object.assign({}, this.state.headerFilters, {
[newvalue.headername]: newValueState.value,
});
this.setState({ headerFilters: newState }, () => {
this.updateTableData({ search: this.searchInputTextVal, });
});
};
filterOnChange = filterOnChange.bind(this);
tabFilterOnChange = tabFilterOnChange.bind(this);
let filterLayout = function (passProps, idx) {
let { labelProps, } = passProps;
let dropdownProps = Object.assign({}, passProps, { labelProps: undefined, });
if (passProps.tabFilter) {
return (
<div key={idx} className="header_filter_button" >
<rb.Label {...labelProps}>{dropdownProps.label}</rb.Label>
<Tab menu={{ attached: false, tabular: false }} {...dropdownProps} onTabChange={tabFilterOnChange}/>
</div>
)
} else {
return (
<div key={idx} className="header_filter_button" >
<rb.Label {...labelProps}>{dropdownProps.label}</rb.Label>
<Dropdown {...dropdownProps}
onChange={filterOnChange}
renderLabel={(label) => ({
icon: label.icon,
content: label.text,
image: label.image,
style: label.selectedLabelStyle
})}
/>
</div>
);
}
};
filterButtons = this.props.filterButtons.map(filterProps => filterLayout(filterProps))
}
return (
<rb.Container {...this.props.containerProps}>
{(this.props.tableSearch && !this.props.simpleSearchFilter)
? (<rb.Addons
{...this.props.filterAddonProps}
>
<rb.Input {...this.props.filterSearchProps}
onChange={(data) => {
this.searchFunction({ search: data.target.value, });
this.searchInputTextVal = data.target.value; //TODO: this is janky fix it
}}
ref={(input) => {
this.searchTextInput = input;
}}
/>
<rb.Button {...this.props.searchButtonProps}
onClick={() => {
this.searchFunction({ search: this.searchInputTextVal, });
}}
>Search</rb.Button>
{fbts}
</rb.Addons>)
: (this.props.tableSearch && this.prop