mirror of
https://github.com/ascribe/onion.git
synced 2025-01-03 10:25:08 +01:00
Merge branch 'master' of bitbucket.org:ascribe/onion
Conflicts: js/components/piece_list.js
This commit is contained in:
commit
f28c6d47f6
@ -11,9 +11,6 @@ let AscribeApp = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Header />
|
<Header />
|
||||||
<nav>
|
|
||||||
<Link to="pieces">pieces</Link>
|
|
||||||
</nav>
|
|
||||||
<RouteHandler />
|
<RouteHandler />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -3,19 +3,21 @@ import React from 'react';
|
|||||||
import TableItem from './table_item';
|
import TableItem from './table_item';
|
||||||
import TableHeader from './table_header';
|
import TableHeader from './table_header';
|
||||||
|
|
||||||
|
import TableColumnModel from '../../models/table_column_model';
|
||||||
|
|
||||||
|
|
||||||
let Table = React.createClass({
|
let Table = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
columnMap: React.PropTypes.object.isRequired
|
columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnModel))
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
if(this.props.itemList && this.props.itemList.length > 0) {
|
if(this.props.itemList && this.props.itemList.length > 0) {
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-table">
|
<div className="ascribe-table">
|
||||||
<TableHeader columnMap={this.props.columnMap} itemList={this.props.itemList} fetchList={this.props.fetchList} orderAsc={this.props.orderAsc} orderBy={this.props.orderBy} />
|
<TableHeader columnList={this.props.columnList} itemList={this.props.itemList} fetchList={this.props.fetchList} orderAsc={this.props.orderAsc} orderBy={this.props.orderBy} />
|
||||||
{this.props.itemList.map((item, i) => {
|
{this.props.itemList.map((item, i) => {
|
||||||
return (
|
return (
|
||||||
<TableItem columnMap={this.props.columnMap} columnContent={item} key={i} />
|
<TableItem columnList={this.props.columnList} columnContent={item} key={i} />
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
50
js/components/ascribe_table/table_header.js
Normal file
50
js/components/ascribe_table/table_header.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import TableColumnMixin from '../../mixins/table_column_mixin';
|
||||||
|
import GeneralUtils from '../../utils/general_utils';
|
||||||
|
import TableHeaderItem from './table_header_item';
|
||||||
|
|
||||||
|
import TableColumnModel from '../../models/table_column_model';
|
||||||
|
|
||||||
|
|
||||||
|
let TableHeader = React.createClass({
|
||||||
|
mixins: [TableColumnMixin],
|
||||||
|
propTypes: {
|
||||||
|
columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnModel)),
|
||||||
|
itemList: React.PropTypes.array.isRequired,
|
||||||
|
fetchList: React.PropTypes.func.isRequired,
|
||||||
|
orderAsc: React.PropTypes.bool.isRequired,
|
||||||
|
orderBy: React.PropTypes.string.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="col-xs-12 col-sm-12 col-md-12 col-lg-12 ascribe-table-header-row">
|
||||||
|
<div className="row">
|
||||||
|
{this.props.columnList.map((val, i) => {
|
||||||
|
|
||||||
|
let columnClasses = this.calcColumnClasses(this.props.columnList, i);
|
||||||
|
let columnName = this.props.columnList[i].columnName;
|
||||||
|
let canBeOrdered = this.props.columnList[i].canBeOrdered;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableHeaderItem
|
||||||
|
key={i}
|
||||||
|
columnClasses={columnClasses}
|
||||||
|
displayName={val.displayName}
|
||||||
|
columnName={columnName}
|
||||||
|
canBeOrdered={canBeOrdered}
|
||||||
|
orderAsc={this.props.orderAsc}
|
||||||
|
orderBy={this.props.orderBy}
|
||||||
|
fetchList={this.props.fetchList}>
|
||||||
|
</TableHeaderItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TableHeader;
|
52
js/components/ascribe_table/table_header_item.js
Normal file
52
js/components/ascribe_table/table_header_item.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import TableHeaderItemCarret from './table_header_item_carret';
|
||||||
|
|
||||||
|
let TableHeaderItem = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
columnClasses: React.PropTypes.string.isRequired,
|
||||||
|
displayName: React.PropTypes.string.isRequired,
|
||||||
|
columnName: React.PropTypes.string.isRequired,
|
||||||
|
canBeOrdered: React.PropTypes.bool.isRequired,
|
||||||
|
orderAsc: React.PropTypes.bool.isRequired,
|
||||||
|
orderBy: React.PropTypes.string.isRequired,
|
||||||
|
fetchList: React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
changeOrder() {
|
||||||
|
this.props.fetchList(1, 10, null, this.props.columnName, !this.props.orderAsc);
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if(this.props.canBeOrdered) {
|
||||||
|
if(this.props.columnName === this.props.orderBy) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={this.props.columnClasses + ' ascribe-table-header-column'}
|
||||||
|
onClick={this.changeOrder}>
|
||||||
|
<span>{this.props.displayName} <TableHeaderItemCarret orderAsc={this.props.orderAsc} /></span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={this.props.columnClasses + ' ascribe-table-header-column'}
|
||||||
|
onClick={this.changeOrder}>
|
||||||
|
<span>{this.props.displayName}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className={this.props.columnClasses + ' ascribe-table-header-column'}>
|
||||||
|
<span>
|
||||||
|
{this.props.displayName}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TableHeaderItem;
|
24
js/components/ascribe_table/table_header_item_carret.js
Normal file
24
js/components/ascribe_table/table_header_item_carret.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
let TableHeaderItemCarret = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
orderAsc: React.PropTypes.bool.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let carretDirection = 'glyphicon-triangle-';
|
||||||
|
|
||||||
|
if(this.props.orderAsc) {
|
||||||
|
carretDirection += 'top';
|
||||||
|
} else {
|
||||||
|
carretDirection += 'bottom';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={'glyphicon ' + carretDirection}>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TableHeaderItemCarret;
|
@ -1,44 +1,34 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import TableColumnMixin from '../mixins/table_column_mixin';
|
import TableColumnMixin from '../../mixins/table_column_mixin';
|
||||||
import TableItemImg from './table_item_img';
|
import TableItemImg from './table_item_img';
|
||||||
import TableItemText from './table_item_text';
|
import TableItemText from './table_item_text';
|
||||||
|
|
||||||
|
import TableColumnModel from '../../models/table_column_model';
|
||||||
|
|
||||||
|
|
||||||
let TableItem = React.createClass({
|
let TableItem = React.createClass({
|
||||||
mixins: [TableColumnMixin],
|
mixins: [TableColumnMixin],
|
||||||
|
|
||||||
// ToDo: Specify that every columnMap should look like this:
|
|
||||||
// {
|
|
||||||
// 'name-of-the-data-point': {
|
|
||||||
// 'displayName': String,
|
|
||||||
// 'displayType': ReactComponent,
|
|
||||||
// 'rowWidth': number
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
columnMap: React.PropTypes.object.isRequired,
|
columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnModel)),
|
||||||
columnContent: React.PropTypes.object.isRequired
|
columnContent: React.PropTypes.object.isRequired
|
||||||
},
|
},
|
||||||
render() {
|
|
||||||
|
|
||||||
let columnContent = this.props.columnContent;
|
|
||||||
let columnMapKeysList = Object.keys(this.props.columnMap);
|
|
||||||
|
|
||||||
|
render() {
|
||||||
/**
|
/**
|
||||||
* An element in the Table can have a certain display_type.
|
* An element in the Table can have a certain display_type.
|
||||||
* A display_type is just
|
* A display_type is just
|
||||||
*/
|
*/
|
||||||
let calcColumnElementContent = () => {
|
let calcColumnElementContent = () => {
|
||||||
return columnMapKeysList.map((key, i) => {
|
return this.props.columnList.map((column, i) => {
|
||||||
|
|
||||||
let TypeElement = this.props.columnMap[key].displayType;
|
let TypeElement = column.displayType;
|
||||||
let columnClass = this.calcColumnClasses(this.props.columnMap, i);
|
let columnClass = this.calcColumnClasses(this.props.columnList, i);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={columnClass + ' ascribe-table-item-column'} key={i}>
|
<div className={columnClass + ' ascribe-table-item-column'} key={i}>
|
||||||
<TypeElement content={this.props.columnContent[key]} width="50" />
|
<TypeElement content={this.props.columnContent[column.columnName]} width="50" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -1,8 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Router from 'react-router';
|
||||||
|
|
||||||
import AltContainer from 'alt/AltContainer';
|
import AltContainer from 'alt/AltContainer';
|
||||||
import UserActions from '../actions/user_actions';
|
import UserActions from '../actions/user_actions';
|
||||||
import UserStore from '../stores/user_store';
|
import UserStore from '../stores/user_store';
|
||||||
|
|
||||||
|
let Link = Router.Link;
|
||||||
|
|
||||||
let Header = React.createClass({
|
let Header = React.createClass({
|
||||||
|
|
||||||
@ -22,37 +25,43 @@ let Header = React.createClass({
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<nav className="navbar navbar-default navbar-fixed-top">
|
<nav className="navbar navbar-default navbar-fixed-top">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="navbar-header">
|
<div className="navbar-header">
|
||||||
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||||
<span className="sr-only">Toggle navigation</span>
|
<span className="sr-only">Toggle navigation</span>
|
||||||
<span className="icon-bar"></span>
|
<span className="icon-bar"></span>
|
||||||
<span className="icon-bar"></span>
|
<span className="icon-bar"></span>
|
||||||
<span className="icon-bar"></span>
|
<span className="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a className="navbar-brand" href="#">
|
<a className="navbar-brand" href="#">
|
||||||
<span>ascribe</span>
|
<span>ascribe </span>
|
||||||
<span className="glyph-ascribe-spool-chunked"></span>
|
<span className="glyph-ascribe-spool-chunked"></span>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="navbar" className="navbar-collapse collapse">
|
||||||
|
<ul className="nav navbar-nav navbar-left">
|
||||||
|
<li>
|
||||||
|
<Link to="pieces">Pieces</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul className="nav navbar-nav navbar-right">
|
||||||
|
<li className="dropdown">
|
||||||
|
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{this.state.currentUser.username} <span className="caret"></span></a>
|
||||||
|
<ul className="dropdown-menu" role="menu">
|
||||||
|
<li><a href="/art/faq/">Account Settings</a></li>
|
||||||
|
<li className="divider"></li>
|
||||||
|
<li><a href="/art/faq/">FAQ</a></li>
|
||||||
|
<li><a href="/art/terms/">Terms of Service</a></li>
|
||||||
|
<li className="divider"></li>
|
||||||
|
<li><a href="/api/users/logout/">Log out</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="navbar" className="navbar-collapse collapse">
|
|
||||||
<ul className="nav navbar-nav navbar-right">
|
|
||||||
<li className="dropdown">
|
|
||||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{this.state.currentUser.username} <span className="caret"></span></a>
|
|
||||||
<ul className="dropdown-menu" role="menu">
|
|
||||||
<li><a href="/art/faq/">Account Settings</a></li>
|
|
||||||
<li className="divider"></li>
|
|
||||||
<li><a href="/art/faq/">FAQ</a></li>
|
|
||||||
<li><a href="/art/terms/">Terms of Service</a></li>
|
|
||||||
<li className="divider"></li>
|
|
||||||
<li><a href="/api/users/logout/">Log out</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5,9 +5,12 @@ import AltContainer from 'alt/AltContainer';
|
|||||||
import PieceListStore from '../stores/piece_list_store';
|
import PieceListStore from '../stores/piece_list_store';
|
||||||
import PieceListActions from '../actions/piece_list_actions';
|
import PieceListActions from '../actions/piece_list_actions';
|
||||||
|
|
||||||
import Table from './table';
|
import Table from './ascribe_table/table';
|
||||||
import TableItemImg from './table_item_img';
|
import TableItemImg from './ascribe_table/table_item_img';
|
||||||
import TableItemText from './table_item_text';
|
import TableItemText from './ascribe_table/table_item_text';
|
||||||
|
|
||||||
|
import TableColumnModel from '../models/table_column_model';
|
||||||
|
|
||||||
import Pagination from './pagination'
|
import Pagination from './pagination'
|
||||||
|
|
||||||
let Link = Router.Link;
|
let Link = Router.Link;
|
||||||
@ -27,32 +30,15 @@ let PieceList = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// TODO:
|
let columnList = [
|
||||||
// Specifiy how a TableItemX should look like
|
new TableColumnModel('thumbnail', '', TableItemImg, 2, false),
|
||||||
let columnMap = {
|
new TableColumnModel('artist_name', 'Artist', TableItemText, 4, true),
|
||||||
'thumbnail': {
|
new TableColumnModel('title', 'Title', TableItemText, 4, true)
|
||||||
'displayName': '',
|
];
|
||||||
'displayType': TableItemImg,
|
|
||||||
'rowWidth': 2,
|
|
||||||
'canBeOrdered': false
|
|
||||||
},
|
|
||||||
'artist_name': {
|
|
||||||
'displayName': 'Artist',
|
|
||||||
'displayType': TableItemText,
|
|
||||||
'rowWidth': 4,
|
|
||||||
'canBeOrdered': true
|
|
||||||
},
|
|
||||||
'title': {
|
|
||||||
'displayName': 'Title',
|
|
||||||
'displayType': TableItemText,
|
|
||||||
'rowWidth': 4,
|
|
||||||
'canBeOrdered': true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AltContainer store={PieceListStore} actions={PieceListActions}>
|
<AltContainer store={PieceListStore} actions={PieceListActions}>
|
||||||
<Table columnMap={columnMap} />
|
<Table columnList={columnList} />
|
||||||
<Pagination currentPage={this.props.query.page} />
|
<Pagination currentPage={this.props.query.page} />
|
||||||
</AltContainer>
|
</AltContainer>
|
||||||
);
|
);
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import TableColumnMixin from '../mixins/table_column_mixin';
|
|
||||||
import GeneralUtils from '../utils/general_utils';
|
|
||||||
|
|
||||||
|
|
||||||
let TableHeader = React.createClass({
|
|
||||||
mixins: [TableColumnMixin],
|
|
||||||
propTypes: {
|
|
||||||
columnMap: React.PropTypes.object.isRequired,
|
|
||||||
itemList: React.PropTypes.array.isRequired,
|
|
||||||
fetchList: React.PropTypes.func.isRequired,
|
|
||||||
orderAsc: React.PropTypes.bool.isRequired,
|
|
||||||
orderBy: React.PropTypes.string.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
sortIndex(i) {
|
|
||||||
|
|
||||||
let orderAsc;
|
|
||||||
|
|
||||||
if(this.props.orderAsc) {
|
|
||||||
orderAsc = false;
|
|
||||||
} else {
|
|
||||||
orderAsc = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.fetchList(1, 10, null, Object.keys(this.props.columnMap)[i], orderAsc);
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
let columnMapValuesList = GeneralUtils.valuesOfObject(this.props.columnMap);
|
|
||||||
|
|
||||||
let calcHeaderText = (val, i, columnClass) => {
|
|
||||||
|
|
||||||
if(columnMapValuesList[i].canBeOrdered && Object.keys(this.props.columnMap)[i] === this.props.orderBy) {
|
|
||||||
|
|
||||||
let boundClick = this.sortIndex.bind(this, i);
|
|
||||||
let carretDirection = 'glyphicon-triangle-';
|
|
||||||
|
|
||||||
if(this.props.orderAsc) {
|
|
||||||
carretDirection += 'top';
|
|
||||||
} else {
|
|
||||||
carretDirection += 'bottom';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={columnClass + ' ascribe-table-header-column'} key={i} onClick={boundClick}>
|
|
||||||
<span>
|
|
||||||
{val.displayName}
|
|
||||||
<span className={'glyphicon ' + carretDirection}></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div className={columnClass + ' ascribe-table-header-column'} key={i}>
|
|
||||||
<span>
|
|
||||||
{val.displayName}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="col-xs-12 col-sm-12 col-md-12 col-lg-12 ascribe-table-header-row">
|
|
||||||
<div className="row">
|
|
||||||
{columnMapValuesList.map((val, i) => {
|
|
||||||
|
|
||||||
let columnClass = this.calcColumnClasses(this.props.columnMap, i);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={i}>
|
|
||||||
{calcHeaderText(val, i, columnClass)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default TableHeader;
|
|
@ -1,9 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
|
|
||||||
let TableHeaderItem = React.createClass({
|
|
||||||
mixins: [TableColumnMixin],
|
|
||||||
render() {
|
|
||||||
return()
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,16 +1,16 @@
|
|||||||
import GeneralUtils from '../utils/general_utils';
|
import React from 'react';
|
||||||
|
|
||||||
|
import GeneralUtils from '../utils/general_utils';
|
||||||
|
|
||||||
let TableColumnMixin = {
|
let TableColumnMixin = {
|
||||||
/**
|
/**
|
||||||
* Generates the bootstrap grid column declarations automatically using
|
* Generates the bootstrap grid column declarations automatically using
|
||||||
* the columnMap.
|
* the columnMap.
|
||||||
*/
|
*/
|
||||||
calcColumnClasses(obj, i) {
|
calcColumnClasses(list, i) {
|
||||||
let bootstrapClasses = ['col-xs-', 'col-sm-', 'col-md-', 'col-lg-'];
|
let bootstrapClasses = ['col-xs-', 'col-sm-', 'col-md-', 'col-lg-'];
|
||||||
|
|
||||||
let rowData = GeneralUtils.valuesOfObject(obj);
|
let listOfRowValues = list.map((column) => column.rowWidth );
|
||||||
let listOfRowValues = rowData.map((val) => val.rowWidth );
|
|
||||||
let numOfColumns = GeneralUtils.sumNumList(listOfRowValues);
|
let numOfColumns = GeneralUtils.sumNumList(listOfRowValues);
|
||||||
|
|
||||||
if(numOfColumns > 12) {
|
if(numOfColumns > 12) {
|
||||||
|
12
js/models/table_column_model.js
Normal file
12
js/models/table_column_model.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class TableColumnItem {
|
||||||
|
constructor(columnName, displayName, displayType, rowWidth, canBeOrdered) {
|
||||||
|
this.columnName = columnName;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.displayType = displayType;
|
||||||
|
this.rowWidth = rowWidth;
|
||||||
|
this.canBeOrdered = canBeOrdered;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TableColumnItem;
|
Loading…
Reference in New Issue
Block a user