mirror of https://github.com/statping/statping
vue
parent
23b230f61f
commit
134bd073ff
5
Makefile
5
Makefile
|
@ -17,6 +17,9 @@ release: dev-deps
|
||||||
gpg --import statping.gpg
|
gpg --import statping.gpg
|
||||||
make build-all
|
make build-all
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
cd frontend && yarn serve
|
||||||
|
|
||||||
# build and push the images to docker hub
|
# build and push the images to docker hub
|
||||||
docker: docker-build-all docker-publish-all
|
docker: docker-build-all docker-publish-all
|
||||||
|
|
||||||
|
@ -371,5 +374,5 @@ heroku:
|
||||||
checkall:
|
checkall:
|
||||||
golangci-lint run ./...
|
golangci-lint run ./...
|
||||||
|
|
||||||
.PHONY: all build build-all build-alpine test-all test test-api docker
|
.PHONY: all build build-all build-alpine test-all test test-api docker frontend
|
||||||
.SILENT: travis_s3_creds
|
.SILENT: travis_s3_creds
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
class Api {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async root () {
|
||||||
|
return axios.get('/api').then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
async services () {
|
||||||
|
return axios.get('/api/services').then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
async groups () {
|
||||||
|
return axios.get('/api/groups').then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
const api = new Api()
|
||||||
|
export default api
|
|
@ -1,24 +1,13 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import Index from "./components/Pages/Index";
|
const router = require("routes")
|
||||||
|
|
||||||
require("./assets/css/bootstrap.min.css")
|
require("./assets/css/bootstrap.min.css")
|
||||||
require("./assets/css/base.css")
|
require("./assets/css/base.css")
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
const router = new VueRouter({
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'Index',
|
|
||||||
component: Index
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
new Vue({
|
new Vue({
|
||||||
router,
|
router,
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
<template>
|
||||||
|
<div class="container col-md-7 col-sm-12 mt-2 sm-container">
|
||||||
|
|
||||||
|
<Header :core="core"/>
|
||||||
|
|
||||||
|
<Group/>
|
||||||
|
<Group/>
|
||||||
|
<Group/>
|
||||||
|
<div v-for="(group, index) in groups" v-bind:key="index">
|
||||||
|
<Group :group=group />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<MessageBlock/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 full-col-12">
|
||||||
|
|
||||||
|
<div v-for="(service, index) in services" v-bind:key="index">
|
||||||
|
<ServiceBlock :service=service />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ServiceBlock from '../components/Service/ServiceBlock.vue'
|
||||||
|
import MessageBlock from "../components/Index/MessageBlock";
|
||||||
|
import Group from "../components/Index/Group";
|
||||||
|
import Header from "../components/Index/Header";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Dashboard',
|
||||||
|
components: {
|
||||||
|
Header,
|
||||||
|
Group,
|
||||||
|
MessageBlock,
|
||||||
|
ServiceBlock,
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
services: null,
|
||||||
|
groups: null,
|
||||||
|
core: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
this.getAPI()
|
||||||
|
this.getGroups()
|
||||||
|
this.getServices()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getAPI: function() {
|
||||||
|
axios
|
||||||
|
.get('/api')
|
||||||
|
.then(response => (this.core = response.data))
|
||||||
|
},
|
||||||
|
getServices: function() {
|
||||||
|
axios
|
||||||
|
.get('/api/services')
|
||||||
|
.then(response => (this.services = response.data))
|
||||||
|
},
|
||||||
|
getGroups: function() {
|
||||||
|
axios
|
||||||
|
.get('/api/groups')
|
||||||
|
.then(response => (this.groups = response.data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,61 @@
|
||||||
|
<template>
|
||||||
|
<div v-show="core" class="container col-md-7 col-sm-12 mt-2 sm-container">
|
||||||
|
|
||||||
|
<Header :core="core"/>
|
||||||
|
|
||||||
|
<div v-for="(group, index) in groups" v-bind:key="index">
|
||||||
|
<Group :group=group />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<MessageBlock/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 full-col-12">
|
||||||
|
|
||||||
|
<div v-for="(service, index) in services" v-bind:key="index">
|
||||||
|
<ServiceBlock :service=service />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ServiceBlock from '../components/Service/ServiceBlock.vue'
|
||||||
|
import MessageBlock from "../components/Index/MessageBlock";
|
||||||
|
import Group from "../components/Index/Group";
|
||||||
|
import Header from "../components/Index/Header";
|
||||||
|
import Api from "../components/API"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Index',
|
||||||
|
components: {
|
||||||
|
Header,
|
||||||
|
Group,
|
||||||
|
MessageBlock,
|
||||||
|
ServiceBlock,
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
services: null,
|
||||||
|
groups: null,
|
||||||
|
core: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
this.loadAll()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async loadAll () {
|
||||||
|
this.core = await Api.root()
|
||||||
|
this.groups = await Api.groups()
|
||||||
|
this.services = await Api.services()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<div class="container col-md-7 col-sm-12 mt-2 sm-container">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Service',
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
service: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<div class="container col-md-7 col-sm-12 mt-2 sm-container">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Services',
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
services: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -25,15 +25,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ServiceBlock from '../Service/ServiceBlock.vue'
|
import ServiceBlock from '../components/Service/ServiceBlock.vue'
|
||||||
import MessageBlock from "../Index/MessageBlock";
|
import MessageBlock from "../components/Index/MessageBlock";
|
||||||
import Group from "../Index/Group";
|
import Group from "../components/Index/Group";
|
||||||
import Header from "../Index/Header";
|
import Header from "../components/Index/Header";
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Index',
|
name: 'Settings',
|
||||||
components: {
|
components: {
|
||||||
Header,
|
Header,
|
||||||
Group,
|
Group,
|
|
@ -1,5 +1,7 @@
|
||||||
import Index from "./components/Pages/Index";
|
import Index from "./pages/Index";
|
||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
|
import Dashboard from "./pages/Dashboard";
|
||||||
|
import Settings from "./pages/Settings";
|
||||||
|
|
||||||
const router = new VueRouter({
|
const router = new VueRouter({
|
||||||
routes: [
|
routes: [
|
||||||
|
@ -7,6 +9,16 @@ const router = new VueRouter({
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Index',
|
name: 'Index',
|
||||||
component: Index
|
component: Index
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/dashboard',
|
||||||
|
name: 'Dashboard',
|
||||||
|
component: Dashboard
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings',
|
||||||
|
name: 'Settings',
|
||||||
|
component: Settings
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,7 @@ module.exports = {
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
logLevel: 'debug',
|
logLevel: 'debug',
|
||||||
target: 'http://0.0.0.0:8585'
|
target: 'http://0.0.0.0:8282'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -272,6 +273,66 @@ func returnJson(d interface{}, w http.ResponseWriter, r *http.Request) {
|
||||||
json.NewEncoder(w).Encode(d)
|
json.NewEncoder(w).Encode(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func safeTypes(obj interface{}) []string {
|
||||||
|
if reflect.ValueOf(obj).Kind() == reflect.Ptr {
|
||||||
|
obj = &obj
|
||||||
|
}
|
||||||
|
switch v := obj.(type) {
|
||||||
|
case types.Service:
|
||||||
|
return types.SafeService
|
||||||
|
default:
|
||||||
|
fmt.Printf("%T\n", v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandServices(s []types.ServiceInterface) []*types.Service {
|
||||||
|
var services []*types.Service
|
||||||
|
for _, v := range s {
|
||||||
|
services = append(services, v.Select())
|
||||||
|
}
|
||||||
|
return services
|
||||||
|
}
|
||||||
|
|
||||||
|
func returnSafeJson(w http.ResponseWriter, r *http.Request, input interface{}) {
|
||||||
|
allData := make([]map[string]*json.RawMessage, 0, 1)
|
||||||
|
s := reflect.ValueOf(input)
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
obj := s.Index(i)
|
||||||
|
allData = append(allData, safeJsonKeys(obj))
|
||||||
|
}
|
||||||
|
returnJson(allData, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func safeJsonKeys(in reflect.Value) map[string]*json.RawMessage {
|
||||||
|
|
||||||
|
thisObj := in.Elem().Interface()
|
||||||
|
nn := make(map[string]*json.RawMessage)
|
||||||
|
|
||||||
|
v := reflect.ValueOf(thisObj)
|
||||||
|
typeOfS := v.Type()
|
||||||
|
fmt.Println("fields: ", v.NumField())
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
inter := v.Field(i).Interface()
|
||||||
|
fmt.Println(v.Field(i).CanSet())
|
||||||
|
if typeOfS.Field(i).Type.String() == "types.NullString" {
|
||||||
|
ggg := inter.(types.NullString)
|
||||||
|
fmt.Println("OKKOKOK: ", ggg)
|
||||||
|
v.Field(i).SetString(ggg.String)
|
||||||
|
}
|
||||||
|
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Type.String(), v.Field(i).Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
data, _ := json.Marshal(thisObj)
|
||||||
|
|
||||||
|
json.Unmarshal(data, &nn)
|
||||||
|
removeKeys := safeTypes(thisObj)
|
||||||
|
for _, k := range removeKeys {
|
||||||
|
delete(nn, k)
|
||||||
|
}
|
||||||
|
return nn
|
||||||
|
}
|
||||||
|
|
||||||
// error404Handler is a HTTP handler for 404 error pages
|
// error404Handler is a HTTP handler for 404 error pages
|
||||||
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
if usingSSL {
|
if usingSSL {
|
||||||
|
|
|
@ -131,7 +131,7 @@ func Router() *mux.Router {
|
||||||
r.Handle("/api/reorder/groups", authenticated(apiGroupReorderHandler, false)).Methods("POST")
|
r.Handle("/api/reorder/groups", authenticated(apiGroupReorderHandler, false)).Methods("POST")
|
||||||
|
|
||||||
// API SERVICE Routes
|
// API SERVICE Routes
|
||||||
r.Handle("/api/services", readOnly(apiAllServicesHandler, false)).Methods("GET")
|
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
|
||||||
r.Handle("/api/services", authenticated(apiCreateServiceHandler, false)).Methods("POST")
|
r.Handle("/api/services", authenticated(apiCreateServiceHandler, false)).Methods("POST")
|
||||||
r.Handle("/api/services/{id}", readOnly(apiServiceHandler, false)).Methods("GET")
|
r.Handle("/api/services/{id}", readOnly(apiServiceHandler, false)).Methods("GET")
|
||||||
r.Handle("/api/reorder/services", authenticated(reorderServiceHandler, false)).Methods("POST")
|
r.Handle("/api/reorder/services", authenticated(reorderServiceHandler, false)).Methods("POST")
|
||||||
|
|
|
@ -294,7 +294,12 @@ func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
|
func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
admin := IsAdmin(r)
|
||||||
services := core.Services()
|
services := core.Services()
|
||||||
|
if !admin {
|
||||||
|
returnSafeJson(w, r, expandServices(services))
|
||||||
|
return
|
||||||
|
}
|
||||||
returnJson(services, w, r)
|
returnJson(services, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
var (
|
||||||
|
SafeService = []string{"domain", "expected_status", "expected", "allow_notifications", "headers", "method",
|
||||||
|
"port", "timeout", "status_code", "verify_ssl", "post_data", "type", "check_interval", "failures"}
|
||||||
|
)
|
|
@ -23,7 +23,7 @@ import (
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||||
Name string `gorm:"column:name" json:"name"`
|
Name string `gorm:"column:name" json:"name"`
|
||||||
Domain string `gorm:"column:domain" json:"domain"`
|
Domain string `gorm:"column:domain" json:"domain" private:"true"`
|
||||||
Expected NullString `gorm:"column:expected" json:"expected"`
|
Expected NullString `gorm:"column:expected" json:"expected"`
|
||||||
ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
|
ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
|
||||||
Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`
|
Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`
|
||||||
|
|
Loading…
Reference in New Issue