Update Datatable, import SearchInput

This commit is contained in:
enzo - Eduardo Garcia 2019-03-22 15:43:51 +11:00 committed by eric-burel
parent bf9b4fda14
commit 91275b2f3d
2 changed files with 270 additions and 265 deletions

View file

@ -39,14 +39,14 @@ const baseStyles = theme => ({
alignItems: 'center', alignItems: 'center',
}, },
addButton: { addButton: {
position: 'absolute', top: '9.5rem',
top: '-8px', right: '2rem',
right: 0, position: 'fixed',
bottom: 'auto',
}, },
search: { table: {
marginBottom: theme.spacing.unit * 8, marginTop:0
}, },
table: {},
denseTable: {}, denseTable: {},
denserTable: {}, denserTable: {},
flatTable: {}, flatTable: {},
@ -70,19 +70,19 @@ const delay = (function () {
})(); })();
class Datatable extends PureComponent { class Datatable extends PureComponent {
constructor (props) { constructor (props) {
super(props); super(props);
this.updateQuery = this.updateQuery.bind(this); this.updateQuery = this.updateQuery.bind(this);
this.state = { this.state = {
value: '', value: '',
query: '', query: '',
currentSort: {}, currentSort: {},
}; };
} }
toggleSort = column => { toggleSort = column => {
let currentSort; let currentSort;
if (!this.state.currentSort[column]) { if (!this.state.currentSort[column]) {
@ -94,7 +94,7 @@ class Datatable extends PureComponent {
} }
this.setState({ currentSort }); this.setState({ currentSort });
}; };
updateQuery (value) { updateQuery (value) {
this.setState({ this.setState({
value: value value: value
@ -105,22 +105,22 @@ class Datatable extends PureComponent {
}); });
}, 700); }, 700);
} }
render () { render () {
if (this.props.data) { if (this.props.data) {
return <Components.DatatableContents return <Components.DatatableContents
columns={this.props.data.length ? Object.keys(this.props.data[0]) : undefined} columns={this.props.data.length ? Object.keys(this.props.data[0]) : undefined}
{...this.props} {...this.props}
results={this.props.data} results={this.props.data}
count={this.props.data.length} count={this.props.data.length}
totalCount={this.props.data.length} totalCount={this.props.data.length}
showEdit={false} showEdit={false}
showNew={false} showNew={false}
/>; />;
} else { } else {
const { const {
className, className,
collection, collection,
@ -130,51 +130,52 @@ class Datatable extends PureComponent {
currentUser, currentUser,
classes, classes,
} = this.props; } = this.props;
const listOptions = { const listOptions = {
collection: collection, collection: collection,
...options, ...options,
}; };
const DatatableWithMulti = withMulti(listOptions)(Components.DatatableContents); const DatatableWithMulti = withMulti(listOptions)(Components.DatatableContents);
// add _id to orderBy when we want to sort a column, to avoid breaking the graphql() hoc; // add _id to orderBy when we want to sort a column, to avoid breaking the graphql() hoc;
// see https://github.com/VulcanJS/Vulcan/issues/2090#issuecomment-433860782 // see https://github.com/VulcanJS/Vulcan/issues/2090#issuecomment-433860782
// this.state.currentSort !== {} is always false, even when console.log(this.state.currentSort) displays // this.state.currentSort !== {} is always false, even when console.log(this.state.currentSort) displays
// {}. So we test on the length of keys for this object. // {}. So we test on the length of keys for this object.
const orderBy = Object.keys(this.state.currentSort).length == 0 ? {} : const orderBy = Object.keys(this.state.currentSort).length == 0 ? {} :
{ ...this.state.currentSort, _id: -1 }; { ...this.state.currentSort, _id: -1 };
return ( return (
<div className={classNames('datatable', `datatable-${collection._name}`, classes.root, <div className={classNames('datatable', `datatable-${collection._name}`, classes.root,
className)}> className)}>
{/* DatatableAbove Component part*/} {/* DatatableAbove Component part*/}
{ {
showSearch && showSearch &&
<Components.SearchInput value={this.state.query} <Components.SearchInput value={this.state.query}
updateQuery={this.updateQuery} updateQuery={this.updateQuery}
className={classes.search} className={classes.search}
labelId={'datatable.search'}
/>
}
{
showNew &&
<Components.NewButton collection={collection}
variant="fab"
color="primary"
className={classes.addButton}
/>
}
<DatatableWithMulti {...this.props}
collection={collection}
terms={{ query: this.state.query, orderBy: orderBy }}
currentUser={this.props.currentUser}
toggleSort={this.toggleSort}
currentSort={this.state.currentSort}
/> />
} </div>
{
showNew &&
<Components.NewButton collection={collection}
variant="fab"
color="primary"
className={classes.addButton}
/>
}
<DatatableWithMulti {...this.props}
collection={collection}
terms={{ query: this.state.query, orderBy: orderBy }}
currentUser={this.props.currentUser}
toggleSort={this.toggleSort}
currentSort={this.state.currentSort}
/>
</div>
); );
} }
} }
@ -262,20 +263,20 @@ const DatatableContents = ({
paginationTerms, paginationTerms,
setPaginationTerms setPaginationTerms
}) => { }) => {
if (loading) { if (loading) {
return <Components.Loading/>; return <Components.Loading/>;
} else if (!results || !results.length) { } else if (!results || !results.length) {
return emptyState || null; return emptyState || null;
} }
if (queryDataRef) queryDataRef(this.props); if (queryDataRef) queryDataRef(this.props);
const denseClass = dense && classes[dense + 'Table']; const denseClass = dense && classes[dense + 'Table'];
// Pagination functions // Pagination functions
const getPage = (paginationTerms) => (parseInt((paginationTerms.limit - 1) / paginationTerms.itemsPerPage)); const getPage = (paginationTerms) => (parseInt((paginationTerms.limit - 1) / paginationTerms.itemsPerPage));
const onChangePage = (event, page) => { const onChangePage = (event, page) => {
setPaginationTerms({ setPaginationTerms({
itemsPerPage: paginationTerms.itemsPerPage, itemsPerPage: paginationTerms.itemsPerPage,
@ -283,7 +284,7 @@ const DatatableContents = ({
offset: page * paginationTerms.itemsPerPage offset: page * paginationTerms.itemsPerPage
}); });
}; };
const onChangeRowsPerPage = (event) => { const onChangeRowsPerPage = (event) => {
let value = event.target.value; let value = event.target.value;
let offset = Math.max(0, parseInt((paginationTerms.limit - paginationTerms.itemsPerPage) / value) * value); let offset = Math.max(0, parseInt((paginationTerms.limit - paginationTerms.itemsPerPage) / value) * value);
@ -294,117 +295,121 @@ const DatatableContents = ({
offset: offset offset: offset
}); });
}; };
return ( return (
<React.Fragment> <React.Fragment>
{
title &&
<Toolbar>
<Typography variant="h6" id="tableTitle">
title
</Typography>
</Toolbar>
}
<Table className={classNames(classes.table, denseClass)}>
<TableHead className={classes.tableHead}>
<TableRow className={classes.tableRow}>
{
_.sortBy(columns, column => column.order).map(
(column, index) =>
<Components.DatatableHeader key={index}
collection={collection}
intlNamespace={intlNamespace}
column={column}
classes={classes}
toggleSort={toggleSort}
currentSort={currentSort}
/>
)
}
{
(showEdit || editComponent) &&
<TableCell className={classes.tableCell}/>
}
</TableRow>
</TableHead>
{ {
results && (title)?
<Toolbar>
<TableBody className={classes.tableBody}> <Typography variant="h6" id="tableTitle">
{ title
results.map( </Typography>
(document, index) => </Toolbar>
<Components.DatatableRow collection={collection} :null
columns={columns}
document={document}
refetch={refetch}
key={index}
showEdit={showEdit}
editComponent={editComponent}
currentUser={currentUser}
classes={classes}
rowClass={rowClass}
handleRowClick={handleRowClick}
/>)
}
</TableBody>
} }
<Table className={classNames(classes.table, denseClass)}>
{
columns &&
<TableHead className={classes.tableHead}>
<TableRow className={classes.tableRow}>
{
_.sortBy(columns, column => column.order).map(
(column, index) =>
<Components.DatatableHeader key={index}
collection={collection}
intlNamespace={intlNamespace}
column={column}
classes={classes}
toggleSort={toggleSort}
currentSort={currentSort}
/>
)
}
{
(showEdit || editComponent) &&
<TableCell className={classes.tableCell}/>
}
</TableRow>
</TableHead>
}
{
results &&
<TableBody className={classes.tableBody}>
{
results.map(
(document, index) =>
<Components.DatatableRow collection={collection}
columns={columns}
document={document}
refetch={refetch}
key={index}
showEdit={showEdit}
editComponent={editComponent}
currentUser={currentUser}
classes={classes}
rowClass={rowClass}
handleRowClick={handleRowClick}
/>)
}
</TableBody>
}
{
footerData &&
<TableFooter className={classes.tableFooter}>
<TableRow className={classes.tableRow}>
{
_.sortBy(columns, column => column.order).map(
(column, index) =>
<TableCell key={index} className={classNames(classes.tableCell, column.footerClass)}>
{footerData[index]}
</TableCell>
)
}
{
(showEdit || editComponent) &&
<TableCell className={classes.tableCell}/>
}
</TableRow>
</TableFooter>
}
</Table>
{ {
footerData && paginate &&
<TableFooter className={classes.tableFooter}> <TablePagination
<TableRow className={classes.tableRow}> component="div"
{ count={totalCount}
_.sortBy(columns, column => column.order).map( rowsPerPage={paginationTerms.itemsPerPage}
(column, index) => page={getPage(paginationTerms)}
<TableCell key={index} className={classNames(classes.tableCell, column.footerClass)}> backIconButtonProps={{
{footerData[index]} 'aria-label': 'Previous Page',
</TableCell> }}
) nextIconButtonProps={{
} 'aria-label': 'Next Page',
{ }}
(showEdit || editComponent) && onChangePage={onChangePage}
onChangeRowsPerPage={onChangeRowsPerPage}
<TableCell className={classes.tableCell}/> />
}
</TableRow>
</TableFooter>
} }
{
</Table> !paginate && loadMore &&
{
paginate && <Components.LoadMore className={classes.loadMore}
count={count}
<TablePagination totalCount={totalCount}
component="div" loadMore={loadMore}
count={totalCount} networkStatus={networkStatus}
rowsPerPage={paginationTerms.itemsPerPage} />
page={getPage(paginationTerms)} }
backIconButtonProps={{ </React.Fragment>
'aria-label': 'Previous Page',
}}
nextIconButtonProps={{
'aria-label': 'Next Page',
}}
onChangePage={onChangePage}
onChangeRowsPerPage={onChangeRowsPerPage}
/>
}
{
!paginate && loadMore &&
<Components.LoadMore className={classes.loadMore}
count={count}
totalCount={totalCount}
loadMore={loadMore}
networkStatus={networkStatus}
/>
}
</React.Fragment>
); );
}; };
@ -420,10 +425,10 @@ DatatableHeader Component
const DatatableHeader = ({ collection, intlNamespace, column, classes, toggleSort, currentSort }, { intl }) => { const DatatableHeader = ({ collection, intlNamespace, column, classes, toggleSort, currentSort }, { intl }) => {
const columnName = typeof column === 'string' ? column : column.name || column.label; const columnName = typeof column === 'string' ? column : column.name || column.label;
let formattedLabel = ''; let formattedLabel = '';
if (collection) { if (collection) {
const schema = collection.simpleSchema()._schema; const schema = collection.simpleSchema()._schema;
/* /*
use either: use either:
@ -433,16 +438,16 @@ const DatatableHeader = ({ collection, intlNamespace, column, classes, toggleSor
*/ */
const defaultMessage = schema[columnName] ? schema[columnName].label : Utils.camelToSpaces(columnName); const defaultMessage = schema[columnName] ? schema[columnName].label : Utils.camelToSpaces(columnName);
formattedLabel = typeof columnName === 'string' ? formattedLabel = typeof columnName === 'string' ?
intl.formatMessage({ intl.formatMessage({
id: `${collection._name}.${columnName}`, id: `${collection._name}.${columnName}`,
defaultMessage: defaultMessage defaultMessage: defaultMessage
}) : }) :
''; '';
// if sortable is a string, use it as the name of the property to sort by. If it's just `true`, use // if sortable is a string, use it as the name of the property to sort by. If it's just `true`, use
// column.name // column.name
const sortPropertyName = typeof column.sortable === 'string' ? column.sortable : column.name; const sortPropertyName = typeof column.sortable === 'string' ? column.sortable : column.name;
if (column.sortable) { if (column.sortable) {
return <Components.DatatableSorter name={sortPropertyName} return <Components.DatatableSorter name={sortPropertyName}
label={formattedLabel} label={formattedLabel}
@ -453,17 +458,17 @@ const DatatableHeader = ({ collection, intlNamespace, column, classes, toggleSor
} }
} else if (intlNamespace) { } else if (intlNamespace) {
formattedLabel = typeof columnName === 'string' ? formattedLabel = typeof columnName === 'string' ?
intl.formatMessage({ intl.formatMessage({
id: `${intlNamespace}.${columnName}`, id: `${intlNamespace}.${columnName}`,
defaultMessage: columnName defaultMessage: columnName
}) : }) :
''; '';
} else { } else {
formattedLabel = intl.formatMessage({ id: columnName, defaultMessage: columnName }); formattedLabel = intl.formatMessage({ id: columnName, defaultMessage: columnName });
} }
return <TableCell return <TableCell
className={classNames(classes.tableHeadCell, column.headerClass)}>{formattedLabel}</TableCell>; className={classNames(classes.tableHeadCell, column.headerClass)}>{formattedLabel}</TableCell>;
}; };
@ -482,23 +487,23 @@ DatatableSorter Component
*/ */
const DatatableSorter = ({ name, label, toggleSort, currentSort, sortable }) => const DatatableSorter = ({ name, label, toggleSort, currentSort, sortable }) =>
<TableCell className="datatable-sorter" <TableCell className="datatable-sorter"
sortDirection={!currentSort[name] ? false : currentSort[name] === 1 ? 'asc' : 'desc'} sortDirection={!currentSort[name] ? false : currentSort[name] === 1 ? 'asc' : 'desc'}
>
<Tooltip
title="Sort"
placement='bottom-start'
enterDelay={300}
> >
<TableSortLabel <Tooltip
active={!currentSort[name] ? false : true} title="Sort"
direction={currentSort[name] === 1 ? 'desc' : 'asc'} placement='bottom-start'
onClick={() => toggleSort(name)} enterDelay={300}
> >
{label} <TableSortLabel
</TableSortLabel> active={!currentSort[name] ? false : true}
</Tooltip> direction={currentSort[name] === 1 ? 'desc' : 'asc'}
</TableCell>; onClick={() => toggleSort(name)}
>
{label}
</TableSortLabel>
</Tooltip>
</TableCell>;
replaceComponent('DatatableSorter', DatatableSorter); replaceComponent('DatatableSorter', DatatableSorter);
@ -532,52 +537,52 @@ const DatatableRow = ({
handleRowClick, handleRowClick,
classes, classes,
}, { intl }) => { }, { intl }) => {
const EditComponent = editComponent; const EditComponent = editComponent;
if (typeof rowClass === 'function') { if (typeof rowClass === 'function') {
rowClass = rowClass(document); rowClass = rowClass(document);
} }
return ( return (
<TableRow <TableRow
className={classNames('datatable-item', classes.tableRow, rowClass, handleRowClick && classes.clickRow)} className={classNames('datatable-item', classes.tableRow, rowClass, handleRowClick && classes.clickRow)}
onClick={handleRowClick && (event => handleRowClick(event, document))} onClick={handleRowClick && (event => handleRowClick(event, document))}
hover hover
> >
{ {
_.sortBy(columns, column => column.order).map( _.sortBy(columns, column => column.order).map(
(column, index) => (column, index) =>
<Components.DatatableCell key={index} <Components.DatatableCell key={index}
column={column} column={column}
document={document} document={document}
currentUser={currentUser} currentUser={currentUser}
classes={classes} classes={classes}
/>) />)
} }
{ {
(showEdit || editComponent) && (showEdit || editComponent) &&
<TableCell className={classes.editCell}> <TableCell className={classes.editCell}>
{ {
EditComponent && EditComponent &&
<EditComponent collection={collection} document={document} refetch={refetch}/> <EditComponent collection={collection} document={document} refetch={refetch}/>
} }
{ {
showEdit && showEdit &&
<Components.EditButton collection={collection} <Components.EditButton collection={collection}
document={document} document={document}
buttonClasses={{ button: classes.editButton }} buttonClasses={{ button: classes.editButton }}
/> />
} }
</TableCell> </TableCell>
} }
</TableRow> </TableRow>
); );
}; };
@ -597,26 +602,26 @@ DatatableCell Component
*/ */
const DatatableCell = ({ column, document, currentUser, classes }) => { const DatatableCell = ({ column, document, currentUser, classes }) => {
const Component = column.component || const Component = column.component ||
Components[column.componentName] || Components[column.componentName] ||
Components.DatatableDefaultCell; Components.DatatableDefaultCell;
const columnName = typeof column === 'string' ? column : column.name; const columnName = typeof column === 'string' ? column : column.name;
const className = typeof columnName === 'string' ? const className = typeof columnName === 'string' ?
`datatable-item-${columnName.toLowerCase()}` : `datatable-item-${columnName.toLowerCase()}` :
''; '';
const cellClass = typeof column.cellClass === 'function' ? const cellClass = typeof column.cellClass === 'function' ?
column.cellClass({ column, document, currentUser }) : column.cellClass({ column, document, currentUser }) :
typeof column.cellClass === 'string' ? typeof column.cellClass === 'string' ?
column.cellClass : column.cellClass :
null; null;
return ( return (
<TableCell className={classNames(classes.tableCell, cellClass, className)}> <TableCell className={classNames(classes.tableCell, cellClass, className)}>
<Component column={column} <Component column={column}
document={document} document={document}
currentUser={currentUser} currentUser={currentUser}
/> />
</TableCell> </TableCell>
); );
}; };
@ -630,15 +635,15 @@ DatatableDefaultCell Component
*/ */
const DatatableDefaultCell = ({ column, document }) => const DatatableDefaultCell = ({ column, document }) =>
<div> <div>
{ {
typeof column === 'string' typeof column === 'string'
? ?
getFieldValue(document[column]) getFieldValue(document[column])
: :
getFieldValue(document[column.name]) getFieldValue(document[column.name])
} }
</div>; </div>;
replaceComponent('DatatableDefaultCell', DatatableDefaultCell); replaceComponent('DatatableDefaultCell', DatatableDefaultCell);

View file

@ -7,7 +7,7 @@ import './accounts/AccountsPasswordOrService';
import './accounts/AccountsSocialButtons'; import './accounts/AccountsSocialButtons';
import './bonus/LoadMore'; import './bonus/LoadMore';
// import './bonus/SearchInput'; import './bonus/SearchInput';
import './bonus/TooltipIntl'; import './bonus/TooltipIntl';
import './bonus/TooltipIconButton'; import './bonus/TooltipIconButton';