mirror of
https://github.com/mgerb/mywebsite
synced 2026-03-05 07:55:23 +00:00
@@ -2,6 +2,7 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
min-height: 600px;
|
||||||
.post+ .post {
|
.post+ .post {
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
}
|
}
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
width: 7em;
|
width: 7em;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-left: -8em;
|
margin-left: -8em;
|
||||||
|
line-height: 2.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.intro {
|
.intro {
|
||||||
|
|||||||
@@ -7,4 +7,13 @@
|
|||||||
border-color: #DADADA;
|
border-color: #DADADA;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
padding-right: calc(50% - 997px / 2);
|
||||||
|
padding-left: calc(50% - 997px / 2);
|
||||||
|
&:after,
|
||||||
|
&:before {
|
||||||
|
content: " ";
|
||||||
|
width: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
client/assets/scss/Header.scss
Normal file
12
client/assets/scss/Header.scss
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.Header {
|
||||||
|
width: 100%;
|
||||||
|
background: url("../images/header.jpg");
|
||||||
|
background-size: cover;
|
||||||
|
height: 30em;
|
||||||
|
border-bottom: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: #DADADA;
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ h5,
|
|||||||
h6 {
|
h6 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
@@ -55,7 +54,19 @@ hr {
|
|||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Footer,
|
select{
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
height: 35px;
|
||||||
|
color: #555;
|
||||||
|
&:focus{
|
||||||
|
border-color: #66afe9;
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.Main {
|
.Main {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-right: calc(50% - 997px / 2);
|
padding-right: calc(50% - 997px / 2);
|
||||||
@@ -71,23 +82,11 @@ hr {
|
|||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header {
|
|
||||||
width: 100%;
|
|
||||||
background: url("../images/header.jpg");
|
|
||||||
background-size: cover;
|
|
||||||
height: 30em;
|
|
||||||
border-bottom: solid;
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: #DADADA;
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.Loading {
|
.Loading {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ ReactDOM.render((
|
|||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
<Route path="/" component={App}>
|
<Route path="/" component={App}>
|
||||||
<IndexRoute component={Preview}/>
|
<IndexRoute component={Preview}/>
|
||||||
<Route path="post/:category/:post" component={Post}/>
|
<Route path="post(/:category)/:post" component={Post}/>
|
||||||
<Route path="sensor/:location/:year/:month" component={SensorInfo}/>
|
<Route path="sensor/:location" component={SensorInfo}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export default class Footer extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div class="Footer">
|
<div class="Footer">
|
||||||
Site created and maintained by Mitchell Gerber
|
Site created by Mitchell Gerber
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {bubble} from '../../assets/js/bubble';
|
import {bubble} from '../../assets/js/bubble';
|
||||||
|
|
||||||
|
import '../../assets/scss/Header.scss';
|
||||||
|
|
||||||
export default class Header extends React.Component {
|
export default class Header extends React.Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
bubble();
|
bubble();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default class Post extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const params = this.props.params;
|
const params = this.props.params;
|
||||||
this.props.appActions.fetchPost(params.category, params.post);
|
this.props.appActions.fetchPost(params.post, params.category);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -1,14 +1,108 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Link} from 'react-router';
|
||||||
|
|
||||||
export default class SensorInfo extends React.Component{
|
import Loading from '../utils/Loading';
|
||||||
|
import _chartjs from 'chart.js';
|
||||||
|
import Chart from 'react-chartjs';
|
||||||
|
import {
|
||||||
|
ChartOptions,
|
||||||
|
DataTemplate
|
||||||
|
}
|
||||||
|
from './chartOptions';
|
||||||
|
|
||||||
componentDidMount(){
|
import './SensorInfo.scss';
|
||||||
this.props.sensorActions.fetchSensorInfoYear('Grand Meadow', '2016');
|
|
||||||
this.props.sensorActions.fetchSensorInfoMonth('Grand Meadow', '2016', 'May');
|
const LineChart = Chart.Line;
|
||||||
|
|
||||||
|
export default class SensorInfo extends React.Component {
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
let location = this.props.params.location;
|
||||||
|
this.props.sensorActions.fetchUniqueDates(location);
|
||||||
}
|
}
|
||||||
render(){
|
|
||||||
return(
|
componentWillUpdate(nextProps) {
|
||||||
<div class="Content">Test123</div>
|
let currentLocation = this.props.params.location,
|
||||||
|
nextLocation = nextProps.params.location;
|
||||||
|
|
||||||
|
if (currentLocation !== nextLocation){
|
||||||
|
this.props.sensorActions.fetchUniqueDates(nextLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadYearOptions = (date, index) => {
|
||||||
|
return (
|
||||||
|
<option key={index} value={index}>{date.year}</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadMonthOptions = (date, index) => {
|
||||||
|
return (
|
||||||
|
<option key={index} value={index}>{date.monthname}</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange(event, type) {
|
||||||
|
let location = this.props.params.location,
|
||||||
|
sensor = this.props.sensor,
|
||||||
|
actions = this.props.sensorActions,
|
||||||
|
yearIndex = sensor.selectedYearIndex,
|
||||||
|
monthIndex = sensor.selectedMonthIndex;
|
||||||
|
|
||||||
|
if (type === 'year') {
|
||||||
|
yearIndex = parseInt(event.target.value);
|
||||||
|
monthIndex = 0;
|
||||||
|
}
|
||||||
|
else if (type === 'month') {
|
||||||
|
monthIndex = parseInt(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let year = sensor.uniqueDates[yearIndex].year;
|
||||||
|
let monthname = sensor.uniqueDates[yearIndex].months[monthIndex].monthname;
|
||||||
|
|
||||||
|
actions.setSelectedMonthIndex(monthIndex);
|
||||||
|
actions.setSelectedYearIndex(yearIndex);
|
||||||
|
this.props.sensorActions.fetchSensorInfoMonth(location, year, monthname);
|
||||||
|
}
|
||||||
|
|
||||||
|
filterData(data) {
|
||||||
|
let temp = JSON.parse(JSON.stringify(DataTemplate));
|
||||||
|
|
||||||
|
for (let d of data) {
|
||||||
|
let label = `${d.month}/${d.day}`;
|
||||||
|
temp.labels.push(label);
|
||||||
|
temp.datasets[0].data.push(d.maxtemp);
|
||||||
|
temp.datasets[1].data.push(d.mintemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let sensor = this.props.sensor;
|
||||||
|
let data = this.filterData(sensor.info);
|
||||||
|
return (
|
||||||
|
<div class="SensorInfo">
|
||||||
|
{sensor.fetchedUniqueDates ?
|
||||||
|
<div class="selector-row">
|
||||||
|
<h2>{this.props.params.location}</h2>
|
||||||
|
<select onChange={(e) => {this.onChange(e, 'year')}}>
|
||||||
|
{sensor.uniqueDates.map(this.loadYearOptions)}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select onChange={(e) => {this.onChange(e, 'month')}} value={sensor.selectedMonthIndex}>
|
||||||
|
{sensor.uniqueDates[sensor.selectedYearIndex].months.map(this.loadMonthOptions)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
: <Loading/>}
|
||||||
|
|
||||||
|
{sensor.fetchedUniqueDates && sensor.fetchedInfo
|
||||||
|
? <LineChart data={data} options={ChartOptions} redraw/>
|
||||||
|
: null}
|
||||||
|
{sensor.fetchedUniqueDates && sensor.fetchedInfo
|
||||||
|
? <div class="home"><Link to="/" class="link"><i class="fa fa-caret-left" aria-hidden="true"></i> Home</Link></div>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
20
client/js/components/sensors/SensorInfo.scss
Normal file
20
client/js/components/sensors/SensorInfo.scss
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
.SensorInfo{
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 600px;
|
||||||
|
width: 80%;
|
||||||
|
.selector-row{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
select{
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.home{
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,8 +20,8 @@ export default class SensorList extends React.Component {
|
|||||||
this.openLink = this.openLink.bind(this);
|
this.openLink = this.openLink.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
openLink(){
|
openLink(location){
|
||||||
browserHistory.push("/");
|
browserHistory.push(`/sensor/${location}`);
|
||||||
this.props.toggleOff();
|
this.props.toggleOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,13 +29,18 @@ export default class SensorList extends React.Component {
|
|||||||
const date = new Date(sensor.updated);
|
const date = new Date(sensor.updated);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={index} class="row" onClick={this.openLink}>
|
<div key={index} class="row" onClick={() => {this.openLink(sensor.location)}}>
|
||||||
<div class="item">
|
<div class="temperature">
|
||||||
<h1>{sensor.temperature}°f</h1>
|
<h1>{sensor.temperature}°f</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="info">
|
||||||
<h3>{sensor.location}</h3>
|
<h3>{sensor.location}</h3>
|
||||||
<span class="date">Updated: {date.toLocaleString('en-us', options)}</span>
|
<span class="date">Updated: {date.toLocaleString('en-us', options)}
|
||||||
|
{Date.now() - date < 420000
|
||||||
|
? <span class="connected"> Connected</span>
|
||||||
|
: <span class="disconnected"> Disconnected</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,11 +9,16 @@
|
|||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
|
||||||
&:hover{
|
&:hover{
|
||||||
background-color: gray;
|
background-color: #D1D1D1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item + .item{
|
.temperature{
|
||||||
|
flex: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info{
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2{
|
h2{
|
||||||
@@ -25,4 +30,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.connected{
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.disconnected{
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
30
client/js/components/sensors/chartOptions.js
Normal file
30
client/js/components/sensors/chartOptions.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
export const ChartOptions = {
|
||||||
|
responsive: true,
|
||||||
|
// scaleOverride: true,
|
||||||
|
//scaleSteps: 20,
|
||||||
|
// scaleStartValue: 0,
|
||||||
|
//scaleStepWidth: 5
|
||||||
|
};
|
||||||
|
|
||||||
|
export let DataTemplate = {
|
||||||
|
labels: [],
|
||||||
|
datasets: [{
|
||||||
|
label: "Max Temperature °F",
|
||||||
|
fillColor: "rgba(220,220,220,0.2)",
|
||||||
|
strokeColor: "rgba(220,220,220,1)",
|
||||||
|
pointColor: "rgba(220,220,220,1)",
|
||||||
|
pointStrokeColor: "#fff",
|
||||||
|
pointHighlightFill: "#fff",
|
||||||
|
pointHighlightStroke: "rgba(220,220,220,1)",
|
||||||
|
data: []
|
||||||
|
}, {
|
||||||
|
label: "Min Temperature °F",
|
||||||
|
fillColor: "rgba(151,187,205,0)",
|
||||||
|
strokeColor: "rgba(151,187,205,1)",
|
||||||
|
pointColor: "rgba(151,187,205,1)",
|
||||||
|
pointStrokeColor: "#fff",
|
||||||
|
pointHighlightFill: "#fff",
|
||||||
|
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||||
|
data: []
|
||||||
|
}]
|
||||||
|
};
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Link} from 'react-router';
|
||||||
|
|
||||||
import me from '../../../assets/images/me.jpg';
|
import me from '../../../assets/images/me.jpg';
|
||||||
|
|
||||||
@@ -12,7 +13,10 @@ export default class AboutMe extends React.Component{
|
|||||||
<p>
|
<p>
|
||||||
My name is Mitchell and I have a passion for software development. I am currently a software engineer and enjoy working on personal projects in my free time.
|
My name is Mitchell and I have a passion for software development. I am currently a software engineer and enjoy working on personal projects in my free time.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-home" aria-hidden="true"></i>
|
||||||
|
<Link to={"/"} class="link"> Home</Link>
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<i class="fa fa-envelope" aria-hidden="true"></i>
|
<i class="fa fa-envelope" aria-hidden="true"></i>
|
||||||
<a class="link" href="mailto:mgerb42@gmail.com"> eMail</a>
|
<a class="link" href="mailto:mgerb42@gmail.com"> eMail</a>
|
||||||
@@ -25,10 +29,12 @@ export default class AboutMe extends React.Component{
|
|||||||
<i class="fa fa-github" aria-hidden="true"></i>
|
<i class="fa fa-github" aria-hidden="true"></i>
|
||||||
<a class="link" href="https://github.com/mgerb" target="_blank"> GitHub</a>
|
<a class="link" href="https://github.com/mgerb" target="_blank"> GitHub</a>
|
||||||
</p>
|
</p>
|
||||||
|
{/*
|
||||||
<p>
|
<p>
|
||||||
<i class="fa fa-wpforms" aria-hidden="true"> </i>
|
<i class="fa fa-wpforms" aria-hidden="true"> </i>
|
||||||
<a href="/resume" class="link"> Resume</a>
|
<a href="/resume" class="link"> Resume</a>
|
||||||
</p>
|
</p>
|
||||||
|
*/}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,14 @@ export function fetchPreview() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchPost(category, post) {
|
//adjust url according to parameters
|
||||||
|
//mainly used to load md files in the parent directory within /posts
|
||||||
|
export function fetchPost(post, category = null) {
|
||||||
|
let url;
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(fetching());
|
dispatch(fetching());
|
||||||
return fetch(`/public/posts/${category}/${post}.md`)
|
url = category !== null || typeof category === 'undefined' ? `/public/posts/${category}/${post}.md` : `/public/posts/${post}.md`;
|
||||||
|
return fetch(url)
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(response => {
|
.then(response => {
|
||||||
dispatch(loadPost(response));
|
dispatch(loadPost(response));
|
||||||
|
|||||||
@@ -8,17 +8,31 @@ function loadSensorList(sensor_list){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSensorInfoYear(sensor_info){
|
function loadSensorInfo(sensor_info){
|
||||||
return{
|
return{
|
||||||
type: types.LOAD_SENSOR_INFO_YEAR,
|
type: types.LOAD_SENSOR_INFO,
|
||||||
sensor_info
|
sensor_info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSensorInfoMonth(sensor_info){
|
function loadUniqueDates(dates){
|
||||||
return{
|
return{
|
||||||
type: types.LOAD_SENSOR_INFO_MONTH,
|
type: types.LOAD_UNIQUE_DATES,
|
||||||
sensor_info
|
dates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSelectedYearIndex(index){
|
||||||
|
return{
|
||||||
|
type: types.SET_SELECTED_YEAR_INDEX,
|
||||||
|
index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSelectedMonthIndex(index){
|
||||||
|
return{
|
||||||
|
type: types.SET_SELECTED_MONTH_INDEX,
|
||||||
|
index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,15 +42,15 @@ function fetchingList(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchingInfoYear(){
|
function fetchingInfo(){
|
||||||
return {
|
return {
|
||||||
type: types.FETCHING_INFO_YEAR
|
type: types.FETCHING_INFO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchingInfoMonth(){
|
function fetchingUniqueDates(){
|
||||||
return {
|
return {
|
||||||
type: types.FETCHING_INFO_MONTH
|
type: types.FETCHING_UNIQUE_DATES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,11 +70,11 @@ export function fetchSensorList(){
|
|||||||
|
|
||||||
export function fetchSensorInfoYear(location, year){
|
export function fetchSensorInfoYear(location, year){
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(fetchingInfoYear());
|
dispatch(fetchingInfo());
|
||||||
return fetch(`/api/sensor/${location}/${year}`)
|
return fetch(`/api/sensor/${location}/${year}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(json => {
|
.then(json => {
|
||||||
dispatch(loadSensorInfoYear(json));
|
dispatch(loadSensorInfo(json));
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@@ -70,11 +84,35 @@ export function fetchSensorInfoYear(location, year){
|
|||||||
|
|
||||||
export function fetchSensorInfoMonth(location, year, month){
|
export function fetchSensorInfoMonth(location, year, month){
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(fetchingInfoMonth());
|
dispatch(fetchingInfo());
|
||||||
return fetch(`/api/sensor/${location}/${year}/${month}`)
|
return fetch(`/api/sensor/${location}/${year}/${month}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(json => {
|
.then(json => {
|
||||||
dispatch(loadSensorInfoMonth(json));
|
dispatch(loadSensorInfo(json));
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is called to initialize the sensor info page
|
||||||
|
//reloads unique dates and resets indexes
|
||||||
|
//then fetches new data for chart
|
||||||
|
export function fetchUniqueDates(location){
|
||||||
|
return (dispatch) => {
|
||||||
|
dispatch(fetchingUniqueDates());
|
||||||
|
dispatch(setSelectedMonthIndex(0));
|
||||||
|
dispatch(setSelectedYearIndex(0));
|
||||||
|
return fetch(`/api/uniquedates/${location}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(json => {
|
||||||
|
dispatch(loadUniqueDates(json));
|
||||||
|
if(json.length > 0){
|
||||||
|
let year = json[0].year;
|
||||||
|
let month = json[0].months[0].monthname;
|
||||||
|
dispatch(fetchSensorInfoMonth(location, year, month));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
//constants
|
//constants
|
||||||
export const LOAD_SENSOR_LIST = 'LOAD_SENSOR_LIST';
|
export const LOAD_SENSOR_LIST = 'LOAD_SENSOR_LIST';
|
||||||
export const LOAD_SENSOR_INFO_YEAR = 'LOAD_SENSOR_INFO_YEAR';
|
export const LOAD_SENSOR_INFO = 'LOAD_SENSOR_INFO';
|
||||||
export const LOAD_SENSOR_INFO_MONTH = 'LOAD_SENSOR_INFO_MONTH';
|
export const LOAD_UNIQUE_DATES = 'LOAD_UNIQUE_DATES';
|
||||||
|
|
||||||
|
|
||||||
//fetching
|
//fetching
|
||||||
export const FETCHING_LIST = 'FETCHING_LIST';
|
export const FETCHING_LIST = 'FETCHING_LIST';
|
||||||
export const FETCHING_INFO_YEAR = 'FETCHING_INFO_YEAR';
|
export const FETCHING_INFO = 'FETCHING_INFO_YEAR';
|
||||||
export const FETCHING_INFO_MONTH = 'FETCHING_INFO_MONTH';
|
export const FETCHING_UNIQUE_DATES = 'FETCHING_UNIQUE_DATES';
|
||||||
|
|
||||||
|
//indexes
|
||||||
|
export const SET_SELECTED_YEAR_INDEX = 'SET_SELECTED_YEAR_INDEX';
|
||||||
|
export const SET_SELECTED_MONTH_INDEX = 'SET_SELECTED_MONTH_INDEX';
|
||||||
@@ -4,54 +4,69 @@ import * as types from '../constants/sensor';
|
|||||||
//defaults -
|
//defaults -
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
list : [],
|
list : [],
|
||||||
infoMonth: [],
|
info: [],
|
||||||
infoYear: [],
|
uniqueDates: {},
|
||||||
|
|
||||||
|
selectedYearIndex: 0,
|
||||||
|
selectedMonthIndex: 0,
|
||||||
|
|
||||||
fetchingList: false,
|
fetchingList: false,
|
||||||
fetchingInfoMonth: false,
|
fetchingInfo: false,
|
||||||
fetchingInfoYear: false,
|
fetchingUniqueDates: false,
|
||||||
|
|
||||||
fetchedList: false,
|
fetchedList: false,
|
||||||
fetchedInfoMonth: false,
|
fetchedInfo: false,
|
||||||
fetchedInfoYear: false
|
fetchedUniqueDates: false
|
||||||
};
|
};
|
||||||
|
|
||||||
//default reducer
|
//default reducer
|
||||||
export default function app(state = defaultState, action) {
|
export default function app(state = defaultState, action) {
|
||||||
switch(action.type){
|
switch(action.type){
|
||||||
|
//fetching functions - we use a fetching state to display loading images
|
||||||
case types.FETCHING_LIST:
|
case types.FETCHING_LIST:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
fetchingList: true,
|
fetchingList: true,
|
||||||
fetchedList: false
|
fetchedList: false
|
||||||
});
|
});
|
||||||
case types.FETCHING_INFO_MONTH:
|
case types.FETCHING_INFO:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
fetchingInfoMonth: true,
|
fetchingInfo: true,
|
||||||
fetchedInfoMonth: false
|
fetchedInfo: false
|
||||||
});
|
});
|
||||||
case types.FETCHING_INFO_YEAR:
|
case types.FETCHING_UNIQUE_DATES:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
fetchingInfoYear: true,
|
fetchingUniqueDates: true,
|
||||||
fetchedInfoYear: false
|
fetchedUniqueDates: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//other functions
|
||||||
case types.LOAD_SENSOR_LIST:
|
case types.LOAD_SENSOR_LIST:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
list: action.sensor_list,
|
list: action.sensor_list,
|
||||||
fetchingList: false,
|
fetchingList: false,
|
||||||
fetchedList: true
|
fetchedList: true
|
||||||
});
|
});
|
||||||
case types.LOAD_SENSOR_INFO_MONTH:
|
case types.LOAD_SENSOR_INFO:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
infoMonth: action.sensor_info,
|
info: action.sensor_info,
|
||||||
fetchingInfoMonth: false,
|
fetchingInfo: false,
|
||||||
fetchedInfoMonth: true
|
fetchedInfo: true
|
||||||
});
|
});
|
||||||
case types.LOAD_SENSOR_INFO_YEAR:
|
case types.LOAD_UNIQUE_DATES:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
infoYear: action.sensor_info,
|
uniqueDates: action.dates,
|
||||||
fetchingInfoYear: false,
|
fetchingUniqueDates: false,
|
||||||
fetchedInfoYear: true
|
fetchedUniqueDates: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//indexes
|
||||||
|
case types.SET_SELECTED_YEAR_INDEX:
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
selectedYearIndex: action.index
|
||||||
|
});
|
||||||
|
case types.SET_SELECTED_MONTH_INDEX:
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
selectedMonthIndex: action.index
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//return present state if no actions get called
|
//return present state if no actions get called
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import {syncHistoryWithStore} from 'react-router-redux';
|
|||||||
|
|
||||||
import reducers from './reducers/reducers';
|
import reducers from './reducers/reducers';
|
||||||
|
|
||||||
const middleware = applyMiddleware(thunk, logger());
|
const debug = process.env.NODE_ENV !== "production";
|
||||||
|
|
||||||
|
//run redux logger if we are in dev mode
|
||||||
|
const middleware = debug ? applyMiddleware(thunk, logger()) : applyMiddleware(thunk);
|
||||||
|
|
||||||
//create the new store with default state as an empty object
|
//create the new store with default state as an empty object
|
||||||
const store = createStore(reducers, {}, middleware);
|
const store = createStore(reducers, {}, middleware);
|
||||||
|
|||||||
11
metadata.js
11
metadata.js
@@ -19,13 +19,15 @@ marked.setOptions({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const dir = './posts/';
|
const rootDirectory = './posts/';
|
||||||
const json = {
|
const json = {
|
||||||
posts: []
|
posts: []
|
||||||
};
|
};
|
||||||
|
|
||||||
//do everything synchronously to keep posts ordered
|
//do everything synchronously to keep posts ordered
|
||||||
function parse_dir(dir, folder_name){
|
//we are not worried about execution time since this script only runs once when building
|
||||||
|
//ignores files that are not in a directory
|
||||||
|
function parse_dir(dir, folder_name = null){
|
||||||
const posts = fs.readdirSync(dir);
|
const posts = fs.readdirSync(dir);
|
||||||
|
|
||||||
for(let post of posts){
|
for(let post of posts){
|
||||||
@@ -33,7 +35,7 @@ function parse_dir(dir, folder_name){
|
|||||||
|
|
||||||
if(stats.isDirectory()){
|
if(stats.isDirectory()){
|
||||||
parse_dir(dir + post + '/', post);
|
parse_dir(dir + post + '/', post);
|
||||||
} else {
|
} else if(folder_name !== null){
|
||||||
const file = fs.readFileSync(dir+post, 'utf8');
|
const file = fs.readFileSync(dir+post, 'utf8');
|
||||||
const tokens = marked.lexer(file, null);
|
const tokens = marked.lexer(file, null);
|
||||||
const temp = {
|
const temp = {
|
||||||
@@ -49,7 +51,8 @@ function parse_dir(dir, folder_name){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//recursively parse posts directory for all markdown files
|
//recursively parse posts directory for all markdown files
|
||||||
parse_dir(dir, 'posts');
|
//folder defaults to null and immediate child files are not added to json
|
||||||
|
parse_dir(rootDirectory);
|
||||||
|
|
||||||
//sort posts by date
|
//sort posts by date
|
||||||
json.posts.sort((a, b) => {
|
json.posts.sort((a, b) => {
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -7,11 +7,12 @@
|
|||||||
"build": "webpack && babel-node metadata.js",
|
"build": "webpack && babel-node metadata.js",
|
||||||
"c9": "webpack-dev-server --port $PORT --host $IP --hot --content-base dist --history-api-fallback",
|
"c9": "webpack-dev-server --port $PORT --host $IP --hot --content-base dist --history-api-fallback",
|
||||||
"check_gzip_size": "gzip -9 -c ./public/client.min.js | wc -c | numfmt --to=iec-i --suffix=B --padding=10",
|
"check_gzip_size": "gzip -9 -c ./public/client.min.js | wc -c | numfmt --to=iec-i --suffix=B --padding=10",
|
||||||
"deploy" : "npm run get_dependencies && npm run prod && ./mywebsite",
|
"deploy": "npm run get_dependencies && npm run prod && ./mywebsite",
|
||||||
"dev": "webpack-dev-server --content-base public --inline --hot --history-api-fallback",
|
"dev": "webpack-dev-server --content-base public --inline --hot --history-api-fallback",
|
||||||
"get_dependencies": "go get ./server && npm install",
|
"get_dependencies": "go get ./server && npm install",
|
||||||
"prod": "export NODE_ENV=production && webpack -p && babel-node metadata.js && go build ./server/mywebsite.go",
|
"prod": "export NODE_ENV=production && webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors && babel-node metadata.js && go build ./server/mywebsite.go",
|
||||||
"prod-win": "set NODE_ENV=production && webpack -p && babel-node metadata.js && go build ./server/mywebsite.go"
|
"prod-win": "set NODE_ENV=production && webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors && babel-node metadata.js && go build ./server/mywebsite.go",
|
||||||
|
"watch": "webpack --watch --colors --progress"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/mgerb/mywebsite#readme",
|
"homepage": "https://github.com/mgerb/mywebsite#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"autoprefixer": "^6.4.1",
|
||||||
"babel": "^6.5.2",
|
"babel": "^6.5.2",
|
||||||
"babel-cli": "^6.11.4",
|
"babel-cli": "^6.11.4",
|
||||||
"babel-core": "^6.13.2",
|
"babel-core": "^6.13.2",
|
||||||
@@ -35,6 +37,7 @@
|
|||||||
"babel-preset-es2015": "^6.13.2",
|
"babel-preset-es2015": "^6.13.2",
|
||||||
"babel-preset-react": "^6.11.1",
|
"babel-preset-react": "^6.11.1",
|
||||||
"babel-preset-stage-0": "^6.5.0",
|
"babel-preset-stage-0": "^6.5.0",
|
||||||
|
"chart.js": "^1.1.1",
|
||||||
"css-loader": "^0.23.1",
|
"css-loader": "^0.23.1",
|
||||||
"exports-loader": "^0.6.3",
|
"exports-loader": "^0.6.3",
|
||||||
"file-loader": "^0.9.0",
|
"file-loader": "^0.9.0",
|
||||||
@@ -44,7 +47,10 @@
|
|||||||
"marked": "^0.3.6",
|
"marked": "^0.3.6",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"node-sass": "^3.8.0",
|
"node-sass": "^3.8.0",
|
||||||
|
"postcss-loader": "^0.13.0",
|
||||||
"react": "^15.3.0",
|
"react": "^15.3.0",
|
||||||
|
"react-addons-transition-group": "^15.3.1",
|
||||||
|
"react-chartjs": "^0.8.0",
|
||||||
"react-dom": "^15.3.0",
|
"react-dom": "^15.3.0",
|
||||||
"react-redux": "^4.4.5",
|
"react-redux": "^4.4.5",
|
||||||
"react-router": "^2.6.1",
|
"react-router": "^2.6.1",
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ func HandleSensorRequest(w http.ResponseWriter, r *http.Request, ps httprouter.P
|
|||||||
storedData.Month = int(t.Month())
|
storedData.Month = int(t.Month())
|
||||||
storedData.MonthName = t.Month().String()
|
storedData.MonthName = t.Month().String()
|
||||||
storedData.Year = t.Year()
|
storedData.Year = t.Year()
|
||||||
|
storedData.Updated = t
|
||||||
|
|
||||||
err := storedData.StoreData()
|
err := storedData.StoreData()
|
||||||
|
|
||||||
@@ -134,21 +135,7 @@ func HandleSensorByLocation(w http.ResponseWriter, r *http.Request, ps httproute
|
|||||||
|
|
||||||
s, err := daily_sensor.GetAllSensorInfo(location)
|
s, err := daily_sensor.GetAllSensorInfo(location)
|
||||||
|
|
||||||
var response string
|
response := createResponse(s, err)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
response = "{message : \"Error loading data from database\""
|
|
||||||
} else {
|
|
||||||
js, err := json.MarshalIndent(s, "", " ")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
response = "{message : \"Error loading data from database\""
|
|
||||||
} else {
|
|
||||||
response = string(js)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(w, response)
|
fmt.Fprint(w, response)
|
||||||
}
|
}
|
||||||
@@ -162,21 +149,7 @@ func HandleSensorByLocationYear(w http.ResponseWriter, r *http.Request, ps httpr
|
|||||||
|
|
||||||
s, err := daily_sensor.GetAllSensorInfoByYear(location, year)
|
s, err := daily_sensor.GetAllSensorInfoByYear(location, year)
|
||||||
|
|
||||||
var response string
|
response := createResponse(s, err)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
response = "{message : \"Error loading data from database\""
|
|
||||||
} else {
|
|
||||||
js, err := json.MarshalIndent(s, "", " ")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
response = "{message : \"Error loading data from database\""
|
|
||||||
} else {
|
|
||||||
response = string(js)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(w, response)
|
fmt.Fprint(w, response)
|
||||||
}
|
}
|
||||||
@@ -191,6 +164,19 @@ func HandleSensorByLocationMonth(w http.ResponseWriter, r *http.Request, ps http
|
|||||||
|
|
||||||
s, err := daily_sensor.GetAllSensorInfoByMonth(location, year, monthname)
|
s, err := daily_sensor.GetAllSensorInfoByMonth(location, year, monthname)
|
||||||
|
|
||||||
|
response := createResponse(s, err)
|
||||||
|
|
||||||
|
fmt.Fprint(w, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleUniqueDates(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
|
||||||
|
location := ps.ByName("location")
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
s, err := daily_sensor.GetUniqueSensorDates(location)
|
||||||
|
|
||||||
var response string
|
var response string
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -209,3 +195,23 @@ func HandleSensorByLocationMonth(w http.ResponseWriter, r *http.Request, ps http
|
|||||||
|
|
||||||
fmt.Fprint(w, response)
|
fmt.Fprint(w, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createResponse(s []daily_sensor.Data, err error) string{
|
||||||
|
var response string
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
response = "{message : \"Error loading data from database\""
|
||||||
|
} else {
|
||||||
|
js, err := json.MarshalIndent(s, "", " ")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
response = "{message : \"Error loading data from database\""
|
||||||
|
} else {
|
||||||
|
response = string(js)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
@@ -16,22 +16,24 @@ const (
|
|||||||
|
|
||||||
type Data struct {
|
type Data struct {
|
||||||
ID bson.ObjectId `bson:"_id,omitempty"`
|
ID bson.ObjectId `bson:"_id,omitempty"`
|
||||||
MaxTemp float64 `json:"maxtemp" bson:"maxtemp"`
|
MaxTemp float64 `json:"maxtemp,omitempty" bson:"maxtemp"`
|
||||||
MinTemp float64 `json:"mintemp" bson:"mintemp"`
|
MinTemp float64 `json:"mintemp,omitempty" bson:"mintemp"`
|
||||||
Location string `json:"location" bson:"location"`
|
Location string `json:"location,omitempty" bson:"location"`
|
||||||
Month int `json:"month" bson:"month"`
|
Month int `json:"month,omitempty" bson:"month"`
|
||||||
MonthName string `json:"monthname" bson:"monthname"`
|
MonthName string `json:"monthname,omitempty" bson:"monthname"`
|
||||||
Day int `json:"day" bson:"day"`
|
Day int `json:"day,omitempty" bson:"day"`
|
||||||
Year int `json:"year" bson:"year"`
|
Year int `json:"year,omitempty" bson:"year"`
|
||||||
|
Updated time.Time `json:"updated,omitempty" bson:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//convert struct to json string
|
//convert struct to json string
|
||||||
func (s *Data) toJson() string {
|
func (s *Data) ToJson() string {
|
||||||
|
|
||||||
b, err := json.MarshalIndent(s, "", " ")
|
b, err := json.MarshalIndent(s, "", " ")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err.Error)
|
log.Println(err)
|
||||||
|
return "{message : \"Error loading data from database\""
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(b)
|
return string(b)
|
||||||
@@ -73,7 +75,7 @@ func (s *Data) UpdateData() error {
|
|||||||
c := session.DB(db.Mongo.Info.Database).C(collection)
|
c := session.DB(db.Mongo.Info.Database).C(collection)
|
||||||
|
|
||||||
colQuerier := bson.M{"location": s.Location, "month": s.Month, "monthname": s.MonthName, "day": s.Day, "year": s.Year}
|
colQuerier := bson.M{"location": s.Location, "month": s.Month, "monthname": s.MonthName, "day": s.Day, "year": s.Year}
|
||||||
change := bson.M{"$set": bson.M{"maxtemp": s.MaxTemp, "mintemp": s.MinTemp}}
|
change := bson.M{"$set": bson.M{"maxtemp": s.MaxTemp, "mintemp": s.MinTemp, "updated": time.Now()}}
|
||||||
|
|
||||||
err := c.Update(colQuerier, change)
|
err := c.Update(colQuerier, change)
|
||||||
|
|
||||||
@@ -130,7 +132,6 @@ func GetAllSensorInfo(sensor_location string) ([]Data, error) {
|
|||||||
|
|
||||||
c := session.DB(db.Mongo.Info.Database).C(collection)
|
c := session.DB(db.Mongo.Info.Database).C(collection)
|
||||||
|
|
||||||
//err := c.Find(bson.M{"location": sensor_location}).Sort("-year, -month").All(&d)
|
|
||||||
err := c.Pipe([]bson.M{{"$match": bson.M{"location": sensor_location}},
|
err := c.Pipe([]bson.M{{"$match": bson.M{"location": sensor_location}},
|
||||||
{"$sort": bson.M{"year": -1, "month": 1}}}).All(&d)
|
{"$sort": bson.M{"year": -1, "month": 1}}}).All(&d)
|
||||||
|
|
||||||
@@ -198,3 +199,55 @@ func GetAllSensorInfoByMonth(sensor_location string, year int, monthname string)
|
|||||||
return d, errors.New("Query failed")
|
return d, errors.New("Query failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//I need to find a better implementation of this
|
||||||
|
//MongoDB $addToSet creates an array of objecta
|
||||||
|
//this ends up being a different type than the Data struct above
|
||||||
|
//it would be nice to make all MongoDB queries load directly into a Data struct
|
||||||
|
/*
|
||||||
|
type UniqueDates struct{
|
||||||
|
Dates []Data `json:"dates" bson:"dates"`
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
type Years struct {
|
||||||
|
Year int `json:"year", bson:"year"`
|
||||||
|
Months []Month `json:"months", bson:"months"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Month struct {
|
||||||
|
Month int `json:"month", bson:"month"`
|
||||||
|
MonthName string `json:"monthname", bson:"monthname"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUniqueSensorDates(sensor_location string) ([]Years, error){
|
||||||
|
d := []Years{}
|
||||||
|
|
||||||
|
if db.Mongo.Connected() == true {
|
||||||
|
|
||||||
|
session := db.Mongo.Session.Copy()
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
c := session.DB(db.Mongo.Info.Database).C(collection)
|
||||||
|
|
||||||
|
err := c.Pipe([]bson.M{bson.M{"$match": bson.M{"location": sensor_location}},
|
||||||
|
bson.M{"$group": bson.M{"_id": "$year", "months": bson.M{"$addToSet": bson.M{"month": "$month", "monthname": "$monthname"}}}},
|
||||||
|
bson.M{"$project": bson.M{"year": "$_id", "months": "$months"}},
|
||||||
|
bson.M{"$unwind": "$months"},
|
||||||
|
bson.M{"$sort": bson.M{"months.month": -1}},
|
||||||
|
bson.M{"$group": bson.M{"_id": "$year", "months": bson.M{"$push": "$months"}}},
|
||||||
|
bson.M{"$project": bson.M{"year": "$_id", "months": "$months"}},
|
||||||
|
|
||||||
|
}).All(&d)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, nil
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return d, errors.New("Query failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,7 +59,8 @@ func (s *Data) StoreData() error {
|
|||||||
|
|
||||||
//handle queries for all sensors page
|
//handle queries for all sensors page
|
||||||
type DataStore_AllSensors struct {
|
type DataStore_AllSensors struct {
|
||||||
ID string `json:"location" bson:"_id"`
|
ID bson.ObjectId `bson:"_id,omitempty"`
|
||||||
|
Location string `json:"location", bson:"location"`
|
||||||
Temperature float64 `json:"temperature" bson:"temperature"`
|
Temperature float64 `json:"temperature" bson:"temperature"`
|
||||||
Updated time.Time `json:"updated" bson:"updated"`
|
Updated time.Time `json:"updated" bson:"updated"`
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,9 @@ func GetAllSensors() ([]DataStore_AllSensors, error) {
|
|||||||
|
|
||||||
err := c.Pipe([]bson.M{{"$group": bson.M{"_id": "$location", "temperature": bson.M{"$last": "$temperature"},
|
err := c.Pipe([]bson.M{{"$group": bson.M{"_id": "$location", "temperature": bson.M{"$last": "$temperature"},
|
||||||
"updated": bson.M{"$last": "$updated"}}},
|
"updated": bson.M{"$last": "$updated"}}},
|
||||||
bson.M{"$sort": bson.M{"_id": 1}}}).All(&s)
|
bson.M{"$sort": bson.M{"_id": 1}},
|
||||||
|
bson.M{"$project": bson.M{"location": "$_id", "temperature": "$temperature", "updated": "$updated"}},
|
||||||
|
}).All(&s)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, nil
|
return s, nil
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func Routes() *httprouter.Router {
|
|||||||
r.GET("/api/sensor/:location", api.HandleSensorByLocation)
|
r.GET("/api/sensor/:location", api.HandleSensorByLocation)
|
||||||
r.GET("/api/sensor/:location/:year", api.HandleSensorByLocationYear)
|
r.GET("/api/sensor/:location/:year", api.HandleSensorByLocationYear)
|
||||||
r.GET("/api/sensor/:location/:year/:monthname", api.HandleSensorByLocationMonth)
|
r.GET("/api/sensor/:location/:year/:monthname", api.HandleSensorByLocationMonth)
|
||||||
|
r.GET("/api/uniquedates/:location", api.HandleUniqueDates)
|
||||||
|
|
||||||
r.GET("/discord", controller.DiscordRedirect)
|
r.GET("/discord", controller.DiscordRedirect)
|
||||||
r.GET("/vpn", controller.VPNRedirect)
|
r.GET("/vpn", controller.VPNRedirect)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ var debug = process.env.NODE_ENV !== "production";
|
|||||||
var webpack = require('webpack');
|
var webpack = require('webpack');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
var autoprefixer = require('autoprefixer');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
devtool: debug ? "inline-sourcemap" : null,
|
devtool: debug ? "inline-sourcemap" : null,
|
||||||
@@ -17,7 +18,7 @@ module.exports = {
|
|||||||
plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'],
|
plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ test: /\.scss$/, loader: "style-loader!css-loader!sass-loader"},
|
{ test: /\.scss$/, loader: "style-loader!css-loader!postcss-loader!sass-loader"},
|
||||||
{ test: /\.css$/, loader: "style-loader!css-loader" },
|
{ test: /\.css$/, loader: "style-loader!css-loader" },
|
||||||
{ test: /\.png$/, loader: "url-loader?limit=100000&name=images/[hash].[ext]" },
|
{ test: /\.png$/, loader: "url-loader?limit=100000&name=images/[hash].[ext]" },
|
||||||
{ test: /\.jpg$/, loader: "url-loader?limit=100000&name=images/[hash].[ext]" },
|
{ test: /\.jpg$/, loader: "url-loader?limit=100000&name=images/[hash].[ext]" },
|
||||||
@@ -32,6 +33,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
postcss: function(){ return [autoprefixer]},
|
||||||
output: {
|
output: {
|
||||||
path: __dirname + "/public/",
|
path: __dirname + "/public/",
|
||||||
publicPath: "/public/",
|
publicPath: "/public/",
|
||||||
|
|||||||
Reference in New Issue
Block a user