* notifier panic fix

* portainer template

* remove default host from discord notifier

* fix for updating fields

* fix for updating fields

* fixed notifier panic

* fixed notifier panic

* test fix

* test fix

* missing login banner image

* dont delete admin if DEMO_MODE

* updatess to service on Dashboard

* notifier endpoint fixes, timeframe rounding chart data

* modal for UI confirmations

* UI fixes, import/export views

* export HTTP test

* start/end time

* i18n language generate script from aws

* i18n language generate script from aws

* i18n language generate

* bug: use v-model.number instead of v-model to capture notify_before (#813)

Co-authored-by: Hunter Long <Info@socialeck.com>

Co-authored-by: Marc Binder <marcandrebinder@gmail.com>
pull/817/head^2
Hunter Long 2020-09-12 13:42:14 -07:00 committed by GitHub
parent 5d85c3ce39
commit 6d8f78db09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 2329 additions and 722 deletions

View File

@ -26,7 +26,7 @@ jobs:
shell: bash
- name: Install Global Dependencies
run: npm install -g yarn sass cross-env
run: npm install -g yarn sass cross-env mjml
- name: Download Frontend Dependencies
working-directory: ./frontend
@ -44,6 +44,8 @@ jobs:
COMMIT: ${{ github.sha }}
MJML_APP: ${{ secrets.MJML_APP }}
MJML_PRIVATE: ${{ secrets.MJML_PRIVATE }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: make clean generate compile
- name: Upload Compiled Frontend (rice-box.go)

View File

@ -26,7 +26,7 @@ jobs:
shell: bash
- name: Install Global Dependencies
run: npm install -g yarn sass cross-env
run: npm install -g yarn sass cross-env mjml
- name: Download Frontend Dependencies
working-directory: ./frontend
@ -44,6 +44,8 @@ jobs:
COMMIT: ${{ github.sha }}
MJML_APP: ${{ secrets.MJML_APP }}
MJML_PRIVATE: ${{ secrets.MJML_PRIVATE }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: make clean generate compile
- name: Upload Compiled Frontend (rice-box.go)

View File

@ -1,9 +1,15 @@
# 0.90.66 (09-08-2020)
- Added Import and Export views in Dashboard
- Modified services list sparkline to use start/end of day timestamp
- Modified i18n language files, added go generate script to automatically translate
# 0.90.65 (09-01-2020)
- Fixed issue with dashboard not logging in (notifier panic)
- Modified static email templates to github.com/statping/emails
- Modified Regenerate API function to keep API_SECRET env
- Added DEMO_MODE env variable, if true, 'admin' cannot be deleted
- Modified Service sparklines on Dashboard
- Added modal popup for UI deletes/edits
# 0.90.64 (08-18-2020)
- Modified max-width for container to 1012px, larger UI

View File

@ -5,14 +5,11 @@ import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/statping/statping/handlers"
"github.com/statping/statping/source"
"github.com/statping/statping/types/checkins"
"github.com/statping/statping/types/configs"
"github.com/statping/statping/types/core"
"github.com/statping/statping/types/groups"
"github.com/statping/statping/types/messages"
"github.com/statping/statping/types/services"
"github.com/statping/statping/types/users"
"github.com/statping/statping/utils"
"io/ioutil"
"os"
@ -109,7 +106,7 @@ func exportCli(args []string) error {
if len(args) == 1 {
filename = fmt.Sprintf("%s/%s", utils.Directory, args)
}
var data []byte
var data *handlers.ExportData
if err := utils.InitLogs(); err != nil {
return err
}
@ -126,10 +123,10 @@ func exportCli(args []string) error {
if _, err := services.SelectAllServices(false); err != nil {
return err
}
if data, err = ExportSettings(); err != nil {
if data, err = handlers.ExportSettings(); err != nil {
return fmt.Errorf("could not export settings: %v", err.Error())
}
if err = utils.SaveFile(filename, data); err != nil {
if err = utils.SaveFile(filename, data.JSON()); err != nil {
return fmt.Errorf("could not write file statping-export.json: %v", err.Error())
}
log.Infoln("Statping export file saved to ", filename)
@ -233,7 +230,7 @@ func importCli(args []string) error {
if data, err = ioutil.ReadFile(args[0]); err != nil {
return err
}
var exportData ExportData
var exportData handlers.ExportData
if err = json.Unmarshal(data, &exportData); err != nil {
return err
}
@ -285,7 +282,6 @@ func importCli(args []string) error {
return err
}
}
if ask("Import Core settings?") {
c := exportData.Core
if err := c.Update(); err != nil {
@ -482,16 +478,16 @@ type gitUploader struct {
// ExportChartsJs renders the charts for the index page
type ExportData struct {
Config *configs.DbConfig `json:"config"`
Core *core.Core `json:"core"`
Services []services.Service `json:"services"`
Messages []*messages.Message `json:"messages"`
Checkins []*checkins.Checkin `json:"checkins"`
Users []*users.User `json:"users"`
Groups []*groups.Group `json:"groups"`
Notifiers []core.AllNotifiers `json:"notifiers"`
}
//type ExportData struct {
// Config *configs.DbConfig `json:"config"`
// Core *core.Core `json:"core"`
// Services []services.Service `json:"services"`
// Messages []*messages.Message `json:"messages"`
// Checkins []*checkins.Checkin `json:"checkins"`
// Users []*users.User `json:"users"`
// Groups []*groups.Group `json:"groups"`
// Notifiers []core.AllNotifiers `json:"notifiers"`
//}
// ExportSettings will export a JSON file containing all of the settings below:
// - Core
@ -501,35 +497,35 @@ type ExportData struct {
// - Services
// - Groups
// - Messages
func ExportSettings() ([]byte, error) {
c, err := core.Select()
if err != nil {
return nil, err
}
var srvs []services.Service
for _, s := range services.AllInOrder() {
s.Failures = nil
srvs = append(srvs, s)
}
cfg, err := configs.LoadConfigs(configFile)
if err != nil {
return nil, err
}
data := ExportData{
Config: cfg,
Core: c,
Notifiers: core.App.Notifications,
Checkins: checkins.All(),
Users: users.All(),
Services: srvs,
Groups: groups.All(),
Messages: messages.All(),
}
export, err := json.Marshal(data)
return export, err
}
//func ExportSettings() ([]byte, error) {
// c, err := core.Select()
// if err != nil {
// return nil, err
// }
// var srvs []services.Service
// for _, s := range services.AllInOrder() {
// s.Failures = nil
// srvs = append(srvs, s)
// }
//
// cfg, err := configs.LoadConfigs(configFile)
// if err != nil {
// return nil, err
// }
//
// data := ExportData{
// Config: cfg,
// Core: c,
// Notifiers: core.App.Notifications,
// Checkins: checkins.All(),
// Users: users.All(),
// Services: srvs,
// Groups: groups.All(),
// Messages: messages.All(),
// }
// export, err := json.Marshal(data)
// return export, err
//}
// ExportIndexHTML returns the HTML of the index page as a string
//func ExportIndexHTML() []byte {

View File

@ -7,8 +7,8 @@ const tokenKey = "statping_auth";
class Api {
constructor() {
this.version = "0.90.65";
this.commit = "5bc10fcc8536a08ce7a099a0b4cbceb2dc9fc35b";
this.version = "0.90.66";
this.commit = "a3ce4124f654b13c7f2af88b8410f998bd57fcef";
}
async oauth() {
@ -97,7 +97,6 @@ class Api {
}
async groups_reorder(data) {
window.console.log('api/reorder/groups', data)
return axios.post('api/reorder/groups', data).then(response => (response.data))
}
@ -233,6 +232,10 @@ class Api {
return axios.post('api/theme', data).then(response => (response.data))
}
async import(data) {
return axios.post('api/settings/import', data).then(response => (response.data))
}
async check_token(token) {
const f = {token: token}
return axios.post('api/users/token', qs.stringify(f)).then(response => (response.data))

View File

@ -4,7 +4,7 @@
.copy-btn {
position: absolute;
right: 0;
z-index: 9999999;
z-index: 995;
}
.copy-btn BUTTON {

View File

@ -15,14 +15,13 @@ A:HOVER {
}
.modal-backdrop {
position: absolute;
top: 0;
left: 0;
position: absolute;
display: block;
z-index: 10000;
z-index: 1040;
width: 100%;
height: 100%;
background-color: #00000073;
background-color: rgb(0 0 0 / 50%);
}
.modal {
@ -204,3 +203,32 @@ A:HOVER {
-ms-user-select: none;
user-select: none;
}
.dates{
padding:10px 0px;
margin:10px 20px;
font-weight:600;
overflow:auto;
color: darken($card-background, 45%);
font-size: 22px;
}
.dates div{
float:left;
width:50%;
text-align:center;
position:relative;
}
.dates strong {
display:block;
color: darken($card-background, 20%);
font-size:20px;
font-weight:700;
}
.dates span{
width:1px;
height:60px;
position:absolute;
right:0;
top:0;
background: darken($card-background, 10%);
}

View File

@ -3,23 +3,23 @@
<div class="row stats_area mb-5">
<div class="col-4">
<span class="font-6 font-weight-bold d-block">{{$store.getters.services.length}}</span>
<span class="font-2">{{ $t('dashboard.total_services') }}</span>
<span class="font-2">{{ $t('total_services') }}</span>
</div>
<div class="col-4">
<span class="font-6 font-weight-bold d-block">{{failuresLast24Hours()}}</span>
<span class="font-2">{{ $t('dashboard.failures_24_hours') }}</span>
<span class="font-2">{{ $t('failures_24_hours') }}</span>
</div>
<div class="col-4">
<span class="font-6 font-weight-bold d-block">{{$store.getters.onlineServices(true).length}}</span>
<span class="font-2">{{ $t('dashboard.online_services') }}</span>
<span class="font-2">{{ $t('online_services') }}</span>
</div>
</div>
<div class="col-12" v-if="services.length === 0">
<div class="alert alert-dark d-block">
You currently don't have any services!
{{$t('no_services')}}
<router-link v-if="$store.state.admin" to="/dashboard/create_service" class="btn btn-sm btn-success float-right">
<font-awesome-icon icon="plus"/> Create
<font-awesome-icon icon="plus"/> {{ $t('create') }}
</router-link>
</div>
</div>

View File

@ -1,7 +1,7 @@
<template>
<div class="col-12">
<div class="card contain-card mb-4">
<div class="card-header">{{ $t('top_nav.announcements') }}</div>
<div class="card-header">{{ $t('announcements') }}</div>
<div class="card-body pt-0">
<div v-if="messages.length === 0">
@ -13,9 +13,9 @@
<table v-else class="table table-striped">
<thead>
<tr>
<th scope="col">{{ $t('dashboard.title') }}</th>
<th scope="col" class="d-none d-md-table-cell">{{ $tc('dashboard.service', 1) }}</th>
<th scope="col" class="d-none d-md-table-cell">{{ $t('dashboard.begins') }}</th>
<th scope="col">{{ $t('title') }}</th>
<th scope="col" class="d-none d-md-table-cell">{{ $tc('service', 1) }}</th>
<th scope="col" class="d-none d-md-table-cell">{{ $t('begins') }}</th>
<th scope="col"></th>
</tr>
</thead>

View File

@ -2,9 +2,9 @@
<div class="col-12">
<div class="card contain-card mb-4">
<div class="card-header">{{ $t('top_nav.services') }}
<div class="card-header">{{ $t('services') }}
<router-link v-if="$store.state.admin" to="/dashboard/create_service" class="btn btn-sm btn-success float-right">
<font-awesome-icon icon="plus"/> Create
<font-awesome-icon icon="plus"/> {{$t('create')}}
</router-link>
</div>
<div class="card-body pt-0">
@ -13,7 +13,7 @@
</div>
<div class="card contain-card mb-4">
<div class="card-header">{{ $t('top_nav.groups') }}</div>
<div class="card-header">{{ $t('groups') }}</div>
<div class="card-body pt-0">
<div v-if="groupsList.length === 0">
@ -25,9 +25,9 @@
<table v-else class="table">
<thead>
<tr>
<th scope="col">{{ $t('dashboard.name') }}</th>
<th scope="col" class="d-none d-md-table-cell">{{ $tc('dashboard.service', 2) }}</th>
<th scope="col">{{ $t('dashboard.visibility') }}</th>
<th scope="col">{{ $t('name') }}</th>
<th scope="col" class="d-none d-md-table-cell">{{ $tc('service', 2) }}</th>
<th scope="col">{{ $t('visibility') }}</th>
<th scope="col"></th>
</tr>
</thead>

View File

@ -1,7 +1,7 @@
<template>
<div class="col-12">
<div class="card contain-card mb-4">
<div class="card-header">{{ $t('top_nav.users') }}</div>
<div class="card-header">{{ $t('users') }}</div>
<div class="card-body pt-0">
<table class="table table-striped">
<thead>

View File

@ -2,9 +2,9 @@
<div class="row">
<h5 v-if="group.name && group_services" class="h5 col-12 mb-3 mt-2 text-dim">
<font-awesome-icon @click="toggle" :icon="expanded ? 'minus' : 'plus'" class="pointer mr-3"/> {{group.name}}
<span class="badge badge-success text-uppercase float-right ml-2">{{services_online.length}} online</span>
<span class="badge badge-success text-uppercase float-right ml-2">{{services_online.length}} {{$t('online')}}</span>
<span v-if="services_online.services_offline > 0" class="badge badge-danger text-uppercase float-right">
{{services_offline.length}} offline
{{services_offline.length}} {{$t('offline')}}
</span>
</h5>
<div class="col-12 col-md-4" v-if="expanded" v-for="service in group_services">

View File

@ -0,0 +1,226 @@
<template>
<div class="mb-5">
<h3 v-if="!loaded" >Import and Export</h3>
<p v-if="!loaded">
You can export your current Statping services, groups, notifiers, and other settings to a JSON file.
</p>
<div v-if="!loaded" class="mt-4 row">
<div class="col-6 custom-file">
<input @change="onFileChange" type="file" class="custom-file-input" id="customFile" accept=".json,application/json">
<label class="custom-file-label" for="customFile">Choose exported Statping JSON file</label>
</div>
<a class="ml-2 col-2 btn btn-light btn-outline-secondary" href="/api/settings/export">Export</a>
</div>
<div v-if="loaded" class="col-12 mb-3">
<h3>Core Settings
<span @click="file.core.enabled = !!file.core.enabled" class="switch switch-sm float-right">
<input @change="update" v-model="file.core.enabled" type="checkbox" class="switch" :id="`switch-core`">
<label :for="`switch-core`"></label>
</span>
</h3>
<div class="row"><span class="col-4">Name</span><span class="col-8 text-right font-weight-bold">{{file.core.name}}</span></div>
<div class="row"><span class="col-4">Description</span><span class="col-8 text-right font-weight-bold">{{file.core.description}}</span></div>
<div class="row"><span class="col-4">Domain</span><span class="col-8 text-right font-weight-bold">{{file.core.domain}}</span></div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<h3>Users
<button @click.prevent="toggle_all(file.users)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
<div v-if="!file.users" class="alert alert-link">
No Users in file
</div>
<div v-for="user in file.users" v-bind:key="user.id" class="row">
<div class="col-4 font-weight-bold">
{{user.username}}
</div>
<div class="col-6">
{{user.email}}
</div>
<div class="col-2 text-right">
<span @click="user.enabled = !!user.enabled" class="switch switch-sm">
<input @change="update" v-model="user.enabled" type="checkbox" class="switch" :id="`switch-user-${user.id}`">
<label :for="`switch-user-${user.id}`"></label>
</span>
</div>
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<h3>Checkins
<button @click.prevent="toggle_all(file.checkins)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
<div v-if="!file.checkins" class="alert alert-link">
No Checkins in file
</div>
<div v-for="checkin in file.checkins" v-bind:key="checkin.id" class="row">
<div class="col-4 font-weight-bold">
{{checkin.id}}
</div>
<div class="col-6">
{{checkin.service_id}}
</div>
<div class="col-2 text-right">
<span @click="checkin.enabled = !!checkin.enabled" class="switch switch-sm">
<input @change="update" v-model="checkin.enabled" type="checkbox" class="switch" :id="`switch-checkin-${checkin.id}`">
<label :for="`switch-checkin-${checkin.id}`"></label>
</span>
</div>
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<h3>Services
<button @click.prevent="toggle_all(file.services)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
<div v-if="!file.services" class="alert alert-link">
No Services in file
</div>
<div v-for="service in file.services" v-bind:key="service.id" class="row">
<div class="col-4 font-weight-bold">
{{service.name}}
</div>
<div class="col-6">
{{service.domain}}
</div>
<div class="col-2 text-right">
<span @click="service.enabled = !!service.enabled" class="switch switch-sm">
<input @change="update" v-model="service.enabled" type="checkbox" class="switch" :id="`switch-service-${service.id}`">
<label :for="`switch-service-${service.id}`"></label>
</span>
</div>
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<h3>Groups
<button @click.prevent="toggle_all(file.groups)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
<div v-if="!file.groups" class="alert alert-link">
No Groups in file
</div>
<div v-for="group in file.groups" v-bind:key="group.id" class="row">
<div class="col-4 font-weight-bold">
{{group.name}}
</div>
<div class="col-8 text-right">
<span @click="group.enabled = !!group.enabled" class="switch switch-sm">
<input @change="update" v-model="group.enabled" type="checkbox" class="switch" :id="`switch-group-${group.id}`">
<label :for="`switch-group-${group.id}`"></label>
</span>
</div>
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<h3>Notifiers
<button @click.prevent="toggle_all(file.notifiers)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
<div v-if="!file.notifiers" class="alert alert-link">
No Notifiers in file
</div>
<div v-for="notifier in file.notifiers" v-bind:key="notifier.id" class="row">
<div class="col-4">
{{notifier.title}}
</div>
<div class="col-8 text-right">
<span @click="notifier.enabled = !!notifier.enabled" class="switch">
<input @change="update" v-model="notifier.enabled" type="checkbox" class="switch" :id="`switch-notifier-${notifier.id}`">
<label :for="`switch-notifier-${notifier.id}`"></label>
</span>
</div>
</div>
</div>
<div v-if="error" class="alert alert-danger">
{{error}}
</div>
<button v-if="loaded" @click.prevent="import_all" class="btn btn-success">Import</button>
</div>
</template>
<script>
import Api from '../../API';
export default {
name: "Importer",
data () {
return {
error: null,
file: null,
loaded: false,
output: null,
all: {
notifiers: false,
services: false,
groups: false,
}
}
},
methods: {
clean_elem(elem) {
if (!elem) {
return null
}
elem.map(e => delete(e.enabled) && delete(e.id))
return elem
},
async import_all() {
this.error = null
const outgoing = {
core: this.output.core,
users: this.clean_elem(this.output.users),
services: this.clean_elem(this.output.services),
groups: this.clean_elem(this.output.groups),
notifiers: this.clean_elem(this.output.notifiers),
checkins: this.clean_elem(this.output.checkins),
}
try {
await Api.import(outgoing)
} catch(e) {
this.error = e
}
},
toggle_all(elem) {
elem.map(s => s.enabled = true)
this.update()
},
update() {
this.output = {
core: this.file.core.enabled ? this.file.core : null,
users: this.file.users.filter(s => s.enabled),
services: this.file.services.filter(s => s.enabled),
groups: this.file.groups.filter(s => s.enabled),
notifiers: this.file.notifiers.filter(s => s.enabled),
checkins: this.file.checkins.filter(s => s.enabled),
}
},
onFileChange(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.processJSON(files[0]);
},
processJSON(file) {
let reader = new FileReader();
reader.onload = (e) => {
this.file = JSON.parse(e.target.result);
this.file.core.enabled = false
};
reader.readAsText(file);
this.loaded = true
},
}
}
</script>
<style scoped>
</style>

View File

@ -37,13 +37,13 @@
<div class="col-7 pr-2 pl-0">
<div class="btn-group float-right">
<button @click="$router.push({path: `/dashboard/service/${service.id}/incidents`, params: {id: service.id}})" @mouseleave="unsetHover" @mouseover="setHover('Incidents')" class="btn btn-sm btn-white incident">
<button @click="$router.push({path: `/dashboard/service/${service.id}/incidents`, params: {id: service.id}})" @mouseleave="unsetHover" @mouseover="setHover($t('incidents'))" class="btn btn-sm btn-white incident">
<font-awesome-icon icon="bullhorn"/>
</button>
<button @click="$router.push({path: `/dashboard/service/${service.id}/checkins`, params: {id: service.id}})" @mouseleave="unsetHover" @mouseover="setHover('Checkins')" class="btn btn-sm btn-white checkins">
<button @click="$router.push({path: `/dashboard/service/${service.id}/checkins`, params: {id: service.id}})" @mouseleave="unsetHover" @mouseover="setHover($t('checkins'))" class="btn btn-sm btn-white checkins">
<font-awesome-icon icon="calendar-check"/>
</button>
<button @click="$router.push({path: `/dashboard/service/${service.id}/failures`, params: {id: service.id}})" @mouseleave="unsetHover" @mouseover="setHover('Failures')" class="btn btn-sm btn-white failures">
<button @click="$router.push({path: `/dashboard/service/${service.id}/failures`, params: {id: service.id}})" @mouseleave="unsetHover" @mouseover="setHover($t('failures'))" class="btn btn-sm btn-white failures">
<font-awesome-icon icon="exclamation-triangle"/> <span v-if="service.stats.failures !== 0" class="badge badge-danger ml-1">{{service.stats.failures}}</span>
</button>
</div>
@ -54,7 +54,7 @@
</div>
<span v-for="(failure, index) in failures" v-bind:key="index" class="alert alert-light">
Failed {{failure.created_at}}<br>
{{ $t('failed') }} {{failure.created_at}}<br>
{{failure.issue}}
</span>

View File

@ -8,12 +8,12 @@
<table v-else class="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col" class="d-none d-md-table-cell">Status</th>
<th scope="col" class="d-none d-md-table-cell">Visibility</th>
<th scope="col">{{$t('name')}}</th>
<th scope="col" class="d-none d-md-table-cell">{{$t('status')}}</th>
<th scope="col" class="d-none d-md-table-cell">{{$t('visibility')}}</th>
<th scope="col" class="d-none d-md-table-cell">{{ $t('group') }}</th>
<th scope="col" class="d-none d-md-table-cell" style="width: 130px">
Failures
{{$t('failures')}}
<div class="btn-group float-right" role="group">
<a @click="list_timeframe='3h'" type="button" class="small" :class="{'text-success': list_timeframe==='3h', 'text-muted': list_timeframe!=='3h'}">3h</a>
<a @click="list_timeframe='12h'" type="button" class="small" :class="{'text-success': list_timeframe==='12h', 'text-muted': list_timeframe!=='12h'}">12h</a>

View File

@ -1,21 +1,21 @@
<template>
<div class="card mb-5">
<div class="card-header">Theme Editor</div>
<div class="card-header">{{$t('theme_editor')}}</div>
<div class="card-body">
<div v-if="error" class="alert alert-danger mt-3" style="white-space: pre-line;">
{{error}}
</div>
<h6 v-if="directory" id="assets_dir" class="text-muted text-monospace text-sm-center font-1 mb-4">
Asset Directory: {{directory}}
{{$t('assets_dir')}}: {{directory}}
</h6>
<div v-if="loaded && !directory" class="jumbotron jumbotron-fluid">
<div class="text-center col-12">
<h1 class="display-5">Enable Local Assets</h1>
<span class="lead">Customize your status page design by enabling local assets. This will create a 'assets' directory containing all CSS.<p>
<h1 class="display-5">{{$t('enable_assets')}}</h1>
<span class="lead">{{$t('assets_desc')}}<p>
<button id="enable_assets" @click.prevent="createAssets" :disabled="pending" href="#" class="btn btn-primary mt-3">
<font-awesome-icon v-if="pending" icon="circle-notch" class="mr-2" spin/>{{pending ? "Creating Assets" : "Enable Local Assets"}}
<font-awesome-icon v-if="pending" icon="circle-notch" class="mr-2" spin/>{{pending ? $t('assets_loading') : $t('assets_btn')}}
</button>
</p></span>
</div>
@ -25,13 +25,13 @@
<h3>Variables</h3>
<codemirror v-show="loaded" v-model="vars" ref="vars" :options="cmOptions" class="codemirrorInput"/>
<h3 class="mt-3">Base Theme</h3>
<h3 class="mt-3">Base {{$t('theme')}}</h3>
<codemirror v-show="loaded" v-model="base" ref="base" :options="cmOptions" class="codemirrorInput"/>
<h3 class="mt-3">Layout Theme</h3>
<h3 class="mt-3">Layout {{$t('theme')}}</h3>
<codemirror v-show="loaded" v-model="layout" ref="layout" :options="cmOptions" class="codemirrorInput"/>
<h3 class="mt-3">Forms Theme</h3>
<h3 class="mt-3">Forms {{$t('theme')}}</h3>
<codemirror v-show="loaded" v-model="forms" ref="forms" :options="cmOptions" class="codemirrorInput"/>
<h3 class="mt-3">Mixins</h3>

View File

@ -9,29 +9,29 @@
<div class="navbar-collapse" :class="{collapse: !navopen}" id="navbarText">
<ul class="navbar-nav mr-auto">
<li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard" class="nav-link">{{ $t('top_nav.dashboard') }}</router-link>
<router-link to="/dashboard" class="nav-link">{{ $t('dashboard') }}</router-link>
</li>
<li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/services" class="nav-link">{{ $t('top_nav.services') }}</router-link>
<router-link to="/dashboard/services" class="nav-link">{{ $t('services') }}</router-link>
</li>
<li v-if="admin" @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/users" class="nav-link">{{ $t('top_nav.users') }}</router-link>
<router-link to="/dashboard/users" class="nav-link">{{ $t('users') }}</router-link>
</li>
<li @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/messages" class="nav-link">{{ $t('top_nav.announcements') }}</router-link>
<router-link to="/dashboard/messages" class="nav-link">{{ $t('announcements') }}</router-link>
</li>
<li v-if="admin" @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/settings" class="nav-link">{{ $t('top_nav.settings') }}</router-link>
<router-link to="/dashboard/settings" class="nav-link">{{ $t('settings') }}</router-link>
</li>
<li v-if="admin" @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/logs" class="nav-link">{{ $t('top_nav.logs') }}</router-link>
<router-link to="/dashboard/logs" class="nav-link">{{ $t('logs') }}</router-link>
</li>
<li v-if="admin" @click="navopen = !navopen" class="nav-item navbar-item">
<router-link to="/dashboard/help" class="nav-link">{{ $t('top_nav.help') }}</router-link>
<router-link to="/dashboard/help" class="nav-link">{{ $t('help') }}</router-link>
</li>
</ul>
<span class="navbar-text">
<a href="#" class="nav-link" @click.prevent="logout">{{ $t('top_nav.logout') }}</a>
<a href="#" class="nav-link" @click.prevent="logout">{{ $t('logout') }}</a>
</span>
</div>
</nav>

View File

@ -1,5 +1,5 @@
<template>
<div v-if="modal.visible" class="modal d-block" tabindex="-1">
<div v-if="modal.visible" class="modal d-block mt-5 pt-5" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">

View File

@ -3,7 +3,7 @@
<div v-if="!core.footer" class="footer text-center mb-4 p-2">
<div class="d-block text-dim">
<div class="mb-3">
<router-link class="links" :to="admin ? '/dashboard' : '/login'">{{$t('top_nav.dashboard')}}</router-link>
<router-link class="links" :to="admin ? '/dashboard' : '/login'">{{$t('dashboard')}}</router-link>
</div>
<span class="font-1 mt-3">
<a href="https://github.com/statping/statping" class="statping" target="_blank">

View File

@ -15,11 +15,11 @@
<div class="row mt-2">
<div class="col-12 no-select">
<p class="divided">
<span class="font-2 text-muted">90 Days Ago</span>
<span class="font-2 text-muted">90 {{$t('days_ago')}}</span>
<span class="divider"></span>
<span class="text-center font-2" :class="{'text-muted': service.online, 'text-danger': !service.online}">{{service_txt}}</span>
<span class="divider"></span>
<span class="font-2 text-muted">Today</span>
<span class="font-2 text-muted">{{$t('today')}}</span>
</p>
</div>
</div>

View File

@ -1,13 +1,20 @@
<template>
<div class="alert alert-secondary pb-3 pt-3 mt-5 mb-3" role="alert">
<h3 class="mb-3">{{message.title}}</h3>
<span class="mb-3">{{message.description}}</span>
<div class="row d-block mt-3">
<span class="col-12 col-md-6 text-left small text-muted">
Started {{niceDate(message.start_on)}} ({{ago(message.start_on)}} ago)
</span>
<span class="col-12 col-md-6 text-right float-right small text-muted">
Ends on {{niceDate(message.end_on)}} (in {{ago(message.end_on)}})</span>
<div class="card shadow mb-4" role="alert">
<div class="card-body pb-2">
<h3 class="mb-3 font-weight-bold">{{message.title}}</h3>
<span class="mb-2">{{message.description}}</span>
<div class="col-12 mb-0">
<div class="dates">
<div class="start">
<strong>STARTS</strong> {{niceDate(message.start_on)}}
<span></span>
</div>
<div class="ends">
<strong>ENDS</strong> {{niceDate(message.end_on)}}
</div>
</div>
</div>
</div>
</div>
</template>
@ -26,4 +33,5 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

View File

@ -48,7 +48,7 @@
<div class="col-md-2 col-6 float-right">
<button v-if="!expanded" @click="setService" class="btn btn-sm float-right dyn-dark text-white" :class="{'bg-success': service.online, 'bg-danger': !service.online}">
{{$t('service.view')}}
{{$t('view')}}
</button>
</div>
</div>

View File

@ -153,7 +153,10 @@ export default {
group = "24h"
}
const data = await Api.service_failures_data(this.service.id, this.toUnix(this.nowSubtract(start)), this.toUnix(this.now()), group, true)
const startTime = this.beginningOf("day", this.nowSubtract(start))
const endTime = this.endOf("day", this.now())
const data = await Api.service_failures_data(this.service.id, this.toUnix(startTime), this.toUnix(endTime), group, true)
this.loaded = true
this.data = [{data: this.convertChartData(data)}]
}

View File

@ -2,15 +2,15 @@
<div class="row stats_area mt-5 mb-4">
<div class="col-4">
<span class="font-5 d-block font-weight-bold">{{humanTime(service.avg_response)}}</span>
<span class="font-1 subtitle">{{$t('service.average')}}</span>
<span class="font-1 subtitle">{{$t('average_response')}}</span>
</div>
<div class="col-4">
<span class="font-5 d-block font-weight-bold">{{service.online_24_hours}} %</span>
<span class="font-1 subtitle">{{$t('service.last_uptime', [24, $tc('hour', 24)])}}</span>
<span class="font-1 subtitle">{{$t('last_uptime', [24, $tc('hour', 24)])}}</span>
</div>
<div class="col-4">
<span class="font-5 d-block font-weight-bold">{{service.online_7_days}} %</span>
<span class="font-1 subtitle">{{$t('service.last_uptime', [7, $tc('day', 7)])}}</span>
<span class="font-1 subtitle">{{$t('last_uptime', [7, $tc('day', 7)])}}</span>
</div>
</div>
</template>

View File

@ -4,12 +4,12 @@
<div class="card-header">Statping Settings</div>
<div class="card-body">
<div class="form-group">
<label>{{ $t('settings.name') }}</label>
<label>{{ $t('project_name') }}</label>
<input v-model="core.name" type="text" class="form-control" placeholder="Great Uptime" id="project">
</div>
<div class="form-group">
<label>{{ $t('settings.description') }}</label>
<label>{{ $t('description') }}</label>
<input v-model="core.description" type="text" class="form-control" placeholder="Great Uptime" id="description">
</div>
@ -19,8 +19,8 @@
<input v-model="core.domain" type="url" class="form-control" id="domain">
</div>
<div class="col-4 col-sm-3 mt-sm-1 mt-0">
<label class="d-inline d-sm-none">Enable CDN</label>
<label class="d-none d-sm-block">Enable CDN</label>
<label class="d-inline d-sm-none">{{$t('enable_cdn')}}</label>
<label class="d-none d-sm-block">{{$t('enable_cdn')}}</label>
<span @click="core.using_cdn = !!core.using_cdn" class="switch" id="using_cdn">
<input v-model="core.using_cdn" type="checkbox" name="using_cdn" class="switch" id="switch-normal" :checked="core.using_cdn">
<label for="switch-normal"></label>
@ -29,24 +29,28 @@
</div>
<div class="form-group">
<label>{{ $t('settings.footer') }}</label>
<label>{{ $t('footer') }}</label>
<textarea v-model="core.footer" rows="4" class="form-control" id="footer">{{core.footer}}</textarea>
<small class="form-text text-muted">{{ $t('settings.footer_notes') }}</small>
<small class="form-text text-muted">{{ $t('footer_notes') }}</small>
</div>
<div class="form-group">
<label>{{ $t('setup.language') }}</label>
<label>{{ $t('language') }}</label>
<select v-model="core.language" class="form-control">
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="ru">Russian</option>
<option value="de">German</option>
<option value="ja">Japanese</option>
<option value="it">Italian</option>
<option value="ko">Korean</option>
<option value="zh">Chinese</option>
</select>
</div>
<div class="form-group row mt-3">
<label class="col-sm-10 col-form-label">{{ $t('settings.error_reporting') }}</label>
<label class="col-sm-10 col-form-label">{{ $t('send_reports') }}</label>
<div class="col-sm-2 float-right">
<span @click="core.allow_reports = !!core.allow_reports" class="switch" id="allow_report">
<input v-model="core.allow_reports" type="checkbox" name="allow_report" class="switch" id="switch_allow_report" :checked="core.allow_reports">
@ -54,14 +58,14 @@
</span>
</div>
<div class="col-12">
<small>{{ $t('settings.error_reporting_notes') }}</small>
<small>{{ $t('send_reports_desc') }}</small>
</div>
</div>
</div>
<div class="card-footer">
<button @click.prevent="saveSettings" id="save_core" type="submit" class="btn btn-primary btn-block" v-bind:disabled="loading">
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/>{{ $t('settings.save') }}
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/>{{ $t('save_settings') }}
</button>
</div>
</div>
@ -88,8 +92,8 @@
this.loading = true
const c = this.core
await Api.core_save(c)
const core = await Api.core()
this.$store.commit('setCore', core)
this.$store.commit('setCore', c)
this.$i18n.locale = c.language || "en";
this.loading = false
},
selectAll() {

View File

@ -1,6 +1,6 @@
<template>
<div class="card contain-card mb-3">
<div class="card-header">{{group.id ? `Update ${group.name}` : "Create Group"}}
<div class="card-header">{{group.id ? `${$t('update')} ${group.name}` : $t('group_create')}}
<transition name="slide-fade">
<button @click="removeEdit" v-if="group.id" class="btn float-right btn-danger btn-sm">
{{ $t('close') }}
@ -10,24 +10,24 @@
<form @submit.prevent="saveGroup">
<div class="form-group row">
<label for="title" class="col-sm-4 col-form-label">{{ $t('dashboard.group') }} {{ $t('dashboard.name') }}</label>
<label for="title" class="col-sm-4 col-form-label">{{ $t('group') }} {{ $t('name') }}</label>
<div class="col-sm-8">
<input v-model="group.name" type="text" class="form-control" id="title" placeholder="Group Name" required>
</div>
</div>
<div class="form-group row">
<label for="switch-group-public" class="col-sm-4 col-form-label text-capitalize">{{ $t('public') }} {{ $t('dashboard.group') }}</label>
<label for="switch-group-public" class="col-sm-4 col-form-label text-capitalize">{{ $t('public') }} {{ $t('group') }}</label>
<div class="col-md-8 col-xs-12 mt-1">
<span @click="group.public = !!group.public" class="switch float-left">
<input v-model="group.public" type="checkbox" class="switch" id="switch-group-public" :checked="group.public">
<label for="switch-group-public">Show group services to the public</label>
<label for="switch-group-public">{{$t('group_public_desc')}}</label>
</span>
</div>
</div>
<div class="form-group row">
<div class="col-sm-12">
<button @click.prevent="saveGroup" type="submit" :disabled="loading || group.name === ''" class="btn btn-block" :class="{'btn-primary': !group.id, 'btn-secondary': group.id}">
{{loading ? "Loading..." : group.id ? "Update Group" : "Create Group"}}
{{loading ? "Loading..." : group.id ? $t('group_update') : $t('group_create')}}
</button>
</div>
</div>

View File

@ -16,10 +16,10 @@
<div class="form-group row">
<div class="col-sm-12">
<div v-if="error" class="alert alert-danger" role="alert">
{{$t('dashboard.wrong_login')}}
{{$t('wrong_login')}}
</div>
<button @click.prevent="login" type="submit" class="btn btn-block btn-primary" :disabled="disabled || loading">
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/>{{loading ? $t('dashboard.loading') : $t('dashboard.sign_in')}}
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/>{{loading ? $t('loading') : $t('sign_in')}}
</button>
</div>
</div>

View File

@ -1,7 +1,7 @@
<template>
<div>
<div class="card contain-card mb-5">
<div class="card-header">{{message.id ? `Update ${message.title}` : "Create Announcement"}}
<div class="card-header">{{message.id ? `${$t('update')} ${message.title}` : $t('message_create')}}
<transition name="slide-fade">
<button @click="removeEdit" v-if="message.id" class="btn btn-sm float-right btn-danger btn-sm">
{{ $t('close') }}
@ -11,31 +11,31 @@
<div class="card-body">
<form @submit="saveMessage">
<div class="form-group row">
<label class="col-sm-4 col-form-label">{{ $t('dashboard.title') }}</label>
<label class="col-sm-4 col-form-label">{{ $t('title') }}</label>
<div class="col-sm-8">
<input v-model="message.title" type="text" name="title" class="form-control" id="title" placeholder="Announcement Title" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Description</label>
<label class="col-sm-4 col-form-label">{{ $t('description') }}</label>
<div class="col-sm-8">
<textarea v-model="message.description" rows="5" name="description" class="form-control" id="description" required></textarea>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Service</label>
<label class="col-sm-4 col-form-label">{{ $t('service') }}</label>
<div class="col-sm-8">
<select v-model="message.service" name="service_id" class="form-control">
<option v-bind:value="0">Global Announcement</option>
<option v-bind:value="0">{{ $t('global_announcement') }}</option>
<option v-for="service in $store.getters.services" :value="service.id" v-bind:key="service.id" >{{service.name}}</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Announcement Date Range</label>
<label class="col-sm-4 col-form-label">{{ $t('announcement_date') }}</label>
<div class="col-sm-4">
<flatPickr v-model="message.start_on" @on-change="startChange" :config="config" type="text" name="start_on" class="form-control form-control-plaintext" id="start_on" value="0001-01-01T00:00:00Z" required />
</div>
@ -45,41 +45,41 @@
</div>
<div v-show="this.service === null" class="form-group row">
<label for="service_id" class="col-sm-4 col-form-label">Service</label>
<label for="service_id" class="col-sm-4 col-form-label">{{ $t('service') }}</label>
<div class="col-sm-8">
<select v-model="message.service" class="form-control" name="service" id="service_id">
<option v-bind:value="0">Global Message</option>
<option v-bind:value="0">{{ $t('global_announcement') }}</option>
<option v-for="service in $store.getters.services" :value="service.id" v-bind:key="service.id">{{service.name}}</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="notify_method" class="col-sm-4 col-form-label">Notify Users</label>
<label for="notify_method" class="col-sm-4 col-form-label">{{ $t('notify_users') }}</label>
<div class="col-sm-8">
<span @click="message.notify = !!message.notify" class="switch">
<input v-model="message.notify" type="checkbox" class="switch" id="switch-normal">
<label for="switch-normal">Notify Users Before Scheduled Time</label>
<label for="switch-normal">{{ $t('notify_desc') }}</label>
</span>
</div>
</div>
<div v-if="message.notify" class="form-group row">
<label for="notify_method" class="col-sm-4 col-form-label">Notification Method</label>
<label for="notify_method" class="col-sm-4 col-form-label">{{ $t('notify_method') }}</label>
<div class="col-sm-8">
<input v-model="message.notify_method" type="text" name="notify_method" class="form-control" id="notify_method" value="" placeholder="email">
</div>
</div>
<div v-if="message.notify" class="form-group row">
<label for="notify_before" class="col-sm-4 col-form-label">Notify Before</label>
<label for="notify_before" class="col-sm-4 col-form-label">{{ $t('notify_before') }}</label>
<div class="col-sm-8">
<div class="form-inline">
<input v-model="message.notify_before" type="number" name="notify_before" class="col-4 form-control" id="notify_before">
<input v-model.number="message.notify_before" type="number" name="notify_before" class="col-4 form-control" id="notify_before">
<select v-model="message.notify_before_scale" class="ml-2 col-7 form-control" name="notify_before_scale" id="notify_before_scale">
<option value="minute">Minutes</option>
<option value="hour">Hours</option>
<option value="day">Days</option>
<option value="minute">{{ $t('minutes') }}</option>
<option value="hour">{{ $t('hours') }}</option>
<option value="day">{{ $t('days') }}</option>
</select>
</div>
</div>
@ -90,7 +90,7 @@
<button @click="saveMessage"
:disabled="!message.title || !message.description"
type="submit" class="btn btn-block" :class="{'btn-primary': !message.id, 'btn-secondary': message.id}">
{{message.id ? "Edit Message" : "Create Message"}}
{{message.id ? $t('message_edit') : $t('message_create')}}
</button>
</div>
</div>

View File

@ -1,25 +1,25 @@
<template>
<form v-if="service.type" @submit.prevent="saveService">
<div class="card contain-card mb-4">
<div class="card-header">{{ $t('service.info') }}</div>
<div class="card-header">{{ $t('service_info') }}</div>
<div class="card-body">
<div class="form-group row">
<label class="col-sm-4 col-form-label">{{ $t('service.name') }}</label>
<label class="col-sm-4 col-form-label">{{ $t('service_name') }}</label>
<div class="col-sm-8">
<input v-model="service.name" @input="updatePermalink" id="name" type="text" name="name" class="form-control" placeholder="Server 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">{{ $t('service.type') }}</label>
<label for="service_type" class="col-sm-4 col-form-label">{{ $t('service_type') }}</label>
<div class="col-sm-8">
<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>
<option value="http">HTTP {{ $t('service') }}</option>
<option value="tcp">TCP {{ $t('service') }}</option>
<option value="udp">UDP {{ $t('service') }}</option>
<option value="icmp">ICMP Ping</option>
<option value="grpc">gRPC Service</option>
<option value="static">Static Service</option>
<option value="grpc">gRPC {{ $t('service') }}</option>
<option value="static">Static {{ $t('service') }}</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>
@ -35,7 +35,7 @@
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Permalink URL</label>
<label class="col-sm-4 col-form-label">{{ $t('permalink') }}</label>
<div class="col-sm-8">
<input v-model="service.permalink" type="text" name="permalink" class="form-control" 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>
@ -43,7 +43,7 @@
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Public Service</label>
<label class="col-sm-4 col-form-label">{{ $t('service_public') }}</label>
<div class="col-12 col-md-8 mt-1 mb-2">
<span @click="service.public = !!service.public" class="switch float-left">
<input v-model="service.public" type="checkbox" name="public-option" class="switch" id="switch-public" v-bind:checked="service.public">
@ -54,7 +54,7 @@
</div>
<div v-if="service.type !== 'static'" class="form-group row">
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval</label>
<label for="service_interval" class="col-sm-4 col-form-label">{{ $t('check_interval') }}</label>
<div class="col-sm-6">
<span class="slider-info">{{secondsHumanize(service.check_interval)}}</span>
<input v-model="service.check_interval" type="range" class="slider" id="service_interval" min="1" max="1800" :step="1">
@ -74,7 +74,7 @@
<div class="form-group row">
<label for="service_url" class="col-sm-4 col-form-label">
Service Endpoint {{service.type === 'http' ? "(URL)" : "(Domain)"}}
{{ $t('service_endpoint') }} {{service.type === 'http' ? "(URL)" : "(Domain)"}}
</label>
<div class="col-sm-8">
<input v-model="service.domain" type="url" class="form-control" id="service_url" :placeholder="service.type === 'http' ? 'https://google.com' : '192.168.1.1'" required autocapitalize="none" spellcheck="false">
@ -90,7 +90,7 @@
</div>
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
<label class="col-sm-4 col-form-label">Service Check Type</label>
<label class="col-sm-4 col-form-label">{{ $t('service_check') }}</label>
<div class="col-sm-8">
<select v-model="service.method" name="method" class="form-control">
<option value="GET" >GET</option>
@ -104,7 +104,7 @@
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Request Timeout</label>
<label class="col-sm-4 col-form-label">{{ $t('service_timeout') }}</label>
<div class="col-sm-6">
<span v-if="service.timeout >= 0" class="slider-info">{{secondsHumanize(service.timeout)}}</span>
<input v-model="service.timeout" type="range" id="timeout" name="timeout" class="slider" min="1" max="180">
@ -132,14 +132,14 @@
</div>
</div>
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
<label class="col-sm-4 col-form-label">Expected Response (Regex)</label>
<label class="col-sm-4 col-form-label">{{ $t('expected_resp') }} (Regex)</label>
<div class="col-sm-8">
<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 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>
<label for="service_response_code" class="col-sm-4 col-form-label">{{ $t('expected_code') }}</label>
<div class="col-sm-8">
<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>
@ -147,7 +147,7 @@
</div>
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
<label class="col-12 col-md-4 col-form-label">Follow HTTP Redirects</label>
<label class="col-12 col-md-4 col-form-label">{{ $t('follow_redir') }}</label>
<div class="col-12 col-md-8 mt-1 mb-2 mb-md-0">
<span @click="service.redirect = !!service.redirect" class="switch float-left">
<input v-model="service.redirect" type="checkbox" name="redirect-option" class="switch" id="switch-redirect" v-bind:checked="service.redirect">
@ -157,7 +157,7 @@
</div>
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
<label class="col-12 col-md-4 col-form-label">Verify SSL</label>
<label class="col-12 col-md-4 col-form-label">{{ $t('verify_ssl') }}</label>
<div class="col-12 col-md-8 mt-1 mb-2 mb-md-0">
<span @click="service.verify_ssl = !!service.verify_ssl" class="switch float-left">
<input v-model="service.verify_ssl" type="checkbox" name="verify_ssl-option" class="switch" id="switch-verify-ssl" v-bind:checked="service.verify_ssl">
@ -168,7 +168,7 @@
</div>
<div v-if="service.type.match(/^(tcp|http)$/)" class="form-group row">
<label class="col-12 col-md-4 col-form-label">Use TLS Certificate</label>
<label class="col-12 col-md-4 col-form-label">{{ $t('tls_cert') }}</label>
<div class="col-12 col-md-8 mt-1 mb-2 mb-md-0">
<span @click="use_tls = !!use_tls" class="switch float-left">
<input v-model="use_tls" type="checkbox" name="verify_ssl-option" class="switch" id="switch-use-tls" v-bind:checked="use_tls">
@ -206,11 +206,11 @@
</div>
<div class="card contain-card mb-4">
<div class="card-header">Notification Options</div>
<div class="card-header">{{ $t('notification_opts') }}</div>
<div class="card-body">
<div class="form-group row">
<label class="col-sm-4 col-form-label">Enable Notifications</label>
<label class="col-sm-4 col-form-label">{{ $t('notifications_enable') }}</label>
<div class="col-12 col-md-8 mt-1 mb-2 mb-md-0">
<span @click="service.allow_notifications = !!service.allow_notifications" class="switch float-left">
<input v-model="service.allow_notifications" type="checkbox" name="allow_notifications-option" class="switch" id="switch-notifications" v-bind:checked="service.allow_notifications">
@ -219,7 +219,7 @@
</div>
</div>
<div v-if="service.allow_notifications" class="form-group row">
<label class="col-sm-4 col-form-label">Notify After Failures</label>
<label class="col-sm-4 col-form-label">{{ $t('notify_after') }}</label>
<div class="col-sm-8">
<span class="slider-info">{{service.notify_after === 0 ? "First Failure" : service.notify_after+' Failures'}}</span>
<input v-model="service.notify_after" type="range" name="notify_after" class="slider" id="notify_after" min="0" max="20">
@ -227,7 +227,7 @@
</div>
</div>
<div v-if="service.allow_notifications" class="form-group row">
<label class="col-sm-4 col-form-label">Notify All Changes</label>
<label class="col-sm-4 col-form-label">{{ $t('notify_all') }}</label>
<div class="col-12 col-md-8 mt-1">
<span @click="service.notify_all_changes = !!service.notify_all_changes" class="switch float-left">
<input v-model="service.notify_all_changes" type="checkbox" name="notify_all-option" class="switch" id="notify_all" v-bind:checked="service.notify_all_changes">
@ -243,7 +243,7 @@
<div class="form-group row">
<div class="col-12">
<button :disabled="loading" @click.prevent="saveService" type="submit" class="btn btn-success btn-block">
{{service.id ? "Update Service" : "Create Service"}}
{{service.id ? $t('service_update') : $t('service_create')}}
</button>
</div>
</div>

View File

@ -9,17 +9,21 @@
<div class="row">
<div class="col-12 col-md-6">
<div class="form-group">
<label class="text-capitalize">{{ $t('setup.language') }}</label>
<label class="text-capitalize">{{ $t('language') }}</label>
<select @change="changeLanguages" v-model="setup.language" id="language" class="form-control">
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="ru">Russian</option>
<option value="de">German</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="it">Italian</option>
<option value="zh">Chinese</option>
</select>
</div>
<div class="form-group">
<label class="text-capitalize">{{ $t('setup.connection') }}</label>
<label class="text-capitalize">{{ $t('db_connection') }}</label>
<select @change="canSubmit" v-model="setup.db_connection" id="db_connection" class="form-control">
<option value="sqlite">SQLite</option>
<option value="postgres">Postgres</option>
@ -29,34 +33,34 @@
<div class="row">
<div class="col-7 col-md-6">
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
<label class="text-capitalize">{{ $t('setup.host') }}</label>
<label class="text-capitalize">{{ $t('db_host') }}</label>
<input @keyup="canSubmit" v-model="setup.db_host" id="db_host" type="text" class="form-control" placeholder="localhost">
</div>
</div>
<div class="col-5 col-md-6">
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
<label class="text-capitalize">{{ $t('port') }}</label>
<label class="text-capitalize">{{ $t('db_port') }}</label>
<input @keyup="canSubmit" v-model="setup.db_port" id="db_port" type="number" class="form-control" placeholder="5432">
</div>
</div>
</div>
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
<label class="text-capitalize">{{ $t('username') }}</label>
<label class="text-capitalize">{{ $t('db_username') }}</label>
<input @keyup="canSubmit" v-model="setup.db_user" id="db_user" type="text" class="form-control" placeholder="root">
</div>
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
<label for="db_password" class="text-capitalize">{{ $t('password') }}</label>
<label for="db_password" class="text-capitalize">{{ $t('db_password') }}</label>
<input @keyup="canSubmit" v-model="setup.db_password" id="db_password" type="password" class="form-control" placeholder="password123">
</div>
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
<label for="db_database" class="text-capitalize">{{ $t('setup.database') }}</label>
<label for="db_database" class="text-capitalize">{{ $t('db_database') }}</label>
<input @keyup="canSubmit" v-model="setup.db_database" id="db_database" type="text" class="form-control" placeholder="Database name">
</div>
<div class="form-group mt-3">
<div class="row">
<div class="col-9">
<span class="text-left text-capitalize">{{ $t('setup.send_reports') }}</span>
<span class="text-left text-capitalize">{{ $t('send_reports') }}</span>
</div>
<div class="col-3 text-right">
<span @click="setup.send_reports = !!setup.send_reports" class="switch">
@ -72,32 +76,32 @@
<div class="col-12 col-md-6">
<div class="form-group">
<label class="text-capitalize">{{ $t('setup.project_name') }}</label>
<label class="text-capitalize">{{ $t('project_name') }}</label>
<input @keyup="canSubmit" v-model="setup.project" id="project" type="text" class="form-control" placeholder="Work Servers" required>
</div>
<div class="form-group">
<label class="text-capitalize">{{ $t('setup.project_description') }}</label>
<label class="text-capitalize">{{ $t('description') }}</label>
<input @keyup="canSubmit" v-model="setup.description" id="description" type="text" class="form-control" placeholder="Monitors all of my work services">
</div>
<div class="form-group">
<label class="text-capitalize" for="domain">{{ $t('setup.domain') }}</label>
<label class="text-capitalize" for="domain">{{ $t('domain') }}</label>
<input @keyup="canSubmit" v-model="setup.domain" type="text" class="form-control" id="domain" required>
</div>
<div class="form-group">
<label class="text-capitalize">{{ $t('setup.username') }}</label>
<label class="text-capitalize">{{ $t('username') }}</label>
<input @keyup="canSubmit" v-model="setup.username" id="username" type="text" class="form-control" placeholder="admin" required>
</div>
<div class="form-group">
<label class="text-capitalize">{{ $t('setup.password') }}</label>
<label class="text-capitalize">{{ $t('password') }}</label>
<input @keyup="canSubmit" v-model="setup.password" id="password" type="password" class="form-control" placeholder="password" required>
</div>
<div class="form-group">
<label class="text-capitalize">{{ $t('setup.password_confirm') }}</label>
<label class="text-capitalize">{{ $t('confirm_password') }}</label>
<input @keyup="canSubmit" v-model="setup.confirm_password" id="password_confirm" type="password" class="form-control" placeholder="password" required>
<span v-if="passnomatch" class="small text-danger">Both passwords should match</span>
</div>
@ -109,14 +113,14 @@
<input @keyup="canSubmit" v-model="setup.email" id="email" type="text" class="form-control" placeholder="myemail@domain.com">
</div>
<div class="col-4 text-right">
<label class="d-none d-sm-block text-capitalize text-capitalize">{{ $t('setup.newsletter') }}</label>
<label class="d-none d-sm-block text-capitalize text-capitalize">{{ $t('newsletter') }}</label>
<span @click="setup.newsletter = !!setup.newsletter" class="switch">
<input v-model="setup.newsletter" type="checkbox" name="send_newsletter" class="switch" id="send_newsletter" :checked="setup.newsletter">
<label for="send_newsletter"></label>
</span>
</div>
</div>
<small>{{ $t('setup.newsletter_note') }}</small>
<small>{{ $t('newsletter_note') }}</small>
</div>
</div>
@ -126,7 +130,7 @@
<div class="col-12">
<button @click.prevent="saveSetup" v-bind:disabled="disabled || loading" type="submit" class="btn btn-primary btn-block" :class="{'btn-primary': !loading, 'btn-default': loading}">
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/>{{loading ? "Loading..." : "Save Settings"}}
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/>{{loading ? $t('loading') : $t('save_settings')}}
</button>
</div>
</div>

View File

@ -1,6 +1,6 @@
<template>
<div class="card contain-card mb-3">
<div class="card-header"> {{user.id ? `Update ${user.username}` : "Create User"}}
<div class="card-header"> {{user.id ? `${$t('update')} ${user.username}` : $t('user_create')}}
<transition name="slide-fade">
<button @click.prevent="removeEdit" v-if="user.id" class="btn btn-sm float-right btn-danger btn-sm">Close</button>
</transition>
@ -8,31 +8,31 @@
<div class="card-body">
<form @submit="saveUser">
<div class="form-group row">
<label class="col-sm-4 col-form-label">Username</label>
<label class="col-sm-4 col-form-label">{{$t('username')}}</label>
<div class="col-6 col-md-4">
<input v-model="user.username" type="text" class="form-control" id="username" placeholder="Username" required autocorrect="off" autocapitalize="none" v-bind:readonly="user.id">
</div>
<div class="col-6 col-md-4">
<span id="admin_switch" @click="user.admin = !!user.admin" class="switch">
<input v-model="user.admin" type="checkbox" class="switch" id="user_admin_switch" v-bind:checked="user.admin">
<label for="user_admin_switch">Administrator</label>
<label for="user_admin_switch">{{$t('administrator')}}</label>
</span>
</div>
</div>
<div class="form-group row">
<label for="email" class="col-sm-4 col-form-label">Email Address</label>
<label for="email" class="col-sm-4 col-form-label">{{$t('email')}}</label>
<div class="col-sm-8">
<input v-model="user.email" type="email" class="form-control" id="email" placeholder="user@domain.com" required autocapitalize="none" spellcheck="false">
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Password</label>
<label class="col-sm-4 col-form-label">{{$t('password')}}</label>
<div class="col-sm-8">
<input v-model="user.password" type="password" id="password" class="form-control" placeholder="Password" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Confirm Password</label>
<label class="col-sm-4 col-form-label">{{$t('confirm_password')}}</label>
<div class="col-sm-8">
<input v-model="user.confirm_password" type="password" id="password_confirm" class="form-control" placeholder="Confirm Password" required>
</div>
@ -54,7 +54,7 @@
class="btn-primary"
:disabled="loading || !user.username || !user.email || !user.password || !user.confirm_password || (user.password !== user.confirm_password)"
:action="saveUser"
:label="user.id ? 'Update User' : 'Create User'"
:label="user.id ? $t('user_update'): $t('user_create')"
/>
</div>
</div>

133
frontend/src/languages/chinese.js Executable file
View File

@ -0,0 +1,133 @@
const chinese = {
settings: "设置",
dashboard: "仪表板",
services: "服务",
service: "服务",
failures: "失败",
users: "用户",
login: "登录",
logout: "注销",
online: "在线",
offline: "离线",
username: "用户名",
password: "密码",
email: "电子邮件",
confirm_password: "确认密码",
uptime: "正常运行时间",
name: "名称",
copy: "复制",
close: "关",
secret: "秘密",
regen_api: "重新生成 API 密钥",
regen_desc: "API 密码用于读取创建更新和删除路由。如果需要,您可以重新生成 API 密钥。",
visibility: "可见性",
group: "小组",
group_create: "创建组",
group_update: "更新组",
group_public_desc: "向公众显示群组服务",
groups: "组",
no_group: "无组",
public: "公共",
private: "私人",
announcements: "公告",
notifiers: "通告程序",
logs: "日志",
help: "帮助",
type: "类型",
edit: "编辑",
update: "更新",
create: "创建",
view: "查看",
save: "保存",
title: "标题",
status: "状态",
begins: "开始",
total_services: "服务总数",
online_services: "在线服务",
request_timeout: "请求超时",
service_never_online: "服务从未在线",
service_online_check: "在线检查",
service_offline_time: "服务已脱机",
days_ago: "天前",
today: "今天",
failures_24_hours: "过去 24 小时失败",
no_services: "您目前没有任何服务!",
theme: "主题",
cache: "高速缓存",
authentication: "身份验证",
import: "导入",
main_settings: "主要设置",
variables: "变量",
docs: "文档",
links: "链接",
changelog: "更改日志",
repo: "存储库",
language: "语言",
db_connection: "数据库连接",
db_host: "数据库主机",
db_port: "数据库端口",
db_username: "数据库用户名",
db_password: "数据库口令",
db_database: "数据库名称",
send_reports: "发送错误报告",
send_reports_desc: "将错误发送到 “状态” 以进行调试",
project_name: "状态页面名称",
description: "说明",
domain: "域",
enable_cdn: "启用 CDN",
newsletter: "新闻通讯",
newsletter_note: "我们只会向您发送重大变更的电子邮件",
loading: "正在加载",
save_settings: "保存设置",
average_response: "平均响应",
last_uptime: "上次正常运行时间",
sign_in: "登录",
last_login: "上次登录",
admin: "管理员",
user: "用户",
failed: "失败",
wrong_login: "用户名或密码不正确",
theme_editor: "主题编辑器",
enable_assets: "启用本地资产",
assets_desc: "通过启用本地资产自定义状态页面设计。这将创建一个包含所有 CSS 的 “资产” 目录。",
assets_btn: "启用本地资产",
assets_loading: "创建资产",
assets_dir: "资产目录",
footer: "页脚",
footer_notes: "您可以在页脚中使用 HTML 标签",
global_announcement: "全球公告",
announcement_date: "公告日期范围",
notify_users: "通知用户",
notify_desc: "在计划时间之前通知用户",
notify_method: "通知方法",
notify_before: "之前通知",
message_create: "创建公告",
message_edit: "编辑公告",
minutes: "分钟",
hours: "小时数",
days: "天数",
user_create: "创建用户",
user_update: "更新用户",
administrator: "管理员",
checkins: "车臣金斯",
incidents: "事件",
service_info: "服务信息",
service_name: "服务名称",
service_type: "服务类型",
permalink: "永久链接 URL",
service_public: "公共服务",
check_interval: "检查间隔",
service_endpoint: "服务终端节点",
service_check: "服务检查类型",
service_timeout: "请求超时",
expected_resp: "预期响应",
expected_code: "预期状态代码",
follow_redir: "跟随重定向",
verify_ssl: "验证 SSL",
tls_cert: "使用 TLS 证书",
notifications_enable: "启用通知",
notify_after: "故障后通知",
notify_all: "通知所有更改"
}
export default chinese

View File

@ -0,0 +1,133 @@
key,en
settings,Settings
dashboard,Dashboard
services,Services
service,Service
failures,Failures
users,Users
login,Login
logout,Logout
online,Online
offline,Offline
username,Username
password,Password
email,Email
confirm_password,Confirm Password
uptime,Uptime
name,Name
copy,Copy
close,Close
secret,Secret
regen_api,Regenerate API Keys
regen_desc,API Secret is used for read create update and delete routes. You can Regenerate API Keys if you need to.
visibility,Visibility
group,Group
group_create,Create Group
group_update,Update Group
group_public_desc,Show group services to the public
groups,Groups
no_group,No Group
public,Public
private,Private
announcements,Announcements
notifiers,Notifiers
logs,Logs
help,Help
type,Type
edit,Edit
update,Update
create,Create
view,View
save,Save
title,Title
status,Status
begins,Begins
total_services,Total Services
online_services,Online Services
request_timeout,Request Timeout
service_never_online,Service has never been online
service_online_check,Online checked
service_offline_time,Service has been offline for
days_ago,Days Ago
today,Today
failures_24_hours,Failures last 24 hours
no_services,You currently don't have any services!
theme,Theme
cache,Cache
authentication,Authentication
import,Import
main_settings,Main Settings
variables,Variables
docs,Documentation
links,Links
changelog,Change Log
repo,Repository
language,Language
db_connection,Database Connection
db_host,Database Host
db_port,Database Port
db_username,Database Username
db_password,Database Password
db_database,Database Name
send_reports,Send Error Reports
send_reports_desc,Send errors to Statping for debugging
project_name,Status Page Name
description,Description
domain,Domain
enable_cdn,Enable CDN
newsletter,Newsletter
newsletter_note,We will only send you an email for major changes
loading,Loading
save_settings,Save Settings
average_response,Average Response
last_uptime,Uptime last
sign_in,Sign In
last_login,Last Login
admin,Admin
user,User
failed,Failed
wrong_login,Incorrect username or password
theme_editor,Theme Editor
enable_assets,Enable Local Assets
assets_desc,Customize your status page design by enabling local assets. This will create a 'assets' directory containing all CSS.
assets_btn,Enable Local Assets
assets_loading,Creating Assets
assets_dir,Assets Directory
footer,Footer
footer_notes,You can use HTML tags in footer
global_announcement,Global Announcement
announcement_date,Announcement Date Range
notify_users,Notify Users
notify_desc,Notify Users Before Scheduled Time
notify_method,Notification Method
notify_before,Notify Before
message_create,Create Announcement
message_edit,Edit Announcement
minutes,Minutes
hours,Hours
days,Days
user_create,Create User
user_update,Update User
administrator,Administrator
checkins,Checkins
incidents,Incidents
service_info,Service Info
service_name,Service Name
service_type,Service Type
permalink,Permalink URL
service_public,Public Service
check_interval,Check Interval
service_endpoint,Service Endpoint
service_check,Service Check Type
service_timeout,Request Timeout
expected_resp,Expected Response
expected_code,Expected Status Code
follow_redir,Follow Redirects
verify_ssl,Verify SSL
tls_cert,Use TLS Cert
notification_opts,Notification Options
notifications_enable,Enable Notifications
notify_after,Notify After Failures
notify_all,Notify All Changes
service_update,Update Service
service_create,Create Service
1 key en
2 settings Settings
3 dashboard Dashboard
4 services Services
5 service Service
6 failures Failures
7 users Users
8 login Login
9 logout Logout
10 online Online
11 offline Offline
12 username Username
13 password Password
14 email Email
15 confirm_password Confirm Password
16 uptime Uptime
17 name Name
18 copy Copy
19 close Close
20 secret Secret
21 regen_api Regenerate API Keys
22 regen_desc API Secret is used for read create update and delete routes. You can Regenerate API Keys if you need to.
23 visibility Visibility
24 group Group
25 group_create Create Group
26 group_update Update Group
27 group_public_desc Show group services to the public
28 groups Groups
29 no_group No Group
30 public Public
31 private Private
32 announcements Announcements
33 notifiers Notifiers
34 logs Logs
35 help Help
36 type Type
37 edit Edit
38 update Update
39 create Create
40 view View
41 save Save
42 title Title
43 status Status
44 begins Begins
45 total_services Total Services
46 online_services Online Services
47 request_timeout Request Timeout
48 service_never_online Service has never been online
49 service_online_check Online checked
50 service_offline_time Service has been offline for
51 days_ago Days Ago
52 today Today
53 failures_24_hours Failures last 24 hours
54 no_services You currently don't have any services!
55 theme Theme
56 cache Cache
57 authentication Authentication
58 import Import
59 main_settings Main Settings
60 variables Variables
61 docs Documentation
62 links Links
63 changelog Change Log
64 repo Repository
65 language Language
66 db_connection Database Connection
67 db_host Database Host
68 db_port Database Port
69 db_username Database Username
70 db_password Database Password
71 db_database Database Name
72 send_reports Send Error Reports
73 send_reports_desc Send errors to Statping for debugging
74 project_name Status Page Name
75 description Description
76 domain Domain
77 enable_cdn Enable CDN
78 newsletter Newsletter
79 newsletter_note We will only send you an email for major changes
80 loading Loading
81 save_settings Save Settings
82 average_response Average Response
83 last_uptime Uptime last
84 sign_in Sign In
85 last_login Last Login
86 admin Admin
87 user User
88 failed Failed
89 wrong_login Incorrect username or password
90 theme_editor Theme Editor
91 enable_assets Enable Local Assets
92 assets_desc Customize your status page design by enabling local assets. This will create a 'assets' directory containing all CSS.
93 assets_btn Enable Local Assets
94 assets_loading Creating Assets
95 assets_dir Assets Directory
96 footer Footer
97 footer_notes You can use HTML tags in footer
98 global_announcement Global Announcement
99 announcement_date Announcement Date Range
100 notify_users Notify Users
101 notify_desc Notify Users Before Scheduled Time
102 notify_method Notification Method
103 notify_before Notify Before
104 message_create Create Announcement
105 message_edit Edit Announcement
106 minutes Minutes
107 hours Hours
108 days Days
109 user_create Create User
110 user_update Update User
111 administrator Administrator
112 checkins Checkins
113 incidents Incidents
114 service_info Service Info
115 service_name Service Name
116 service_type Service Type
117 permalink Permalink URL
118 service_public Public Service
119 check_interval Check Interval
120 service_endpoint Service Endpoint
121 service_check Service Check Type
122 service_timeout Request Timeout
123 expected_resp Expected Response
124 expected_code Expected Status Code
125 follow_redir Follow Redirects
126 verify_ssl Verify SSL
127 tls_cert Use TLS Cert
128 notification_opts Notification Options
129 notifications_enable Enable Notifications
130 notify_after Notify After Failures
131 notify_all Notify All Changes
132 service_update Update Service
133 service_create Create Service

View File

@ -1,101 +1,133 @@
const english = {
top_nav: {
settings: "Settings",
dashboard: "Dashboard",
services: "Services",
service: "Service",
failures: "Failures",
users: "Users",
login: "Login",
logout: "Logout",
online: "Online",
offline: "Offline",
username: "Username",
password: "Password",
email: "Email",
confirm_password: "Confirm Password",
uptime: "Uptime",
name: "Name",
copy: "Copy",
close: "Close",
secret: "Secret",
regen_api: "Regenerate API Keys",
regen_desc: "API Secret is used for read create update and delete routes. You can Regenerate API Keys if you need to.",
visibility: "Visibility",
group: "Group",
group_create: "Create Group",
group_update: "Update Group",
group_public_desc: "Show group services to the public",
groups: "Groups",
no_group: "No Group",
public: "Public",
private: "Private",
announcements: "Announcements",
settings: "Settings",
notifiers: "Notifiers",
logs: "Logs",
help: "Help",
logout: 'Logout',
},
setup: {
language: "Language",
connection: "Database Connection",
host: "Host",
database: "Database",
project_name: "Project Name",
project_description: "Project Description",
domain: "Domain URL",
username: "Admin Username",
password: "Admin Password",
password_confirm: "Confirm Admin Password",
newsletter: "Newsletter",
newsletter_note: "We will not share your email, emails are only for major updates.",
send_reports: "Send Error Reports to Statping"
},
dashboard: {
type: "Type",
edit: "Edit",
update: "Update",
create: "Create",
view: "View",
save: "Save",
title: "Title",
status: "Status",
begins: "Begins",
total_services: "Total Services",
failures_24_hours: "Failures last 24 Hours",
online_services: "Online Services",
service: 'Service | Services',
group: 'Group',
title: 'Title',
begins: 'Begins',
name: 'Name',
loading: 'Loading',
login: 'Login',
sign_in: "Sign In",
visibility: 'Visibility',
wrong_login: 'Incorrect username or password'
},
settings: {
name: "Site Name",
description: "Site Description",
footer: "Custom Footer",
footer_notes: "HTML is allowed inside the footer",
error_reporting: "Enable Error Reporting",
error_reporting_notes: "Help the Statping project out by sending anonymous error logs back to our server.",
save: "Save Settings",
main: "Main Settings",
theme: "Theme Editor",
request_timeout: "Request Timeout",
service_never_online: "Service has never been online",
service_online_check: "Online checked",
service_offline_time: "Service has been offline for",
days_ago: "Days Ago",
today: "Today",
failures_24_hours: "Failures last 24 hours",
no_services: "You currently don't have any services!",
theme: "Theme",
cache: "Cache",
oauth: "OAuth",
beta: "BETA",
changelog: "Changelog",
repo: "Statping Github Repo",
authentication: "Authentication",
import: "Import",
main_settings: "Main Settings",
variables: "Variables",
docs: "Documentation",
},
service: {
name: "Service Name",
type: "Service Type",
info: "Service Information",
view: "View Service",
average: "Average Response",
last_uptime: "Uptime last {0} {1}",
},
email: "Email Address",
port: "Database Port",
setting: "Settings",
username: "Username",
password: 'Password',
services: 'Services',
domain: 'Domain',
online: 'online',
public: 'Public',
private: 'Private',
admin: 'Admin',
offline: 'offline',
failure: 'failure | failures',
incident: 'incident | incidents',
checkin: 'checkin | checkins',
user: 'User | Users',
group: 'Group',
message: 'message',
edit: 'Edit',
type: 'Type',
sample_data: 'Sample Data',
today: 'Today',
last_login: 'Last Login',
uptime: '{0}% Uptime',
close: 'Close',
second: 'second | seconds',
minute: 'minute | minutes',
hour: 'hour | hours',
day: 'day | days',
week: 'week | weeks',
month: 'month | months',
links: "Links",
changelog: "Change Log",
repo: "Repository",
language: "Language",
db_connection: "Database Connection",
db_host: "Database Host",
db_port: "Database Port",
db_username: "Database Username",
db_password: "Database Password",
db_database: "Database Name",
send_reports: "Send Error Reports",
send_reports_desc: "Send errors to Statping for debugging",
project_name: "Status Page Name",
description: "Description",
domain: "Domain",
enable_cdn: "Enable CDN",
newsletter: "Newsletter",
newsletter_note: "We will only send you an email for major changes",
loading: "Loading",
save_settings: "Save Settings",
average_response: "Average Response",
last_uptime: "Uptime last",
sign_in: "Sign In",
last_login: "Last Login",
admin: "Admin",
user: "User",
failed: "Failed",
wrong_login: "Incorrect username or password",
theme_editor: "Theme Editor",
enable_assets: "Enable Local Assets",
assets_desc: "Customize your status page design by enabling local assets. This will create a 'assets' directory containing all CSS.",
assets_btn: "Enable Local Assets",
assets_loading: "Creating Assets",
assets_dir: "Assets Directory",
footer: "Footer",
footer_notes: "You can use HTML tags in footer",
global_announcement: "Global Announcement",
announcement_date: "Announcement Date Range",
notify_users: "Notify Users",
notify_desc: "Notify Users Before Scheduled Time",
notify_method: "Notification Method",
notify_before: "Notify Before",
message_create: "Create Announcement",
message_edit: "Edit Announcement",
minutes: "Minutes",
hours: "Hours",
days: "Days",
user_create: "Create User",
user_update: "Update User",
administrator: "Administrator",
checkins: "Checkins",
incidents: "Incidents",
service_info: "Service Info",
service_name: "Service Name",
service_type: "Service Type",
permalink: "Permalink URL",
service_public: "Public Service",
check_interval: "Check Interval",
service_endpoint: "Service Endpoint",
service_check: "Service Check Type",
service_timeout: "Request Timeout",
expected_resp: "Expected Response",
expected_code: "Expected Status Code",
follow_redir: "Follow Redirects",
verify_ssl: "Verify SSL",
tls_cert: "Use TLS Cert",
notifications_enable: "Enable Notifications",
notify_after: "Notify After Failures",
notify_all: "Notify All Changes"
}
export default english
export default english

View File

@ -1,101 +1,133 @@
const french = {
top_nav: {
dashboard: "Dashboard",
settings: "Paramètres",
dashboard: "Tableau de bord",
services: "Services",
users: "Users",
groups: "Groups",
announcements: "Announcements",
settings: "Settings",
logs: "Logs",
help: "Help",
logout: 'Logout',
},
setup: {
language: "Language",
connection: "Database Connection",
host: "Host",
database: "Database",
project_name: "Project Name",
project_description: "Project Description",
domain: "Domain URL",
username: "Admin Username",
password: "Admin Password",
password_confirm: "Confirm Admin Password",
newsletter: "Newsletter",
newsletter_note: "We will not share your email, emails are only for major updates.",
send_reports: "Send Error Reports to Statping"
},
dashboard: {
total_services: "Total Services",
failures_24_hours: "Failures last 24 Hours",
online_services: "Online Services",
service: 'Service | Services',
group: 'Group',
title: 'Title',
begins: 'Begins',
name: 'Name',
loading: 'Loading',
login: 'Login',
sign_in: "Sign In",
visibility: 'Visibility',
wrong_login: 'Incorrect username or password'
},
settings: {
name: "Project Name",
description: "Project Name",
footer: "Custom Footer",
footer_notes: "HTML is allowed inside the footer",
error_reporting: "Enable Error Reporting",
error_reporting_notes: "Help the Statping project out by sending anonymous error logs back to our server.",
save: "Save Settings",
main: "Main Settings",
theme: "Theme Editor",
service: "Service",
failures: "Échecs",
users: "Utilisateurs",
login: "Identifiant",
logout: "Déconnexion",
online: "En ligne",
offline: "Offline",
username: "Nom d'utilisateur",
password: "mot de passe",
email: "Email",
confirm_password: "Confirmer le",
uptime: "Temps de disponibilité",
name: "Nom",
copy: "Copie",
close: "Fermer",
secret: "Secret",
regen_api: "Régénérer les clés d'API",
regen_desc: "API Secret est utilisé pour lire créer des routes de mise à jour et de suppression. Vous pouvez Régénérer les clés d'API si vous en avez besoin.",
visibility: "Visibilité",
group: "Groupe",
group_create: "Créer un groupe",
group_update: "Groupe Mettre à jour",
group_public_desc: "Afficher les services de groupe au public",
groups: "Groupes",
no_group: "Pas de groupe",
public: "Publique",
private: "Privé",
announcements: "Annonces",
notifiers: "Notifiants",
logs: "Journaux",
help: "Aider",
type: "Type",
edit: "Éditer",
update: "Mise à jour",
create: "Créer",
view: "Voir",
save: "Sauvegarder",
title: "Titre",
status: "Statut",
begins: "Commence",
total_services: "Total des services",
online_services: "Services en ligne",
request_timeout: "Délai d'attente de",
service_never_online: "Le service n'a jamais été en ligne",
service_online_check: "Vérifié en ligne",
service_offline_time: "Le service a été hors ligne pour",
days_ago: "Il y a jours",
today: "Aujourd'hui",
failures_24_hours: "Les échecs durent 24 heures",
no_services: "Vous n'avez actuellement aucun service !",
theme: "Thème",
cache: "Cache",
oauth: "OAuth",
beta: "BETA",
changelog: "Changelog",
repo: "Statping Github Repo",
authentication: "Authentification",
import: "Importer",
main_settings: "Paramètres principaux",
variables: "Variables",
docs: "Documentation",
},
service: {
name: "Service Name",
type: "Service Type",
info: "Service Information",
view: "View Service",
average: "Average Response",
last_uptime: "Uptime last {0} {1}",
},
email: "Email Address",
port: "Database Port",
setting: "Settings",
username: "Username",
password: 'Password',
services: 'Services',
domain: 'Domain',
online: 'online',
public: 'Public',
private: 'Private',
admin: 'Admin',
offline: 'offline',
failure: 'failure | failures',
incident: 'incident | incidents',
checkin: 'checkin | checkins',
user: 'User | Users',
group: 'Group',
message: 'message',
edit: 'Edit',
type: 'Type',
sample_data: 'Sample Data',
today: 'Today',
last_login: 'Last Login',
uptime: '{0}% Uptime',
close: 'Close',
second: 'second | seconds',
minute: 'minute | minutes',
hour: 'hour | hours',
day: 'day | days',
week: 'week | weeks',
month: 'month | months',
links: "Links",
changelog: "Journal des modifications",
repo: "Référentiel",
language: "Langue",
db_connection: "Connexion à la base",
db_host: "Hôte de base",
db_port: "Port base de données",
db_username: "Nom utilisateur de base",
db_password: "Mot de passe",
db_database: "Nom de la base",
send_reports: "Envoyer des rapports d'erreurs",
send_reports_desc: "Envoyer des erreurs à Statping pour le débogage",
project_name: "Nom de la page d'état",
description: "Description",
domain: "Domaine",
enable_cdn: "Activer le CDN",
newsletter: "Bulletin",
newsletter_note: "Nous ne vous enverrons qu'un e-mail pour les modifications majeures",
loading: "Chargement",
save_settings: "Enregistrer les paramètres",
average_response: "Réponse moyenne",
last_uptime: "Temps de disponibilité dernier",
sign_in: "Se connecter",
last_login: "Dernière connexion",
admin: "Admin",
user: "Utilisateur",
failed: "Échec",
wrong_login: "Nom d'utilisateur ou mot de passe",
theme_editor: "Editeur de thème",
enable_assets: "Activer les actifs locaux",
assets_desc: "Personnalisez la conception de votre page d'état en activant les ressources locales. Cela va créer un répertoire 'assets' contenant tous les CSS.",
assets_btn: "Activer les actifs locaux",
assets_loading: "Création d'actifs",
assets_dir: "Répertoire des actifs",
footer: "Pied de page",
footer_notes: "Vous pouvez utiliser des balises HTML dans le pied de page",
global_announcement: "Annonce mondiale",
announcement_date: "Fourchette de dates d'annonce",
notify_users: "Aviser les utilisateurs",
notify_desc: "Avertir les utilisateurs avant l'heure prévue",
notify_method: "Méthode de notification",
notify_before: "Avertir avant",
message_create: "Créer une annonce",
message_edit: "Modifier l'annonce",
minutes: "Procès-Verbal",
hours: "Heures",
days: "Jours",
user_create: "Créer un utilisateur",
user_update: "Mise à jour utilisateur",
administrator: "Administrateur",
checkins: "Checkins",
incidents: "Incidents",
service_info: "Informations sur le service",
service_name: "Nom du service",
service_type: "Type de service",
permalink: "URL Permalien",
service_public: "Fonction publique",
check_interval: "Période de vérification",
service_endpoint: "Point de terminaison de service",
service_check: "Type de vérification de service",
service_timeout: "Délai d'attente de",
expected_resp: "Réponse attendue",
expected_code: "Code d'état attendu",
follow_redir: "Suivre les redirections",
verify_ssl: "Vérifier SSL",
tls_cert: "Utiliser le certificat TLS",
notifications_enable: "Activer les notifications",
notify_after: "Notification après les échecs",
notify_all: "Notifier toutes les modifications"
}
export default french
export default french

View File

@ -1,101 +1,133 @@
const german = {
top_nav: {
dashboard: "Dashboard",
services: "Services",
users: "Users",
groups: "Groups",
announcements: "Announcements",
settings: "Settings",
logs: "Logs",
help: "Help",
logout: 'Logout',
},
setup: {
language: "Language",
connection: "Database Connection",
host: "Host",
database: "Database",
project_name: "Project Name",
project_description: "Project Description",
domain: "Domain URL",
username: "Admin Username",
password: "Admin Password",
password_confirm: "Confirm Admin Password",
newsletter: "Newsletter",
newsletter_note: "We will not share your email, emails are only for major updates.",
send_reports: "Send Error Reports to Statping"
},
dashboard: {
total_services: "Total Services",
failures_24_hours: "Failures last 24 Hours",
online_services: "Online Services",
service: 'Service | Services',
group: 'Group',
title: 'Title',
begins: 'Begins',
name: 'Name',
loading: 'Loading',
login: 'Login',
sign_in: "Sign In",
visibility: 'Visibility',
wrong_login: 'Incorrect username or password'
},
settings: {
name: "Project Name",
description: "Project Name",
footer: "Custom Footer",
footer_notes: "HTML is allowed inside the footer",
error_reporting: "Enable Error Reporting",
error_reporting_notes: "Help the Statping project out by sending anonymous error logs back to our server.",
save: "Save Settings",
main: "Main Settings",
theme: "Theme Editor",
settings: "Einstellungen",
dashboard: "Armaturenbrett",
services: "Dienstleistungen",
service: "Service",
failures: "Ausfälle",
users: "Benutzer",
login: "Login",
logout: "Abmelden",
online: "Online",
offline: "Offline",
username: "Benutzername",
password: "Kennwort",
email: "Mail",
confirm_password: "Passwort bestätigen",
uptime: "Betriebszeit",
name: "Name",
copy: "Kopie",
close: "Schließen",
secret: "Geheimnis",
regen_api: "API-Schlüssel neu generieren",
regen_desc: "API Secret wird für Lesen erstellen Update und Löschen Routen verwendet. Sie können API-Schlüssel bei Bedarf neu generieren.",
visibility: "Sichtbarkeit",
group: "Gruppe",
group_create: "Gruppe erstellen",
group_update: "Gruppe aktualisieren",
group_public_desc: "Gruppendienste für die Öffentlichkeit anzeigen",
groups: "Gruppen",
no_group: "Keine Gruppe",
public: "Öffentlichkeit",
private: "Privat",
announcements: "Ankündigungen",
notifiers: "Notifizierer",
logs: "Protokolle",
help: "Helfen",
type: "Typ",
edit: "Bearbeiten",
update: "Update",
create: "Schaffen",
view: "Ansicht",
save: "sparen",
title: "Titel",
status: "Status",
begins: "Beginnt",
total_services: "Dienstleistungen insgesamt",
online_services: "Online-Dienste",
request_timeout: "Zeitüberschreitung anfordern",
service_never_online: "Service war noch nie online",
service_online_check: "Online geprüft",
service_offline_time: "Dienst war offline für",
days_ago: "Vor Tagen",
today: "Heute",
failures_24_hours: "Ausfälle dauern 24 Stunden",
no_services: "Sie haben derzeit keine Dienste!",
theme: "Thema",
cache: "Cache",
oauth: "OAuth",
beta: "BETA",
changelog: "Changelog",
repo: "Statping Github Repo",
docs: "Documentation",
},
service: {
name: "Service Name",
type: "Service Type",
info: "Service Information",
view: "View Service",
average: "Average Response",
last_uptime: "Uptime last {0} {1}",
},
email: "Email Address",
port: "Database Port",
setting: "Settings",
username: "Username",
password: 'Password',
services: 'Services',
domain: 'Domain',
online: 'online',
public: 'Public',
private: 'Private',
admin: 'Admin',
offline: 'offline',
failure: 'failure | failures',
incident: 'incident | incidents',
checkin: 'checkin | checkins',
user: 'User | Users',
group: 'Group',
message: 'message',
edit: 'Edit',
type: 'Type',
sample_data: 'Sample Data',
today: 'Today',
last_login: 'Last Login',
uptime: '{0}% Uptime',
close: 'Close',
second: 'second | seconds',
minute: 'minute | minutes',
hour: 'hour | hours',
day: 'day | days',
week: 'week | weeks',
month: 'month | months',
authentication: "Authentifikation",
import: "Importieren",
main_settings: "Haupteinstellungen",
variables: "Variablen",
docs: "Dokumentation",
links: "Links",
changelog: "Protokoll ändern",
repo: "Depot",
language: "Sprache",
db_connection: "Datenbankverbindung",
db_host: "Datenbank-Host",
db_port: "Datenbank-Port",
db_username: "Datenbank-Benutzername",
db_password: "Datenbank-Kennwort",
db_database: "Name der Datenbank",
send_reports: "Fehlerberichte senden",
send_reports_desc: "Fehler zum Debuggen an Statping senden",
project_name: "Name der Seite „Status“",
description: "Beschreibung",
domain: "Domäne",
enable_cdn: "CDN aktivieren",
newsletter: "Newsletter",
newsletter_note: "Wir senden Ihnen nur eine E-Mail für größere Änderungen",
loading: "Laden",
save_settings: "Einstellungen speichern",
average_response: "Durchschnittliche Antwort",
last_uptime: "Betriebszeit zuletzt",
sign_in: "Anmelden",
last_login: "Letzte Anmeldung",
admin: "Admin",
user: "Benutzer",
failed: "Fehlgeschlagen",
wrong_login: "Falscher Benutzername oder Passwort",
theme_editor: "Theme-Editor",
enable_assets: "Lokale Assets aktivieren",
assets_desc: "Passen Sie das Design Ihrer Statusseite an, indem Sie lokale Elemente aktivieren. Dadurch wird ein Verzeichnis „Assets“ erstellt, das alle CSS enthält.",
assets_btn: "Lokale Assets aktivieren",
assets_loading: "Erstellen von Assets",
assets_dir: "Assets Verzeichnis",
footer: "Fußzeile",
footer_notes: "Sie können HTML-Tags in der Fußzeile verwenden",
global_announcement: "Globale Ankündigung",
announcement_date: "Datumsbereich für Ankündigung",
notify_users: "Benutzer benachrichtigen",
notify_desc: "Benutzer vor geplanter Zeit benachrichtigen",
notify_method: "Benachrichtigungsmethode",
notify_before: "Vor benachrichtigen",
message_create: "Ankündigung erstellen",
message_edit: "Ankündigung bearbeiten",
minutes: "Protokoll",
hours: "Stunden",
days: "Tage",
user_create: "Benutzer erstellen",
user_update: "Benutzer aktualisieren",
administrator: "Administrator",
checkins: "Checkins",
incidents: "Vorfälle",
service_info: "Service-Info",
service_name: "Dienstname",
service_type: "Service-Art",
permalink: "Permalink-URL",
service_public: "Öffentlicher Dienst",
check_interval: "Intervall prüfen",
service_endpoint: "Service-Endpunkt",
service_check: "Service-Prüfungstyp",
service_timeout: "Zeitüberschreitung anfordern",
expected_resp: "Erwartete Antwort",
expected_code: "Erwarteter Statuscode",
follow_redir: "Weiterleitungen folgen",
verify_ssl: "SSL verifizieren",
tls_cert: "TLS-Zertifikat verwenden",
notifications_enable: "Benachrichtigungen aktivieren",
notify_after: "Benachrichtigung nach Fehlern",
notify_all: "Alle Änderungen benachrichtigen"
}
export default german
export default german

View File

@ -3,6 +3,10 @@ import spanish from "./spanish"
import german from "./german"
import russian from "./russian";
import french from "./french";
import japanese from "./japanese";
import chinese from "./chinese";
import korean from "./korean";
import italian from "./italian";
const language = {
en: english,
@ -10,6 +14,10 @@ const language = {
de: german,
ru: russian,
fr: french,
ja: japanese,
zh: chinese,
ko: korean,
it: italian,
}
export default language

133
frontend/src/languages/italian.js Executable file
View File

@ -0,0 +1,133 @@
const italian = {
settings: "Impostazioni",
dashboard: "cruscotto",
services: "Servizi",
service: "Servizio",
failures: "Fallimenti",
users: "Utenti",
login: "Login",
logout: "Disconnetti",
online: "Online",
offline: "Offline",
username: "Nome utente",
password: "Password",
email: "E-mail",
confirm_password: "Conferma password",
uptime: "Tempi di attività",
name: "Nome",
copy: "Copia",
close: "Vicino",
secret: "Segreto",
regen_api: "Rigenera chiavi API",
regen_desc: "API Secret viene utilizzato per leggere creare aggiornamento ed eliminare route. Se necessario, è possibile rigenerare le chiavi API.",
visibility: "Visibilità",
group: "Gruppo",
group_create: "Crea gruppo",
group_update: "Aggiorna gruppo",
group_public_desc: "Mostra i servizi di gruppo al pubblico",
groups: "Gruppi",
no_group: "Nessun gruppo",
public: "Pubblico",
private: "Privato",
announcements: "Comunicazioni",
notifiers: "Notificatori",
logs: "Log",
help: "Guida",
type: "Tipo",
edit: "Modifica",
update: "Aggiorna",
create: "Crea",
view: "Visualizza",
save: "Salvare",
title: "Titolo",
status: "Stato",
begins: "Inizia",
total_services: "Totale servizi",
online_services: "Servizi online",
request_timeout: "Timeout richiesta",
service_never_online: "Il servizio non è mai stato online",
service_online_check: "Controllato online",
service_offline_time: "Il servizio è stato offline per",
days_ago: "Giorni fa",
today: "Oggi",
failures_24_hours: "Errori nelle ultime 24 ore",
no_services: "Al momento non hai alcun servizio!",
theme: "Tema",
cache: "Cache",
authentication: "autenticazione",
import: "Importa",
main_settings: "Impostazioni principali",
variables: "Variabili",
docs: "Documentazione",
links: "Collegamenti",
changelog: "Registro delle modifiche",
repo: "repository",
language: "Lingua",
db_connection: "Connessione al database",
db_host: "Host del database",
db_port: "Porta del database",
db_username: "Nome utente del database",
db_password: "Password del database",
db_database: "Nome database",
send_reports: "Invia segnalazioni errori",
send_reports_desc: "Invia errori a Statping per il debug",
project_name: "Nome pagina di stato",
description: "Descrizione",
domain: "Dominio",
enable_cdn: "Abilita CDN",
newsletter: "Bollettino",
newsletter_note: "Ti invieremo solo una e-mail per le modifiche più importanti",
loading: "Caricamento",
save_settings: "Salva impostazioni",
average_response: "Risposta media",
last_uptime: "Ultimo tempo di attività",
sign_in: "Accedi",
last_login: "Ultimo Login",
admin: "Amministratore",
user: "Utente",
failed: "Non riuscito",
wrong_login: "Nome utente o password non corretti",
theme_editor: "Editor tema",
enable_assets: "Abilita risorse locali",
assets_desc: "Personalizza la progettazione della pagina di stato abilitando le risorse locali. Questo creerà una directory 'asset' contenente tutti i CSS.",
assets_btn: "Abilita risorse locali",
assets_loading: "Creazione di risorse",
assets_dir: "Directory delle risorse",
footer: "Piè di pagina",
footer_notes: "È possibile utilizzare i tag HTML nel piè di pagina",
global_announcement: "Annuncio globale",
announcement_date: "Intervallo di date di annuncio",
notify_users: "Notify agli utenti",
notify_desc: "Notifichi agli utenti prima dell'ora pianific",
notify_method: "Metodo di notifica",
notify_before: "Notifichi prima",
message_create: "Crea annuncio",
message_edit: "Modifica annuncio",
minutes: "Minuti",
hours: "Ore",
days: "Giorni",
user_create: "Crea utente",
user_update: "Aggiorna utente",
administrator: "Amministratore",
checkins: "Check-ins",
incidents: "Incidenti",
service_info: "Info servizio",
service_name: "Nome servizio",
service_type: "Tipo di servizio",
permalink: "URL Permalink",
service_public: "Servizio pubblico",
check_interval: "Intervallo controllo",
service_endpoint: "Endpoint servizio",
service_check: "Tipo di controllo del servizio",
service_timeout: "Timeout richiesta",
expected_resp: "Risposta prevista",
expected_code: "Codice di stato previsto",
follow_redir: "Segui i reindirizzamenti",
verify_ssl: "Verifica SSL",
tls_cert: "Usa certificato TLS",
notifications_enable: "Abilita notifiche",
notify_after: "Notify dopo gli errori",
notify_all: "Notifichi tutte le modifiche"
}
export default italian

View File

@ -0,0 +1,133 @@
const japanese = {
settings: "設定",
dashboard: "ダッシュボード",
services: "サービス",
service: "サービス",
failures: "障害",
users: "ユーザー",
login: "ログイン",
logout: "ログアウト",
online: "オンライン",
offline: "オフライン",
username: "ユーザ名",
password: "パスワード",
email: "Eメール",
confirm_password: "パスワードの確認",
uptime: "稼働時間",
name: "氏名",
copy: "コピー",
close: "閉じる",
secret: "秘密",
regen_api: "API キーの再生成",
regen_desc: "APIシークレットは、ルート作成の更新と削除の読み込みに使用されます。必要に応じて、API キーを再生成できます。",
visibility: "可視性",
group: "グループ",
group_create: "[グループを作成]",
group_update: "[グループを更新]",
group_public_desc: "グループサービスを一般公開する",
groups: "グループ",
no_group: "グループなし",
public: "パブリック",
private: "私立",
announcements: "アナウンス",
notifiers: "通知者",
logs: "ログ",
help: "ヘルプ",
type: "タイプ",
edit: "編集",
update: "更新",
create: "作成",
view: "ビュー",
save: "保存する",
title: "タイトル",
status: "ステータス",
begins: "開始する",
total_services: "トータルサービス",
online_services: "オンラインサービス",
request_timeout: "リクエストのタイムアウト",
service_never_online: "サービスがオンラインになったことがない",
service_online_check: "オンラインチェック済み",
service_offline_time: "のサービスがオフラインになりました",
days_ago: "日前",
today: "今日",
failures_24_hours: "過去 24 時間の障害",
no_services: "現在、サービスをお持ちになりません。",
theme: "テーマ",
cache: "キャッシュ",
authentication: "認証",
import: "インポート",
main_settings: "メイン設定",
variables: "変数",
docs: "ドキュメント",
links: "リンク",
changelog: "変更ログ",
repo: "リポジトリ",
language: "言語",
db_connection: "データベース接続",
db_host: "データベース・ホスト",
db_port: "データベースポート",
db_username: "データベースのユーザー名",
db_password: "データベースパスワード",
db_database: "データベース名",
send_reports: "エラーレポートを送信",
send_reports_desc: "デバッグのためにエラーを Statping に送信する",
project_name: "ステータスページ名",
description: "説明",
domain: "ドメイン",
enable_cdn: "CDN を有効にする",
newsletter: "ニュースレター",
newsletter_note: "大きな変更についてのみメールをお送りします",
loading: "ロード中",
save_settings: "設定を保存",
average_response: "平均応答",
last_uptime: "稼働時間最後",
sign_in: "サインイン",
last_login: "最終ログイン",
admin: "管理者",
user: "ユーザー",
failed: "失敗しました",
wrong_login: "ユーザー名またはパスワードが正しくありません",
theme_editor: "テーマ・エディター",
enable_assets: "ローカルアセットを有効にする",
assets_desc: "ローカルアセットを有効にして、ステータスページのデザインをカスタマイズします。これにより、すべてのCSSを含む「assets」ディレクトリが作成されます。",
assets_btn: "ローカルアセットを有効にする",
assets_loading: "アセットの作成",
assets_dir: "アセットディレクトリ",
footer: "フッター",
footer_notes: "あなたはフッターにHTMLタグを使用することができます",
global_announcement: "グローバル発表",
announcement_date: "発表日の範囲",
notify_users: "ユーザーに通知",
notify_desc: "スケジュールされた時間前にユーザーに通知する",
notify_method: "通知方法",
notify_before: "前に通知する",
message_create: "アナウンスの作成",
message_edit: "アナウンスの編集",
minutes: "分単位",
hours: "時間",
days: "日数",
user_create: "ユーザーの作成",
user_update: "ユーザーの更新",
administrator: "管理者",
checkins: "チェックイン",
incidents: "事変",
service_info: "サービス情報",
service_name: "サービス名",
service_type: "サービスタイプ",
permalink: "パーマリンクURL",
service_public: "公共サービス",
check_interval: "チェック間隔",
service_endpoint: "サービスエンドポイント",
service_check: "サービス・チェック・タイプ",
service_timeout: "リクエストのタイムアウト",
expected_resp: "期待される応答",
expected_code: "予想されるステータスコード",
follow_redir: "リダイレクトに従う",
verify_ssl: "SSL の確認",
tls_cert: "TLS 証明書を使用",
notifications_enable: "通知を有効にする",
notify_after: "障害発生後に通知する",
notify_all: "すべての変更を通知"
}
export default japanese

133
frontend/src/languages/korean.js Executable file
View File

@ -0,0 +1,133 @@
const korean = {
settings: "설정",
dashboard: "대시보드",
services: "서비스",
service: "서비스",
failures: "장애",
users: "사용자",
login: "로그인",
logout: "로그아웃",
online: "온라인",
offline: "오프라인",
username: "사용자 이름",
password: "비밀번호",
email: "이메일",
confirm_password: "비밀번호 확인",
uptime: "가동 시간",
name: "이름",
copy: "복사",
close: "닫기",
secret: "비밀",
regen_api: "API 키 재생성",
regen_desc: "API 비밀은 읽기 생성 업데이트 및 삭제 경로를 위해 사용됩니다.필요한 경우 API 키를 재생성할 수 있습니다.",
visibility: "가시성",
group: "그룹",
group_create: "그룹 만들기",
group_update: "그룹 업데이트",
group_public_desc: "일반인에게 그룹 서비스 표시",
groups: "그룹",
no_group: "그룹 없음",
public: "공공",
private: "비공개",
announcements: "공지사항",
notifiers: "통지자",
logs: "로그",
help: "도움말",
type: "유형",
edit: "편집",
update: "업데이트",
create: "만들기",
view: "보기",
save: "저장",
title: "제목",
status: "상태",
begins: "시작",
total_services: "총 서비스",
online_services: "온라인 서비스",
request_timeout: "요청 시간 초과",
service_never_online: "서비스는 온라인 적이 없습니다",
service_online_check: "온라인 확인",
service_offline_time: "서비스가 에 대해 오프라인되었습니다.",
days_ago: "일 전",
today: "오늘",
failures_24_hours: "지난 24시간 동안 장애 발생",
no_services: "현재 서비스가 없습니다!",
theme: "테마",
cache: "캐시",
authentication: "인증",
import: "가져오기",
main_settings: "주 설정",
variables: "변수",
docs: "설명서",
links: "링크",
changelog: "변경 로그",
repo: "저장소",
language: "언어",
db_connection: "데이터베이스 연결",
db_host: "데이터베이스 호스트",
db_port: "데이터베이스 포트",
db_username: "데이터베이스 사용자 이름",
db_password: "데이터베이스 암호",
db_database: "데이터베이스 이름",
send_reports: "오류 보고서 보내기",
send_reports_desc: "디버깅을 위해 스태핑에 오류 보내기",
project_name: "상태 페이지 이름",
description: "설명",
domain: "도메인",
enable_cdn: "CDN 사용",
newsletter: "신제품",
newsletter_note: "주요 변경 사항에 대한 이메일만 보내드립니다.",
loading: "로드 중",
save_settings: "설정 저장",
average_response: "평균 응답",
last_uptime: "마지막 가동 시간",
sign_in: "로그인",
last_login: "마지막 로그인",
admin: "관리자",
user: "사용자",
failed: "실패",
wrong_login: "잘못된 사용자 이름 또는 암호",
theme_editor: "테마 편집기",
enable_assets: "로컬 자산 활성화",
assets_desc: "로컬 자산을 활성화하여 상태 페이지 디자인을 사용자 지정할 수 있습니다.이렇게하면 모든 CSS를 포함하는 '자산'디렉토리가 만들어집니다.",
assets_btn: "로컬 자산 활성화",
assets_loading: "자산 생성",
assets_dir: "자산 디렉토리",
footer: "바닥글",
footer_notes: "당신은 바닥 글에 HTML 태그를 사용할 수 있습니다",
global_announcement: "글로벌 발표",
announcement_date: "발표 날짜 범위",
notify_users: "사용자에게 알림",
notify_desc: "예약된 시간 전에 사용자에게 알림",
notify_method: "통지 방법",
notify_before: "다음 전에 알림",
message_create: "공지사항 만들기",
message_edit: "공지사항 편집",
minutes: "몇 분",
hours: "영업 시간",
days: "일 수",
user_create: "사용자 생성",
user_update: "사용자 업데이트",
administrator: "관리자",
checkins: "체크인",
incidents: "인시던트",
service_info: "서비스 정보",
service_name: "서비스 이름",
service_type: "서비스 유형",
permalink: "영구 링크 URL",
service_public: "공공 서비스",
check_interval: "확인 간격",
service_endpoint: "서비스 엔드포인트",
service_check: "서비스 검사 유형",
service_timeout: "요청 시간 초과",
expected_resp: "예상 응답",
expected_code: "예상 상태 코드",
follow_redir: "리다이렉트 따르기",
verify_ssl: "SSL 확인",
tls_cert: "TLS 인증서 사용",
notifications_enable: "알림 활성화",
notify_after: "실패 후 알림",
notify_all: "모든 변경 사항 알림"
}
export default korean

View File

@ -1,101 +1,133 @@
const russian = {
top_nav: {
dashboard: "Dashboard",
services: "Services",
users: "Users",
groups: "Groups",
announcements: "Announcements",
settings: "Settings",
logs: "Logs",
help: "Help",
logout: 'Logout',
},
setup: {
language: "Language",
connection: "Database Connection",
host: "Host",
database: "Database",
project_name: "Project Name",
project_description: "Project Description",
domain: "Domain URL",
username: "Admin Username",
password: "Admin Password",
password_confirm: "Confirm Admin Password",
newsletter: "Newsletter",
newsletter_note: "We will not share your email, emails are only for major updates.",
send_reports: "Send Error Reports to Statping"
},
dashboard: {
total_services: "Total Services",
failures_24_hours: "Failures last 24 Hours",
online_services: "Online Services",
service: 'Service | Services',
group: 'Group',
title: 'Title',
begins: 'Begins',
name: 'Name',
loading: 'Loading',
login: 'Login',
sign_in: "Sign In",
visibility: 'Visibility',
wrong_login: 'Incorrect username or password'
},
settings: {
name: "Project Name",
description: "Project Name",
footer: "Custom Footer",
footer_notes: "HTML is allowed inside the footer",
error_reporting: "Enable Error Reporting",
error_reporting_notes: "Help the Statping project out by sending anonymous error logs back to our server.",
save: "Save Settings",
main: "Main Settings",
theme: "Theme Editor",
cache: "Cache",
oauth: "OAuth",
beta: "BETA",
changelog: "Changelog",
repo: "Statping Github Repo",
docs: "Documentation",
},
service: {
name: "Service Name",
type: "Service Type",
info: "Service Information",
view: "View Service",
average: "Average Response",
last_uptime: "Uptime last {0} {1}",
},
email: "Email Address",
port: "Database Port",
setting: "Settings",
username: "Username",
password: 'Password',
services: 'Services',
domain: 'Domain',
online: 'онлайн',
public: 'Public',
private: 'Private',
admin: 'Admin',
offline: 'не в сети',
failure: 'failure | failures',
incident: 'incident | incidents',
checkin: 'checkin | checkins',
user: 'User | Users',
group: 'Group',
message: 'message',
edit: 'Edit',
type: 'Type',
sample_data: 'Sample Data',
today: 'Today',
last_login: 'Last Login',
uptime: '{0}% Uptime',
close: 'близко',
second: 'второй | секунд',
minute: 'минут | минут',
hour: 'час | часов',
day: 'день | дней',
week: 'неделя | недель',
month: 'месяц | месяцы',
settings: "Настройки",
dashboard: "Панель управления",
services: "служб",
service: "обслуживания",
failures: "Сбои",
users: "Пользователи",
login: "Войти",
logout: "Выход из системы",
online: "Онлайн",
offline: "Оффлайн",
username: "Имя пользователя",
password: "Пароль",
email: "Электронная почта",
confirm_password: "Подтвердить пароль",
uptime: "Время бесперебойной работы",
name: "Имя",
copy: "Копия",
close: "Закрыть",
secret: "Секрет",
regen_api: "Регенерация ключей API",
regen_desc: "API Secret используется для чтения создания обновлений и удаления маршрутов. Вы можете регенерировать ключи API, если вам нужно.",
visibility: "Видимость",
group: "Группы",
group_create: "Создать группу",
group_update: "Обновить группу",
group_public_desc: "Показать групповые услуги публике",
groups: "Группы",
no_group: "Нет группы",
public: "Общественный",
private: "Частные",
announcements: "Объявления",
notifiers: "Уведомлятели",
logs: "Журналы",
help: "Помогите",
type: "Тип",
edit: "Редактировать",
update: "Обновить",
create: "Создайте",
view: "Посмотреть",
save: "Сохранить",
title: "Название",
status: "положению",
begins: "Начинается",
total_services: "Всего услуг",
online_services: "Онлайн-сервисы",
request_timeout: "Тайм-аут запроса",
service_never_online: "Сервис никогда не был в сети",
service_online_check: "Проверено онлайн",
service_offline_time: "Служба была отключена для",
days_ago: "Дней назад",
today: "Сегодня",
failures_24_hours: "Сбои за 24 часа",
no_services: "В настоящее время у вас нет услуг!",
theme: "Тема",
cache: "Кэш",
authentication: "Проверка подлинности",
import: "Импорт",
main_settings: "Основные настройки",
variables: "Переменные",
docs: "Документация",
links: "Ссылки",
changelog: "Журнал изменений",
repo: "Репозиторий",
language: "Язык",
db_connection: "Подключение к базе данных",
db_host: "Узел базы данных",
db_port: "Порт базы данных",
db_username: "Имя пользователя базы данных",
db_password: "Пароль базы данных",
db_database: "Имя базы данных",
send_reports: "Отправка отчетов об ошибках",
send_reports_desc: "Отправить ошибки в Statping для отладки",
project_name: "Имя страницы состояния",
description: "Описание",
domain: "Домен",
enable_cdn: "Включить CDN",
newsletter: "Информационный бюллетень",
newsletter_note: "Мы отправим вам только сообщение по электронной почте для серьезных изменений",
loading: "Загрузка",
save_settings: "Сохранить настройки",
average_response: "Средний ответ",
last_uptime: "Время безотказной работы",
sign_in: "Войти",
last_login: "Последний вход",
admin: "Администратор",
user: "Пользователя",
failed: "Не удалось",
wrong_login: "Неверное имя пользователя или пароль",
theme_editor: "Редактор тем",
enable_assets: "Включить локальные ресурсы",
assets_desc: "Настройте дизайн страницы состояния, включив локальные ресурсы. Это создаст каталог 'assets', содержащий все CSS.",
assets_btn: "Включить локальные ресурсы",
assets_loading: "Создание компонентов",
assets_dir: "Каталог активов",
footer: "Подколонтитул",
footer_notes: "Вы можете использовать HTML-теги в нижнем колонтитуле",
global_announcement: "Глобальное объявление",
announcement_date: "Диапазон дат объявления",
notify_users: "Уведомлять пользователей",
notify_desc: "Уведомлять пользователей до запланированного времени",
notify_method: "Способ уведомления",
notify_before: "Уведомить до",
message_create: "Создать объявление",
message_edit: "Редактировать объявление",
minutes: "Минуты",
hours: "Часы",
days: "Дни",
user_create: "Создать пользователя",
user_update: "Обновить пользователя",
administrator: "Администратора",
checkins: "Чеккинс",
incidents: "Инциденты",
service_info: "Информация о сервисе",
service_name: "Имя службы",
service_type: "Тип услуги",
permalink: "URL-адрес Постоянной ссылки",
service_public: "Государственная служба",
check_interval: "Интервал проверки",
service_endpoint: "Конечная точка службы",
service_check: "Тип проверки службы",
service_timeout: "Тайм-аут запроса",
expected_resp: "Ожидаемый ответ",
expected_code: "Код ожидаемого состояния",
follow_redir: "Следуйте за перенаправленными",
verify_ssl: "Проверить SSL",
tls_cert: "Использовать сертификат TLS",
notifications_enable: "Включить уведомления",
notify_after: "Уведомлять после сбоев",
notify_all: "Уведомлять обо всех изменениях"
}
export default russian
export default russian

View File

@ -1,101 +1,133 @@
const spanish = {
top_nav: {
dashboard: "Dashboard",
services: "Services",
users: "Users",
groups: "Groups",
announcements: "Announcements",
settings: "Settings",
logs: "Logs",
help: "Help",
logout: 'Logout',
},
setup: {
language: "Language",
connection: "Database Connection",
host: "Host",
database: "Database",
project_name: "Project Name",
project_description: "Project Description",
domain: "Domain URL",
username: "Admin Username",
password: "Admin Password",
password_confirm: "Confirm Admin Password",
settings: "Configuración",
dashboard: "Salpicadero",
services: "Servicios",
service: "Servicio",
failures: "Fallos",
users: "Usuarios",
login: "Iniciar sesión",
logout: "Cerrar sesión",
online: "En línea",
offline: "Offline",
username: "Nombre de usuario",
password: "Contraseña",
email: "Correo",
confirm_password: "Confirmar contraseña",
uptime: "Tiempo de actividad",
name: "Nombre",
copy: "Copia",
close: "Cerrar",
secret: "Secreto",
regen_api: "Regenerar claves de API",
regen_desc: "API Secret se utiliza para leer crear actualizaciones y eliminar rutas. Puede regenerar claves de API si lo necesita.",
visibility: "Visibilidad",
group: "Grupo",
group_create: "Crear grupo",
group_update: "Actualizar grupo",
group_public_desc: "Mostrar servicios de grupo al público",
groups: "Grupos",
no_group: "Ningún grupo",
public: "Público",
private: "Privado",
announcements: "Anuncios",
notifiers: "Notificadores",
logs: "Registros",
help: "Ayudar",
type: "Tipo",
edit: "Editar",
update: "Actualizar",
create: "Crear",
view: "Ver",
save: "Guardar",
title: "Título",
status: "Estado",
begins: "Comienza",
total_services: "Total de servicios",
online_services: "Servicios en línea",
request_timeout: "Tiempo de espera de solicitud",
service_never_online: "El servicio nunca ha estado en línea",
service_online_check: "Verificado en línea",
service_offline_time: "El servicio ha estado desconectado para",
days_ago: "Hace días",
today: "Hoy",
failures_24_hours: "Fallos de las últimas 24 horas",
no_services: "¡Actualmente no tienes ningún servicio!",
theme: "Tema",
cache: "Caché",
authentication: "Autentificación",
import: "Importación",
main_settings: "Configuración principal",
variables: "Variables",
docs: "Documentación",
links: "Enlaces",
changelog: "Registro de cambios",
repo: "Repositorio",
language: "Idioma",
db_connection: "Conexión a la base",
db_host: "Host de base",
db_port: "Puerto base de datos",
db_username: "Nombre de usuario de",
db_password: "Contraseña",
db_database: "Nombre de la base",
send_reports: "Enviar informes de errores",
send_reports_desc: "Enviar errores a Statping para la depuración",
project_name: "Nombre de página de estado",
description: "Descripción",
domain: "Dominio",
enable_cdn: "Habilitar CDN",
newsletter: "Newsletter",
newsletter_note: "We will not share your email, emails are only for major updates.",
send_reports: "Send Error Reports to Statping"
},
dashboard: {
total_services: "Total Services",
failures_24_hours: "Failures last 24 Hours",
online_services: "Online Services",
service: 'Service | Services',
group: 'Group',
title: 'Title',
begins: 'Begins',
name: 'Name',
loading: 'Loading',
login: 'Login',
sign_in: "Sign In",
visibility: 'Visibility',
wrong_login: 'Incorrect username or password'
},
settings: {
name: "Project Name",
description: "Project Name",
footer: "Custom Footer",
footer_notes: "HTML is allowed inside the footer",
error_reporting: "Enable Error Reporting",
error_reporting_notes: "Help the Statping project out by sending anonymous error logs back to our server.",
save: "Save Settings",
main: "Main Settings",
theme: "Theme Editor",
cache: "Cache",
oauth: "OAuth",
beta: "BETA",
changelog: "Changelog",
repo: "Statping Github Repo",
docs: "Documentation",
},
service: {
name: "Service Name",
type: "Service Type",
info: "Service Information",
view: "View Service",
average: "Average Response",
last_uptime: "Uptime last {0} {1}",
},
email: "Email Address",
port: "Database Port",
setting: "Settings",
username: "Username",
password: 'Password',
services: 'Services',
domain: 'Domain',
online: 'online',
public: 'Public',
private: 'Private',
admin: 'Admin',
offline: 'offline',
failure: 'failure | failures',
incident: 'incident | incidents',
checkin: 'checkin | checkins',
user: 'User | Users',
group: 'Group',
message: 'message',
edit: 'Edit',
type: 'Type',
sample_data: 'Sample Data',
today: 'Today',
last_login: 'Last Login',
uptime: '{0}% Uptime',
close: 'Close',
second: 'second | seconds',
minute: 'minute | minutes',
hour: 'hour | hours',
day: 'day | days',
week: 'week | weeks',
month: 'month | months',
newsletter_note: "Sólo le enviaremos un correo electrónico para cambios importantes",
loading: "Cargando",
save_settings: "Guardar configuración",
average_response: "Respuesta media",
last_uptime: "Tiempo de actividad último",
sign_in: "Iniciar sesión",
last_login: "Último Login",
admin: "Admin",
user: "Usuario",
failed: "Falló",
wrong_login: "Nombre de usuario o contraseña incorrectos",
theme_editor: "Editor de temas",
enable_assets: "Habilitar activos locales",
assets_desc: "Personalice el diseño de la página de estado habilitando los activos locales. Esto creará un directorio de 'activos' que contiene todos los CSS.",
assets_btn: "Habilitar activos locales",
assets_loading: "Creación de Activos",
assets_dir: "Directorio de activos",
footer: "Pie de página",
footer_notes: "Puede usar etiquetas HTML en pie de página",
global_announcement: "Anuncio global",
announcement_date: "Rango de fechas del anuncio",
notify_users: "Notificar a usuarios",
notify_desc: "Notificar a los usuarios antes del horario programado",
notify_method: "Método de notificación",
notify_before: "Notificar antes",
message_create: "Crear anuncio",
message_edit: "Editar anuncio",
minutes: "Acta",
hours: "Horas",
days: "Días",
user_create: "Crear usuario",
user_update: "Actualizar usuario",
administrator: "Administrador",
checkins: "Checkins",
incidents: "Incidentes",
service_info: "Información de servicio",
service_name: "Nombre del servicio",
service_type: "Tipo de servicio",
permalink: "URL de enlace permanente",
service_public: "Servicio Público",
check_interval: "Intervalo Comprobar",
service_endpoint: "Punto final de servicio",
service_check: "Tipo de comprobación de servicio",
service_timeout: "Tiempo de espera de solicitud",
expected_resp: "Respuesta esperada",
expected_code: "Código de estado esperado",
follow_redir: "Seguir redirecciones",
verify_ssl: "Verificar SSL",
tls_cert: "Usar Cert TLS",
notifications_enable: "Habilitar notificaciones",
notify_after: "Notificar después de errores",
notify_all: "Notificar todos los cambios"
}
export default spanish
export default spanish

View File

@ -103,16 +103,16 @@ export default Vue.mixin({
},
smallText(s) {
if (s.online) {
return `Online, checked ${this.ago(s.last_success)} ago`
return `${this.$t('service_online_check')} ${this.ago(s.last_success)} ago`
} else {
const last = s.last_failure
if (last) {
return `Offline, last error: ${last} ${this.ago(last.created_at)}`
}
if (this.isZero(s.last_success)) {
return `Service has never been online`
return this.$t('service_never_online')
}
return `Service has been offline for ${this.ago(s.last_success)}`
return `${this.$t('service_offline_time')} ${this.ago(s.last_success)}`
}
},
round_time(frame, val) {

View File

@ -2275,7 +2275,7 @@ OluFxewsEO0QNDrfFb+0gnjYlnGqOFcZjUMXbDdY5oLSPtXohynuTK1qyQ==
</div>
<div class="text-center small text-dim" v-pre>
Automatically generated from Statping's Wiki on 2020-09-02 02:46:04.864615 &#43;0000 UTC
Automatically generated from Statping's Wiki on 2020-09-09 01:24:21.649582 &#43;0000 UTC
</div>
</div>

View File

@ -10,22 +10,25 @@
<a href="https://github.com/statping/statping/blob/master/CHANGELOG.md" class="btn btn-sm text-dim mt-2">Changelog</a>
</div>
<h6 class="text-muted">{{ $t('settings.main') }}</h6>
<h6 class="text-muted">{{ $t('main_settings') }}</h6>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-home-tab')}" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">
<font-awesome-icon icon="cog" class="mr-2"/> {{ $t('setting') }}
<font-awesome-icon icon="cog" class="mr-2"/> {{ $t('settings') }}
</a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-style-tab')}" id="v-pills-style-tab" data-toggle="pill" href="#v-pills-style" role="tab" aria-controls="v-pills-style" aria-selected="false">
<font-awesome-icon icon="image" class="mr-2"/> {{ $t('settings.theme') }}
<font-awesome-icon icon="image" class="mr-2"/> {{ $t('theme') }}
</a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-cache-tab')}" id="v-pills-cache-tab" data-toggle="pill" href="#v-pills-cache" role="tab" aria-controls="v-pills-cache" aria-selected="false">
<font-awesome-icon icon="paperclip" class="mr-2"/> {{ $t('settings.cache') }}
</a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-oauth-tab')}" id="v-pills-oauth-tab" data-toggle="pill" href="#v-pills-oauth" role="tab" aria-controls="v-pills-oauth" aria-selected="false">
<font-awesome-icon icon="key" class="mr-2"/> {{ $t('settings.oauth') }}
<font-awesome-icon icon="paperclip" class="mr-2"/> {{ $t('cache') }}
</a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-oauth-tab')}" id="v-pills-oauth-tab" data-toggle="pill" href="#v-pills-oauth" role="tab" aria-controls="v-pills-oauth" aria-selected="false">
<font-awesome-icon icon="key" class="mr-2"/> {{ $t('authentication') }}
</a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-import-tab')}" id="v-pills-import-tab" data-toggle="pill" href="#v-pills-import" role="tab" aria-controls="v-pills-import" aria-selected="false">
<font-awesome-icon icon="cloud-download-alt" class="mr-2"/> {{ $t('import') }}
</a>
<h6 class="mt-4 text-muted">Notifiers</h6>
<h6 class="mt-4 text-muted">{{$t('notifiers')}}</h6>
<div id="notifiers_tabs">
<a v-for="(notifier, index) in notifiers" v-bind:key="`${notifier.method}`" @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}" v-bind:id="`v-pills-${notifier.method.toLowerCase()}-tab`" data-toggle="pill" v-bind:href="`#v-pills-${notifier.method.toLowerCase()}`" role="tab" v-bind:aria-controls="`v-pills-${notifier.method.toLowerCase()}`" aria-selected="false">
@ -33,26 +36,26 @@
<span v-if="notifier.enabled" class="badge badge-pill float-right mt-1" :class="{'badge-success': !liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), 'badge-light': liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), 'text-dark': liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}">ON</span>
</a>
<a @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-notifier-docs-tab`)}" v-bind:id="`v-pills-notifier-docs-tab`" data-toggle="pill" v-bind:href="`#v-pills-notifier-docs`" role="tab" v-bind:aria-controls="`v-pills-notifier-docs`" aria-selected="false">
<font-awesome-icon icon="question" class="mr-2"/> Variables
<font-awesome-icon icon="question" class="mr-2"/> {{$t('variables')}}
</a>
</div>
<h6 class="mt-4 mb-3 text-muted">Statping Links</h6>
<h6 class="mt-4 mb-3 text-muted">Statping {{$t('links')}}</h6>
<a href="https://github.com/statping/statping/wiki" class="mb-2 font-2 text-decoration-none text-muted">
<font-awesome-icon icon="question" class="mr-3"/> {{$t('settings.docs')}}
<font-awesome-icon icon="question" class="mr-3"/> {{$t('docs')}}
</a>
<a href="https://github.com/statping/statping/wiki/API" class="mb-2 font-2 text-decoration-none text-muted">
<font-awesome-icon icon="laptop" class="mr-2"/> API {{$t('settings.docs')}}
<font-awesome-icon icon="laptop" class="mr-2"/> API {{$t('docs')}}
</a>
<a href="https://raw.githubusercontent.com/statping/statping/master/CHANGELOG.md" class="mb-2 font-2 text-decoration-none text-muted">
<font-awesome-icon icon="book" class="mr-3"/> {{$t('settings.changelog')}}
<font-awesome-icon icon="book" class="mr-3"/> {{$t('changelog')}}
</a>
<a href="https://github.com/statping/statping" class="mb-2 font-2 text-decoration-none text-muted">
<font-awesome-icon icon="code-branch" class="mr-3"/> {{$t('settings.repo')}}
<font-awesome-icon icon="code-branch" class="mr-3"/> {{$t('repo')}}
</a>
<span class="small text-dim text-center mt-5">Statping v{{core.version}}<br>
@ -71,25 +74,24 @@
<CoreSettings/>
<div class="card mt-3">
<div class="card-header">API Settings</div>
<div class="card-header">API {{$t('settings')}}</div>
<div class="card-body">
<div class="form-group row">
<label class="col-sm-3 col-form-label">API Secret</label>
<label class="col-sm-3 col-form-label">API {{$t('secret')}}</label>
<div class="col-sm-9">
<div class="input-group">
<input v-model="core.api_secret" @focus="$event.target.select()" type="text" class="form-control select-input" id="api_secret" readonly>
<div class="input-group-append copy-btn">
<button @click="copy(core.api_secret)" class="btn btn-outline-secondary" type="button">Copy</button>
<button @click="copy(core.api_secret)" class="btn btn-outline-secondary" type="button">{{$t('copy')}}</button>
</div>
</div>
<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 Regenerate API Keys if you need to.</small>
<small class="form-text text-muted">{{$t('regen_desc')}}</small>
</div>
</div>
</div>
<div class="card-footer">
<button id="regenkeys" @click="renewApiKeys" class="btn btn-sm btn-danger float-right">Regenerate API Keys</button>
<button id="regenkeys" @click="renewApiKeys" class="btn btn-sm btn-danger float-right">{{$t('regen_api')}}</button>
</div>
</div>
@ -107,6 +109,10 @@
<OAuth/>
</div>
<div class="tab-pane fade" v-bind:class="{active: liClass('v-pills-import-tab'), show: liClass('v-pills-import-tab')}" id="v-pills-import" role="tabpanel" aria-labelledby="v-pills-import-tab">
<Importer/>
</div>
<div class="tab-pane fade" v-bind:class="{active: liClass(`v-pills-notifier-docs-tab`), show: liClass(`v-pills-notifier-docs-tab`)}" v-bind:id="`v-pills-notifier-docs-tab`" role="tabpanel" v-bind:aria-labelledby="`v-pills-notifier-docs-tab`">
<Variables/>
</div>
@ -124,7 +130,6 @@
<script>
import Api from '../API';
import Variables from "@/components/Dashboard/Variables";
const semver = require('semver')
const CoreSettings = () => import(/* webpackChunkName: "dashboard" */ '@/forms/CoreSettings')
@ -133,10 +138,13 @@
const OAuth = () => import(/* webpackChunkName: "dashboard" */ '@/forms/OAuth')
const ThemeEditor = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/ThemeEditor')
const Cache = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Cache')
const Importer = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Importer')
const Variables = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Variables')
export default {
name: 'Settings',
components: {
Importer,
Variables,
OAuth,
Cache,

View File

@ -15,6 +15,7 @@ const Incidents = () => import(/* webpackChunkName: "dashboard" */ '@/components
const Checkins = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Checkins')
const Failures = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Failures')
const NotFound = () => import(/* webpackChunkName: "index" */ '@/pages/NotFound')
const Importer = () => import(/* webpackChunkName: "index" */ '@/components/Dashboard/Importer')
import VueRouter from "vue-router";
import Api from "./API";
@ -164,6 +165,13 @@ const routes = [
requiresAuth: true,
title: 'Statping - Help',
}
},{
path: 'import',
component: Importer,
meta: {
requiresAuth: true,
title: 'Statping - Import',
}
}]
},
{

23
go.mod
View File

@ -10,40 +10,29 @@ require (
github.com/fatih/structs v1.1.0
github.com/foomo/simplecert v1.7.5
github.com/foomo/tlsconfig v0.0.0-20180418120404-b67861b076c9
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/getsentry/sentry-go v0.5.1
github.com/go-mail/mail v2.3.1+incompatible
github.com/golang/protobuf v1.4.0
github.com/gomarkdown/markdown v0.0.0-20200820230800-3724143f5294 // indirect
github.com/gorilla/mux v1.7.4
github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9
github.com/jinzhu/gorm v1.9.12
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/pelletier/go-toml v1.7.0 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.1.0
github.com/shopspring/decimal v1.2.0 // indirect
github.com/sirupsen/logrus v1.5.0
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.0.0
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.6.3
github.com/statping/emails v1.0.0
github.com/stretchr/testify v1.5.1
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1
github.com/tdewolff/minify/v2 v2.8.0 // indirect
github.com/wellington/go-libsass v0.9.2
github.com/wellington/sass v0.0.0-20160911051022-cab90b3986d6
github.com/tensorflow/tensorflow v2.3.0+incompatible // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c // indirect
google.golang.org/grpc v1.28.1
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v2 v2.2.8
gorm.io/driver/mysql v1.0.1
gorm.io/driver/postgres v1.0.0
gorm.io/driver/sqlite v1.1.1
gorm.io/gorm v1.20.0
gorm.io/plugin/dbresolver v1.0.0
)

112
go.sum
View File

@ -83,6 +83,7 @@ github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4K
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@ -98,6 +99,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/aliyun/alibaba-cloud-sdk-go v1.61.112/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.131 h1:ePFkFbwr/u1HM9/p+azqI5UaxwY1hYKv+H8dkaRCLs4=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.131/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.30.20 h1:ktsy2vodSZxz/arYqo7DlpkIeNohHL+4Rmjdo7YGtrE=
@ -123,6 +125,7 @@ github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYut
github.com/cloudflare/cloudflare-go v0.11.6 h1:gErXaYucoS8aHdmoJnF4RMFiXJH449sk6rCtoP6EhrE=
github.com/cloudflare/cloudflare-go v0.11.6/go.mod h1:lmCbgQdBeSQlMv0W0OSqoGgl8aFrgc5oXHhWMt47dh0=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@ -130,12 +133,14 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpu/goacmedns v0.0.2 h1:hYAgjnPu7HogTgb8trqQouR/RrBgXq1TPBgmxbK9eRA=
github.com/cpu/goacmedns v0.0.2/go.mod h1:4MipLkI+qScwqtVxcNO6okBhbgRrr7/tKXUSgSL0teQ=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
@ -323,6 +328,56 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.6.4 h1:S7T6cx5o2OqmxdHaXLH1ZeD1SbI8jBznyYE9Ec0RCQ8=
github.com/jackc/pgconn v1.6.4/go.mod h1:w2pne1C2tZgP+TvjqLpOigGzNqjBgQW9dUw/4Chex78=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.2 h1:q1Hsy66zh4vuNsajBUF2PNqfAMMfxU5mk594lPE9vjY=
github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
github.com/jackc/pgtype v1.4.2 h1:t+6LWm5eWPLX1H5Se702JSBcirq6uWa4jiG4wV1rAWY=
github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.8.1 h1:SUbCLP2pXvf/Sr/25KsuI4aTxiFYIvpfk4l6aTSdyCw=
github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
@ -376,6 +431,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -387,8 +443,11 @@ github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvf
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lextoumbourou/goodhosts v2.1.0+incompatible h1:1U1p5Z1wrXl23/fW/GY4zdTbQ8UJbyvrkPbqAZ6tzbw=
github.com/lextoumbourou/goodhosts v2.1.0+incompatible/go.mod h1:89s48k108X3gKDWn8AHk3gUzUGTcMZCCAOsE4QU1bbo=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
@ -401,14 +460,20 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.2/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
@ -518,6 +583,9 @@ github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKc
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
@ -526,12 +594,16 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
github.com/sacloud/libsacloud v1.36.1 h1:tCpFjWsvu/2Im8/SDmRZ49SttVXy7nHerobRc1LU9pI=
github.com/sacloud/libsacloud v1.36.1/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
@ -574,6 +646,7 @@ github.com/statping/statping v0.90.64/go.mod h1:lbyNPB73IjWtnommV4wSejYfgUT1yLhh
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -583,13 +656,14 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1 h1:HGVkRrwDCbmSP6h1CoBDj6l/mhnvsP5JbYaQ4ss0R6o=
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1/go.mod h1:I3xbaE9ud9/TEXzehwkHx86SyJwqeSNsX2X5oV61jIg=
github.com/tdewolff/minify v1.1.0 h1:nxHQi1ML+g3ZbZHffiZ6eC7vMqNvSRfX3KB5Y5y/kfw=
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
github.com/tdewolff/minify/v2 v2.8.0 h1:t3tOPWkTpKhsgxm3IM9Sy8hE2eIt30Oaa+2havJGGIE=
github.com/tdewolff/minify/v2 v2.8.0/go.mod h1:6zN8VLhMfFxNrwHROcboYNo2+huPNu4SV8DPh3PUQ8E=
github.com/tdewolff/parse/v2 v2.4.4 h1:uMdbQRtYbKR/msP9CbI7li9wK6pionYiH6s7ipltyGY=
github.com/tdewolff/parse/v2 v2.4.4/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tensorflow/tensorflow v1.15.3 h1:xE0S0nl5ZTJPyvHm9jisVaovZWVSj58eWJz637ASW7Q=
github.com/tensorflow/tensorflow v2.3.0+incompatible h1:FbjZGMOzvKFeLAnToZb+J7PJEpki6Ee1uC1w07cu/yI=
github.com/tensorflow/tensorflow v2.3.0+incompatible/go.mod h1:itOSERT4trABok4UOoG+X4BoKds9F3rIsySdn+Lvu90=
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7 h1:CpHxIaZzVy26GqJn8ptRyto8fuoYOd1v0fXm9bG3wQ8=
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@ -627,6 +701,7 @@ github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FB
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@ -638,10 +713,14 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
go.uber.org/ratelimit v0.1.0 h1:U2AruXqeTb4Eh9sYQSTrMhH8Cb7M0Ian2ibBOnBcnAw=
go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -650,15 +729,19 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a h1:y6sBfNd1b9Wy08a6K1Z1DZc4aXABUN5TKjkYhz7UKmo=
@ -695,6 +778,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -715,6 +799,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -772,6 +857,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -779,6 +865,7 @@ golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -796,6 +883,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -814,14 +903,18 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -841,6 +934,8 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
@ -924,6 +1019,7 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -951,6 +1047,18 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gorm.io/driver/mysql v1.0.1 h1:omJoilUzyrAp0xNoio88lGJCroGdIOen9hq2A/+3ifw=
gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw=
gorm.io/driver/postgres v1.0.0 h1:Yh4jyFQ0a7F+JPU0Gtiam/eKmpT/XFc1FKxotGqc6FM=
gorm.io/driver/postgres v1.0.0/go.mod h1:wtMFcOzmuA5QigNsgEIb7O5lhvH1tHAF1RbWmLWV4to=
gorm.io/driver/sqlite v1.1.1 h1:qtWqNAEUyi7gYSUAJXeiAMz0lUOdakZF5ia9Fqnp5G4=
gorm.io/driver/sqlite v1.1.1/go.mod h1:hm2olEcl8Tmsc6eZyxYSeznnsDaMqamBvEXLNtBg4cI=
gorm.io/gorm v1.9.19 h1:NMrwpxOZIHWJEFzZ0MM8PdYlcXyKLaXTHWfpDEDdBNg=
gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.0 h1:qfIlyaZvrF7kMWY3jBdEBXkXJ2M5MFYMTppjILxS3fQ=
gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/plugin/dbresolver v1.0.0 h1:fHIWRRkoDmXkBPYyg9GMmLugcM9fcbZiG0Zy/cwiPlM=
gorm.io/plugin/dbresolver v1.0.0/go.mod h1:sK1Alv120lfrjRQXrzyAw4ssxDPJjamm2cbBOZBHM68=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -9,12 +9,15 @@ import (
_ "github.com/statping/statping/notifiers"
"github.com/statping/statping/source"
"github.com/statping/statping/types"
"github.com/statping/statping/types/checkins"
"github.com/statping/statping/types/core"
"github.com/statping/statping/types/groups"
"github.com/statping/statping/types/messages"
"github.com/statping/statping/types/services"
"github.com/statping/statping/types/users"
"github.com/statping/statping/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"io/ioutil"
"net/http"
"net/http/httptest"
@ -254,6 +257,26 @@ func TestMainApiRoutes(t *testing.T) {
Method: "GET",
ExpectedStatus: 200,
},
{
Name: "Export Settings",
URL: "/api/settings/export",
Method: "GET",
ExpectedStatus: 200,
BeforeTest: SetTestENV,
AfterTest: UnsetTestENV,
ResponseFunc: func(r *httptest.ResponseRecorder, t *testing.T, bytes []byte) error {
var data ExportData
err := json.Unmarshal(r.Body.Bytes(), &data)
require.Nil(t, err)
assert.Len(t, data.Services, len(services.All()))
assert.Len(t, data.Groups, len(groups.All()))
assert.Len(t, data.Notifiers, len(services.AllNotifiers()))
assert.Len(t, data.Users, len(users.All()))
assert.Len(t, data.Messages, len(messages.All()))
assert.Len(t, data.Checkins, len(checkins.All()))
return nil
},
},
}
for _, v := range tests {

View File

@ -1,12 +1,22 @@
package handlers
import (
"bytes"
"encoding/json"
"fmt"
"github.com/statping/statping/source"
"github.com/statping/statping/types/checkins"
"github.com/statping/statping/types/configs"
"github.com/statping/statping/types/core"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/types/groups"
"github.com/statping/statping/types/messages"
"github.com/statping/statping/types/notifications"
"github.com/statping/statping/types/services"
"github.com/statping/statping/types/users"
"github.com/statping/statping/utils"
"io"
"io/ioutil"
"net/http"
"os"
)
@ -150,6 +160,122 @@ func apiThemeRemoveHandler(w http.ResponseWriter, r *http.Request) {
sendJsonAction(utils.Directory+"/assets", "deleted", w, r)
}
type ExportData struct {
Config *configs.DbConfig `json:"config,omitempty"`
Core *core.Core `json:"core"`
Services []services.Service `json:"services"`
Messages []*messages.Message `json:"messages"`
Checkins []*checkins.Checkin `json:"checkins"`
Users []*users.User `json:"users"`
Groups []*groups.Group `json:"groups"`
Notifiers []notifications.Notification `json:"notifiers"`
}
func (e *ExportData) JSON() []byte {
d, _ := json.Marshal(e)
return d
}
func ExportSettings() (*ExportData, error) {
var notifiers []notifications.Notification
for _, n := range services.AllNotifiers() {
notifiers = append(notifiers, *n.Select())
}
data := &ExportData{
Core: core.App,
Notifiers: notifiers,
Checkins: checkins.All(),
Users: users.All(),
Services: services.AllInOrder(),
Groups: groups.All(),
Messages: messages.All(),
}
return data, nil
}
func settingsImportHandler(w http.ResponseWriter, r *http.Request) {
data, err := ioutil.ReadAll(r.Body)
if err != nil {
sendErrorJson(err, w, r)
return
}
defer r.Body.Close()
var exportData *ExportData
if err := json.Unmarshal(data, &exportData); err != nil {
sendErrorJson(err, w, r)
return
}
if exportData.Core != nil {
core.App = exportData.Core
if err := core.App.Update(); err != nil {
sendErrorJson(err, w, r)
return
}
}
if exportData.Groups != nil {
for _, s := range exportData.Groups {
s.Id = 0
if err := s.Create(); err != nil {
sendErrorJson(err, w, r)
return
}
}
}
if exportData.Services != nil {
for _, s := range exportData.Services {
s.Id = 0
if err := s.Create(); err != nil {
sendErrorJson(err, w, r)
return
}
}
}
if exportData.Users != nil {
for _, s := range exportData.Users {
s.Id = 0
if err := s.Create(); err != nil {
sendErrorJson(err, w, r)
return
}
}
}
if exportData.Notifiers != nil {
for _, s := range exportData.Notifiers {
notif := services.ReturnNotifier(s.Method)
n := notif.Select().UpdateFields(&s)
if err := n.Update(); err != nil {
sendErrorJson(err, w, r)
return
}
}
}
sendJsonAction(exportData, "import", w, r)
}
func settingsExportHandler(w http.ResponseWriter, r *http.Request) {
exported, err := ExportSettings()
if err != nil {
sendErrorJson(err, w, r)
return
}
file := bytes.NewBuffer(exported.JSON())
w.Header().Set("Content-Disposition", "attachment; filename=statping.json")
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Length", utils.ToString(len(exported.JSON())))
io.Copy(w, file)
}
func logsLineHandler(w http.ResponseWriter, r *http.Request) {
if lastLine := utils.GetLastLine(); lastLine != nil {
w.Header().Set("Content-Type", "text/plain")

View File

@ -101,6 +101,8 @@ func Router() *mux.Router {
api.Handle("/api/core", authenticated(apiCoreHandler, false)).Methods("POST")
api.Handle("/api/logs", authenticated(logsHandler, false)).Methods("GET")
api.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
api.Handle("/api/settings/import", authenticated(settingsImportHandler, false)).Methods("POST")
api.Handle("/api/settings/export", authenticated(settingsExportHandler, false)).Methods("GET")
// API OAUTH Routes
api.Handle("/api/oauth", scoped(apiOAuthHandler)).Methods("GET")

View File

@ -0,0 +1,227 @@
// +build ignore
package main
import (
"encoding/csv"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/translate"
"io"
"io/ioutil"
"os"
"strings"
)
var (
tr *translate.Translate
awsKey string
awsSecret string
)
type Text struct {
Key string
En string
Fr string
De string
Ru string
Sp string
Jp string
Cn string
Ko string
It string
}
func main() {
fmt.Println("RUNNING: ./source/generate_languages.go")
awsKey = os.Getenv("AWS_ACCESS_KEY_ID")
awsSecret = os.Getenv("AWS_SECRET_ACCESS_KEY")
if awsKey == "" || awsSecret == "" {
fmt.Println("AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY not set")
os.Exit(0)
return
}
InitAWS()
file, _ := os.Open("../frontend/src/languages/data.csv")
defer file.Close()
c := csv.NewReader(file)
var translations []*Text
line := 0
for {
// Read each record from csv
record, err := c.Read()
if err == io.EOF {
break
}
if line == 0 {
line++
continue
}
if err != nil {
fmt.Println(err)
continue
}
key := record[0]
english := record[1]
translated := TranslateAll(key, english)
translations = append(translations, translated)
fmt.Printf("%s | English: %s | French: %s | German: %s | Russian: %s\n", translated.Key, translated.En, translated.Fr, translated.De, translated.Ru)
line++
}
//CreateGo(translations)
CreateJS("english", translations)
CreateJS("russian", translations)
CreateJS("french", translations)
CreateJS("german", translations)
CreateJS("spanish", translations)
CreateJS("japanese", translations)
CreateJS("chinese", translations)
CreateJS("italian", translations)
CreateJS("korean", translations)
}
func Translate(val, language string) string {
input := &translate.TextInput{
SourceLanguageCode: aws.String("en"),
TargetLanguageCode: aws.String(language),
Text: aws.String(val),
}
req, out := tr.TextRequest(input)
if err := req.Send(); err != nil {
panic(req.Error)
}
return *out.TranslatedText
}
func TranslateAll(key, en string) *Text {
return &Text{
Key: key,
En: en,
Fr: Translate(en, "fr"),
De: Translate(en, "de"),
Ru: Translate(en, "ru"),
Sp: Translate(en, "es"),
Jp: Translate(en, "ja"),
Cn: Translate(en, "zh"),
Ko: Translate(en, "ko"),
It: Translate(en, "it"),
}
}
func (t *Text) String(lang string) string {
switch lang {
case "english":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.En)
case "russian":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.Ru)
case "spanish":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.Sp)
case "german":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.De)
case "french":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.Fr)
case "japanese":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.Jp)
case "chinese":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.Cn)
case "korean":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.Ko)
case "italian":
return fmt.Sprintf(` %s: "%s"`, t.Key, t.It)
default:
return fmt.Sprintf(` %s: "%s"`, t.Key, t.En)
}
}
func GoLang(trs []*Text) string {
var allvars []string
languages := []string{"english", "russian"}
for _, language := range languages {
allvars = append(allvars, language+" := make(map[string]string)")
for _, t := range trs {
allvars = append(allvars, GoLine(language, t))
}
allvars = append(allvars, "\nLanguage[\""+language+"\"] = "+language)
}
return strings.Join(allvars, "\n")
}
func GoLine(lang string, t *Text) string {
switch lang {
case "english":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.En)
case "russian":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.Ru)
case "spanish":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.Sp)
case "german":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.De)
case "french":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.Fr)
case "japanese":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.Jp)
case "chinese":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.Cn)
case "korean":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.Ko)
case "italian":
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.It)
default:
return fmt.Sprintf(` %s["%s"] = "%s"`, lang, t.Key, t.En)
}
}
func CreateGo(trs []*Text) {
data := `package utils
var Language map[string]map[string]string
func init() {
Language = make(map[string]map[string]string)
` + GoLang(trs) + `
}
`
ioutil.WriteFile("../utils/languages.go", []byte(data), os.ModePerm)
}
func CreateJS(name string, trs []*Text) {
data := "const " + name + " = {\n"
var allvars []string
for _, v := range trs {
allvars = append(allvars, v.String(name))
}
data += strings.Join(allvars, ",\n")
data += "\n}\n\nexport default " + name
ioutil.WriteFile("../frontend/src/languages/"+name+".js", []byte(data), os.ModePerm)
}
func InitAWS() {
creds := credentials.NewStaticCredentials(awsKey, awsSecret, "")
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
Credentials: creds,
})
if err != nil {
panic(err)
}
tr = translate.New(sess)
}

View File

@ -2,6 +2,7 @@ package source
//go:generate go run generate_help.go
//go:generate go run generate_version.go
//go:generate go run generate_languages.go
import (
"fmt"

View File

@ -17,7 +17,7 @@ func DeleteDirectory(directory string) error {
// CreateDirectory("assets")
func CreateDirectory(directory string) error {
Log.Debugln("creating directory: " + directory)
if err := os.Mkdir(directory, os.FileMode(0755)); err != os.ErrExist {
if err := os.Mkdir(directory, os.ModePerm); err != os.ErrExist {
return err
}
return nil

View File

@ -1 +1 @@
0.90.65
0.90.66