mirror of https://github.com/statping/statping
450 lines
15 KiB
Vue
450 lines
15 KiB
Vue
<template>
|
|
<div class="container col-md-7 col-sm-12 mt-md-5 bg-light">
|
|
|
|
<div class="col-12 mb-4">
|
|
|
|
<span class="mt-3 mb-3 text-white d-md-none btn d-block d-md-none text-uppercase" :class="{'bg-success': service.online, 'bg-danger': !service.online}">
|
|
{{service.online ? $t('online') : $t('offline')}}
|
|
</span>
|
|
|
|
<h4 class="mt-2">
|
|
<router-link to="/" class="text-black-50 text-decoration-none">{{core.name}}</router-link> - <span class="text-muted">{{service.name}}</span>
|
|
<span class="badge float-right d-none d-md-block text-uppercase" :class="{'bg-success': service.online, 'bg-danger': !service.online}">
|
|
{{service.online ? $t('online') : $t('offline')}}
|
|
</span>
|
|
</h4>
|
|
|
|
<ServiceTopStats :service="service"/>
|
|
|
|
<MessageBlock v-for="message in messagesInRange" v-bind:key="message.id" :message="message"/>
|
|
|
|
<div class="card text-black-50 bg-white mt-3">
|
|
<div class="card-header text-capitalize">Timeframe</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-12 col-md-4 font-2">
|
|
<flatPickr :disabled="loading" @on-change="onnn" v-model="start_time" :config="{ enableTime: true, altInput: true, altFormat: 'Y-m-d h:i K', maxDate: new Date() }" type="text" class="btn btn-white text-left" required />
|
|
<small class="d-block">From {{this.format(new Date(start_time))}}</small>
|
|
</div>
|
|
<div class="col-12 col-md-4 font-2">
|
|
<flatPickr :disabled="loading" @on-change="onnn" v-model="end_time" :config="{ enableTime: true, altInput: true, altFormat: 'Y-m-d h:i K', maxDate: new Date()}" type="text" class="btn btn-white text-left" required />
|
|
<small class="d-block">To {{this.format(new Date(end_time))}}</small>
|
|
</div>
|
|
<div class="col-12 col-md-4">
|
|
<select :disabled="loading" @change="chartHits" v-model="group" class="form-control">
|
|
<option value="1m">1 Minute</option>
|
|
<option value="5m">5 Minutes</option>
|
|
<option value="15m">15 Minute</option>
|
|
<option value="30m">30 Minutes</option>
|
|
<option value="1h">1 Hour</option>
|
|
<option value="3h">3 Hours</option>
|
|
<option value="6h">6 Hours</option>
|
|
<option value="12h">12 Hours</option>
|
|
<option value="24h">1 Day</option>
|
|
<option value="168h">7 Days</option>
|
|
<option value="360h">15 Days</option>
|
|
</select>
|
|
<small class="d-block d-md-none d-block">Increment Timeframe</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<AdvancedChart :group="group" :updated="updated_chart" :start="start_time.toString()" :end="end_time.toString()" :service="service"/>
|
|
|
|
<div v-if="!loading" class="row">
|
|
<apexchart width="100%" height="120" type="rangeBar" :options="timeRangeOptions" :series="uptime_data"></apexchart>
|
|
</div>
|
|
|
|
<div class="card text-black-50 bg-white mb-3">
|
|
<div class="card-header text-capitalize">Service Failures</div>
|
|
<div class="card-body">
|
|
<div class="service-chart-heatmap mt-5 mb-4">
|
|
<ServiceHeatmap :service="service"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<script>
|
|
import Api from "../API"
|
|
const MessageBlock = () => import('@/components/Index/MessageBlock')
|
|
const ServiceFailures = () => import('@/components/Service/ServiceFailures')
|
|
const Checkin = () => import('@/forms/Checkin')
|
|
const ServiceHeatmap = () => import('@/components/Service/ServiceHeatmap')
|
|
const ServiceTopStats = () => import('@/components/Service/ServiceTopStats')
|
|
const AdvancedChart = () => import('@/components/Service/AdvancedChart')
|
|
|
|
import flatPickr from 'vue-flatpickr-component';
|
|
import 'flatpickr/dist/flatpickr.css';
|
|
const timeoptions = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };
|
|
|
|
const axisOptions = {
|
|
labels: {
|
|
show: true
|
|
},
|
|
crosshairs: {
|
|
show: false
|
|
},
|
|
lines: {
|
|
show: true
|
|
},
|
|
tooltip: {
|
|
enabled: false
|
|
},
|
|
axisTicks: {
|
|
show: true
|
|
},
|
|
grid: {
|
|
show: true
|
|
},
|
|
marker: {
|
|
show: false
|
|
}
|
|
};
|
|
|
|
export default {
|
|
name: 'Service',
|
|
components: {
|
|
AdvancedChart,
|
|
ServiceTopStats,
|
|
ServiceHeatmap,
|
|
ServiceFailures,
|
|
MessageBlock,
|
|
Checkin,
|
|
flatPickr
|
|
},
|
|
data() {
|
|
return {
|
|
tab: "failures",
|
|
authenticated: false,
|
|
ready: true,
|
|
group: "1h",
|
|
data: null,
|
|
uptime_data: null,
|
|
loading: true,
|
|
messages: [],
|
|
failures: [],
|
|
start_time: this.nowSubtract(84600 * 30),
|
|
end_time: this.nowSubtract(0),
|
|
timedata: null,
|
|
load_timedata: false,
|
|
dailyRangeOpts: {
|
|
chart: {
|
|
height: 500,
|
|
width: "100%",
|
|
type: "area",
|
|
}
|
|
},
|
|
timeRangeOptions: {
|
|
chart: {
|
|
id: 'uptime',
|
|
height: 120,
|
|
type: 'rangeBar',
|
|
toolbar: {
|
|
show: false
|
|
},
|
|
zoom: {
|
|
enabled: false
|
|
}
|
|
},
|
|
selection: {
|
|
enabled: true
|
|
},
|
|
zoom: {
|
|
enabled: true
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: true,
|
|
distributed: true,
|
|
dataLabels: {
|
|
hideOverflowingLabels: false
|
|
}
|
|
}
|
|
},
|
|
dataLabels: {
|
|
enabled: false
|
|
},
|
|
tooltip: {
|
|
enabled: false,
|
|
},
|
|
xaxis: {
|
|
type: 'datetime'
|
|
},
|
|
yaxis: {
|
|
show: false
|
|
},
|
|
grid: {
|
|
row: {
|
|
colors: ['#f3f4f5', '#fff'],
|
|
opacity: 1
|
|
}
|
|
}
|
|
},
|
|
chartOptions: {
|
|
noData: {
|
|
text: "Loading...",
|
|
align: 'center',
|
|
verticalAlign: 'middle',
|
|
offsetX: 0,
|
|
offsetY: -20,
|
|
style: {
|
|
color: "#bababa",
|
|
fontSize: '27px'
|
|
}
|
|
},
|
|
chart: {
|
|
id: 'mainchart',
|
|
events: {
|
|
dataPointSelection: (event, chartContext, config) => {
|
|
window.console.log('slect')
|
|
window.console.log(event)
|
|
},
|
|
updated: (chartContext, config) => {
|
|
window.console.log('updated')
|
|
},
|
|
beforeZoom: (chartContext, { xaxis }) => {
|
|
const start = (xaxis.min / 1000).toFixed(0)
|
|
const end = (xaxis.max / 1000).toFixed(0)
|
|
this.start_time = this.fromUnix(start)
|
|
this.end_time = this.fromUnix(end)
|
|
return {
|
|
xaxis: {
|
|
min: this.fromUnix(start),
|
|
max: this.fromUnix(end)
|
|
}
|
|
}
|
|
},
|
|
scrolled: (chartContext, { xaxis }) => {
|
|
window.console.log(xaxis)
|
|
},
|
|
},
|
|
height: 500,
|
|
width: "100%",
|
|
type: "area",
|
|
animations: {
|
|
enabled: true,
|
|
initialAnimation: {
|
|
enabled: true
|
|
}
|
|
},
|
|
selection: {
|
|
enabled: true
|
|
},
|
|
zoom: {
|
|
enabled: true
|
|
},
|
|
toolbar: {
|
|
show: true
|
|
},
|
|
stroke: {
|
|
show: false,
|
|
curve: 'smooth',
|
|
lineCap: 'butt',
|
|
},
|
|
},
|
|
xaxis: {
|
|
type: "datetime",
|
|
labels: {
|
|
show: true
|
|
},
|
|
tooltip: {
|
|
enabled: false
|
|
}
|
|
},
|
|
yaxis: {
|
|
labels: {
|
|
show: true
|
|
},
|
|
},
|
|
markers: {
|
|
size: 0,
|
|
strokeWidth: 0,
|
|
hover: {
|
|
size: undefined,
|
|
sizeOffset: 0
|
|
}
|
|
},
|
|
tooltip: {
|
|
theme: false,
|
|
enabled: true,
|
|
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
|
|
let ts = w.globals.seriesX[seriesIndex][dataPointIndex];
|
|
const dt = new Date(ts).toLocaleDateString("en-us", timeoptions)
|
|
let val = series[seriesIndex][dataPointIndex];
|
|
if (val >= 10000) {
|
|
val = Math.round(val / 1000) + " ms"
|
|
} else {
|
|
val = val + " μs"
|
|
}
|
|
return `<div class="chartmarker"><span>Response Time: </span><span class="font-3">${val}</span><span>${dt}</span></div>`
|
|
},
|
|
fixed: {
|
|
enabled: true,
|
|
position: 'topRight',
|
|
offsetX: -30,
|
|
offsetY: 40,
|
|
},
|
|
x: {
|
|
show: true,
|
|
|
|
},
|
|
y: {
|
|
formatter: undefined,
|
|
title: {
|
|
formatter: (seriesName) => seriesName,
|
|
},
|
|
},
|
|
},
|
|
legend: {
|
|
show: false,
|
|
},
|
|
dataLabels: {
|
|
enabled: false
|
|
},
|
|
floating: true,
|
|
axisTicks: {
|
|
show: true
|
|
},
|
|
axisBorder: {
|
|
show: false
|
|
},
|
|
fill: {
|
|
colors: ["#48d338"],
|
|
opacity: 1,
|
|
type: 'solid'
|
|
},
|
|
stroke: {
|
|
show: true,
|
|
curve: 'smooth',
|
|
lineCap: 'butt',
|
|
colors: ["#3aa82d"],
|
|
}
|
|
},
|
|
series: [{
|
|
data: []
|
|
}],
|
|
heatmap_data: [],
|
|
config: {
|
|
enableTime: true
|
|
},
|
|
}
|
|
},
|
|
computed: {
|
|
service () {
|
|
return this.$store.getters.serviceByAll(this.id)
|
|
},
|
|
core () {
|
|
return this.$store.getters.core
|
|
},
|
|
params () {
|
|
return {start: this.toUnix(new Date(this.start_time)), end: this.toUnix(new Date(this.end_time))}
|
|
},
|
|
id () {
|
|
return this.$route.params.id;
|
|
},
|
|
uptimeSeries () {
|
|
return this.timedata.series
|
|
},
|
|
mainChart () {
|
|
return [{
|
|
name: this.service.name,
|
|
...this.convertToChartData(this.data)
|
|
}]
|
|
},
|
|
messagesInRange() {
|
|
return this.$store.getters.serviceMessages(this.service.id).filter(m => this.inRange(m))
|
|
},
|
|
},
|
|
watch: {
|
|
service: function(n, o) {
|
|
this.onnn()
|
|
},
|
|
load_timedata: function(n, o) {
|
|
this.onnn()
|
|
}
|
|
},
|
|
async mounted() {
|
|
if (!this.$store.getters.service) {
|
|
const s = await Api.service(this.id)
|
|
this.$store.commit('setService', s)
|
|
}
|
|
},
|
|
methods: {
|
|
async updated_chart(start, end) {
|
|
this.start_time = start
|
|
this.end_time = end
|
|
this.loading = false
|
|
},
|
|
async onnn() {
|
|
this.loading = true
|
|
await this.chartHits()
|
|
await this.fetchUptime()
|
|
this.loading = false
|
|
},
|
|
async fetchUptime() {
|
|
const uptime = await Api.service_uptime(this.service.id, this.params.start, this.params.end)
|
|
window.console.log(uptime)
|
|
this.uptime_data = this.parse_uptime(uptime)
|
|
},
|
|
parse_uptime(timedata) {
|
|
const data = timedata.series.filter((g) => g.online) || []
|
|
const offData = timedata.series.filter((g) => !g.online) || []
|
|
let arr = [];
|
|
window.console.log(data)
|
|
if (data) {
|
|
data.forEach((d) => {
|
|
arr.push({
|
|
x: 'Online',
|
|
y: [
|
|
new Date(d.start).getTime(),
|
|
new Date(d.end).getTime()
|
|
],
|
|
fillColor: '#0db407'
|
|
})
|
|
})
|
|
}
|
|
if (offData) {
|
|
offData.forEach((d) => {
|
|
arr.push({
|
|
x: 'Offline',
|
|
y: [
|
|
new Date(d.start).getTime(),
|
|
new Date(d.end).getTime()
|
|
],
|
|
fillColor: '#b40707'
|
|
})
|
|
})
|
|
}
|
|
return [{data: arr}]
|
|
},
|
|
inRange(message) {
|
|
return this.isBetween(this.now(), message.start_on, message.start_on === message.end_on ? this.maxDate().toISOString() : message.end_on)
|
|
},
|
|
async getService() {
|
|
await this.chartHits()
|
|
await this.serviceFailures()
|
|
},
|
|
async serviceFailures() {
|
|
this.failures = await Api.service_failures(this.service.id, this.params.start, this.params.end)
|
|
},
|
|
async chartHits(start=0, end=99999999999) {
|
|
this.data = await Api.service_hits(this.service.id, this.params.start, this.params.end, this.group, false)
|
|
if (this.data.length === 0 && this.group !== "1h") {
|
|
this.group = "1h"
|
|
await this.chartHits("1h")
|
|
}
|
|
this.ready = true
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
<style scoped>
|
|
</style>
|