-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#865 Write projects overview in react/javascript
* move Table to projects/assets/js/components * work on Table sort, config store and Projects
- Loading branch information
Showing
11 changed files
with
346 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
|
||
const TextField = ({ value, onChange, placeholder }) => { | ||
return ( | ||
<div className="form-group mb-0"> | ||
<div className="input-group"> | ||
<input type="text" className="form-control" placeholder={placeholder} | ||
value={ value } onChange={e => onChange(e.target.value)}></input> | ||
<span className="input-group-btn"> | ||
<button className="btn btn-default" onClick={() => onChange('')}> | ||
<span className="fa fa-times"></span> | ||
</button> | ||
</span> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
TextField.propTypes = { | ||
value: PropTypes.string.isRequired, | ||
onChange: PropTypes.func.isRequired, | ||
placeholder: PropTypes.string.isRequired | ||
} | ||
|
||
const Select = ({ value, options, onChange, placeholder }) => { | ||
return ( | ||
<div className="form-group mb-0"> | ||
<select className="form-control" value={value} onChange={e => onChange(e.target.value)}> | ||
<option value="">{placeholder}</option> | ||
{ | ||
options.map((option, index) => <option value={option} key={index}>{option}</option>) | ||
} | ||
</select> | ||
</div> | ||
) | ||
} | ||
|
||
Select.propTypes = { | ||
value: PropTypes.string, | ||
options: PropTypes.array.isRequired, | ||
onChange: PropTypes.func, | ||
placeholder: PropTypes.string | ||
} | ||
|
||
export { TextField, Select } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { UPDATE_CONFIG } from './types' | ||
|
||
export function updateConfig(path, value) { | ||
return {type: UPDATE_CONFIG, path, value} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
import { get } from 'lodash' | ||
|
||
const Table = ({ | ||
cellFormatters, | ||
columnWidths, | ||
data, | ||
headerFormatters, | ||
initialRows = 3, | ||
rowsToLoad = 2, | ||
sortableColumns, | ||
/* order of elements in 'visibleColumns' corresponds to order of columns in table */ | ||
visibleColumns, | ||
configActions, | ||
config | ||
}) => { | ||
|
||
const displayedRows = get(config, 'table.rows', 0) | ||
displayedRows == 0 && configActions.updateConfig('table.rows', initialRows) | ||
const { column: sortColumn, order: sortOrder } = get(config, 'table.sort', '') | ||
// const sortColumn = get(config, 'table.sort.column', '') | ||
// const sortOrder = get(config, 'table.sort.order', '') | ||
console.log('sortColumn', sortColumn) | ||
const loadMore = () => { | ||
configActions.updateConfig('table.rows', parseInt(displayedRows) + parseInt(rowsToLoad)) | ||
} | ||
|
||
const handleHeaderClick = column=> { | ||
if (sortableColumns.includes(column)) { | ||
if (sortColumn === column) { | ||
// configActions.updateConfig('table.sort', { column: column, order: sortOrder === 'asc' ? 'desc' : 'asc' }) | ||
configActions.updateConfig('table.sort.column', column) | ||
configActions.updateConfig('table.sort.order', sortOrder === 'asc' ? 'desc' : 'asc') | ||
} else { | ||
// configActions.updateConfig('table.sort', { column: column, order: 'asc'}) | ||
configActions.updateConfig('table.sort.column', column) | ||
configActions.updateConfig('table.sort.order', 'asc') | ||
} | ||
} | ||
} | ||
|
||
const sortedData = () => { | ||
// const slicedData = data //.slice(0, displayedRows) | ||
const sorted = data | ||
if (sortColumn) { | ||
// const sorted = slicedData | ||
console.log('sorted', sorted) | ||
|
||
sorted.sort((a, b) => { | ||
let valueA = a[sortColumn] | ||
let valueB = b[sortColumn] | ||
const sortRawContent = ( | ||
headerFormatters[sortColumn]?.sortRawContent ?? true | ||
) | ||
|
||
if (!sortRawContent) { | ||
valueA = formatCellContent(a, sortColumn, a[sortColumn]) | ||
valueB = formatCellContent(b, sortColumn, b[sortColumn]) | ||
} | ||
|
||
if (sortOrder === 'asc') { | ||
return valueA.localeCompare ? valueA.localeCompare(valueB) : valueA - valueB | ||
} else { | ||
return valueB.localeCompare ? valueB.localeCompare(valueA) : valueB - valueA | ||
} | ||
}) | ||
} | ||
// return sorted.slice(0, displayedRows) | ||
return sorted | ||
} | ||
|
||
const renderSortIcon = (column) => { | ||
const isSortColumn = sortColumn === column | ||
const isAsc = sortOrder === 'asc' | ||
|
||
return ( | ||
<span className="ml-5 sort-icon"> | ||
<i className={`fa fa-sort${isSortColumn ? isAsc ? '-asc' : '-desc' : ''} ${isSortColumn ? '' : 'text-muted'}`} /> | ||
</span> | ||
) | ||
} | ||
|
||
const renderHeaders = () => { | ||
return ( | ||
<thead className="thead-dark"> | ||
<tr> | ||
{visibleColumns.map((column, index) => { | ||
const headerFormatter = headerFormatters[column] | ||
const columnHeaderContent = headerFormatter && headerFormatter.render ? headerFormatter.render(column) : column | ||
|
||
return ( | ||
<th key={column} style={{ width: columnWidths[index] }} onClick={() => handleHeaderClick(column)}> | ||
{columnHeaderContent} | ||
{sortableColumns.includes(column) && renderSortIcon(column)} | ||
</th> | ||
) | ||
})} | ||
</tr> | ||
</thead> | ||
) | ||
} | ||
|
||
const formatCellContent = (row, column, content) => { | ||
if (cellFormatters && cellFormatters[column] && typeof cellFormatters[column] === 'function') { | ||
return cellFormatters[column](content, row) | ||
} | ||
return content | ||
} | ||
|
||
const renderRows = () => { | ||
const sortedRows = sortedData().slice(0, displayedRows) | ||
// const sortedRows = sortedData() | ||
return ( | ||
<tbody> | ||
{sortedRows.map((row, index) => ( | ||
<tr key={index}> | ||
{visibleColumns.map((column, index) => ( | ||
<td key={column}style={{ width: columnWidths[index] }}> | ||
{formatCellContent(row, column, row[column])} | ||
</td> | ||
))} | ||
</tr> | ||
))} | ||
</tbody> | ||
) | ||
} | ||
|
||
return ( | ||
<div className="table-container"> | ||
<table className="table table-borderless"> | ||
{renderHeaders()} | ||
{renderRows()} | ||
</table> | ||
{displayedRows < data.length && ( | ||
<button onClick={loadMore} className="load-more-btn"> | ||
{gettext('Load More')} | ||
</button> | ||
)} | ||
</div> | ||
) | ||
} | ||
|
||
Table.propTypes = { | ||
cellFormatters: PropTypes.object, | ||
columnWidths: PropTypes.arrayOf(PropTypes.string), | ||
data: PropTypes.arrayOf(PropTypes.object).isRequired, | ||
headerFormatters: PropTypes.object, | ||
initialRows: PropTypes.number, | ||
rowsToLoad: PropTypes.number, | ||
sortableColumns: PropTypes.arrayOf(PropTypes.string), | ||
visibleColumns: PropTypes.arrayOf(PropTypes.string), | ||
configActions: PropTypes.object, | ||
config: PropTypes.object | ||
} | ||
|
||
export default Table |
Oops, something went wrong.