+
{this.openLink(sensor.location)}}>
+
{sensor.temperature}°f
-
+
{sensor.location}
- Updated: {date.toLocaleString('en-us', options)}
+ Updated: {date.toLocaleString('en-us', options)}
+ {Date.now() - date < 420000
+ ? Connected
+ : Disconnected
+ }
+
);
diff --git a/client/js/components/sensors/SensorList.scss b/client/js/components/sensors/SensorList.scss
index 893884f..ba5f99d 100644
--- a/client/js/components/sensors/SensorList.scss
+++ b/client/js/components/sensors/SensorList.scss
@@ -9,11 +9,16 @@
padding: 1em;
&:hover{
- background-color: gray;
+ background-color: #D1D1D1;
}
- .item + .item{
+ .temperature{
+ flex: .5;
+ }
+
+ .info{
margin-left: 1em;
+ flex: 1;
}
h2{
@@ -25,4 +30,11 @@
}
}
+ .connected{
+ color: green;
+ }
+ .disconnected{
+ color: red;
+ }
+
}
\ No newline at end of file
diff --git a/client/js/components/sensors/chartOptions.js b/client/js/components/sensors/chartOptions.js
new file mode 100644
index 0000000..f2bac62
--- /dev/null
+++ b/client/js/components/sensors/chartOptions.js
@@ -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: []
+ }]
+};
\ No newline at end of file
diff --git a/client/js/components/utils/AboutMe.js b/client/js/components/utils/AboutMe.js
index f9dd82d..fd4588f 100644
--- a/client/js/components/utils/AboutMe.js
+++ b/client/js/components/utils/AboutMe.js
@@ -1,4 +1,5 @@
import React from 'react';
+import {Link} from 'react-router';
import me from '../../../assets/images/me.jpg';
@@ -12,7 +13,10 @@ export default class AboutMe extends React.Component{
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.
-
+
+
+ Home
+
eMail
@@ -25,10 +29,12 @@ export default class AboutMe extends React.Component{
GitHub
+ {/*
Resume
+ */}
);
}
diff --git a/client/js/redux/actions/app.js b/client/js/redux/actions/app.js
index b1c9018..5759223 100644
--- a/client/js/redux/actions/app.js
+++ b/client/js/redux/actions/app.js
@@ -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) => {
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 => {
dispatch(loadPost(response));
diff --git a/client/js/redux/actions/sensor.js b/client/js/redux/actions/sensor.js
index e356e99..b97c5f2 100644
--- a/client/js/redux/actions/sensor.js
+++ b/client/js/redux/actions/sensor.js
@@ -8,17 +8,31 @@ function loadSensorList(sensor_list){
}
}
-function loadSensorInfoYear(sensor_info){
+function loadSensorInfo(sensor_info){
return{
- type: types.LOAD_SENSOR_INFO_YEAR,
+ type: types.LOAD_SENSOR_INFO,
sensor_info
}
}
-function loadSensorInfoMonth(sensor_info){
+function loadUniqueDates(dates){
return{
- type: types.LOAD_SENSOR_INFO_MONTH,
- sensor_info
+ type: types.LOAD_UNIQUE_DATES,
+ 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,16 +42,16 @@ function fetchingList(){
}
}
-function fetchingInfoYear(){
+function fetchingInfo(){
return {
- type: types.FETCHING_INFO_YEAR
+ type: types.FETCHING_INFO
}
}
-function fetchingInfoMonth(){
+function fetchingUniqueDates(){
return {
- type: types.FETCHING_INFO_MONTH
- }
+ type: types.FETCHING_UNIQUE_DATES
+ }
}
export function fetchSensorList(){
@@ -56,11 +70,11 @@ export function fetchSensorList(){
export function fetchSensorInfoYear(location, year){
return (dispatch) => {
- dispatch(fetchingInfoYear());
+ dispatch(fetchingInfo());
return fetch(`/api/sensor/${location}/${year}`)
.then(response => response.json())
.then(json => {
- dispatch(loadSensorInfoYear(json));
+ dispatch(loadSensorInfo(json));
})
.catch(error => {
console.log(error);
@@ -70,14 +84,38 @@ export function fetchSensorInfoYear(location, year){
export function fetchSensorInfoMonth(location, year, month){
return (dispatch) => {
- dispatch(fetchingInfoMonth());
+ dispatch(fetchingInfo());
return fetch(`/api/sensor/${location}/${year}/${month}`)
.then(response => response.json())
.then(json => {
- dispatch(loadSensorInfoMonth(json));
+ dispatch(loadSensorInfo(json));
})
.catch(error => {
console.log(error);
});
}
-}
\ No newline at end of file
+}
+
+//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 => {
+ console.log(error);
+ });
+ }
+}
diff --git a/client/js/redux/constants/sensor.js b/client/js/redux/constants/sensor.js
index ae93469..a23112b 100644
--- a/client/js/redux/constants/sensor.js
+++ b/client/js/redux/constants/sensor.js
@@ -1,10 +1,13 @@
//constants
export const LOAD_SENSOR_LIST = 'LOAD_SENSOR_LIST';
-export const LOAD_SENSOR_INFO_YEAR = 'LOAD_SENSOR_INFO_YEAR';
-export const LOAD_SENSOR_INFO_MONTH = 'LOAD_SENSOR_INFO_MONTH';
-
+export const LOAD_SENSOR_INFO = 'LOAD_SENSOR_INFO';
+export const LOAD_UNIQUE_DATES = 'LOAD_UNIQUE_DATES';
//fetching
export const FETCHING_LIST = 'FETCHING_LIST';
-export const FETCHING_INFO_YEAR = 'FETCHING_INFO_YEAR';
-export const FETCHING_INFO_MONTH = 'FETCHING_INFO_MONTH';
\ No newline at end of file
+export const FETCHING_INFO = 'FETCHING_INFO_YEAR';
+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';
\ No newline at end of file
diff --git a/client/js/redux/reducers/sensor.js b/client/js/redux/reducers/sensor.js
index 8d5a4af..bb32411 100644
--- a/client/js/redux/reducers/sensor.js
+++ b/client/js/redux/reducers/sensor.js
@@ -4,54 +4,69 @@ import * as types from '../constants/sensor';
//defaults -
const defaultState = {
list : [],
- infoMonth: [],
- infoYear: [],
+ info: [],
+ uniqueDates: {},
+
+ selectedYearIndex: 0,
+ selectedMonthIndex: 0,
fetchingList: false,
- fetchingInfoMonth: false,
- fetchingInfoYear: false,
+ fetchingInfo: false,
+ fetchingUniqueDates: false,
fetchedList: false,
- fetchedInfoMonth: false,
- fetchedInfoYear: false
+ fetchedInfo: false,
+ fetchedUniqueDates: false
};
//default reducer
export default function app(state = defaultState, action) {
switch(action.type){
+ //fetching functions - we use a fetching state to display loading images
case types.FETCHING_LIST:
return Object.assign({}, state, {
fetchingList: true,
fetchedList: false
});
- case types.FETCHING_INFO_MONTH:
+ case types.FETCHING_INFO:
return Object.assign({}, state, {
- fetchingInfoMonth: true,
- fetchedInfoMonth: false
+ fetchingInfo: true,
+ fetchedInfo: false
});
- case types.FETCHING_INFO_YEAR:
+ case types.FETCHING_UNIQUE_DATES:
return Object.assign({}, state, {
- fetchingInfoYear: true,
- fetchedInfoYear: false
+ fetchingUniqueDates: true,
+ fetchedUniqueDates: false
});
+ //other functions
case types.LOAD_SENSOR_LIST:
return Object.assign({}, state, {
list: action.sensor_list,
fetchingList: false,
fetchedList: true
});
- case types.LOAD_SENSOR_INFO_MONTH:
+ case types.LOAD_SENSOR_INFO:
return Object.assign({}, state, {
- infoMonth: action.sensor_info,
- fetchingInfoMonth: false,
- fetchedInfoMonth: true
+ info: action.sensor_info,
+ fetchingInfo: false,
+ fetchedInfo: true
});
- case types.LOAD_SENSOR_INFO_YEAR:
+ case types.LOAD_UNIQUE_DATES:
return Object.assign({}, state, {
- infoYear: action.sensor_info,
- fetchingInfoYear: false,
- fetchedInfoYear: true
+ uniqueDates: action.dates,
+ fetchingUniqueDates: false,
+ 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
diff --git a/client/js/redux/store.js b/client/js/redux/store.js
index b28f24c..3e62523 100644
--- a/client/js/redux/store.js
+++ b/client/js/redux/store.js
@@ -6,7 +6,10 @@ import {syncHistoryWithStore} from 'react-router-redux';
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
const store = createStore(reducers, {}, middleware);
diff --git a/metadata.js b/metadata.js
index fa3bce8..476a068 100644
--- a/metadata.js
+++ b/metadata.js
@@ -19,13 +19,15 @@ marked.setOptions({
}
});
-const dir = './posts/';
+const rootDirectory = './posts/';
const json = {
posts: []
};
//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);
for(let post of posts){
@@ -33,7 +35,7 @@ function parse_dir(dir, folder_name){
if(stats.isDirectory()){
parse_dir(dir + post + '/', post);
- } else {
+ } else if(folder_name !== null){
const file = fs.readFileSync(dir+post, 'utf8');
const tokens = marked.lexer(file, null);
const temp = {
@@ -49,7 +51,8 @@ function parse_dir(dir, folder_name){
}
//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
json.posts.sort((a, b) => {
diff --git a/package.json b/package.json
index 72b6bf9..d9969dd 100644
--- a/package.json
+++ b/package.json
@@ -7,11 +7,12 @@
"build": "webpack && babel-node metadata.js",
"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",
- "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",
"get_dependencies": "go get ./server && npm install",
- "prod": "export NODE_ENV=production && webpack -p && 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": "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 --define process.env.NODE_ENV='\"production\"' --progress --colors && babel-node metadata.js && go build ./server/mywebsite.go",
+ "watch": "webpack --watch --colors --progress"
},
"repository": {
"type": "git",
@@ -24,6 +25,7 @@
},
"homepage": "https://github.com/mgerb/mywebsite#readme",
"dependencies": {
+ "autoprefixer": "^6.4.1",
"babel": "^6.5.2",
"babel-cli": "^6.11.4",
"babel-core": "^6.13.2",
@@ -35,6 +37,7 @@
"babel-preset-es2015": "^6.13.2",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-0": "^6.5.0",
+ "chart.js": "^1.1.1",
"css-loader": "^0.23.1",
"exports-loader": "^0.6.3",
"file-loader": "^0.9.0",
@@ -44,7 +47,10 @@
"marked": "^0.3.6",
"ncp": "^2.0.0",
"node-sass": "^3.8.0",
+ "postcss-loader": "^0.13.0",
"react": "^15.3.0",
+ "react-addons-transition-group": "^15.3.1",
+ "react-chartjs": "^0.8.0",
"react-dom": "^15.3.0",
"react-redux": "^4.4.5",
"react-router": "^2.6.1",
diff --git a/server/controller/api/sensor.go b/server/controller/api/sensor.go
index 5dd87be..5fefa2d 100644
--- a/server/controller/api/sensor.go
+++ b/server/controller/api/sensor.go
@@ -61,6 +61,7 @@ func HandleSensorRequest(w http.ResponseWriter, r *http.Request, ps httprouter.P
storedData.Month = int(t.Month())
storedData.MonthName = t.Month().String()
storedData.Year = t.Year()
+ storedData.Updated = t
err := storedData.StoreData()
@@ -134,21 +135,7 @@ func HandleSensorByLocation(w http.ResponseWriter, r *http.Request, ps httproute
s, err := daily_sensor.GetAllSensorInfo(location)
- 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)
- }
- }
+ response := createResponse(s, err)
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)
- 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)
- }
- }
+ response := createResponse(s, err)
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)
+ 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
if err != nil {
@@ -209,3 +195,23 @@ func HandleSensorByLocationMonth(w http.ResponseWriter, r *http.Request, ps http
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
+}
\ No newline at end of file
diff --git a/server/model/daily_sensor/daily_sensor.go b/server/model/daily_sensor/daily_sensor.go
index 99837bb..0a80db1 100644
--- a/server/model/daily_sensor/daily_sensor.go
+++ b/server/model/daily_sensor/daily_sensor.go
@@ -16,22 +16,24 @@ const (
type Data struct {
ID bson.ObjectId `bson:"_id,omitempty"`
- MaxTemp float64 `json:"maxtemp" bson:"maxtemp"`
- MinTemp float64 `json:"mintemp" bson:"mintemp"`
- Location string `json:"location" bson:"location"`
- Month int `json:"month" bson:"month"`
- MonthName string `json:"monthname" bson:"monthname"`
- Day int `json:"day" bson:"day"`
- Year int `json:"year" bson:"year"`
+ MaxTemp float64 `json:"maxtemp,omitempty" bson:"maxtemp"`
+ MinTemp float64 `json:"mintemp,omitempty" bson:"mintemp"`
+ Location string `json:"location,omitempty" bson:"location"`
+ Month int `json:"month,omitempty" bson:"month"`
+ MonthName string `json:"monthname,omitempty" bson:"monthname"`
+ Day int `json:"day,omitempty" bson:"day"`
+ Year int `json:"year,omitempty" bson:"year"`
+ Updated time.Time `json:"updated,omitempty" bson:"updated"`
}
//convert struct to json string
-func (s *Data) toJson() string {
+func (s *Data) ToJson() string {
b, err := json.MarshalIndent(s, "", " ")
if err != nil {
- log.Println(err.Error)
+ log.Println(err)
+ return "{message : \"Error loading data from database\""
}
return string(b)
@@ -73,7 +75,7 @@ func (s *Data) UpdateData() error {
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}
- 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)
@@ -130,7 +132,6 @@ func GetAllSensorInfo(sensor_location string) ([]Data, error) {
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}},
{"$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")
}
}
+
+//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")
+ }
+}
\ No newline at end of file
diff --git a/server/model/raw_sensor/raw_sensor.go b/server/model/raw_sensor/raw_sensor.go
index 9b91b54..560fda8 100644
--- a/server/model/raw_sensor/raw_sensor.go
+++ b/server/model/raw_sensor/raw_sensor.go
@@ -59,9 +59,10 @@ func (s *Data) StoreData() error {
//handle queries for all sensors page
type DataStore_AllSensors struct {
- ID string `json:"location" bson:"_id"`
- Temperature float64 `json:"temperature" bson:"temperature"`
- Updated time.Time `json:"updated" bson:"updated"`
+ ID bson.ObjectId `bson:"_id,omitempty"`
+ Location string `json:"location", bson:"location"`
+ Temperature float64 `json:"temperature" bson:"temperature"`
+ Updated time.Time `json:"updated" bson:"updated"`
}
//get latest update from each unique sensor
@@ -78,7 +79,9 @@ func GetAllSensors() ([]DataStore_AllSensors, error) {
err := c.Pipe([]bson.M{{"$group": bson.M{"_id": "$location", "temperature": bson.M{"$last": "$temperature"},
"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 {
return s, nil
diff --git a/server/route/route.go b/server/route/route.go
index 8d7b9a6..90a6efe 100644
--- a/server/route/route.go
+++ b/server/route/route.go
@@ -20,7 +20,8 @@ func Routes() *httprouter.Router {
r.GET("/api/sensor/:location", api.HandleSensorByLocation)
r.GET("/api/sensor/:location/:year", api.HandleSensorByLocationYear)
r.GET("/api/sensor/:location/:year/:monthname", api.HandleSensorByLocationMonth)
-
+ r.GET("/api/uniquedates/:location", api.HandleUniqueDates)
+
r.GET("/discord", controller.DiscordRedirect)
r.GET("/vpn", controller.VPNRedirect)
r.GET("/camera", controller.CameraRedirect)
diff --git a/webpack.config.js b/webpack.config.js
index 3b6726a..447595f 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -2,6 +2,7 @@ var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
+var autoprefixer = require('autoprefixer');
module.exports = {
devtool: debug ? "inline-sourcemap" : null,
@@ -17,7 +18,7 @@ module.exports = {
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: /\.png$/, 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: {
path: __dirname + "/public/",
publicPath: "/public/",