mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-05 12:22:44 +00:00
Finished stats and brew lookup on admin panel
This commit is contained in:
@@ -1,38 +1,35 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const HomebrewAdmin = require('./homebrewAdmin/homebrewAdmin.jsx');
|
|
||||||
|
const BrewCleanup = require('./brewCleanup/brewCleanup.jsx');
|
||||||
|
const BrewLookup = require('./brewLookup/brewLookup.jsx');
|
||||||
|
const Stats = require('./stats/stats.jsx');
|
||||||
|
|
||||||
const Admin = createClass({
|
const Admin = createClass({
|
||||||
getDefaultProps : function() {
|
getDefaultProps : function() {
|
||||||
return {
|
return {
|
||||||
url : '',
|
adminKey : ''
|
||||||
admin_key : '',
|
|
||||||
homebrews : [],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return (
|
return <div className='admin'>
|
||||||
<div className='admin'>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<div className='container'>
|
|
||||||
<i className='fa fa-rocket' />
|
|
||||||
naturalcrit admin
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
|
<header>
|
||||||
<div className='container'>
|
<div className='container'>
|
||||||
|
<i className='fa fa-rocket' />
|
||||||
<HomebrewAdmin homebrews={this.props.homebrews} admin_key={this.props.admin_key} />
|
homebrewery admin
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
<div className='container'>
|
||||||
|
<Stats adminKey={this.props.adminKey} />
|
||||||
|
<hr />
|
||||||
|
<BrewLookup adminKey={this.props.adminKey} />
|
||||||
|
<hr />
|
||||||
|
<BrewCleanup adminKey={this.props.adminKey} />
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -36,4 +36,60 @@ body{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.homebrewAdmin{
|
||||||
|
margin-bottom: 80px;
|
||||||
|
.brewTable{
|
||||||
|
table{
|
||||||
|
|
||||||
|
th{
|
||||||
|
padding : 10px;
|
||||||
|
font-weight : 800;
|
||||||
|
}
|
||||||
|
tr:nth-child(even){
|
||||||
|
background-color : fade(@green, 10%);
|
||||||
|
}
|
||||||
|
tr.isEmpty{
|
||||||
|
background-color : fade(@red, 30%);
|
||||||
|
}
|
||||||
|
td{
|
||||||
|
min-width : 100px;
|
||||||
|
padding : 10px;
|
||||||
|
text-align : center;
|
||||||
|
|
||||||
|
&.preview{
|
||||||
|
position : relative;
|
||||||
|
&:hover{
|
||||||
|
.content{
|
||||||
|
display : block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content{
|
||||||
|
position : absolute;
|
||||||
|
display : none;
|
||||||
|
top : 100%;
|
||||||
|
left : 0px;
|
||||||
|
z-index : 1000;
|
||||||
|
max-height : 500px;
|
||||||
|
width : 300px;
|
||||||
|
padding : 30px;
|
||||||
|
background-color : white;
|
||||||
|
font-family : monospace;
|
||||||
|
text-align : left;
|
||||||
|
pointer-events : none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.deleteButton{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button.clearOldButton{
|
||||||
|
float : right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
19
client/admin/brewCleanup/brewCleanup.jsx
Normal file
19
client/admin/brewCleanup/brewCleanup.jsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const createClass = require('create-react-class');
|
||||||
|
const cx = require('classnames');
|
||||||
|
|
||||||
|
|
||||||
|
const BrewCleanup = createClass({
|
||||||
|
displayName : 'BrewCleanup',
|
||||||
|
getDefaultProps(){
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
render(){
|
||||||
|
return <div className='BrewCleanup'>
|
||||||
|
BrewCleanup Component Ready.
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = BrewCleanup;
|
||||||
3
client/admin/brewCleanup/brewCleanup.less
Normal file
3
client/admin/brewCleanup/brewCleanup.less
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.BrewCleanup{
|
||||||
|
|
||||||
|
}
|
||||||
86
client/admin/brewLookup/brewLookup.jsx
Normal file
86
client/admin/brewLookup/brewLookup.jsx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const createClass = require('create-react-class');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const cx = require('classnames');
|
||||||
|
|
||||||
|
const request = require('superagent');
|
||||||
|
const Moment = require('moment');
|
||||||
|
|
||||||
|
|
||||||
|
const BrewLookup = createClass({
|
||||||
|
getDefaultProps() {
|
||||||
|
return {
|
||||||
|
adminKey : '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getInitialState() {
|
||||||
|
return {
|
||||||
|
query : '',
|
||||||
|
foundBrew : null,
|
||||||
|
searching : false,
|
||||||
|
error : null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChange(e){
|
||||||
|
this.setState({ query : e.target.value });
|
||||||
|
},
|
||||||
|
lookup(){
|
||||||
|
this.setState({ searching: true, error: null });
|
||||||
|
|
||||||
|
request.get(`/admin/lookup/${this.state.query}`)
|
||||||
|
.query({ admin_key: this.props.adminKey })
|
||||||
|
.then((res)=> this.setState({foundBrew : res.body}))
|
||||||
|
.catch((err)=>this.setState({ error : err }))
|
||||||
|
.finally(()=>this.setState({ searching : false }))
|
||||||
|
},
|
||||||
|
|
||||||
|
renderFoundBrew(){
|
||||||
|
const brew = this.state.foundBrew;
|
||||||
|
return <div className='foundBrew'>
|
||||||
|
<dl>
|
||||||
|
<dt>Title</dt>
|
||||||
|
<dd>{brew.title}</dd>
|
||||||
|
|
||||||
|
<dt>Authors</dt>
|
||||||
|
<dd>{brew.authors.join(', ')}</dd>
|
||||||
|
|
||||||
|
<dt>Edit Link</dt>
|
||||||
|
<dd><a href={`/edit/${brew.editId}`} target='_blank' rel='noopener noreferrer'>/edit/{brew.editId}</a></dd>
|
||||||
|
|
||||||
|
<dt>Share Link</dt>
|
||||||
|
<dd><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>/share/{brew.shareId}</a></dd>
|
||||||
|
|
||||||
|
<dt>Last Updated</dt>
|
||||||
|
<dd>{Moment(brew.updatedAt).fromNow()}</dd>
|
||||||
|
|
||||||
|
<dt>Num of Views</dt>
|
||||||
|
<dd>{brew.views}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>;
|
||||||
|
},
|
||||||
|
|
||||||
|
render(){
|
||||||
|
return <div className='brewLookup'>
|
||||||
|
<h2>Brew Lookup</h2>
|
||||||
|
<input type='text' value={this.state.query} onChange={this.handleChange} placeholder='edit or share id' />
|
||||||
|
<button onClick={this.lookup}>
|
||||||
|
<i className={cx('fa', {
|
||||||
|
'fa-search' : !this.state.searching,
|
||||||
|
'fa-spin fa-spinner' : this.state.searching,
|
||||||
|
})} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{this.state.error
|
||||||
|
&& <div className='error'>{this.state.error}</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{this.state.foundBrew
|
||||||
|
? this.renderFoundBrew()
|
||||||
|
: <div className='noBrew'>No brew found.</div>
|
||||||
|
}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = BrewLookup;
|
||||||
30
client/admin/brewLookup/brewLookup.less
Normal file
30
client/admin/brewLookup/brewLookup.less
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
.brewLookup{
|
||||||
|
input{
|
||||||
|
height : 33px;
|
||||||
|
margin-bottom : 20px;
|
||||||
|
padding : 0px 10px;
|
||||||
|
font-family : monospace;
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
vertical-align : middle;
|
||||||
|
height : 37px;
|
||||||
|
}
|
||||||
|
dl{
|
||||||
|
@maxItemWidth : 132px;
|
||||||
|
dt{
|
||||||
|
float : left;
|
||||||
|
clear : left;
|
||||||
|
width : @maxItemWidth;
|
||||||
|
text-align : right;
|
||||||
|
&::after {
|
||||||
|
content: " : ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd{
|
||||||
|
height : 1em;
|
||||||
|
margin-left : @maxItemWidth + 6px;
|
||||||
|
padding : 0 0 0.5em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
const React = require('react');
|
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const _ = require('lodash');
|
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const request = require('superagent');
|
|
||||||
const Moment = require('moment');
|
|
||||||
|
|
||||||
|
|
||||||
const BrewLookup = createClass({
|
|
||||||
getDefaultProps : function() {
|
|
||||||
return {
|
|
||||||
adminKey : '',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getInitialState : function() {
|
|
||||||
return {
|
|
||||||
query : '',
|
|
||||||
resultBrew : null,
|
|
||||||
searching : false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
handleChange : function(e){
|
|
||||||
this.setState({
|
|
||||||
query : e.target.value
|
|
||||||
});
|
|
||||||
},
|
|
||||||
lookup : function(){
|
|
||||||
this.setState({ searching: true });
|
|
||||||
|
|
||||||
request.get(`/admin/lookup/${this.state.query}`)
|
|
||||||
.query({ admin_key: this.props.adminKey })
|
|
||||||
.end((err, res)=>{
|
|
||||||
this.setState({
|
|
||||||
searching : false,
|
|
||||||
resultBrew : (err ? null : res.body)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
renderFoundBrew : function(){
|
|
||||||
if(this.state.searching) return <div className='searching'><i className='fa fa-spin fa-spinner' /></div>;
|
|
||||||
if(!this.state.resultBrew) return <div className='noBrew'>No brew found.</div>;
|
|
||||||
|
|
||||||
const brew = this.state.resultBrew;
|
|
||||||
return <div className='brewRow'>
|
|
||||||
<div>{brew.title}</div>
|
|
||||||
<div>{brew.authors.join(', ')}</div>
|
|
||||||
<div><a href={`/edit/${brew.editId}`} target='_blank' rel='noopener noreferrer'>/edit/{brew.editId}</a></div>
|
|
||||||
<div><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>/share/{brew.shareId}</a></div>
|
|
||||||
<div>{Moment(brew.updatedAt).fromNow()}</div>
|
|
||||||
<div>{brew.views}</div>
|
|
||||||
</div>;
|
|
||||||
},
|
|
||||||
|
|
||||||
render : function(){
|
|
||||||
return <div className='brewLookup'>
|
|
||||||
<h1>Brew Lookup</h1>
|
|
||||||
<input type='text' value={this.state.query} onChange={this.handleChange} placeholder='edit or share id...' />
|
|
||||||
<button onClick={this.lookup}><i className='fa fa-search'/></button>
|
|
||||||
|
|
||||||
{this.renderFoundBrew()}
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = BrewLookup;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
.brewLookup{
|
|
||||||
height : 200px;
|
|
||||||
input{
|
|
||||||
height : 33px;
|
|
||||||
padding : 0px 10px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
const React = require('react');
|
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const _ = require('lodash');
|
|
||||||
const cx = require('classnames');
|
|
||||||
|
|
||||||
const request = require('superagent');
|
|
||||||
|
|
||||||
const BrewSearch = createClass({
|
|
||||||
|
|
||||||
getDefaultProps : function() {
|
|
||||||
return {
|
|
||||||
admin_key : ''
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState : function() {
|
|
||||||
return {
|
|
||||||
searchTerm : '',
|
|
||||||
brew : null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
search : function(){
|
|
||||||
request.get(`/homebrew/api/search?id=${this.state.searchTerm}`)
|
|
||||||
.query({
|
|
||||||
admin_key : this.props.admin_key,
|
|
||||||
})
|
|
||||||
.end((err, res)=>{
|
|
||||||
console.log(err, res, res.body.brews[0]);
|
|
||||||
this.setState({
|
|
||||||
brew : res.body.brews[0],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
handleChange : function(e){
|
|
||||||
this.setState({
|
|
||||||
searchTerm : e.target.value
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleSearchClick : function(){
|
|
||||||
this.search();
|
|
||||||
},
|
|
||||||
|
|
||||||
renderBrew : function(){
|
|
||||||
if(!this.state.brew) return null;
|
|
||||||
return <div className='brew'>
|
|
||||||
<div>Edit id : {this.state.brew.editId}</div>
|
|
||||||
<div>Share id : {this.state.brew.shareId}</div>
|
|
||||||
</div>;
|
|
||||||
},
|
|
||||||
|
|
||||||
render : function(){
|
|
||||||
return <div className='search'>
|
|
||||||
<input type='text' value={this.state.searchTerm} onChange={this.handleChange} />
|
|
||||||
|
|
||||||
<button onClick={this.handleSearchClick}>Search</button>
|
|
||||||
|
|
||||||
{this.renderBrew()}
|
|
||||||
</div>;
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = BrewSearch;
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
const React = require('react');
|
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const _ = require('lodash');
|
|
||||||
const cx = require('classnames');
|
|
||||||
const request = require('superagent');
|
|
||||||
|
|
||||||
const Moment = require('moment');
|
|
||||||
|
|
||||||
|
|
||||||
const BrewLookup = require('./brewLookup/brewLookup.jsx');
|
|
||||||
|
|
||||||
|
|
||||||
const HomebrewAdmin = createClass({
|
|
||||||
getDefaultProps : function() {
|
|
||||||
return {
|
|
||||||
admin_key : ''
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState : function() {
|
|
||||||
return {
|
|
||||||
page : 0,
|
|
||||||
count : 20,
|
|
||||||
brewCache : {},
|
|
||||||
total : 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
fetchBrews : function(page){
|
|
||||||
request.get('/api/search')
|
|
||||||
.query({
|
|
||||||
admin_key : this.props.admin_key,
|
|
||||||
count : this.state.count,
|
|
||||||
page : page
|
|
||||||
})
|
|
||||||
.end((err, res)=>{
|
|
||||||
if(err || !res.body || !res.body.brews) return;
|
|
||||||
const newCache = _.extend({}, this.state.brewCache);
|
|
||||||
newCache[page] = res.body.brews;
|
|
||||||
this.setState({
|
|
||||||
brewCache : newCache,
|
|
||||||
total : res.body.total,
|
|
||||||
count : res.body.count
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount : function() {
|
|
||||||
this.fetchBrews(this.state.page);
|
|
||||||
},
|
|
||||||
|
|
||||||
changePageTo : function(page){
|
|
||||||
if(!this.state.brewCache[page]){
|
|
||||||
this.fetchBrews(page);
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
page : page
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
clearInvalidBrews : function(){
|
|
||||||
request.get('/api/invalid')
|
|
||||||
.query({ admin_key: this.props.admin_key })
|
|
||||||
.end((err, res)=>{
|
|
||||||
if(!confirm(`This will remove ${res.body.count} brews. Are you sure?`)) return;
|
|
||||||
request.get('/api/invalid')
|
|
||||||
.query({ admin_key: this.props.admin_key, do_it: true })
|
|
||||||
.end((err, res)=>{
|
|
||||||
alert('Done!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
deleteBrew : function(brewId){
|
|
||||||
if(!confirm(`Are you sure you want to delete '${brewId}'?`)) return;
|
|
||||||
request.get(`/api/remove/${brewId}`)
|
|
||||||
.query({ admin_key: this.props.admin_key })
|
|
||||||
.end(function(err, res){
|
|
||||||
window.location.reload();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
handlePageChange : function(dir){
|
|
||||||
this.changePageTo(this.state.page + dir);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
renderPagnination : function(){
|
|
||||||
let outOf;
|
|
||||||
if(this.state.total){
|
|
||||||
outOf = `${this.state.page} / ${Math.round(this.state.total/this.state.count)}`;
|
|
||||||
}
|
|
||||||
return <div className='pagnination'>
|
|
||||||
<i className='fa fa-chevron-left' onClick={()=>this.handlePageChange(-1)}/>
|
|
||||||
{outOf}
|
|
||||||
<i className='fa fa-chevron-right' onClick={()=>this.handlePageChange(1)}/>
|
|
||||||
</div>;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
renderBrews : function(){
|
|
||||||
const brews = this.state.brewCache[this.state.page] || _.times(this.state.count);
|
|
||||||
return _.map(brews, (brew)=>{
|
|
||||||
return <tr className={cx('brewRow', { 'isEmpty': brew.text == 'false' })} key={brew.shareId || brew}>
|
|
||||||
<td><a href={`/edit/${brew.editId}`} target='_blank' rel='noopener noreferrer'>{brew.editId}</a></td>
|
|
||||||
<td><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>{brew.shareId}</a></td>
|
|
||||||
<td>{Moment(brew.createdAt).fromNow()}</td>
|
|
||||||
<td>{Moment(brew.updatedAt).fromNow()}</td>
|
|
||||||
<td>{Moment(brew.lastViewed).fromNow()}</td>
|
|
||||||
<td>{brew.views}</td>
|
|
||||||
<td>
|
|
||||||
<div className='deleteButton' onClick={()=>this.deleteBrew(brew.editId)}>
|
|
||||||
<i className='fa fa-trash' />
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
renderBrewTable : function(){
|
|
||||||
return <div className='brewTable'>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Edit Id</th>
|
|
||||||
<th>Share Id</th>
|
|
||||||
<th>Created At</th>
|
|
||||||
<th>Last Updated</th>
|
|
||||||
<th>Last Viewed</th>
|
|
||||||
<th>Views</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{this.renderBrews()}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>;
|
|
||||||
},
|
|
||||||
|
|
||||||
render : function(){
|
|
||||||
return <div className='homebrewAdmin'>
|
|
||||||
|
|
||||||
<BrewLookup adminKey={this.props.admin_key} />
|
|
||||||
|
|
||||||
{/*
|
|
||||||
<h2>
|
|
||||||
Homebrews - {this.state.total}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{this.renderPagnination()}
|
|
||||||
{this.renderBrewTable()}
|
|
||||||
|
|
||||||
<button className='clearOldButton' onClick={this.clearInvalidBrews}>
|
|
||||||
Clear Old
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<BrewSearch admin_key={this.props.admin_key} />
|
|
||||||
*/}
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = HomebrewAdmin;
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
|
|
||||||
.homebrewAdmin{
|
|
||||||
margin-bottom: 80px;
|
|
||||||
.brewTable{
|
|
||||||
table{
|
|
||||||
|
|
||||||
th{
|
|
||||||
padding : 10px;
|
|
||||||
font-weight : 800;
|
|
||||||
}
|
|
||||||
tr:nth-child(even){
|
|
||||||
background-color : fade(@green, 10%);
|
|
||||||
}
|
|
||||||
tr.isEmpty{
|
|
||||||
background-color : fade(@red, 30%);
|
|
||||||
}
|
|
||||||
td{
|
|
||||||
min-width : 100px;
|
|
||||||
padding : 10px;
|
|
||||||
text-align : center;
|
|
||||||
|
|
||||||
&.preview{
|
|
||||||
position : relative;
|
|
||||||
&:hover{
|
|
||||||
.content{
|
|
||||||
display : block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.content{
|
|
||||||
position : absolute;
|
|
||||||
display : none;
|
|
||||||
top : 100%;
|
|
||||||
left : 0px;
|
|
||||||
z-index : 1000;
|
|
||||||
max-height : 500px;
|
|
||||||
width : 300px;
|
|
||||||
padding : 30px;
|
|
||||||
background-color : white;
|
|
||||||
font-family : monospace;
|
|
||||||
text-align : left;
|
|
||||||
pointer-events : none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.deleteButton{
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
button.clearOldButton{
|
|
||||||
float : right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
48
client/admin/stats/stats.jsx
Normal file
48
client/admin/stats/stats.jsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const createClass = require('create-react-class');
|
||||||
|
const cx = require('classnames');
|
||||||
|
|
||||||
|
const request = require('superagent');
|
||||||
|
|
||||||
|
|
||||||
|
const Stats = createClass({
|
||||||
|
displayName : 'Stats',
|
||||||
|
getDefaultProps(){
|
||||||
|
return {
|
||||||
|
adminKey : ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getInitialState(){
|
||||||
|
return {
|
||||||
|
stats : {
|
||||||
|
totalBrews : 0
|
||||||
|
},
|
||||||
|
fetching : false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentDidMount(){
|
||||||
|
this.fetchStats();
|
||||||
|
},
|
||||||
|
fetchStats(){
|
||||||
|
this.setState({ fetching : true})
|
||||||
|
request.get('/admin/stats')
|
||||||
|
.query({ admin_key : this.props.adminKey })
|
||||||
|
.then((res)=> this.setState({ stats : res.body }))
|
||||||
|
.finally(()=>this.setState({fetching : false}));
|
||||||
|
},
|
||||||
|
render(){
|
||||||
|
return <div className='Stats'>
|
||||||
|
<h2> Stats </h2>
|
||||||
|
<dl>
|
||||||
|
<dt>Total Brew Count</dt>
|
||||||
|
<dd>{this.state.stats.totalBrews}</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
{this.state.fetching
|
||||||
|
&& <div className='pending'><i className='fa fa-spin fa-spinner' /></div>
|
||||||
|
}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Stats;
|
||||||
28
client/admin/stats/stats.less
Normal file
28
client/admin/stats/stats.less
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
.Stats{
|
||||||
|
position : relative;
|
||||||
|
.pending{
|
||||||
|
position : absolute;
|
||||||
|
top : 0px;
|
||||||
|
left : 0px;
|
||||||
|
height : 100%;
|
||||||
|
width : 100%;
|
||||||
|
background-color : rgba(238,238,238, 0.5);
|
||||||
|
}
|
||||||
|
dl{
|
||||||
|
@maxItemWidth : 132px;
|
||||||
|
dt{
|
||||||
|
float : left;
|
||||||
|
clear : left;
|
||||||
|
width : @maxItemWidth;
|
||||||
|
text-align : right;
|
||||||
|
&::after {
|
||||||
|
content: " : ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd{
|
||||||
|
margin : 0 0 0 @maxItemWidth + 10px;
|
||||||
|
padding : 0 0 0.5em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,8 +17,8 @@ process.env.ADMIN_KEY = process.env.ADMIN_KEY || 'admin_key';
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Removes all empty brews that are older than 3 days and that are shorter than a tweet
|
/* Removes all empty brews that are older than 3 days and that are shorter than a tweet */
|
||||||
router.get('/api/invalid', mw.adminOnly, (req, res)=>{
|
router.get('/admin/clear_invalid', mw.adminOnly, (req, res)=>{
|
||||||
const invalidBrewQuery = HomebrewModel.find({
|
const invalidBrewQuery = HomebrewModel.find({
|
||||||
'$where' : 'this.text.length < 140',
|
'$where' : 'this.text.length < 140',
|
||||||
createdAt : {
|
createdAt : {
|
||||||
@@ -28,12 +28,12 @@ router.get('/api/invalid', mw.adminOnly, (req, res)=>{
|
|||||||
|
|
||||||
if(req.query.do_it){
|
if(req.query.do_it){
|
||||||
invalidBrewQuery.remove().exec((err, objs)=>{
|
invalidBrewQuery.remove().exec((err, objs)=>{
|
||||||
refreshCount();
|
if(err) return res.status(500).send(err);
|
||||||
return res.send(200);
|
return res.send(200);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
invalidBrewQuery.exec((err, objs)=>{
|
invalidBrewQuery.exec((err, objs)=>{
|
||||||
if(err) console.log(err);
|
if(err) return res.status(500).send(err);
|
||||||
return res.json({
|
return res.json({
|
||||||
count : objs.length
|
count : objs.length
|
||||||
});
|
});
|
||||||
@@ -41,10 +41,11 @@ router.get('/api/invalid', mw.adminOnly, (req, res)=>{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* Searches for matching edit or share id, also attempts to partial match */
|
||||||
router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{
|
router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{
|
||||||
//search for mathcing edit id
|
|
||||||
//search for matching share id
|
console.log('lookup');
|
||||||
// search for partial match
|
|
||||||
|
|
||||||
HomebrewModel.findOne({ $or : [
|
HomebrewModel.findOne({ $or : [
|
||||||
{ editId: { '$regex': req.params.id, '$options': 'i' } },
|
{ editId: { '$regex': req.params.id, '$options': 'i' } },
|
||||||
@@ -54,6 +55,17 @@ router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/admin/stats', mw.adminOnly, (req, res)=>{
|
||||||
|
console.log('hittting stats');
|
||||||
|
|
||||||
|
HomebrewModel.count({}, (err, count)=>{
|
||||||
|
return res.json({
|
||||||
|
totalBrews : count
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Admin route
|
//Admin route
|
||||||
@@ -68,7 +80,7 @@ router.get('/admin', function(req, res){
|
|||||||
}
|
}
|
||||||
render('admin', templateFn, {
|
render('admin', templateFn, {
|
||||||
url : req.originalUrl,
|
url : req.originalUrl,
|
||||||
admin_key : process.env.ADMIN_KEY,
|
adminKey : process.env.ADMIN_KEY
|
||||||
})
|
})
|
||||||
.then((page)=>{
|
.then((page)=>{
|
||||||
return res.send(page);
|
return res.send(page);
|
||||||
|
|||||||
Reference in New Issue
Block a user