mirror of https://github.com/statping/statping
UI changes
parent
37303351d5
commit
d26faec077
|
@ -233,10 +233,6 @@ func ParseQueries(r *http.Request, o isObject) (*GroupQuery, error) {
|
|||
if endField == 0 {
|
||||
query.End = utils.Now()
|
||||
}
|
||||
if query.End.After(utils.Now()) {
|
||||
query.End = utils.Now()
|
||||
}
|
||||
|
||||
if query.Limit != 0 {
|
||||
q = q.Limit(query.Limit)
|
||||
}
|
||||
|
|
|
@ -52,17 +52,17 @@ class Api {
|
|||
return axios.post('api/services/' + data.id, data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async service_hits(id, start, end, group, fill=true) {
|
||||
async service_hits(id, start, end, group, fill = true) {
|
||||
return axios.get('api/services/' + id + '/hits_data?start=' + start + '&end=' + end + '&group=' + group + '&fill=' + fill).then(response => (response.data))
|
||||
}
|
||||
|
||||
async service_ping(id, start, end, group, fill=true) {
|
||||
return axios.get('api/services/' + id + '/ping_data?start=' + start + '&end=' + end + '&group=' + group + '&fill=' + fill).then(response => (response.data))
|
||||
}
|
||||
async service_ping(id, start, end, group, fill = true) {
|
||||
return axios.get('api/services/' + id + '/ping_data?start=' + start + '&end=' + end + '&group=' + group + '&fill=' + fill).then(response => (response.data))
|
||||
}
|
||||
|
||||
async service_failures_data(id, start, end, group, fill=true) {
|
||||
return axios.get('api/services/' + id + '/failure_data?start=' + start + '&end=' + end + '&group=' + group + '&fill=' + fill).then(response => (response.data))
|
||||
}
|
||||
async service_failures_data(id, start, end, group, fill = true) {
|
||||
return axios.get('api/services/' + id + '/failure_data?start=' + start + '&end=' + end + '&group=' + group + '&fill=' + fill).then(response => (response.data))
|
||||
}
|
||||
|
||||
async service_uptime(id, start, end) {
|
||||
return axios.get('api/services/' + id + '/uptime_data?start=' + start + '&end=' + end).then(response => (response.data))
|
||||
|
@ -73,7 +73,7 @@ class Api {
|
|||
}
|
||||
|
||||
async service_failures(id, start, end, limit = 999, offset = 0) {
|
||||
return axios.get('api/services/' + id + '/failures?start=' + start + '&end=' + end + '&limit=' + limit+ '&offset=' + offset).then(response => (response.data))
|
||||
return axios.get('api/services/' + id + '/failures?start=' + start + '&end=' + end + '&limit=' + limit + '&offset=' + offset).then(response => (response.data))
|
||||
}
|
||||
|
||||
async service_failures_delete(service) {
|
||||
|
@ -88,16 +88,16 @@ class Api {
|
|||
return axios.post('api/reorder/services', data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async checkins() {
|
||||
return axios.get('api/checkins').then(response => (response.data))
|
||||
}
|
||||
async checkins() {
|
||||
return axios.get('api/checkins').then(response => (response.data))
|
||||
}
|
||||
|
||||
async groups() {
|
||||
return axios.get('api/groups').then(response => (response.data))
|
||||
}
|
||||
|
||||
async groups_reorder(data) {
|
||||
window.console.log('api/reorder/groups', data)
|
||||
window.console.log('api/reorder/groups', data)
|
||||
return axios.post('api/reorder/groups', data).then(response => (response.data))
|
||||
}
|
||||
|
||||
|
@ -130,40 +130,40 @@ class Api {
|
|||
}
|
||||
|
||||
async incident_updates(incident) {
|
||||
return axios.get('api/incidents/'+incident.id+'/updates').then(response => (response.data))
|
||||
return axios.get('api/incidents/' + incident.id + '/updates').then(response => (response.data))
|
||||
}
|
||||
|
||||
async incident_update_create(update) {
|
||||
return axios.post('api/incidents/'+update.incident+'/updates', update).then(response => (response.data))
|
||||
return axios.post('api/incidents/' + update.incident + '/updates', update).then(response => (response.data))
|
||||
}
|
||||
|
||||
async incident_update_delete(update) {
|
||||
return axios.delete('api/incidents/'+update.incident+'/updates/'+update.id).then(response => (response.data))
|
||||
return axios.delete('api/incidents/' + update.incident + '/updates/' + update.id).then(response => (response.data))
|
||||
}
|
||||
|
||||
async incidents_service(id) {
|
||||
return axios.get('api/services/'+id+'/incidents').then(response => (response.data))
|
||||
}
|
||||
async incidents_service(id) {
|
||||
return axios.get('api/services/' + id + '/incidents').then(response => (response.data))
|
||||
}
|
||||
|
||||
async incident_create(service_id, data) {
|
||||
return axios.post('api/services/'+service_id+'/incidents', data).then(response => (response.data))
|
||||
}
|
||||
async incident_create(service_id, data) {
|
||||
return axios.post('api/services/' + service_id + '/incidents', data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async incident_delete(incident) {
|
||||
return axios.delete('api/incidents/'+incident.id).then(response => (response.data))
|
||||
}
|
||||
async incident_delete(incident) {
|
||||
return axios.delete('api/incidents/' + incident.id).then(response => (response.data))
|
||||
}
|
||||
|
||||
async checkin(api) {
|
||||
return axios.get('api/checkins/'+api).then(response => (response.data))
|
||||
return axios.get('api/checkins/' + api).then(response => (response.data))
|
||||
}
|
||||
|
||||
async checkin_create(data) {
|
||||
return axios.post('api/checkins', data).then(response => (response.data))
|
||||
}
|
||||
async checkin_create(data) {
|
||||
return axios.post('api/checkins', data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async checkin_delete(checkin) {
|
||||
return axios.delete('api/checkins/'+checkin.api_key).then(response => (response.data))
|
||||
}
|
||||
async checkin_delete(checkin) {
|
||||
return axios.delete('api/checkins/' + checkin.api_key).then(response => (response.data))
|
||||
}
|
||||
|
||||
async messages() {
|
||||
return axios.get('api/messages').then(response => (response.data))
|
||||
|
|
|
@ -113,7 +113,7 @@ A:HOVER {
|
|||
|
||||
.list-group-item:HOVER {
|
||||
background-color: lighten($group-list-background, 5%) !important;
|
||||
box-shadow: #00000014 0px 4px 4px 2px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px 1px;
|
||||
-webkit-transition-duration: 300ms;
|
||||
-moz-transition-duration: 300ms;
|
||||
-o-transition-duration: 300ms;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<div class="col-12 mt-4 mt-md-3">
|
||||
|
||||
<div class="row stats_area mb-5">
|
||||
<div class="col-4">
|
||||
<span class="font-6 font-weight-bold d-block">{{$store.getters.services.length}}</span>
|
||||
|
@ -34,27 +33,26 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<ServiceInfo v-for="(service, index) in services_no_group" v-bind:key="index" :service="service" />
|
||||
<div v-for="(service, index) in services_no_group" class="col-12 col-md-4">
|
||||
<ServiceInfo :service="service" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" v-for="group in groups">
|
||||
<h4 class="h4 col-12 mb-3 mt-2 text-dim"><font-awesome-icon icon="minus" class="mr-3"/> {{group.name}}</h4>
|
||||
<ServiceInfo v-if="group_services(group.id)" v-for="(service, index) in group_services(group.id)" v-bind:key="index" :service="service" />
|
||||
<div v-for="group in groups">
|
||||
<GroupedServices :group="group"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import isAfter from "date-fns/isAfter";
|
||||
import parseISO from "date-fns/parseISO";
|
||||
import isBefore from "date-fns/isBefore";
|
||||
|
||||
import GroupedServices from "@/components/Dashboard/GroupedServices";
|
||||
const ServiceInfo = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/ServiceInfo')
|
||||
|
||||
export default {
|
||||
name: 'DashboardIndex',
|
||||
components: {
|
||||
GroupedServices,
|
||||
ServiceInfo
|
||||
},
|
||||
data() {
|
||||
|
@ -77,9 +75,6 @@
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
group_services(id) {
|
||||
return this.$store.getters.servicesInGroup(id)
|
||||
},
|
||||
failuresLast24Hours() {
|
||||
let total = 0;
|
||||
this.services.map((s) => {
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<div class="row">
|
||||
<h5 v-if="group.name" class="h5 col-12 mb-3 mt-2 text-dim">
|
||||
<font-awesome-icon @click="toggle" :icon="expanded ? 'minus' : 'plus'" class="pointer mr-3"/> {{group.name}}
|
||||
<span class="badge badge-success text-uppercase float-right ml-2">{{services_online.length}} online</span>
|
||||
<span v-if="services_online.services_offline > 0" class="badge badge-danger text-uppercase float-right">
|
||||
{{services_offline.length}} offline
|
||||
</span>
|
||||
</h5>
|
||||
<div class="col-12 col-md-4" v-if="expanded" v-for="service in group_services">
|
||||
<ServiceInfo :service="service" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const ServiceInfo = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/ServiceInfo')
|
||||
|
||||
|
||||
export default {
|
||||
name: "GroupedServices",
|
||||
components: {
|
||||
ServiceInfo
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: true
|
||||
}
|
||||
},
|
||||
props: {
|
||||
group: {
|
||||
required: true,
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
services_online() {
|
||||
return this.$store.getters.servicesInGroup(this.group.id).filter((s) => s.online)
|
||||
},
|
||||
services_offline() {
|
||||
return this.$store.getters.servicesInGroup(this.group.id).filter((s) => !s.online)
|
||||
},
|
||||
group_services() {
|
||||
return this.$store.getters.servicesInGroup(this.group.id)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.expanded = !this.expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,26 +1,27 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="row p-2">
|
||||
<Loading :loading="!loaded"/>
|
||||
<div v-if="loaded && last_failure && failureBefore" class="text-danger font-2 p-0 m-0 mb-2">
|
||||
<div v-if="loaded && last_failure && failureBefore" class="col-12 text-danger font-2 m-0 mb-2">
|
||||
<font-awesome-icon icon="exclamation" class="mr-1 text-danger" size="1x"/> Recent Failure<br>
|
||||
<span class="font-italic d-inline-block text-dim" style="max-width: 270px">
|
||||
Last failure was {{ago(service.last_error)}} ago. {{last_failure.issue}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="loaded" v-for="message in messages" class="font-2 p-0 m-0 mb-2">
|
||||
<div v-if="loaded" v-for="message in messages" class="col-12 font-2 m-0 mb-2">
|
||||
<font-awesome-icon icon="calendar" class="mr-1" size="1x"/> Upcoming Announcement<br>
|
||||
<span class="font-italic font-weight-light text-dim">{{message.description}}</span>
|
||||
<span class="font-0 text-dim float-right font-weight-light mt-1">@ <strong>{{niceDate(message.start_on)}}</strong>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="loaded" v-for="incident in incidents" class="font-2 p-0 m-0 mb-2">
|
||||
|
||||
<div v-if="loaded" v-for="incident in incidents" class="col-12 font-2 m-0 mb-2">
|
||||
<font-awesome-icon icon="bullhorn" class="mr-1" size="1x"/>Recent Incident<br>
|
||||
<span class="font-italic d-inline-block text-dim" style="max-width: 270px">{{incident.title}} - {{incident.description}}</span>
|
||||
<span class="font-0 text-dim float-right font-weight-light mt-1">@ <strong>{{niceDate(incident.created_at)}}</strong></span>
|
||||
</div>
|
||||
|
||||
<div v-if="success_event && !failureBefore" class="font-2 p-0 m-0 mt-1 mb-3">
|
||||
<div v-if="success_event && !failureBefore" class="col-12 font-2 m-0 mb-2">
|
||||
<span class="text-success"><font-awesome-icon icon="check" class="mr-1" size="1x"/>No New Events</span>
|
||||
<span class="font-italic d-inline-block text-truncate text-dim" style="max-width: 270px">
|
||||
Last failure was {{ago(service.last_error)}} ago.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<template>
|
||||
<div class="col-4">
|
||||
<div class="dashboard_card card mb-4" :class="{'offline-card': !service.online}">
|
||||
<div class="card-header pb-1">
|
||||
<h6 v-observe-visibility="setVisible">
|
||||
|
@ -11,25 +10,23 @@
|
|||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<transition name="fade">
|
||||
<div v-if="loaded" class="row pl-2 pr-2">
|
||||
<div class="col-md-6 col-sm-12 mt-2 mt-md-0 mb-3 pl-0 pr-0">
|
||||
<div v-if="loaded" class="row pl-2">
|
||||
<div class="col-md-6 col-sm-12 pl-2 mt-2 mt-md-0 mb-3">
|
||||
<ServiceSparkLine :title="set2_name" subtitle="Latency Last 24 Hours" :series="set2"/>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12 mt-4 mt-md-0 mb-3">
|
||||
<div class="col-md-6 col-sm-12 pl-0 mt-4 mt-md-0 mb-3">
|
||||
<ServiceSparkLine :title="set1_name" subtitle="Latency Last 7 Days" :series="set1"/>
|
||||
</div>
|
||||
<ServiceEvents :service="service"/>
|
||||
</div>
|
||||
<div v-else class="row mb-5 pt-5 pb-5">
|
||||
<div class="col-6 text-center">
|
||||
<font-awesome-icon icon="circle-notch" class="text-dim" size="3x" spin/>
|
||||
<div v-else class="row mb-5">
|
||||
<div class="col-12 col-md-6 text-center">
|
||||
<font-awesome-icon icon="circle-notch" class="text-dim" size="2x" spin/>
|
||||
</div>
|
||||
<div class="col-6 text-center text-dim">
|
||||
<font-awesome-icon icon="circle-notch" class="text-dim" size="3x" spin/>
|
||||
<div class="col-12 col-md-6 text-center text-dim">
|
||||
<font-awesome-icon icon="circle-notch" class="text-dim" size="2x" spin/>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
|
||||
|
@ -62,7 +59,6 @@
|
|||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div>
|
||||
<div v-observe-visibility="{callback: visibleChart, once: true}" v-if="!loaded" class="row">
|
||||
<div class="col-12 text-center mt-3">
|
||||
<font-awesome-icon icon="circle-notch" class="text-dim" size="1x" spin/>
|
||||
<font-awesome-icon icon="circle-notch" class="text-dim" size="2x" spin/>
|
||||
</div>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
|
@ -77,8 +77,9 @@ export default {
|
|||
this.hover_text = `${e.date.toLocaleDateString()} - ${txt}`
|
||||
},
|
||||
async lastDaysFailures() {
|
||||
const start = this.nowSubtract(86400 * 90)
|
||||
const data = await Api.service_failures_data(this.service.id, this.toUnix(start), this.toUnix(this.now()), "24h", true)
|
||||
const start = this.beginningOf('day', this.nowSubtract(86400 * 90))
|
||||
const end = this.endOf('tomorrow')
|
||||
const data = await Api.service_failures_data(this.service.id, this.toUnix(start), this.toUnix(end), "24h", true)
|
||||
data.forEach((d) => {
|
||||
let date = this.parseISO(d.timeframe)
|
||||
this.failureData.push({month: date.getMonth(), day: date.getDate(), date: date, amount: d.amount})
|
||||
|
|
|
@ -58,7 +58,7 @@ export default Vue.mixin({
|
|||
return roundToNearestMinutes(minutes)
|
||||
},
|
||||
endOf(method, val) {
|
||||
switch (val) {
|
||||
switch (method) {
|
||||
case "day":
|
||||
return endOfDay(val)
|
||||
case "today":
|
||||
|
@ -73,7 +73,7 @@ export default Vue.mixin({
|
|||
return roundToNearestMinutes(val)
|
||||
},
|
||||
beginningOf(method, val) {
|
||||
switch (val) {
|
||||
switch (method) {
|
||||
case "day":
|
||||
return startOfDay(val)
|
||||
case "today":
|
||||
|
@ -106,6 +106,24 @@ export default Vue.mixin({
|
|||
return `Service has been offline for ${this.ago(s.last_success)}`
|
||||
}
|
||||
},
|
||||
round_time(frame, val) {
|
||||
switch(frame) {
|
||||
case "15m":
|
||||
return roundToNearestMinutes(val, {nearestTo: 60 * 15})
|
||||
case "30m":
|
||||
return roundToNearestMinutes(val, {nearestTo: 60 * 30})
|
||||
case "1h":
|
||||
return roundToNearestMinutes(val, {nearestTo: 3600})
|
||||
case "3h":
|
||||
return roundToNearestMinutes(val, {nearestTo: 3600 * 3})
|
||||
case "6h":
|
||||
return roundToNearestMinutes(val, {nearestTo: 3600 * 6})
|
||||
case "12h":
|
||||
return roundToNearestMinutes(val, {nearestTo: 3600 * 12})
|
||||
case "24h":
|
||||
return roundToNearestMinutes(val, {nearestTo: 3600 * 24})
|
||||
}
|
||||
},
|
||||
toUnix(val) {
|
||||
return getUnixTime(val)
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue