mirror of https://github.com/statping/statping
updates
parent
01cb463b88
commit
37d543d7ab
|
@ -50,8 +50,8 @@ func (s *Service) CreateFailure(f *types.Failure) (int64, error) {
|
|||
}
|
||||
|
||||
// AllFailures will return all failures attached to a service
|
||||
func (s *Service) AllFailures() []*Failure {
|
||||
var fails []*Failure
|
||||
func (s *Service) AllFailures() []*types.Failure {
|
||||
var fails []*types.Failure
|
||||
col := failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc")
|
||||
err := col.Find(&fails)
|
||||
if err.Error != nil {
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
"apexcharts": "^3.15.0",
|
||||
"axios": "^0.19.1",
|
||||
"core-js": "^3.4.4",
|
||||
"moment": "^2.24.0",
|
||||
"querystring": "^0.2.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-apexcharts": "^1.5.2",
|
||||
"vue-moment": "^4.1.0",
|
||||
"vue-router": "~3.0",
|
||||
"vuedraggable": "^2.23.2",
|
||||
"vuex": "^3.1.2"
|
||||
|
|
|
@ -28,10 +28,18 @@ class Api {
|
|||
return axios.get('/api/services/'+id+'/data?start=' + start + '&end=' + end + '&group=' + group).then(response => (response.data))
|
||||
}
|
||||
|
||||
async service_failures (id, start, end) {
|
||||
return axios.get('/api/services/'+id+'/failures?start=' + start + '&end=' + end).then(response => (response.data))
|
||||
}
|
||||
|
||||
async service_delete (id) {
|
||||
return axios.delete('/api/services/'+id).then(response => (response.data))
|
||||
}
|
||||
|
||||
async services_reorder (data) {
|
||||
return axios.post('/api/services/reorder', data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async groups () {
|
||||
return axios.get('/api/groups').then(response => (response.data))
|
||||
}
|
||||
|
@ -48,8 +56,8 @@ class Api {
|
|||
return axios.get('/api/users').then(response => (response.data))
|
||||
}
|
||||
|
||||
async user_create (id) {
|
||||
return axios.post('/api/users').then(response => (response.data))
|
||||
async user_create (data) {
|
||||
return axios.post('/api/users', data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async user_delete (id) {
|
||||
|
@ -72,6 +80,14 @@ class Api {
|
|||
return axios.get('/api/notifiers').then(response => (response.data))
|
||||
}
|
||||
|
||||
async notifier_save (data) {
|
||||
return axios.post('/api/notifier/'+data.method, data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async notifier_test (data) {
|
||||
return axios.post('/api/notifier/'+data.method+'/test', data).then(response => (response.data))
|
||||
}
|
||||
|
||||
async renewApiKeys () {
|
||||
return axios.get('/api/renew').then(response => (response.data))
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-for="(service, index) in $store.getters.services" v-bind:key="index">
|
||||
<div v-for="(service, index) in $store.getters.servicesInOrder()" v-bind:key="index">
|
||||
<ServiceInfo :service=service />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
<div>
|
||||
<div class="col-12">
|
||||
<h1 class="text-black-50">Services
|
||||
<router-link to="/service/create" class="btn btn-outline-success mt-1 float-right"><i class="fas fa-plus"></i> Create</router-link>
|
||||
<router-link to="/dashboard/create_service" class="btn btn-outline-success mt-1 float-right">
|
||||
<i class="fas fa-plus"></i> Create
|
||||
</router-link>
|
||||
</h1>
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
@ -31,34 +33,37 @@
|
|||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="sortable" id="services_table">
|
||||
|
||||
<tr v-for="(service, index) in $store.getters.services" v-bind:key="index">
|
||||
<draggable tag="tbody" :list="services" :key="services.length" class="sortable" handle=".drag_icon">
|
||||
<tr v-for="(service, index) in services" :key="index">
|
||||
<td>
|
||||
<span class="drag_icon d-none d-md-inline"><font-awesome-icon icon="bars" /></span> {{service.name}}
|
||||
<span class="drag_icon d-none d-md-inline">
|
||||
<font-awesome-icon icon="bars" />
|
||||
</span> {{service.name}}
|
||||
</td>
|
||||
<td class="d-none d-md-table-cell">
|
||||
<div v-if="service.online"><span class="badge badge-success">ONLINE</span><ToggleSwitch :next="stopChecking" :service="service"/></div>
|
||||
<div v-if="!service.online"><span class="badge badge-success">OFFLINE</span><ToggleSwitch :next="stopChecking" :service="service"/></div>
|
||||
<span class="badge" :class="{'badge-success': service.online, 'badge-danger': !service.online}">{{service.online ? "ONLINE" : "OFFLINE"}}</span>
|
||||
<ToggleSwitch :service="service"/>
|
||||
</td>
|
||||
<td class="d-none d-md-table-cell">
|
||||
<div v-if="service.public"><span class="badge badge-primary">PUBLIC</span></div>
|
||||
<div v-if="!service.public"><span class="badge badge-secondary">PRIVATE</span></div>
|
||||
<span class="badge" :class="{'badge-primary': service.public, 'badge-secondary': !service.public}">
|
||||
{{service.public ? "PUBLIC" : "PRIVATE"}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="d-none d-md-table-cell">
|
||||
<div v-if="service.group_id !== 0"><span class="badge badge-secondary">{{serviceGroup(service)}}</span></div>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<div class="btn-group">
|
||||
<router-link :to="{path: `/service/${service.id}`, params: {service: service} }" class="btn btn-outline-secondary"><i class="fas fa-chart-area"></i> View</router-link>
|
||||
<router-link :to="{path: `/dashboard/edit_service/${service.id}`, params: {service: service} }" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-chart-area"></i> View
|
||||
</router-link>
|
||||
<a @click="deleteService(service)" href="#" class="btn btn-danger">
|
||||
<font-awesome-icon icon="times" />
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</draggable>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
@ -75,8 +80,8 @@
|
|||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="sortable_groups" id="groups_table">
|
||||
|
||||
<draggable tag="tbody" v-model="groupsList" class="sortable_groups" handle=".drag_icon">
|
||||
<tr v-for="(group, index) in $store.getters.cleanGroups()" v-bind:key="index">
|
||||
<td><span class="drag_icon d-none d-md-inline"><font-awesome-icon icon="bars" /></span> {{group.name}}</td>
|
||||
<td>{{$store.getters.servicesInGroup(group.id).length}}</td>
|
||||
|
@ -94,7 +99,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</draggable>
|
||||
</table>
|
||||
|
||||
<h1 class="text-muted mt-5">Create Group</h1>
|
||||
|
@ -110,27 +115,64 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import FormGroup from "../../forms/Group";
|
||||
import Api from "../../components/API";
|
||||
import ToggleSwitch from "../../forms/ToggleSwitch";
|
||||
import FormGroup from "../../forms/Group";
|
||||
import Api from "../../components/API";
|
||||
import ToggleSwitch from "../../forms/ToggleSwitch";
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
export default {
|
||||
export default {
|
||||
name: 'DashboardServices',
|
||||
components: {
|
||||
ToggleSwitch,
|
||||
FormGroup
|
||||
FormGroup,
|
||||
draggable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
services: []
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
const services = await Api.services()
|
||||
this.$store.commit('setServices', services)
|
||||
this.services = this.$store.getters.servicesInOrder()
|
||||
},
|
||||
computed: {
|
||||
servicesList: {
|
||||
get() {
|
||||
return this.$store.getters.servicesInOrder()
|
||||
},
|
||||
async set(value) {
|
||||
let data = [];
|
||||
value.forEach((s, k) => {
|
||||
data.push({service: s.id, order: k+1})
|
||||
});
|
||||
alert(JSON.stringify(data))
|
||||
const ord = await Api.services_reorder(data)
|
||||
alert(JSON.parse(ord))
|
||||
}
|
||||
},
|
||||
groupsList: {
|
||||
get() {
|
||||
return this.$store.state.groups
|
||||
},
|
||||
async set(value) {
|
||||
let data = [];
|
||||
value.forEach((s, k) => {
|
||||
data.push({group: s.id, order: k+1})
|
||||
});
|
||||
alert(JSON.stringify(data))
|
||||
const ord = await Api.services_reorder(data)
|
||||
alert(JSON.parse(ord))
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
stopChecking(s) {
|
||||
alert(JSON.stringify(s))
|
||||
reordered_services() {
|
||||
|
||||
},
|
||||
serviceGroup(s) {
|
||||
let group = this.$store.getters.groupById(s.group_id)
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
<tr v-for="(user, index) in $store.getters.users" v-bind:key="index" >
|
||||
<td>{{user.username}}</td>
|
||||
<td class="text-right">
|
||||
<div class="btn-group"><font-awesome-icon icon="user-edit" />
|
||||
<a href="user/1" class="btn btn-outline-secondary"><i class="fas fa-user-edit"></i> Edit</a>
|
||||
<div class="btn-group">
|
||||
<a href="user/1" class="btn btn-outline-secondary"><font-awesome-icon icon="user" /> Edit</a>
|
||||
<a @click="deleteUser(user)" href="#" class="btn btn-danger"><font-awesome-icon icon="times" /></a>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -41,31 +41,14 @@
|
|||
components: {FormUser},
|
||||
data () {
|
||||
return {
|
||||
user: {
|
||||
username: "",
|
||||
admin: false,
|
||||
email: "",
|
||||
password: "",
|
||||
confirm_password: ""
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
async created() {
|
||||
const users = await Api.users()
|
||||
this.$store.commit('setUsers', users)
|
||||
},
|
||||
methods: {
|
||||
async saveUser(e) {
|
||||
e.preventDefault();
|
||||
let u = this.user;
|
||||
if (u.password === u.confirm_password) {
|
||||
alert("Both password do not match")
|
||||
return
|
||||
}
|
||||
const data = {name: this.group.name, public: this.group.public}
|
||||
await Api.user_create(data)
|
||||
const users = await Api.users()
|
||||
this.$store.commit('setUsers', users)
|
||||
},
|
||||
async deleteUser(u) {
|
||||
let c = confirm(`Are you sure you want to delete user '${u.username}'?`)
|
||||
if (c) {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<FormService v-if="ready" :in_service="service"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FormGroup from "../../forms/Group";
|
||||
import Api from "../../components/API";
|
||||
import ToggleSwitch from "../../forms/ToggleSwitch";
|
||||
import draggable from 'vuedraggable'
|
||||
import FormService from "../../forms/Service";
|
||||
|
||||
export default {
|
||||
name: 'EditService',
|
||||
components: {
|
||||
FormService,
|
||||
ToggleSwitch,
|
||||
FormGroup,
|
||||
draggable
|
||||
},
|
||||
props: {
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
ready: false,
|
||||
service: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
async beforeCreate() {
|
||||
if (this.$route.params.id) {
|
||||
this.service = await Api.service(this.$route.params.id)
|
||||
}
|
||||
this.ready = true
|
||||
},
|
||||
beforeMount() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -1,185 +0,0 @@
|
|||
<template>
|
||||
<div class="col-12">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form class="ajax_form" action="api/services" data-redirect="services" method="POST">
|
||||
<h4 class="mb-5 text-muted">Basic Information</h4>
|
||||
<div class="form-group row">
|
||||
<label for="service_name" class="col-sm-4 col-form-label">Service Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="name" class="form-control" id="service_name" value="" placeholder="Name" required spellcheck="false" autocorrect="off">
|
||||
<small class="form-text text-muted">Give your service a name you can recognize</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Service Type</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="type" class="form-control" id="service_type" value="" >
|
||||
<option value="http" >HTTP Service</option>
|
||||
<option value="tcp" >TCP Service</option>
|
||||
<option value="udp" >UDP Service</option>
|
||||
<option value="icmp" >ICMP Ping</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">Use HTTP if you are checking a website or use TCP if you are checking a server</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="domain" class="form-control" id="service_url" value="" placeholder="https://google.com" required autocapitalize="none" spellcheck="false">
|
||||
<small class="form-text text-muted">Statping will attempt to connect to this URL</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Group</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="group_id" class="form-control" id="group_id">
|
||||
<option value="0" selected>None</option>
|
||||
|
||||
<option value="1" >JSON Test Servers</option>
|
||||
|
||||
<option value="2" >Google Servers</option>
|
||||
|
||||
<option value="3" >Statping Servers</option>
|
||||
|
||||
</select>
|
||||
<small class="form-text text-muted">Attach this service to a group</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="mt-5 mb-5 text-muted">Request Details</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="service_check_type" class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="method" class="form-control" id="service_check_type" value="">
|
||||
<option value="GET" >GET</option>
|
||||
<option value="POST" >POST</option>
|
||||
<option value="DELETE" >DELETE</option>
|
||||
<option value="PATCH" >PATCH</option>
|
||||
<option value="PUT" >PUT</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">A GET request will simply request the endpoint, you can also send data with POST.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="post_data" class="col-sm-4 col-form-label">Optional Post Data (JSON)</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea name="post_data" class="form-control" id="post_data" rows="3" autocapitalize="none" spellcheck="false" placeholder='{"data": { "method": "success", "id": 148923 } }'></textarea>
|
||||
<small class="form-text text-muted">Insert a JSON string to send data to the endpoint.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="headers" class="col-sm-4 col-form-label">HTTP Headers</label>
|
||||
<div class="col-sm-8">
|
||||
<input name="headers" class="form-control" id="headers" autocapitalize="none" spellcheck="false" placeholder='Authorization=1010101,Content-Type=application/json' value="">
|
||||
<small class="form-text text-muted">Comma delimited list of HTTP Headers (KEY=VALUE,KEY=VALUE)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_response" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea name="expected" class="form-control" id="service_response" rows="3" autocapitalize="none" spellcheck="false" placeholder='(method)": "((\\"|[success])*)"'></textarea>
|
||||
<small class="form-text text-muted">You can use plain text or insert <a target="_blank" href="https://regex101.com/r/I5bbj9/1">Regex</a> to validate the response</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_response_code" class="col-sm-4 col-form-label">Expected Status Code</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="expected_status" class="form-control" value="200" placeholder="200" id="service_response_code">
|
||||
<small class="form-text text-muted">A status code of 200 is success, or view all the <a target="_blank" href="https://www.restapitutorial.com/httpstatuscodes.html">HTTP Status Codes</a></small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="port" class="col-sm-4 col-form-label">TCP Port</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="port" class="form-control" value="" id="service_port" placeholder="8080">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="mt-5 mb-5 text-muted">Additional Options</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="check_interval" class="form-control" value="60" min="1" id="service_interval" required>
|
||||
<small id="interval" class="form-text text-muted">10,000+ will be checked in Microseconds (1 millisecond = 1000 microseconds).</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_timeout" class="col-sm-4 col-form-label">Timeout in Seconds</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="timeout" class="form-control" value="15" placeholder="15" id="service_timeout" min="1">
|
||||
<small class="form-text text-muted">If the endpoint does not respond within this time it will be considered to be offline</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="post_data" class="col-sm-4 col-form-label">Permalink URL</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="permalink" class="form-control" value="" id="permalink" autocapitalize="none" spellcheck="true" placeholder='awesome_service'>
|
||||
<small class="form-text text-muted">Use text for the service URL rather than the service number.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="order" class="col-sm-4 col-form-label">List Order</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="order" class="form-control" min="0" value="0" id="order">
|
||||
<small class="form-text text-muted">You can also drag and drop services to reorder on the Services tab.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">Verify SSL</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="verify_ssl-option" class="switch" id="switch-verify-ssl" checked>
|
||||
<label for="switch-verify-ssl">Verify SSL Certificate for this service</label>
|
||||
<input type="hidden" name="verify_ssl" id="switch-verify-ssl-value" value="true">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">Notifications</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="allow_notifications-option" class="switch" id="switch-notifications" checked>
|
||||
<label for="switch-notifications">Allow notifications to be sent for this service</label>
|
||||
<input type="hidden" name="allow_notifications" id="switch-notifications-value" value="true">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">Visible</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="public-option" class="switch" id="switch-public" checked>
|
||||
<label for="switch-public">Show service details to the public</label>
|
||||
<input type="hidden" name="public" id="switch-public-value" value="true">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-success btn-block">Create Service</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ServiceForm',
|
||||
props: {
|
||||
service: Object
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -8,27 +8,27 @@
|
|||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a v-on:click="changeView('DashboardIndex', '/dashboard')" class="nav-link" href="#">Dashboard</a>
|
||||
<router-link to="/dashboard" class="nav-link">Dashboard</router-link>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a v-on:click="changeView('DashboardServices', '/dashboard/services')" class="nav-link" href="#">Services</a>
|
||||
<router-link to="/dashboard/services" class="nav-link">Services</router-link>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a v-on:click="changeView('DashboardUsers', '/dashboard/users')" class="nav-link" href="#">Users</a>
|
||||
<router-link to="/dashboard/users" class="nav-link">Users</router-link>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a v-on:click="changeView('DashboardMessages', '/dashboard/messages')" class="nav-link" href="#">Messages</a>
|
||||
<router-link to="/dashboard/messages" class="nav-link">Messages</router-link>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a v-on:click="changeView('Settings', '/dashboard/settings')" class="nav-link" href="#">Settings</a>
|
||||
<router-link to="/dashboard/settings" class="nav-link">Settings</router-link>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a v-on:click="changeView('Logs', '/dashboard/logs')" class="nav-link" href="#">Logs</a>
|
||||
<router-link to="/dashboard/logs" class="nav-link">Logs</router-link>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a v-on:click="changeView('DashboardIndex', '/dashboard/help')" class="nav-link" href="#">Help</a>
|
||||
<router-link to="/dashboard/help" class="nav-link">Help</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="navbar-text">
|
||||
|
@ -45,7 +45,7 @@
|
|||
export default {
|
||||
name: 'TopNav',
|
||||
props: {
|
||||
changeView: Function
|
||||
|
||||
},
|
||||
methods: {
|
||||
async logout () {
|
||||
|
|
|
@ -8,8 +8,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
import Dashboard from "../pages/Dashboard";
|
||||
|
||||
export default {
|
||||
name: 'Footer',
|
||||
components: {
|
||||
Dashboard
|
||||
},
|
||||
props: {
|
||||
version: String
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<apexchart width="500" type="line" :options="options" :series="series"></apexchart>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueApexCharts from 'vue-apexcharts'
|
||||
|
||||
Vue.component('apexchart', VueApexCharts)
|
||||
|
||||
export default {
|
||||
name: 'ServiceChart',
|
||||
props: {
|
||||
service: Object
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<ServiceChart service="service"/>
|
||||
<ServiceChart :service="service"/>
|
||||
</div>
|
||||
|
||||
<div class="row lower_canvas full-col-12 text-white">
|
||||
|
@ -50,7 +50,10 @@
|
|||
name: 'ServiceBlock',
|
||||
components: {ServiceChart},
|
||||
props: {
|
||||
service: Object
|
||||
service: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,34 @@
|
|||
<template>
|
||||
<div>{{data}}</div>
|
||||
<apexchart v-if="ready" width="100%" height="215" type="area" :options="chartOptions" :series="series"></apexchart>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "../../components/API"
|
||||
|
||||
const axisOptions = {
|
||||
labels: {
|
||||
show: false
|
||||
},
|
||||
crosshairs: {
|
||||
show: false
|
||||
},
|
||||
lines: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
axisTicks: {
|
||||
show: false
|
||||
},
|
||||
grid: {
|
||||
show: false
|
||||
},
|
||||
marker: {
|
||||
show: false
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'ServiceChart',
|
||||
props: {
|
||||
|
@ -18,39 +42,94 @@
|
|||
},
|
||||
methods: {
|
||||
async chartHits() {
|
||||
this.data = await Api.service_hits(this.props.service.id, 0, 99999999999, "minute")
|
||||
this.series = [this.data]
|
||||
this.data = await Api.service_hits(this.service.id, 0, 99999999999, "hour")
|
||||
this.series = [{
|
||||
name: this.service.name,
|
||||
...this.data
|
||||
}]
|
||||
this.ready = true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
ready: true,
|
||||
ready: false,
|
||||
data: null,
|
||||
chartOptions: {
|
||||
chart: {
|
||||
id: 'vuechart-example',
|
||||
height: 210,
|
||||
width: "100%",
|
||||
type: "area",
|
||||
animations: {
|
||||
enabled: true,
|
||||
initialAnimation: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
selection: {
|
||||
enabled: false
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
},
|
||||
toolbar: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
show: false,
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: -10,
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998],
|
||||
type: "datetime",
|
||||
...axisOptions
|
||||
},
|
||||
yaxis: {
|
||||
...axisOptions
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
marker: {
|
||||
show: false,
|
||||
},
|
||||
x: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
floating: true,
|
||||
axisTicks: {
|
||||
show: false
|
||||
},
|
||||
axisBorder: {
|
||||
show: false
|
||||
},
|
||||
fill: {
|
||||
colors: ["#48d338"],
|
||||
opacity: 1,
|
||||
type: 'solid'
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
curve: 'smooth',
|
||||
lineCap: 'butt',
|
||||
colors: ["#3aa82d"],
|
||||
}
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
name: 'Vue Chart',
|
||||
data: [30, 40, 45, 50, 49, 60, 70, 81]
|
||||
name: this.service.name,
|
||||
data: []
|
||||
}]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const max = 90;
|
||||
const min = 20;
|
||||
const newData = this.series[0].data.map(() => {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||
})
|
||||
// In the same way, update the series option
|
||||
this.series = [{
|
||||
data: newData
|
||||
}]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<form @submit="saveCheckin">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-3">
|
||||
<label for="checkin_interval" class="col-form-label">Checkin Name</label>
|
||||
<input v-model="checkin.name" type="text" name="name" class="form-control" id="checkin_name" placeholder="New Checkin">
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label for="checkin_interval" class="col-form-label">Interval (seconds)</label>
|
||||
<input v-model="checkin.interval" type="number" name="interval" class="form-control" id="checkin_interval" placeholder="60">
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label for="grace_period" class="col-form-label">Grace Period</label>
|
||||
<input v-model="checkin.grace" type="number" name="grace" class="form-control" id="grace_period" placeholder="10">
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button @click="saveCheckin" type="submit" id="submit" class="btn btn-success d-block" style="margin-top: 14px;">Save Checkin</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "../components/API";
|
||||
|
||||
export default {
|
||||
name: 'Checkin',
|
||||
props: {
|
||||
service: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
checkin: {
|
||||
name: "",
|
||||
interval: 60,
|
||||
grace: 60,
|
||||
service: this.service.id
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
async saveCheckin(e) {
|
||||
e.preventDefault();
|
||||
const data = {name: this.group.name, public: this.group.public}
|
||||
await Api.group_create(data)
|
||||
const groups = await Api.groups()
|
||||
this.$store.commit('setGroups', groups)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -69,7 +69,7 @@
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<button v-on:submit="saveSettings" type="submit" class="btn btn-primary btn-block">Save Settings</button>
|
||||
<button @click="saveSettings" type="submit" class="btn btn-primary btn-block">Save Settings</button>
|
||||
|
||||
<div class="form-group row mt-3">
|
||||
<label class="col-sm-3 col-form-label">API Key</label>
|
||||
|
@ -84,7 +84,7 @@
|
|||
<div class="col-sm-9">
|
||||
<input v-model="core.api_secret" type="text" class="form-control select-input" readonly>
|
||||
<small class="form-text text-muted">API Secret is used for read, create, update and delete routes</small>
|
||||
<small class="form-text text-muted">You can <a href="#" v-on:click="renewApiKeys">Regenerate API Keys</a> if you need to.</small>
|
||||
<small class="form-text text-muted">You can <a href="#" @click="renewApiKeys">Regenerate API Keys</a> if you need to.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<template>
|
||||
<form @submit="login">
|
||||
<div class="form-group row">
|
||||
<label for="username" class="col-sm-2 col-form-label">Username</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="username" name="username" class="form-control" id="username" placeholder="Username" autocorrect="off" autocapitalize="none">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-sm-2 col-form-label">Password</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" v-model="password" name="password" class="form-control" id="password" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-12">
|
||||
<button v-on:click="login" type="submit" class="btn btn-primary btn-block mb-3">Sign in</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "../components/API";
|
||||
|
||||
export default {
|
||||
name: 'FormLogin',
|
||||
props: {
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
username: "",
|
||||
password: "",
|
||||
auth: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
async login (e) {
|
||||
e.preventDefault();
|
||||
const auth = await Api.login(this.username, this.password)
|
||||
if (auth.token !== null) {
|
||||
this.auth = Api.saveToken(this.username, auth.token)
|
||||
this.$store.commit('setToken', auth)
|
||||
this.$router.push('/dashboard')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -1,15 +1,13 @@
|
|||
<template>
|
||||
<form class="ajax_form command">
|
||||
<form @submit="saveNotifier">
|
||||
<h4 class="text-capitalize">{{notifier.title}}</h4>
|
||||
<p class="small text-muted" v-html="notifier.description"></p>
|
||||
|
||||
<div v-for="(form, index) in notifier.form" v-bind:key="index" class="form-group">
|
||||
<label class="text-capitalize">{{form.title}}</label>
|
||||
|
||||
<input v-if="form.type === 'text' || 'number' || 'password'" v-model="notifier[notifier.field]" :type="form.type" class="form-control" :placeholder="form.placeholder" >
|
||||
<input v-if="form.type === 'text' || 'number' || 'password'" v-model="notifier[form.field]" :type="form.type" class="form-control" :placeholder="form.placeholder" >
|
||||
|
||||
<small class="form-text text-muted" v-html="form.small_text"></small>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
@ -18,7 +16,7 @@
|
|||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">Limit</div>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="limits" min="1" max="60" id="limits_per_hour_command" value="3" placeholder="7">
|
||||
<input v-model="notifier.limits" type="number" class="form-control" name="limits" min="1" max="60" placeholder="7">
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">Per Minute</div>
|
||||
</div>
|
||||
|
@ -27,18 +25,18 @@
|
|||
|
||||
<div class="col-3 col-sm-2 mt-1">
|
||||
<span class="switch">
|
||||
<input @change="notifier.enabled = !notifier.enabled" type="checkbox" name="enabled-option" class="switch" v-bind:id="`switch-${notifier.method}`" >
|
||||
<input @change="notifier.enabled = !notifier.enabled" type="checkbox" name="enabled-option" class="switch" v-model="notifier.enabled" v-bind:id="`switch-${notifier.method}`">
|
||||
<label v-bind:for="`switch-${notifier.method}`"></label>
|
||||
<input type="hidden" name="enabled" v-bind:id="`switch-${notifier.method}`">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-4 mb-2 mb-sm-0 mt-2 mt-sm-0">
|
||||
<button type="submit" class="btn btn-primary btn-block text-capitalize"><i class="fa fa-check-circle"></i> Save</button>
|
||||
<button @click="saveNotifier" type="submit" class="btn btn-primary btn-block text-capitalize"><i class="fa fa-check-circle"></i> Save</button>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-12">
|
||||
<button class="test_notifier btn btn-secondary btn-block text-capitalize col-12 float-right"><i class="fa fa-vial"></i> Test Notifier</button>
|
||||
<button @click="testNotifier" class="btn btn-secondary btn-block text-capitalize col-12 float-right"><i class="fa fa-vial"></i> Test Notifier</button>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-12 mt-2">
|
||||
|
@ -53,10 +51,10 @@
|
|||
</div>
|
||||
|
||||
<span class="d-block small text-center mt-3 mb-5">
|
||||
<span class="text-capitalize">{{notifier.title}}</span> Notifier created by <a :href="notifier.author_url" target="_blank">{{notifier.author}}</a>
|
||||
</span>
|
||||
<span class="text-capitalize">{{notifier.title}}</span> Notifier created by <a :href="notifier.author_url" target="_blank">{{notifier.author}}</a>
|
||||
</span>
|
||||
|
||||
<div class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
||||
<div v-if="error" class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
@ -73,21 +71,41 @@
|
|||
},
|
||||
data () {
|
||||
return {
|
||||
notifier: {
|
||||
|
||||
}
|
||||
error: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
async saveGroup(e) {
|
||||
async saveNotifier(e) {
|
||||
e.preventDefault();
|
||||
const data = {name: this.group.name, public: this.group.public}
|
||||
await Api.group_create(data)
|
||||
const groups = await Api.groups()
|
||||
this.$store.commit('setGroups', groups)
|
||||
let form = {}
|
||||
this.notifier.form.forEach((f) => {
|
||||
form[f.field] = this.notifier[f.field]
|
||||
});
|
||||
form.enabled = this.notifier.enabled
|
||||
form.limits = parseInt(this.notifier.limits)
|
||||
form.method = this.notifier.method
|
||||
await Api.notifier_save(form)
|
||||
const notifiers = await Api.notifiers()
|
||||
this.$store.commit('setNotifiers', notifiers)
|
||||
},
|
||||
async testNotifier(e) {
|
||||
e.preventDefault();
|
||||
let form = {}
|
||||
this.notifier.form.forEach((f) => {
|
||||
form[f.field] = this.notifier[f.field]
|
||||
});
|
||||
form.enabled = this.notifier.enabled
|
||||
form.limits = parseInt(this.notifier.limits)
|
||||
form.method = this.notifier.method
|
||||
const tested = await Api.notifier_test(form)
|
||||
if (tested === "ok") {
|
||||
alert('This notifier seems to be working!')
|
||||
} else {
|
||||
this.error = tested
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<form class="ajax_form" action="api/services" data-redirect="services" method="POST">
|
||||
<form @submit="saveService">
|
||||
<h4 class="mb-5 text-muted">Basic Information</h4>
|
||||
<div class="form-group row">
|
||||
<label for="service_name" class="col-sm-4 col-form-label">Service Name</label>
|
||||
<label class="col-sm-4 col-form-label">Service Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="name" class="form-control" id="service_name" value="" placeholder="Name" required spellcheck="false" autocorrect="off">
|
||||
<input v-model="service.name" @keypress="service.permalink=service.name.split(' ').join('_')" type="text" name="name" class="form-control" placeholder="Name" required spellcheck="false" autocorrect="off">
|
||||
<small class="form-text text-muted">Give your service a name you can recognize</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Service Type</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="type" class="form-control" id="service_type" value="" >
|
||||
<select v-model="service.type" class="form-control" id="service_type" >
|
||||
<option value="http" >HTTP Service</option>
|
||||
<option value="tcp" >TCP Service</option>
|
||||
<option value="udp" >UDP Service</option>
|
||||
|
@ -23,22 +23,16 @@
|
|||
<div class="form-group row">
|
||||
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="domain" class="form-control" id="service_url" value="" placeholder="https://google.com" required autocapitalize="none" spellcheck="false">
|
||||
<input v-model="service.domain" type="text" class="form-control" id="service_url" placeholder="https://google.com" required autocapitalize="none" spellcheck="false">
|
||||
<small class="form-text text-muted">Statping will attempt to connect to this URL</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Group</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="group_id" class="form-control" id="group_id">
|
||||
<option value="0" selected>None</option>
|
||||
|
||||
<option value="1" >JSON Test Servers</option>
|
||||
|
||||
<option value="2" >Google Servers</option>
|
||||
|
||||
<option value="3" >Statping Servers</option>
|
||||
|
||||
<select v-model="service.group_id" class="form-control">
|
||||
<option value="0" >No Group</option>
|
||||
<option v-for="(group, index) in $store.getters.cleanGroups()" :value="group.id">{{group.name}}</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">Attach this service to a group</small>
|
||||
</div>
|
||||
|
@ -46,10 +40,10 @@
|
|||
|
||||
<h4 class="mt-5 mb-5 text-muted">Request Details</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="service_check_type" class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="method" class="form-control" id="service_check_type" value="">
|
||||
<select v-model="service.method" name="method" class="form-control">
|
||||
<option value="GET" >GET</option>
|
||||
<option value="POST" >POST</option>
|
||||
<option value="DELETE" >DELETE</option>
|
||||
|
@ -59,38 +53,38 @@
|
|||
<small class="form-text text-muted">A GET request will simply request the endpoint, you can also send data with POST.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="post_data" class="col-sm-4 col-form-label">Optional Post Data (JSON)</label>
|
||||
<div v-if="service.type.match(/^(http)$/) && service.method.match(/^(POST|PATCH|DELETE|PUT)$/)" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Optional Post Data (JSON)</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea name="post_data" class="form-control" id="post_data" rows="3" autocapitalize="none" spellcheck="false" placeholder='{"data": { "method": "success", "id": 148923 } }'></textarea>
|
||||
<textarea v-model="service.post_data" class="form-control" rows="3" autocapitalize="none" spellcheck="false" placeholder='{"data": { "method": "success", "id": 148923 } }'></textarea>
|
||||
<small class="form-text text-muted">Insert a JSON string to send data to the endpoint.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="headers" class="col-sm-4 col-form-label">HTTP Headers</label>
|
||||
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">HTTP Headers</label>
|
||||
<div class="col-sm-8">
|
||||
<input name="headers" class="form-control" id="headers" autocapitalize="none" spellcheck="false" placeholder='Authorization=1010101,Content-Type=application/json' value="">
|
||||
<input v-model="service.headers" class="form-control" autocapitalize="none" spellcheck="false" placeholder='Authorization=1010101,Content-Type=application/json' value="">
|
||||
<small class="form-text text-muted">Comma delimited list of HTTP Headers (KEY=VALUE,KEY=VALUE)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_response" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea name="expected" class="form-control" id="service_response" rows="3" autocapitalize="none" spellcheck="false" placeholder='(method)": "((\\"|[success])*)"'></textarea>
|
||||
<textarea v-model="service.expected" class="form-control" rows="3" autocapitalize="none" spellcheck="false" placeholder='(method)": "((\\"|[success])*)"'></textarea>
|
||||
<small class="form-text text-muted">You can use plain text or insert <a target="_blank" href="https://regex101.com/r/I5bbj9/1">Regex</a> to validate the response</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
||||
<label for="service_response_code" class="col-sm-4 col-form-label">Expected Status Code</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="expected_status" class="form-control" value="200" placeholder="200" id="service_response_code">
|
||||
<input v-model="service.expected_status" type="number" name="expected_status" class="form-control" placeholder="200" id="service_response_code">
|
||||
<small class="form-text text-muted">A status code of 200 is success, or view all the <a target="_blank" href="https://www.restapitutorial.com/httpstatuscodes.html">HTTP Status Codes</a></small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="port" class="col-sm-4 col-form-label">TCP Port</label>
|
||||
<div v-if="service.type.match(/^(tcp|udp)$/)" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">TCP Port</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="port" class="form-control" value="" id="service_port" placeholder="8080">
|
||||
<input v-model="service.port" type="number" name="port" class="form-control" id="service_port" placeholder="8080">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -99,36 +93,36 @@
|
|||
<div class="form-group row">
|
||||
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="check_interval" class="form-control" value="60" min="1" id="service_interval" required>
|
||||
<input v-model="service.check_interval" type="number" class="form-control" value="60" min="1" id="service_interval" required>
|
||||
<small id="interval" class="form-text text-muted">10,000+ will be checked in Microseconds (1 millisecond = 1000 microseconds).</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_timeout" class="col-sm-4 col-form-label">Timeout in Seconds</label>
|
||||
<label class="col-sm-4 col-form-label">Timeout in Seconds</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="timeout" class="form-control" value="15" placeholder="15" id="service_timeout" min="1">
|
||||
<input v-model="service.timeout" type="number" name="timeout" class="form-control" value="15" placeholder="15" min="1">
|
||||
<small class="form-text text-muted">If the endpoint does not respond within this time it will be considered to be offline</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="post_data" class="col-sm-4 col-form-label">Permalink URL</label>
|
||||
<label class="col-sm-4 col-form-label">Permalink URL</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="permalink" class="form-control" value="" id="permalink" autocapitalize="none" spellcheck="true" placeholder='awesome_service'>
|
||||
<input v-model="service.permalink" type="text" name="permalink" class="form-control" value="" id="permalink" autocapitalize="none" spellcheck="true" placeholder='awesome_service'>
|
||||
<small class="form-text text-muted">Use text for the service URL rather than the service number.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<div class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">List Order</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="order" class="form-control" min="0" value="0" id="order">
|
||||
<input v-model="service.order" type="number" name="order" class="form-control" min="0" value="0" id="order">
|
||||
<small class="form-text text-muted">You can also drag and drop services to reorder on the Services tab.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">Verify SSL</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="verify_ssl-option" class="switch" id="switch-verify-ssl" checked>
|
||||
<input v-model="service.verify_ssl" type="checkbox" name="verify_ssl-option" class="switch" id="switch-verify-ssl" checked>
|
||||
<label for="switch-verify-ssl">Verify SSL Certificate for this service</label>
|
||||
<input type="hidden" name="verify_ssl" id="switch-verify-ssl-value" value="true">
|
||||
</span>
|
||||
|
@ -138,7 +132,7 @@
|
|||
<label for="order" class="col-sm-4 col-form-label">Notifications</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="allow_notifications-option" class="switch" id="switch-notifications" checked>
|
||||
<input v-model="service.allow_notifications" type="checkbox" name="allow_notifications-option" class="switch" id="switch-notifications" checked>
|
||||
<label for="switch-notifications">Allow notifications to be sent for this service</label>
|
||||
<input type="hidden" name="allow_notifications" id="switch-notifications-value" value="true">
|
||||
</span>
|
||||
|
@ -148,7 +142,7 @@
|
|||
<label for="order" class="col-sm-4 col-form-label">Visible</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="public-option" class="switch" id="switch-public" checked>
|
||||
<input v-model="service.public" type="checkbox" name="public-option" class="switch" id="switch-public" checked>
|
||||
<label for="switch-public">Show service details to the public</label>
|
||||
<input type="hidden" name="public" id="switch-public-value" value="true">
|
||||
</span>
|
||||
|
@ -156,19 +150,64 @@
|
|||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-success btn-block">Create Service</button>
|
||||
<button @click="saveService" type="submit" class="btn btn-success btn-block">Create Service</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
||||
|
||||
{{JSON.stringify(service)}}
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
import Api from "../components/API";
|
||||
|
||||
export default {
|
||||
name: 'FormService',
|
||||
data () {
|
||||
return {
|
||||
service: {
|
||||
name: "",
|
||||
type: "http",
|
||||
domain: "",
|
||||
group_id: 0,
|
||||
method: "GET",
|
||||
post_data: "",
|
||||
headers: "",
|
||||
expected: "",
|
||||
expected_status: 200,
|
||||
port: 80,
|
||||
check_interval: 60,
|
||||
timeout: 15,
|
||||
permalink: "",
|
||||
order: 0,
|
||||
verify_ssl: true,
|
||||
allow_notifications: true,
|
||||
public: true,
|
||||
},
|
||||
groups: [],
|
||||
}
|
||||
},
|
||||
props: {
|
||||
service: Object
|
||||
in_service: {
|
||||
type: Object,
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
if (this.in_service) {
|
||||
this.service = this.in_service
|
||||
}
|
||||
if (!this.$store.getters.groups) {
|
||||
const groups = await Api.groups()
|
||||
this.$store.commit('setGroups', groups)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveService(e) {
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
<template>
|
||||
<font-awesome-icon @click="toggleChecking" class="toggle-service text-success" icon="toggle-on" />
|
||||
<font-awesome-icon @click="toggleChecking" class="toggle-service" :class="{'text-success': running, 'text-muted': !running}" :icon="icon" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "../components/API";
|
||||
|
||||
export default {
|
||||
export default {
|
||||
name: 'ToggleSwitch',
|
||||
props: {
|
||||
next: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
service: {
|
||||
type: Object,
|
||||
required: true
|
||||
|
@ -19,19 +14,27 @@ export default {
|
|||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
icon: "toggle-on",
|
||||
running: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
if (this.service.online) {
|
||||
this.running = true
|
||||
this.icon = "toggle-on"
|
||||
} else {
|
||||
this.running = false
|
||||
this.icon = "toggle-off"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleChecking() {
|
||||
let c = confirm(`Are you sure you want to stop monitoring '${this.service.name}'?`)
|
||||
if (c) {
|
||||
|
||||
if (this.running) {
|
||||
this.icon = "toggle-off"
|
||||
} else {
|
||||
this.icon = "toggle-on"
|
||||
}
|
||||
this.props.next(this.props.service)
|
||||
this.running = !this.running
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,16 +66,13 @@
|
|||
|
||||
},
|
||||
methods: {
|
||||
saveUser (e) {
|
||||
async saveUser(e) {
|
||||
e.preventDefault();
|
||||
alert(JSON.stringify(this.user))
|
||||
},
|
||||
async saveGroup(e) {
|
||||
e.preventDefault();
|
||||
const data = {name: this.group.name, public: this.group.public}
|
||||
await Api.group_create(data)
|
||||
const groups = await Api.groups()
|
||||
this.$store.commit('setGroups', groups)
|
||||
let user = this.user
|
||||
delete user.confirm_password
|
||||
await Api.user_create(user)
|
||||
const users = await Api.users()
|
||||
this.$store.commit('setUsers', users)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,20 +8,22 @@ 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 DashboardIndex from "./components/Dashboard/DashboardIndex";
|
||||
import DashboardUsers from "./components/Dashboard/DashboardUsers";
|
||||
import DashboardServices from "./components/Dashboard/DashboardServices";
|
||||
import DashboardMessages from "./components/Dashboard/DashboardMessages";
|
||||
import Settings from "./pages/Settings";
|
||||
import EditService from "./components/Dashboard/EditService";
|
||||
import Dashboard from "./pages/Dashboard";
|
||||
import Index from "./pages/Index";
|
||||
import Login from "./pages/Login";
|
||||
import Service from "./pages/Service";
|
||||
|
||||
library.add(fas)
|
||||
|
||||
Vue.component('apexchart', VueApexCharts)
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
||||
|
||||
|
||||
const Index = () => import("@/pages/Index");
|
||||
const Dashboard = () => import("@/pages/Dashboard");
|
||||
const Login = () => import("@/pages/Login");
|
||||
const Settings = () => import("@/pages/Settings");
|
||||
const Services = () => import("@/pages/Services");
|
||||
const Service = () => import("@/pages/Service");
|
||||
|
||||
require("@/assets/css/bootstrap.min.css")
|
||||
require("@/assets/css/base.css")
|
||||
|
||||
|
@ -42,8 +44,34 @@ const routes = [
|
|||
path: '/dashboard',
|
||||
name: 'Dashboard',
|
||||
component: Dashboard,
|
||||
alias: ['/dashboard/settings', '/dashboard/services', '/dashboard/messages', '/dashboard/groups', '/dashboard/users', '/dashboard/logs', '/dashboard/help',
|
||||
'/service/create']
|
||||
children: [{
|
||||
path: '',
|
||||
component: DashboardIndex
|
||||
},{
|
||||
path: 'users',
|
||||
component: DashboardUsers
|
||||
},{
|
||||
path: 'services',
|
||||
component: DashboardServices
|
||||
},{
|
||||
path: 'create_service',
|
||||
component: EditService
|
||||
},{
|
||||
path: 'edit_service/:id',
|
||||
component: EditService
|
||||
},{
|
||||
path: 'messages',
|
||||
component: DashboardMessages
|
||||
},{
|
||||
path: 'settings',
|
||||
component: Settings
|
||||
},{
|
||||
path: 'logs',
|
||||
component: DashboardUsers
|
||||
},{
|
||||
path: 'help',
|
||||
component: DashboardUsers
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
|
@ -51,16 +79,6 @@ const routes = [
|
|||
component: Login
|
||||
},
|
||||
{ path: '/logout', redirect: '/' },
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'Settings',
|
||||
component: Settings
|
||||
},
|
||||
{
|
||||
path: '/services',
|
||||
name: 'Services',
|
||||
component: Services
|
||||
},
|
||||
{
|
||||
path: '/service/:id',
|
||||
name: 'Service',
|
||||
|
@ -75,6 +93,7 @@ const router = new VueRouter({
|
|||
})
|
||||
|
||||
Vue.use(VueRouter);
|
||||
Vue.use(require('vue-moment'));
|
||||
|
||||
Vue.config.productionTip = false
|
||||
new Vue({
|
||||
|
|
|
@ -1,106 +1,37 @@
|
|||
<template>
|
||||
<div>
|
||||
<Login v-show="$store.getters.token === null"/>
|
||||
<Login v-if="!authenticated"/>
|
||||
|
||||
<div v-show="$store.getters.token !== null" class="container col-md-7 col-sm-12 mt-md-5 bg-light">
|
||||
|
||||
<TopNav :changeView="changeView"/>
|
||||
|
||||
<DashboardIndex v-show="view === 'DashboardIndex'"/>
|
||||
|
||||
<DashboardServices v-show="view === 'DashboardServices'"/>
|
||||
|
||||
<DashboardUsers v-show="view === 'DashboardUsers'"/>
|
||||
|
||||
<DashboardMessages v-show="view === 'DashboardMessages'"/>
|
||||
|
||||
<Settings v-show="view === 'Settings'"/>
|
||||
|
||||
<ServiceForm v-show="view === 'ServiceForm'"/>
|
||||
|
||||
</div>
|
||||
<div v-if="authenticated" class="container col-md-7 col-sm-12 mt-md-5 bg-light">
|
||||
<TopNav/>
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "../components/API"
|
||||
import ServiceForm from '../components/Dashboard/ServiceForm';
|
||||
import Login from "./Login";
|
||||
import TopNav from "../components/Dashboard/TopNav";
|
||||
import DashboardIndex from "../components/Dashboard/DashboardIndex";
|
||||
import DashboardServices from "../components/Dashboard/DashboardServices";
|
||||
import DashboardUsers from "../components/Dashboard/DashboardUsers";
|
||||
import DashboardMessages from "../components/Dashboard/DashboardMessages";
|
||||
import Settings from "./Settings";
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
ServiceForm,
|
||||
Settings,
|
||||
DashboardMessages,
|
||||
DashboardUsers,
|
||||
DashboardServices,
|
||||
DashboardIndex,
|
||||
TopNav,
|
||||
Login,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
view: "DashboardIndex",
|
||||
authenticated: false
|
||||
authenticated: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.pathView(this.$route.path)
|
||||
this.isAuthenticated()
|
||||
mounted() {
|
||||
if (this.$store.getters.token !== null) {
|
||||
this.authenticated = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pathView (path) {
|
||||
switch (path) {
|
||||
case "/dashboard/settings":
|
||||
this.view = "Settings"
|
||||
break
|
||||
case "/dashboard/users":
|
||||
this.view = "DashboardUsers"
|
||||
break
|
||||
case "/dashboard/messages":
|
||||
this.view = "DashboardMessages"
|
||||
break
|
||||
case "/dashboard/services":
|
||||
this.view = "DashboardServices"
|
||||
break
|
||||
case "/service/create":
|
||||
this.view = "ServiceForm"
|
||||
break
|
||||
default:
|
||||
this.view = "DashboardIndex"
|
||||
}
|
||||
},
|
||||
changeView (v, name) {
|
||||
this.view = v
|
||||
this.$router.push('/'+name)
|
||||
},
|
||||
isAuthenticated () {
|
||||
const token = this.$store.getters.token
|
||||
if (token.token) {
|
||||
this.authenticated = true
|
||||
if (!this.$store.getters.hasAllData) {
|
||||
this.loadAllData()
|
||||
}
|
||||
}
|
||||
},
|
||||
async loadAllData () {
|
||||
const users = await Api.users()
|
||||
const groups = await Api.groups()
|
||||
const messages = await Api.messages()
|
||||
const notifiers = await Api.notifiers()
|
||||
this.$store.commit('setMessages', messages)
|
||||
this.$store.commit('setUsers', users)
|
||||
this.$store.commit('setGroups', groups)
|
||||
this.$store.commit('setNotifiers', notifiers)
|
||||
this.$store.commit('setHasAllData', true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -4,54 +4,24 @@
|
|||
<div class="col-12 col-md-8 offset-md-2 mb-4">
|
||||
<img class="col-12 mt-5 mt-md-0" src="../assets/banner.png">
|
||||
</div>
|
||||
<form id="login_form" @submit="login" method="post">
|
||||
<div class="form-group row">
|
||||
<label for="username" class="col-sm-2 col-form-label">Username</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="username" name="username" class="form-control" id="username" placeholder="Username" autocorrect="off" autocapitalize="none">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-sm-2 col-form-label">Password</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" v-model="password" name="password" class="form-control" id="password" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-12">
|
||||
<button v-on:click="login" type="submit" class="btn btn-primary btn-block mb-3">Sign in</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<FormLogin/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "../components/API"
|
||||
import FormLogin from "../forms/Login";
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
components: {
|
||||
|
||||
FormLogin
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
username: "",
|
||||
password: "",
|
||||
auth: null
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
async login (e) {
|
||||
e.preventDefault();
|
||||
const auth = await Api.login(this.username, this.password)
|
||||
if (auth.token !== null) {
|
||||
this.auth = Api.saveToken(this.username, auth.token)
|
||||
this.$store.commit('setToken', auth)
|
||||
this.$router.push('/dashboard')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
<template>
|
||||
<div class="container col-md-7 col-sm-12 mt-md-5 bg-light">
|
||||
|
||||
<TopNav/>
|
||||
<div v-if="ready" 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 bg-success d-block d-md-none">ONLINE</span>
|
||||
<span class="mt-3 mb-3 text-white d-md-none btn d-block d-md-none" :class="{'bg-success': service.online, 'bg-danger': !service.online}">
|
||||
{{service.online ? "ONLINE" : "OFFLINE"}}
|
||||
</span>
|
||||
|
||||
|
||||
<h4 class="mt-2"><a href="">{{service.name}}</a> - {{service.name}}
|
||||
|
||||
<span class="badge bg-success float-right d-none d-md-block">ONLINE</span>
|
||||
<h4 class="mt-2"><a href="/">{{$store.getters.core.name}}</a> - {{service.name}}
|
||||
<span class="badge float-right d-none d-md-block" :class="{'bg-success': service.online, 'bg-danger': !service.online}">
|
||||
{{service.online ? "ONLINE" : "OFFLINE"}}
|
||||
</span>
|
||||
</h4>
|
||||
|
||||
<div class="row stats_area mt-5 mb-5">
|
||||
<div class="col-4">
|
||||
<span class="lg_number">100%</span>
|
||||
<span class="lg_number">{{service.online_24_hours}}%</span>
|
||||
Online last 24 Hours
|
||||
</div>
|
||||
<div class="col-4">
|
||||
|
@ -28,11 +28,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="service-chart-container">
|
||||
<div id="service"></div>
|
||||
<div id="service-bar"></div>
|
||||
<apexchart width="100%" height="215" type="area" :options="chartOptions" :series="series"></apexchart>
|
||||
</div>
|
||||
|
||||
<div class="service-chart-heatmap">
|
||||
|
@ -49,191 +46,42 @@
|
|||
<div id="end_container"></div>
|
||||
</form>
|
||||
|
||||
|
||||
<nav class="nav nav-pills flex-column flex-sm-row mt-3" id="service_tabs" role="serviceLists">
|
||||
<a class="flex-sm-fill text-sm-center nav-link active" id="edit-tab" data-toggle="tab" href="#edit" role="tab" aria-controls="edit" aria-selected="false">Edit Service</a>
|
||||
<a class="flex-sm-fill text-sm-center nav-link" id="failures-tab" data-toggle="tab" href="#failures" role="tab" aria-controls="failures" aria-selected="true">Failures</a>
|
||||
<a class="flex-sm-fill text-sm-center nav-link disabled" id="incidents-tab" data-toggle="tab" href="#incidents" role="tab" aria-controls="incidents" aria-selected="true">Incidents</a>
|
||||
<a class="flex-sm-fill text-sm-center nav-link" id="checkins-tab" data-toggle="tab" href="#checkins" role="tab" aria-controls="checkins" aria-selected="false">Checkins</a>
|
||||
<a class="flex-sm-fill text-sm-center nav-link" id="response-tab" data-toggle="tab" href="#response" role="tab" aria-controls="response" aria-selected="false">Response</a>
|
||||
<nav class="nav nav-pills flex-column flex-sm-row mt-3" id="service_tabs">
|
||||
<a @click="tab='failures'" class="flex-sm-fill text-sm-center nav-link active">Failures</a>
|
||||
<a @click="tab='incidents'" class="flex-sm-fill text-sm-center nav-link">Incidents</a>
|
||||
<a @click="tab='checkins'" v-if="$store.getters.token.token" class="flex-sm-fill text-sm-center nav-link">Checkins</a>
|
||||
<a @click="tab='response'" v-if="$store.getters.token.token" class="flex-sm-fill text-sm-center nav-link">Response</a>
|
||||
</nav>
|
||||
<div class="tab-content" id="myTabContent">
|
||||
|
||||
<div class="tab-pane fade" id="failures" role="serviceLists" aria-labelledby="failures-tab">
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade active show">
|
||||
<div class="list-group mt-3 mb-4">
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div v-for="(failure, index) in failures" :key="index" class="mb-2 list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Incorrect HTTP Status Code</h5>
|
||||
<small>4 weeks ago</small>
|
||||
<h5 class="mb-1">{{failure.issue}}</h5>
|
||||
<small>{{failure.created_at | moment("dddd, MMMM Do YYYY")}}</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Status Code 502 did not match 200</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Error Get https://api.statping.com: dial tcp 162.248.92.36:443: connect: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Error Get https://api.statping.com: dial tcp 162.248.92.36:443: connect: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Error Get https://api.statping.com: dial tcp 162.248.92.36:443: connect: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Error Get https://api.statping.com: dial tcp 162.248.92.36:443: connect: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Error Get https://api.statping.com: dial tcp 162.248.92.36:443: connect: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Reset</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Error Get https://api.statping.com: read tcp 172.27.0.8:46586->162.248.92.36:443: read: connection reset by peer</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">Could not get IP address for domain https://api.statping.com, lookup api.statping.com on 127.0.0.11:53: read udp 127.0.0.1:50890->127.0.0.11:53: read: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">Could not get IP address for domain https://api.statping.com, lookup api.statping.com on 127.0.0.11:53: read udp 127.0.0.1:35222->127.0.0.11:53: read: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">Could not get IP address for domain https://api.statping.com, lookup api.statping.com on 127.0.0.11:53: read udp 127.0.0.1:49817->127.0.0.11:53: read: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Failed</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">Could not get IP address for domain https://api.statping.com, lookup api.statping.com on 127.0.0.11:53: read udp 127.0.0.1:57247->127.0.0.11:53: read: connection refused</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Reset</h5>
|
||||
<small>4 weeks ago</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Error Get https://api.statping.com: read tcp 172.27.0.10:52594->162.248.92.36:443: read: connection reset by peer</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Timed Out</h5>
|
||||
<small>Last month</small>
|
||||
</div>
|
||||
<p class="mb-1">Could not get IP address for domain https://api.statping.com, lookup api.statping.com on 127.0.0.11:53: read udp 127.0.0.1:51238->127.0.0.11:53: i/o timeout</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Connection Timed Out</h5>
|
||||
<small>Last month</small>
|
||||
</div>
|
||||
<p class="mb-1">Could not get IP address for domain https://api.statping.com, lookup api.statping.com on 127.0.0.11:53: read udp 127.0.0.1:47323->127.0.0.11:53: i/o timeout</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Incorrect HTTP Status Code</h5>
|
||||
<small>Last month</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Status Code 503 did not match 200</p>
|
||||
</a>
|
||||
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Incorrect HTTP Status Code</h5>
|
||||
<small>Last month</small>
|
||||
</div>
|
||||
<p class="mb-1">HTTP Status Code 503 did not match 200</p>
|
||||
</a>
|
||||
|
||||
<p class="mb-1">{{failure.issue}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" :class="{active: tab === 'incidents'}" id="incidents">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="incidents" role="serviceLists" aria-labelledby="incidents-tab">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="checkins" role="serviceLists" aria-labelledby="checkins-tab">
|
||||
|
||||
|
||||
<div class="tab-pane fade" :class="{show: tab === 'checkins'}" id="checkins">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form class="ajax_form" action="api/checkin" data-redirect="/service/7" method="POST">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-3">
|
||||
<label for="checkin_interval" class="col-form-label">Checkin Name</label>
|
||||
<input type="text" name="name" class="form-control" id="checkin_name" placeholder="New Checkin">
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label for="checkin_interval" class="col-form-label">Interval (seconds)</label>
|
||||
<input type="number" name="interval" class="form-control" id="checkin_interval" placeholder="60">
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label for="grace_period" class="col-form-label">Grace Period</label>
|
||||
<input type="number" name="grace" class="form-control" id="grace_period" placeholder="10">
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label for="submit" class="col-form-label"></label>
|
||||
<input type="hidden" name="service_id" class="form-control" id="service_id" value="7">
|
||||
<button type="submit" id="submit" class="btn btn-success d-block" style="margin-top: 14px;">Save Checkin</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<Checkin :service="service"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="response" role="serviceLists" aria-labelledby="response-tab">
|
||||
<div class="tab-pane fade" :class="{show: tab === 'response'}" id="response">
|
||||
<div class="col-12 mt-4">
|
||||
<h3>Last Response</h3>
|
||||
<textarea rows="8" class="form-control" readonly>invalid route</textarea>
|
||||
|
@ -246,183 +94,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade show active" id="edit" role="serviceLists" aria-labelledby="edit-tab">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<form class="ajax_form" action="api/services/7" data-redirect="services" method="POST">
|
||||
<h4 class="mb-5 text-muted">Basic Information</h4>
|
||||
<div class="form-group row">
|
||||
<label for="service_name" class="col-sm-4 col-form-label">Service Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="name" class="form-control" id="service_name" value="Statping API" placeholder="Name" required spellcheck="false" autocorrect="off">
|
||||
<small class="form-text text-muted">Give your service a name you can recognize</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Service Type</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="type" class="form-control" id="service_type" value="http" readonly>
|
||||
<option value="http" selected>HTTP Service</option>
|
||||
<option value="tcp" >TCP Service</option>
|
||||
<option value="udp" >UDP Service</option>
|
||||
<option value="icmp" >ICMP Ping</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">Use HTTP if you are checking a website or use TCP if you are checking a server</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="domain" class="form-control" id="service_url" value="https://api.statping.com" placeholder="https://google.com" required autocapitalize="none" spellcheck="false">
|
||||
<small class="form-text text-muted">Statping will attempt to connect to this URL</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Group</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="group_id" class="form-control" id="group_id">
|
||||
<option value="0" >None</option>
|
||||
|
||||
<option value="1" >JSON Test Servers</option>
|
||||
|
||||
<option value="2" >Google Servers</option>
|
||||
|
||||
<option value="3" selected>Statping Servers</option>
|
||||
|
||||
</select>
|
||||
<small class="form-text text-muted">Attach this service to a group</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="mt-5 mb-5 text-muted">Request Details</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="service_check_type" class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="method" class="form-control" id="service_check_type" value="GET">
|
||||
<option value="GET" selected>GET</option>
|
||||
<option value="POST" >POST</option>
|
||||
<option value="DELETE" >DELETE</option>
|
||||
<option value="PATCH" >PATCH</option>
|
||||
<option value="PUT" >PUT</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">A GET request will simply request the endpoint, you can also send data with POST.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="post_data" class="col-sm-4 col-form-label">Optional Post Data (JSON)</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea name="post_data" class="form-control" id="post_data" rows="3" autocapitalize="none" spellcheck="false" placeholder='{"data": { "method": "success", "id": 148923 } }'></textarea>
|
||||
<small class="form-text text-muted">Insert a JSON string to send data to the endpoint.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="headers" class="col-sm-4 col-form-label">HTTP Headers</label>
|
||||
<div class="col-sm-8">
|
||||
<input name="headers" class="form-control" id="headers" autocapitalize="none" spellcheck="false" placeholder='Authorization=1010101,Content-Type=application/json' value="">
|
||||
<small class="form-text text-muted">Comma delimited list of HTTP Headers (KEY=VALUE,KEY=VALUE)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_response" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea name="expected" class="form-control" id="service_response" rows="3" autocapitalize="none" spellcheck="false" placeholder='(method)": "((\\"|[success])*)"'></textarea>
|
||||
<small class="form-text text-muted">You can use plain text or insert <a target="_blank" href="https://regex101.com/r/I5bbj9/1">Regex</a> to validate the response</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_response_code" class="col-sm-4 col-form-label">Expected Status Code</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="expected_status" class="form-control" value="200" placeholder="200" id="service_response_code">
|
||||
<small class="form-text text-muted">A status code of 200 is success, or view all the <a target="_blank" href="https://www.restapitutorial.com/httpstatuscodes.html">HTTP Status Codes</a></small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="port" class="col-sm-4 col-form-label">TCP Port</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="port" class="form-control" value="" id="service_port" placeholder="8080">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="mt-5 mb-5 text-muted">Additional Options</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="check_interval" class="form-control" value="60" min="1" id="service_interval" required>
|
||||
<small id="interval" class="form-text text-muted">10,000+ will be checked in Microseconds (1 millisecond = 1000 microseconds).</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_timeout" class="col-sm-4 col-form-label">Timeout in Seconds</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="timeout" class="form-control" value="15" placeholder="15" id="service_timeout" min="1">
|
||||
<small class="form-text text-muted">If the endpoint does not respond within this time it will be considered to be offline</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="post_data" class="col-sm-4 col-form-label">Permalink URL</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="permalink" class="form-control" value="" id="permalink" autocapitalize="none" spellcheck="true" placeholder='awesome_service'>
|
||||
<small class="form-text text-muted">Use text for the service URL rather than the service number.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row d-none">
|
||||
<label for="order" class="col-sm-4 col-form-label">List Order</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="order" class="form-control" min="0" value="0" id="order">
|
||||
<small class="form-text text-muted">You can also drag and drop services to reorder on the Services tab.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">Verify SSL</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="verify_ssl-option" class="switch" id="switch-verify-ssl" >
|
||||
<label for="switch-verify-ssl">Verify SSL Certificate for this service</label>
|
||||
<input type="hidden" name="verify_ssl" id="switch-verify-ssl-value" value="false">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">Notifications</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="allow_notifications-option" class="switch" id="switch-notifications" checked>
|
||||
<label for="switch-notifications">Allow notifications to be sent for this service</label>
|
||||
<input type="hidden" name="allow_notifications" id="switch-notifications-value" value="true">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="order" class="col-sm-4 col-form-label">Visible</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span class="switch float-left">
|
||||
<input type="checkbox" name="public-option" class="switch" id="switch-public" checked>
|
||||
<label for="switch-public">Show service details to the public</label>
|
||||
<input type="hidden" name="public" id="switch-public-value" value="true">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-6">
|
||||
<button type="submit" class="btn btn-success btn-block">Update Service</button>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<a href="service/7/delete_failures" data-method="GET" data-redirect="/service/7" class="btn btn-danger btn-block confirm-btn">Delete All Failures</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -432,32 +103,148 @@
|
|||
|
||||
<script>
|
||||
import Api from "../components/API"
|
||||
import TopNav from "../components/Dashboard/TopNav";
|
||||
import Checkin from "../forms/Checkin";
|
||||
|
||||
export default {
|
||||
const axisOptions = {
|
||||
labels: {
|
||||
show: false
|
||||
},
|
||||
crosshairs: {
|
||||
show: false
|
||||
},
|
||||
lines: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
axisTicks: {
|
||||
show: true
|
||||
},
|
||||
grid: {
|
||||
show: true
|
||||
},
|
||||
marker: {
|
||||
show: false
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'Service',
|
||||
components: {
|
||||
TopNav
|
||||
Checkin
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
id: null,
|
||||
tab: "failures",
|
||||
service: null,
|
||||
authenticated: false,
|
||||
ready: false,
|
||||
data: null,
|
||||
failures: [],
|
||||
chartOptions: {
|
||||
chart: {
|
||||
height: 500,
|
||||
width: "100%",
|
||||
type: "area",
|
||||
animations: {
|
||||
enabled: true,
|
||||
initialAnimation: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
selection: {
|
||||
enabled: false
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
},
|
||||
toolbar: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
show: true,
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: -10,
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
type: "datetime",
|
||||
...axisOptions
|
||||
},
|
||||
yaxis: {
|
||||
...axisOptions
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
marker: {
|
||||
show: false,
|
||||
},
|
||||
x: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
floating: true,
|
||||
axisTicks: {
|
||||
show: false
|
||||
},
|
||||
axisBorder: {
|
||||
show: false
|
||||
},
|
||||
fill: {
|
||||
colors: ["#48d338"],
|
||||
opacity: 1,
|
||||
type: 'solid'
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
curve: 'smooth',
|
||||
lineCap: 'butt',
|
||||
colors: ["#3aa82d"],
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
data: []
|
||||
}]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.service = this.$route.params.service
|
||||
this.id = this.$route.params.id
|
||||
if (!this.service) {
|
||||
this.getService(this.id)
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
created() {
|
||||
this.service = this.$route.params.service
|
||||
this.id = this.$route.params.id
|
||||
if (!this.service) {
|
||||
this.getService(this.id)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
async getService(id) {
|
||||
this.service = await Api.service(id)
|
||||
await this.chartHits()
|
||||
await this.serviceFailures()
|
||||
},
|
||||
async serviceFailures() {
|
||||
this.failures = await Api.service_failures(this.service.id, 0, 99999999999)
|
||||
},
|
||||
async chartHits() {
|
||||
this.data = await Api.service_hits(this.service.id, 0, 99999999999, "hour")
|
||||
this.series = [{
|
||||
name: this.service.name,
|
||||
...this.data
|
||||
}]
|
||||
this.ready = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,13 +251,11 @@
|
|||
|
||||
<button type="submit" class="btn btn-block btn-info fetch_integrator">Fetch Services</button>
|
||||
|
||||
<div class="alert alert-danger d-none" id="integration_alerter" role="alert"></div>
|
||||
<div class="alert alert-danger d-none" role="alert"></div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="tab-pane fade" id="v-pills-browse" role="tabpanel" aria-labelledby="v-pills-browse-tab">
|
||||
|
||||
</div>
|
||||
|
@ -277,6 +275,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Api from '../components/API';
|
||||
import CoreSettings from '../forms/CoreSettings';
|
||||
import Notifier from "../forms/Notifier";
|
||||
|
||||
|
@ -284,16 +283,18 @@
|
|||
name: 'Settings',
|
||||
components: {
|
||||
Notifier,
|
||||
CoreSettings
|
||||
|
||||
CoreSettings
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tab: "v-pills-home-tab",
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
async created() {
|
||||
const core = await Api.core()
|
||||
this.$store.commit('setCore', core)
|
||||
const notifiers = await Api.notifiers()
|
||||
this.$store.commit('setNotifiers', notifiers)
|
||||
},
|
||||
beforeMount() {
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Vuex from 'vuex'
|
||||
import Vue from 'vue'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export const HAS_ALL_DATA = 'HAS_ALL_DATA'
|
||||
|
@ -45,6 +46,9 @@ export default new Vuex.Store({
|
|||
servicesInGroup: (state) => (id) => {
|
||||
return state.services.filter(s => s.group_id === id)
|
||||
},
|
||||
servicesInOrder: (state) => () => {
|
||||
return state.services.sort((a, b) => a.order_id - b.order_id)
|
||||
},
|
||||
onlineServices: (state) => (online) => {
|
||||
return state.services.filter(s => s.online === online)
|
||||
},
|
||||
|
|
|
@ -2605,7 +2605,7 @@ debug@=3.1.0:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
|
||||
debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
|
@ -2648,11 +2648,6 @@ deep-equal@^1.0.1:
|
|||
object-keys "^1.1.1"
|
||||
regexp.prototype.flags "^1.2.0"
|
||||
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||
|
||||
deep-is@~0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
|
@ -2747,11 +2742,6 @@ detect-file@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
|
||||
integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
|
||||
|
||||
detect-libc@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
|
||||
|
||||
detect-node@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
|
||||
|
@ -3654,13 +3644,6 @@ from2@^2.1.0:
|
|||
inherits "^2.0.1"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
fs-minipass@^1.2.5:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
|
||||
integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
|
||||
dependencies:
|
||||
minipass "^2.6.0"
|
||||
|
||||
fs-write-stream-atomic@^1.0.8:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
|
||||
|
@ -4125,7 +4108,7 @@ https-browserify@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
|
@ -4154,13 +4137,6 @@ iferr@^0.1.5:
|
|||
resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
|
||||
integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
|
||||
|
||||
ignore-walk@^3.0.1:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37"
|
||||
integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==
|
||||
dependencies:
|
||||
minimatch "^3.0.4"
|
||||
|
||||
ignore@^3.0.11:
|
||||
version "3.3.10"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
|
||||
|
@ -4245,7 +4221,7 @@ inherits@2.0.3:
|
|||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
ini@^1.3.4, ini@~1.3.0:
|
||||
ini@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||
|
@ -5149,21 +5125,6 @@ minimist@^1.1.3, minimist@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
|
||||
integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
|
||||
dependencies:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
|
||||
minizlib@^1.2.1:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
|
||||
integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
|
||||
dependencies:
|
||||
minipass "^2.9.0"
|
||||
|
||||
mississippi@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f"
|
||||
|
@ -5219,6 +5180,11 @@ mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd
|
|||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
moment@^2.19.2, moment@^2.24.0:
|
||||
version "2.24.0"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
|
||||
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
|
||||
|
||||
move-concurrently@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
||||
|
@ -5291,15 +5257,6 @@ natural-compare@^1.4.0:
|
|||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
needle@^2.2.1:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
|
||||
integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
|
||||
dependencies:
|
||||
debug "^3.2.6"
|
||||
iconv-lite "^0.4.4"
|
||||
sax "^1.2.4"
|
||||
|
||||
negotiator@0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||
|
@ -5383,22 +5340,6 @@ node-libs-browser@^2.0.0, node-libs-browser@^2.2.1:
|
|||
util "^0.11.0"
|
||||
vm-browserify "^1.0.1"
|
||||
|
||||
node-pre-gyp@*:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83"
|
||||
integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==
|
||||
dependencies:
|
||||
detect-libc "^1.0.2"
|
||||
mkdirp "^0.5.1"
|
||||
needle "^2.2.1"
|
||||
nopt "^4.0.1"
|
||||
npm-packlist "^1.1.6"
|
||||
npmlog "^4.0.2"
|
||||
rc "^1.2.7"
|
||||
rimraf "^2.6.1"
|
||||
semver "^5.3.0"
|
||||
tar "^4.4.2"
|
||||
|
||||
node-releases@^1.1.44:
|
||||
version "1.1.46"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.46.tgz#6b262afef1bdc9a950a96df2e77e0d2290f484bf"
|
||||
|
@ -5436,14 +5377,6 @@ node-sass@~4.12:
|
|||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
|
||||
integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
osenv "^0.1.4"
|
||||
|
||||
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
||||
|
@ -5471,26 +5404,6 @@ normalize-url@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
|
||||
integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
|
||||
|
||||
npm-bundled@^1.0.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b"
|
||||
integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==
|
||||
dependencies:
|
||||
npm-normalize-package-bin "^1.0.1"
|
||||
|
||||
npm-normalize-package-bin@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2"
|
||||
integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==
|
||||
|
||||
npm-packlist@^1.1.6:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.7.tgz#9e954365a06b80b18111ea900945af4f88ed4848"
|
||||
integrity sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==
|
||||
dependencies:
|
||||
ignore-walk "^3.0.1"
|
||||
npm-bundled "^1.0.1"
|
||||
|
||||
npm-run-path@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
||||
|
@ -5498,7 +5411,7 @@ npm-run-path@^2.0.0:
|
|||
dependencies:
|
||||
path-key "^2.0.0"
|
||||
|
||||
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
|
||||
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
|
||||
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
|
||||
|
@ -5721,7 +5634,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||
|
||||
osenv@0, osenv@^0.1.4:
|
||||
osenv@0:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
|
||||
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
|
||||
|
@ -6516,16 +6429,6 @@ raw-body@2.4.0:
|
|||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc@^1.2.7:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
dependencies:
|
||||
deep-extend "^0.6.0"
|
||||
ini "~1.3.0"
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
read-pkg-up@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
|
||||
|
@ -6915,7 +6818,7 @@ sass-loader@~7.1:
|
|||
pify "^3.0.0"
|
||||
semver "^5.5.0"
|
||||
|
||||
sax@^1.2.4, sax@~1.2.4:
|
||||
sax@~1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
@ -6965,7 +6868,7 @@ selfsigned@^1.9.1:
|
|||
dependencies:
|
||||
node-forge "0.9.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
@ -7488,7 +7391,7 @@ strip-indent@^1.0.1:
|
|||
dependencies:
|
||||
get-stdin "^4.0.1"
|
||||
|
||||
strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
|
||||
strip-json-comments@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||
|
@ -7617,19 +7520,6 @@ tar@^2.0.0:
|
|||
fstream "^1.0.12"
|
||||
inherits "2"
|
||||
|
||||
tar@^4.4.2:
|
||||
version "4.4.13"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
|
||||
integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==
|
||||
dependencies:
|
||||
chownr "^1.1.1"
|
||||
fs-minipass "^1.2.5"
|
||||
minipass "^2.8.6"
|
||||
minizlib "^1.2.1"
|
||||
mkdirp "^0.5.0"
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.3"
|
||||
|
||||
terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
|
||||
|
@ -8095,6 +7985,13 @@ vue-loader@~15.6:
|
|||
vue-hot-reload-api "^2.3.0"
|
||||
vue-style-loader "^4.1.0"
|
||||
|
||||
vue-moment@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-moment/-/vue-moment-4.1.0.tgz#092a8ff723a96c6f85a0a8e23ad30f0bf320f3b0"
|
||||
integrity sha512-Gzisqpg82ItlrUyiD9d0Kfru+JorW2o4mQOH06lEDZNgxci0tv/fua1Hl0bo4DozDV2JK1r52Atn/8QVCu8qQw==
|
||||
dependencies:
|
||||
moment "^2.19.2"
|
||||
|
||||
vue-router@~3.0:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b"
|
||||
|
@ -8437,7 +8334,7 @@ yallist@^2.1.2:
|
|||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
|
||||
|
||||
yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
|
||||
yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
|
Loading…
Reference in New Issue