pull/429/head
hunterlong 2020-02-19 00:13:09 -08:00
parent d2331fe14b
commit b8dbad85fe
24 changed files with 8580 additions and 196 deletions

View File

@ -29,7 +29,6 @@ const webpackConfig = merge(commonConfig, {
new FriendlyErrorsPlugin(), new FriendlyErrorsPlugin(),
new HtmlPlugin({ new HtmlPlugin({
template: 'public/index.html', template: 'public/index.html',
chunksSortMode: 'dependency'
}) })
], ],
devServer: { devServer: {

View File

@ -11,7 +11,7 @@
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free-solid": "^5.1.0-3", "@fortawesome/fontawesome-free-solid": "^5.1.0-3",
"@fortawesome/fontawesome-svg-core": "^1.2.26", "@fortawesome/fontawesome-svg-core": "^1.2.26",
"@fortawesome/free-brands-svg-icons": "^5.12.0", "@fortawesome/free-brands-svg-icons": "^5.12.1",
"@fortawesome/free-solid-svg-icons": "^5.12.0", "@fortawesome/free-solid-svg-icons": "^5.12.0",
"@fortawesome/vue-fontawesome": "^0.1.9", "@fortawesome/vue-fontawesome": "^0.1.9",
"apexcharts": "^3.15.0", "apexcharts": "^3.15.0",

View File

@ -3,10 +3,10 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>{{Name}}</title> <title>{{CoreApp.Name}}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1.0, user-scalable=0"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1.0, user-scalable=0">
<meta name="description" content="{{Description}}"> <meta name="description" content="{{CoreApp.Description}}">
<base href="{{BasePath}}"> <base href="{{BasePath}}">
{{if USE_CDN}} {{if USE_CDN}}
<link rel="shortcut icon" type="image/x-icon" href="https://assets.statping.com/favicon.ico"> <link rel="shortcut icon" type="image/x-icon" href="https://assets.statping.com/favicon.ico">

View File

@ -1,13 +1,13 @@
<template> <template>
<div id="app"> <div id="app">
<router-view :loaded="loaded"/> <router-view :loaded="loaded"/>
<Footer :version="version" v-if="$route.path !== '/setup'"/> <Footer :logged_in="logged_in" :version="version" v-if="$route.path !== '/setup'"/>
</div> </div>
</template> </template>
<script> <script>
import Api from './components/API'; import Api from './components/API';
import Footer from "./components/Footer"; import Footer from "./components/Index/Footer";
export default { export default {
name: 'app', name: 'app',
@ -23,6 +23,10 @@
}, },
async created() { async created() {
await this.$store.dispatch('loadRequired') await this.$store.dispatch('loadRequired')
if (this.$store.getters.core.logged_in) {
await this.$store.dispatch('loadAdmin')
}
this.loaded = true this.loaded = true
if (!this.$store.getters.core.setup) { if (!this.$store.getters.core.setup) {
this.$router.push('/setup') this.$router.push('/setup')
@ -32,8 +36,9 @@
async mounted() { async mounted() {
if (this.$route.path !== '/setup') { if (this.$route.path !== '/setup') {
const tk = localStorage.getItem("statping_user") const tk = localStorage.getItem("statping_user")
if (tk) { if (this.$store.getters.core.logged_in) {
// await this.$store.dispatch('loadAdmin') this.logged_in = true
await this.$store.dispatch('loadAdmin')
} }
} }
}, },

View File

@ -147,9 +147,14 @@ HTML,BODY {
text-decoration: none; text-decoration: none;
} }
.card-title A {
color: $service-title;
text-decoration: none;
}
.chart-container { .chart-container {
position: relative; position: relative;
height: 200px; height: 24.1vh;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
} }
@ -284,6 +289,33 @@ input.inputTags-field:focus {
margin-right: 10px; margin-right: 10px;
} }
@keyframes fadeInOut {
0% { opacity:1; }
50% { opacity:0.3; }
100% { opacity:1; }
}
@-o-keyframes fadeInOut {
0% { opacity:1; }
50% { opacity:0.3; }
100% { opacity:1; }
}
@-moz-keyframes fadeInOut {
0% { opacity:1; }
50% { opacity:0.3; }
100% { opacity:1; }
}
@-webkit-keyframes fadeInOut {
0% { opacity:1; }
50% { opacity:0.3; }
100% { opacity:1; }
}
.animate-fader {
-webkit-animation: fadeInOut 1s infinite;
-moz-animation: fadeInOut 1s infinite;
-o-animation: fadeInOut 1s infinite;
animation: fadeInOut 21 infinite;
}
.CodeMirror { .CodeMirror {
/* Bootstrap Settings */ /* Bootstrap Settings */
box-sizing: border-box; box-sizing: border-box;

View File

@ -52,7 +52,7 @@
} }
.lg_number { .lg_number {
font-size: 7.8vw; font-size: 7vw;
} }
.stats_area { .stats_area {
@ -66,6 +66,10 @@
font-size: 0.6rem; font-size: 0.6rem;
} }
.navbar-item {
border-bottom: 1px solid #eaeaea;
}
.list-group-item { .list-group-item {
border-top: 1px solid #e4e4e4; border-top: 1px solid #e4e4e4;
border: 0px; border: 0px;

View File

@ -25,8 +25,10 @@
</span> {{service.name}} </span> {{service.name}}
</td> </td>
<td class="d-none d-md-table-cell"> <td class="d-none d-md-table-cell">
<span class="badge" :class="{'badge-success': service.online, 'badge-danger': !service.online}">{{service.online ? "ONLINE" : "OFFLINE"}}</span> <span class="badge" :class="{'animate-fader': !service.online, 'badge-success': service.online, 'badge-danger': !service.online}">
<ToggleSwitch :service="service"/> {{service.online ? "ONLINE" : "OFFLINE"}}
</span>
<ToggleSwitch v-if="service.online" :service="service"/>
</td> </td>
<td class="d-none d-md-table-cell"> <td class="d-none d-md-table-cell">
<span class="badge" :class="{'badge-primary': service.public, 'badge-secondary': !service.public}"> <span class="badge" :class="{'badge-primary': service.public, 'badge-secondary': !service.public}">
@ -117,7 +119,7 @@
computed: { computed: {
servicesList: { servicesList: {
get() { get() {
return this.$store.getters.servicesInOrder return this.$store.state.servicesInOrder
}, },
async set(value) { async set(value) {
let data = []; let data = [];

View File

@ -7,10 +7,10 @@
</span> </span>
</h5> </h5>
<div v-if="loaded && service.online" class="row"> <div v-if="loaded && service.online" class="row">
<div class="col-6"> <div class="col-md-6 col-sm-12">
<ServiceSparkLine :title="set1_name" subtitle="Last Day Latency" :series="set1"/> <ServiceSparkLine :title="set1_name" subtitle="Last Day Latency" :series="set1"/>
</div> </div>
<div class="col-6"> <div class="col-md-6 col-sm-12">
<ServiceSparkLine :title="set2_name" subtitle="Last 7 Days Latency" :series="set2"/> <ServiceSparkLine :title="set2_name" subtitle="Last 7 Days Latency" :series="set2"/>
</div> </div>
</div> </div>

View File

@ -1,33 +1,34 @@
<template> <template>
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
<router-link to="/" class="navbar-brand">Statping</router-link> <router-link to="/" class="navbar-brand">Statping</router-link>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"> <button @click="navopen = !navopen" class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <font-awesome-icon v-if="!navopen" icon="bars"/>
<font-awesome-icon v-if="navopen" icon="times"/>
</button> </button>
<div class="collapse navbar-collapse" id="navbarText"> <div class="navbar-collapse" :class="{collapse: !navopen}" id="navbarText">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li class="nav-item"> <li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard" class="nav-link">Dashboard</router-link> <router-link to="/dashboard" class="nav-link">Dashboard</router-link>
</li> </li>
<li class="nav-item"> <li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/services" class="nav-link">Services</router-link> <router-link to="/dashboard/services" class="nav-link">Services</router-link>
</li> </li>
<li class="nav-item"> <li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/users" class="nav-link">Users</router-link> <router-link to="/dashboard/users" class="nav-link">Users</router-link>
</li> </li>
<li class="nav-item"> <li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/messages" class="nav-link">Messages</router-link> <router-link to="/dashboard/messages" class="nav-link">Messages</router-link>
</li> </li>
<li class="nav-item"> <li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/settings" class="nav-link">Settings</router-link> <router-link to="/dashboard/settings" class="nav-link">Settings</router-link>
</li> </li>
<li class="nav-item"> <li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/logs" class="nav-link">Logs</router-link> <router-link to="/dashboard/logs" class="nav-link">Logs</router-link>
</li> </li>
<li class="nav-item"> <li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/help" class="nav-link">Help</router-link> <router-link to="/dashboard/help" class="nav-link">Help</router-link>
</li> </li>
</ul> </ul>
@ -44,8 +45,10 @@
export default { export default {
name: 'TopNav', name: 'TopNav',
props: { data () {
return {
navopen: false,
}
}, },
methods: { methods: {
async logout () { async logout () {

View File

@ -1,16 +1,17 @@
<template> <template>
<footer> <footer>
<div v-if="!$store.getters.core.footer" class="footer text-center mb-4 p-2"> <div v-if="!$store.getters.core.footer" class="footer text-center mb-4 p-2">
<a href="https://github.com/hunterlong/statping" target="_blank">Statping {{version}} made with <i class="text-danger fas fa-heart"></i></a> | <a href="https://github.com/hunterlong/statping" target="_blank">
<a href="/dashboard">Dashboard</a> Statping {{$store.getters.core.version}} made with <font-awesome-icon style="color: #d40d0d" icon="heart"/>
</div> </a> |
<div v-else class="footer text-center mb-4 p-2" v-html="$store.getters.core.footer"> <router-link :to="$store.getters.core.logged_in ? '/dashboard' : '/login'">Dashboard</router-link>
</div> </div>
<div v-else class="footer text-center mb-4 p-2" v-html="$store.getters.core.footer"></div>
</footer> </footer>
</template> </template>
<script> <script>
import Dashboard from "../pages/Dashboard"; import Dashboard from "../../pages/Dashboard";
export default { export default {
name: 'Footer', name: 'Footer',
@ -18,7 +19,13 @@
Dashboard Dashboard
}, },
props: { props: {
version: String version: String,
logged_in: Boolean
},
watch: {
logged_in() {
}
} }
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<apexchart v-if="ready" width="100%" height="215" type="area" :options="chartOptions" :series="series"></apexchart> <apexchart v-if="ready" width="100%" height="225" type="area" :options="chartOptions" :series="series"></apexchart>
</template> </template>
<script> <script>

View File

@ -17,7 +17,7 @@
<small class="form-text text-muted" v-html="form.small_text"></small> <small class="form-text text-muted" v-html="form.small_text"></small>
</div> </div>
<div class="row"> <div class="row mt-4">
<div class="col-9 col-sm-6"> <div class="col-9 col-sm-6">
<div class="input-group mb-2"> <div class="input-group mb-2">
<div class="input-group-prepend"> <div class="input-group-prepend">
@ -43,14 +43,14 @@
</button> </button>
</div> </div>
<div class="col-12 col-sm-12"> <div class="col-12 col-sm-12 mt-3">
<button @click="testNotifier" class="btn btn-secondary btn-block text-capitalize col-12 float-right"><i class="fa fa-vial"></i> <button @click="testNotifier" class="btn btn-secondary btn-block text-capitalize col-12 float-right"><i class="fa fa-vial"></i>
{{loading ? "Loading..." : "Test Notifier"}}</button> {{loading ? "Loading..." : "Test Notifier"}}</button>
</div> </div>
</div> </div>
<span class="d-block small text-center mt-3 mb-5"> <span class="d-block small text-center mt-5 mb-5">
<span class="text-capitalize">{{notifier.title}}</span> Notifier created by <a :href="notifier.author_url" target="_blank">{{notifier.author}}</a> <span class="text-capitalize">{{notifier.title}}</span> Notifier created by <a :href="notifier.author_url" target="_blank">{{notifier.author}}</a>
</span> </span>
</form> </form>

9
frontend/src/icons.js Normal file
View File

@ -0,0 +1,9 @@
import {library} from '@fortawesome/fontawesome-svg-core'
import {fas} from '@fortawesome/fontawesome-free-solid';
import {fab} from '@fortawesome/free-brands-svg-icons';
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'
import Vue from "vue";
library.add(fas, fab)
Vue.component('font-awesome-icon', FontAwesomeIcon)

View File

@ -5,16 +5,11 @@ import VueApexCharts from 'vue-apexcharts'
import App from '@/App.vue' import App from '@/App.vue'
import store from './store' import store from './store'
import {library} from '@fortawesome/fontawesome-svg-core'
import {fas} from '@fortawesome/fontawesome-free-solid';
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'
import router from './routes' import router from './routes'
import "./mixin" import "./mixin"
import "./icons"
library.add(fas)
Vue.component('apexchart', VueApexCharts) Vue.component('apexchart', VueApexCharts)
Vue.component('font-awesome-icon', FontAwesomeIcon)
Vue.use(VueRouter); Vue.use(VueRouter);
Vue.use(require('vue-moment')); Vue.use(require('vue-moment'));

View File

@ -56,6 +56,36 @@ export default Vue.mixin({
loggedIn() { loggedIn() {
const core = this.$store.getters.core const core = this.$store.getters.core
return core.logged_in === true return core.logged_in === true
},
iconName(name) {
switch (name) {
case "fas fa-terminal":
return "terminal"
case "fab fa-discord":
return ["fab", "discord"]
case "far fa-envelope":
return "envelope"
case "far fa-bell":
return "bell"
case "fas fa-mobile-alt":
return "mobile"
case "fab fa-slack":
return ["fab", "slack-hash"]
case "fab fa-telegram-plane":
return ["fab", "telegram-plane"]
case "far fa-comment-alt":
return "comment"
case "fas fa-code-branch":
return "code-branch"
case "csv":
return "file"
case "docker":
return ["fab", "docker"]
case "traefik":
return "server"
default:
return "bars"
} }
},
} }
}); });

View File

@ -14,6 +14,15 @@
components: { components: {
TopNav, TopNav,
}, },
async mounted() {
if (this.$route.path !== "/login") {
try {
const u = await Api.users()
} catch (e) {
this.$router.push('/logout')
}
}
},
data () { data () {
return { return {
authenticated: false authenticated: false

View File

@ -2,7 +2,7 @@
<div class="container col-md-7 col-sm-12 mt-md-5 bg-light"> <div class="container col-md-7 col-sm-12 mt-md-5 bg-light">
<div class="col-10 offset-1 col-md-8 offset-md-2 mt-md-2"> <div class="col-10 offset-1 col-md-8 offset-md-2 mt-md-2">
<div class="col-12 col-md-8 offset-md-2 mb-4"> <div class="col-12 col-md-8 offset-md-2 mb-4">
<img class="col-12 mt-5 mt-md-0" src="/public/banner.png"> <img class="col-12 mt-5 mt-md-0" src="/banner.png">
</div> </div>
<FormLogin/> <FormLogin/>

View File

@ -5,20 +5,26 @@
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical"> <div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<h6 class="text-muted">Main Settings</h6> <h6 class="text-muted">Main Settings</h6>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-home-tab')}" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true"><i class="fa fa-cogs"></i> Settings</a> <a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-home-tab')}" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-style-tab')}" id="v-pills-style-tab" data-toggle="pill" href="#v-pills-style" role="tab" aria-controls="v-pills-style" aria-selected="false"><i class="fa fa-image"></i> Theme Editor</a> <font-awesome-icon icon="cog" class="mr-2"/> Settings
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-cache-tab')}" id="v-pills-cache-tab" data-toggle="pill" href="#v-pills-cache" role="tab" aria-controls="v-pills-cache" aria-selected="false"><i class="fa fa-paperclip"></i> Cache</a> </a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-style-tab')}" id="v-pills-style-tab" data-toggle="pill" href="#v-pills-style" role="tab" aria-controls="v-pills-style" aria-selected="false">
<font-awesome-icon icon="image" class="mr-2"/> Theme Editor
</a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-cache-tab')}" id="v-pills-cache-tab" data-toggle="pill" href="#v-pills-cache" role="tab" aria-controls="v-pills-cache" aria-selected="false">
<font-awesome-icon icon="paperclip" class="mr-2"/> Cache
</a>
<h6 class="mt-4 text-muted">Notifiers</h6> <h6 class="mt-4 text-muted">Notifiers</h6>
<a v-for="(notifier, index) in $store.getters.notifiers" v-bind:key="`${notifier.method}_${index}`" @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}" v-bind:id="`v-pills-${notifier.method.toLowerCase()}-tab`" data-toggle="pill" v-bind:href="`#v-pills-${notifier.method.toLowerCase()}`" role="tab" v-bind:aria-controls="`v-pills-${notifier.method.toLowerCase()}`" aria-selected="false"> <a v-for="(notifier, index) in $store.getters.notifiers" v-bind:key="`${notifier.method}_${index}`" @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}" v-bind:id="`v-pills-${notifier.method.toLowerCase()}-tab`" data-toggle="pill" v-bind:href="`#v-pills-${notifier.method.toLowerCase()}`" role="tab" v-bind:aria-controls="`v-pills-${notifier.method.toLowerCase()}`" aria-selected="false">
<i class="fas fa-terminal"></i> {{notifier.method}} <font-awesome-icon :icon="iconName(notifier.icon)" class="mr-2"/> {{notifier.method}}
</a> </a>
<h6 class="mt-4 text-muted">Integrations (beta)</h6> <h6 class="mt-4 text-muted">Integrations (beta)</h6>
<a v-for="(integration, index) in $store.getters.integrations" v-bind:key="`${integration.name}_${index}`" @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-integration-${integration.name}`)}" v-bind:id="`v-pills-integration-${integration.name}`" data-toggle="pill" v-bind:href="`#v-pills-integration-${integration.name}`" role="tab" :aria-controls="`v-pills-integration-${integration.name}`" aria-selected="false"> <a v-for="(integration, index) in $store.getters.integrations" v-bind:key="`${integration.name}_${index}`" @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-integration-${integration.name}`)}" v-bind:id="`v-pills-integration-${integration.name}`" data-toggle="pill" v-bind:href="`#v-pills-integration-${integration.name}`" role="tab" :aria-controls="`v-pills-integration-${integration.name}`" aria-selected="false">
<i class="fas fa-file-csv"></i> {{integration.full_name}} <font-awesome-icon :icon="iconName(integration.name)" class="mr-2"/> {{integration.full_name}}
</a> </a>
</div> </div>

View File

@ -126,7 +126,15 @@ export default new Vuex.Store({
window.console.log('finished loading required data') window.console.log('finished loading required data')
}, },
async loadAdmin (context) { async loadAdmin (context) {
await context.dispatch('loadRequired') const core = await Api.core()
context.commit("setCore", core);
const groups = await Api.groups()
context.commit("setGroups", groups);
const services = await Api.services()
context.commit("setServices", services);
const messages = await Api.messages()
context.commit("setMessages", messages)
context.commit("setHasPublicData", true)
const notifiers = await Api.notifiers() const notifiers = await Api.notifiers()
context.commit("setNotifiers", notifiers); context.commit("setNotifiers", notifiers);
const users = await Api.users() const users = await Api.users()

8410
frontend/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,9 @@
package handlers package handlers
import ( import (
"encoding/json"
"fmt"
"github.com/hunterlong/statping/core" "github.com/hunterlong/statping/core"
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
"html/template" "html/template"
"net/http" "net/http"
"reflect"
"time"
) )
var ( var (
@ -18,137 +12,19 @@ var (
var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap { var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap {
return template.FuncMap{ return template.FuncMap{
"js": func(html interface{}) template.JS {
return template.JS(utils.ToString(html))
},
"safe": func(html string) template.HTML {
return template.HTML(html)
},
"safeURL": func(u string) template.URL {
return template.URL(u)
},
"Auth": func() bool {
return IsFullAuthenticated(r)
},
"IsUser": func() bool {
return IsUser(r)
},
"VERSION": func() string { "VERSION": func() string {
return core.VERSION return core.VERSION
}, },
"CoreApp": func() *core.Core { "CoreApp": func() core.Core {
return core.CoreApp c := *core.CoreApp
}, if c.Name == "" {
"Services": func() []types.ServiceInterface { c.Name = "Statping"
return core.CoreApp.Services }
}, return c
"VisibleServices": func() []*core.Service {
auth := IsUser(r)
return core.SelectServices(auth)
},
"VisibleGroupServices": func(group *core.Group) []*core.Service {
auth := IsUser(r)
return group.VisibleServices(auth)
},
"Groups": func(includeAll bool) []*core.Group {
auth := IsUser(r)
return core.SelectGroups(includeAll, auth)
},
"Group": func(id int) *core.Group {
return core.SelectGroup(int64(id))
},
"len": func(g interface{}) int {
val := reflect.ValueOf(g)
return val.Len()
},
"IsNil": func(g interface{}) bool {
return g == nil
}, },
"USE_CDN": func() bool { "USE_CDN": func() bool {
return core.CoreApp.UseCdn.Bool return core.CoreApp.UseCdn.Bool
}, },
"UPDATENOTIFY": func() bool {
return core.CoreApp.UpdateNotify.Bool
},
"QrAuth": func() string {
return fmt.Sprintf("statping://setup?domain=%v&api=%v", core.CoreApp.Domain, core.CoreApp.ApiSecret)
},
"Type": func(g interface{}) []string {
fooType := reflect.TypeOf(g)
var methods []string
methods = append(methods, fooType.String())
for i := 0; i < fooType.NumMethod(); i++ {
method := fooType.Method(i)
fmt.Println(method.Name)
methods = append(methods, method.Name)
}
return methods
},
"ToJSON": func(g interface{}) template.HTML {
data, _ := json.Marshal(g)
return template.HTML(string(data))
},
"underscore": func(html string) string {
return utils.UnderScoreString(html)
},
"URL": func() string {
return basePath + r.URL.String()
},
"CHART_DATA": func() string {
return ""
},
"Error": func() string {
return ""
},
"Cache": func() Cacher {
return CacheStorage
},
"ToString": func(v interface{}) string {
return utils.ToString(v)
},
"Ago": func(t time.Time) string {
return utils.Timestamp(t).Ago()
},
"Duration": func(t time.Duration) string {
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", t.Seconds()))
return utils.FormatDuration(duration)
},
"ToUnix": func(t time.Time) int64 {
return t.UTC().Unix()
},
"ParseTime": func(t time.Time, format string) string {
return t.Format(format)
},
"FromUnix": func(t int64) string {
return utils.Timezoner(time.Unix(t, 0), core.CoreApp.Timezone).Format("Monday, January 02")
},
"UnixTime": func(t int64, nano bool) string {
if nano {
t = t / 1e9
}
return utils.Timezoner(time.Unix(t, 0), core.CoreApp.Timezone).String()
},
"ServiceLink": func(s *core.Service) string {
if s.Permalink.Valid {
return s.Permalink.String
}
return utils.ToString(s.Id)
},
"NewService": func() *types.Service {
return new(types.Service)
},
"NewUser": func() *types.User {
return new(types.User)
},
"NewCheckin": func() *types.Checkin {
return new(types.Checkin)
},
"NewMessage": func() *types.Message {
return new(types.Message)
},
"NewGroup": func() *types.Group {
return new(types.Group)
},
"BasePath": func() string { "BasePath": func() string {
return basePath return basePath
}, },

View File

@ -44,7 +44,7 @@ var (
httpServer *http.Server httpServer *http.Server
usingSSL bool usingSSL bool
mainTmpl = `{{define "main" }} {{ template "base" . }} {{ end }}` mainTmpl = `{{define "main" }} {{ template "base" . }} {{ end }}`
templates = []string{"base.gohtml", "head.gohtml", "nav.gohtml", "footer.gohtml", "scripts.gohtml", "form_service.gohtml", "form_notifier.gohtml", "form_integration.gohtml", "form_group.gohtml", "form_user.gohtml", "form_checkin.gohtml", "form_message.gohtml"} templates = []string{"base.gohtml"}
) )
// RunHTTPServer will start a HTTP server on a specific IP and port // RunHTTPServer will start a HTTP server on a specific IP and port

View File

@ -25,7 +25,7 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/setup", http.StatusSeeOther) http.Redirect(w, r, "/setup", http.StatusSeeOther)
return return
} }
ExecuteResponse(w, r, "index.html", core.CoreApp, nil) ExecuteResponse(w, r, "base.gohtml", core.CoreApp, nil)
} }
func healthCheckHandler(w http.ResponseWriter, r *http.Request) { func healthCheckHandler(w http.ResponseWriter, r *http.Request) {

View File

@ -1,11 +0,0 @@
{{ define "base" }}
<!doctype html>
<html lang="en">
{{block "head" .}} {{end}}
<body>
{{template "content" .}}
</body>
<footer>{{template "footer" .}}</footer>
{{template "scripts" .}}
</html>
{{end}}