add start point of panel
This commit is contained in:
parent
9d9589f9a0
commit
1cd64aa9f2
|
|
@ -6,6 +6,8 @@ use App\Http\Resources\ScheduleResource;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Schedule;
|
use App\Schedule;
|
||||||
|
use App\Client;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class ScheduleController extends Controller
|
class ScheduleController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -13,4 +15,58 @@ class ScheduleController extends Controller
|
||||||
{
|
{
|
||||||
return ScheduleResource::collection(Schedule::all());
|
return ScheduleResource::collection(Schedule::all());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function success(){
|
||||||
|
$count = $this->statusCount();
|
||||||
|
$schedules = Schedule::where('last_backup_status', 'Success')->orderBy('updated_at', 'desc')->paginate(10);
|
||||||
|
return ScheduleResource::collection($schedules)->additional(['count' =>
|
||||||
|
$count
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function warnings(){
|
||||||
|
$count = $this->statusCount();
|
||||||
|
$data = ScheduleResource::collection(Schedule::all()->where('last_backup_status', 'Warning')->sortByDesc('updated_at'));
|
||||||
|
return compact('count','data');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errors(){
|
||||||
|
$count = $this->statusCount();
|
||||||
|
$data = ScheduleResource::collection(Schedule::all()->where('last_backup_status', 'Error')->sortByDesc('updated_at'));
|
||||||
|
return compact('count','data');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function noschedules(){
|
||||||
|
$count = $this->statusCount();
|
||||||
|
// $data = ScheduleResource::collection(Schedule::all()->where('last_backup_status', 'Errors')->sortByDesc('updated_at'));
|
||||||
|
$data = Client::whereDoesntHave('schedules')->get();
|
||||||
|
return compact('count','data');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function norecent(){
|
||||||
|
$count = $this->statusCount();
|
||||||
|
$data = ScheduleResource::collection(Schedule::where('last_backup_time', '<=', Carbon::now()
|
||||||
|
->subHours(48)
|
||||||
|
->toDateTimeString())
|
||||||
|
->get()->sortByDesc('updated_at'));
|
||||||
|
return compact('count','data');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function statusCount()
|
||||||
|
{
|
||||||
|
// $results= DB::table('backup_schedules')->select('last_backup_status', DB::raw('count(*) as count'))->groupBy('last_backup_status')->get();
|
||||||
|
$noschedules = Client::whereDoesntHave('schedules')->count();
|
||||||
|
$norecent = Schedule::where('last_backup_time', '<=', Carbon::now()
|
||||||
|
->subHours(48)
|
||||||
|
->toDateTimeString())
|
||||||
|
->count();
|
||||||
|
$errors = Schedule::where('last_backup_status' , 'Error')->count();
|
||||||
|
$successful = Schedule::where('last_backup_status' , 'Success')->count();
|
||||||
|
$warnings = Schedule::where('last_backup_status' , 'Warning')->count();
|
||||||
|
|
||||||
|
return compact('noschedules','norecent','errors','successful','warnings');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ class ScheduleResource extends JsonResource
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'last_backup_status' => $this->last_backup_status,
|
'last_backup_status' => $this->last_backup_status,
|
||||||
|
'updated_at' => $this->updated_at,
|
||||||
|
'date' => \Carbon\Carbon::parse($this->updated_at)->diffForHumans(),
|
||||||
'client' => $this->client->client_name,
|
'client' => $this->client->client_name,
|
||||||
'client_id' => $this->client->id,
|
'client_id' => $this->client->id,
|
||||||
];
|
];
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -18,5 +18,10 @@
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
"popper.js": "^1.12",
|
"popper.js": "^1.12",
|
||||||
"vue": "^2.5.7"
|
"vue": "^2.5.7"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bulma": "^0.7.2",
|
||||||
|
"bulma-badge": "^2.0.0",
|
||||||
|
"vue-router": "^3.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"/js/app.js": "/js/app.js",
|
||||||
|
"/css/app.css": "/css/app.css"
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First we will load all of this project's JavaScript dependencies which
|
* First we will load all of this project's JavaScript dependencies which
|
||||||
* includes Vue and other libraries. It is a great starting point when
|
* includes Vue and other libraries. It is a great starting point when
|
||||||
|
|
@ -7,7 +6,9 @@
|
||||||
|
|
||||||
require('./bootstrap');
|
require('./bootstrap');
|
||||||
|
|
||||||
window.Vue = require('vue');
|
import Vue from 'vue'
|
||||||
|
import VueRouter from 'vue-router'
|
||||||
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Next, we will create a fresh Vue application instance and attach it to
|
* Next, we will create a fresh Vue application instance and attach it to
|
||||||
|
|
@ -15,8 +16,58 @@ window.Vue = require('vue');
|
||||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Vue.component('example-component', require('./components/ExampleComponent.vue'));
|
Vue.component('scheduletabs', require('./components/schedules/Tabs.vue'));
|
||||||
|
Vue.component('headernav', require('./components/HeaderNav.vue'));
|
||||||
|
Vue.component('pagination', require('./components/PaginationComponent.vue'));
|
||||||
|
// let headernav = require('./components/HeaderNav.vue');
|
||||||
|
let sidebar = require('./components/SideBar.vue');
|
||||||
|
// let scheduletabs = require('./components/schedules/Tabs.vue')
|
||||||
|
|
||||||
|
let SchedulesSuccessfull = require('./components/schedules/Successfull.vue');
|
||||||
|
let SchedulesNoSchedules = require('./components/schedules/NoSchedules.vue');
|
||||||
|
let SchedulesWarnings = require('./components/schedules/Warnings.vue');
|
||||||
|
let SchedulesErrors = require('./components/schedules/Errors.vue');
|
||||||
|
let SchedulesNoRecent = require('./components/schedules/NoRecent.vue');
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/schedules',
|
||||||
|
redirect: '/schedules/successfull'
|
||||||
|
// component: SchedulesSuccessfull
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/schedules/successfull',
|
||||||
|
component: SchedulesSuccessfull
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/schedules/noschedules',
|
||||||
|
component: SchedulesNoSchedules
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/schedules/norecent',
|
||||||
|
component: SchedulesNoRecent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/schedules/warnings',
|
||||||
|
component: SchedulesWarnings
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/schedules/errors',
|
||||||
|
component: SchedulesErrors
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: 'history',
|
||||||
|
routes // short for `routes: routes`
|
||||||
|
})
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
el: '#app'
|
el: '#app',
|
||||||
|
router,
|
||||||
|
components: {
|
||||||
|
sidebar,
|
||||||
|
// headernav,
|
||||||
|
// scheduletabs,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ window.Popper = require('popper.js').default;
|
||||||
try {
|
try {
|
||||||
window.$ = window.jQuery = require('jquery');
|
window.$ = window.jQuery = require('jquery');
|
||||||
|
|
||||||
require('bootstrap');
|
// require('bootstrap');
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<nav class="level">
|
||||||
|
<div class="level-item level-left">
|
||||||
|
<div>
|
||||||
|
<p class="title is-4">{{ section }}</p>
|
||||||
|
<p class="heading is-4">{{ subsection }}</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="level-item level-right">
|
||||||
|
|
||||||
|
<div class="feh-actions">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="mdi mdi-24px mdi-tune"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
section: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
subsection: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="https://bulma.io">
|
||||||
|
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="navbarBasicExample" class="navbar-menu">
|
||||||
|
<div class="navbar-start">
|
||||||
|
<a class="navbar-item">
|
||||||
|
Home
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="navbar-item">
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
|
<a class="navbar-link">
|
||||||
|
More
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="navbar-dropdown">
|
||||||
|
<a class="navbar-item">
|
||||||
|
About
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item">
|
||||||
|
Jobs
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item">
|
||||||
|
Contact
|
||||||
|
</a>
|
||||||
|
<hr class="navbar-divider">
|
||||||
|
<a class="navbar-item">
|
||||||
|
Report an issue
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="navbar-end">
|
||||||
|
<div class="navbar-item">
|
||||||
|
<div class="buttons">
|
||||||
|
<a class="button is-primary">
|
||||||
|
<strong>Sign up</strong>
|
||||||
|
</a>
|
||||||
|
<a class="button is-light">
|
||||||
|
Log in
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<nav class="pagination is-centered is-rounded" role="navigation" aria-label="pagination">
|
||||||
|
<a class="pagination-previous" @click.prevent="changePage(1)" :disabled="pagination.current_page <= 1">First page</a>
|
||||||
|
<a class="pagination-previous" @click.prevent="changePage(pagination.current_page - 1)" :disabled="pagination.current_page <= 1">Previous</a>
|
||||||
|
<a class="pagination-next" @click.prevent="changePage(pagination.current_page + 1)" :disabled="pagination.current_page >= pagination.last_page">Next page</a>
|
||||||
|
<a class="pagination-next" @click.prevent="changePage(pagination.last_page)" :disabled="pagination.current_page >= pagination.last_page">Last page</a>
|
||||||
|
<ul class="pagination-list">
|
||||||
|
<li v-for="page in pages">
|
||||||
|
<a class="pagination-link" :class="isCurrentPage(page) ? 'is-current' : ''" @click.prevent="changePage(page)">{{ page }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.pagination {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ['pagination', 'offset'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
isCurrentPage(page) {
|
||||||
|
return this.pagination.current_page === page;
|
||||||
|
},
|
||||||
|
|
||||||
|
changePage(page) {
|
||||||
|
if (page > this.pagination.last_page) {
|
||||||
|
page = this.pagination.last_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pagination.current_page = page;
|
||||||
|
this.$emit('paginate');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
pages() {
|
||||||
|
let pages = [];
|
||||||
|
|
||||||
|
let from = this.pagination.current_page - Math.floor(this.offset / 2);
|
||||||
|
|
||||||
|
if (from < 1) {
|
||||||
|
from = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let to = from + this.offset - 1;
|
||||||
|
|
||||||
|
if (to > this.pagination.last_page) {
|
||||||
|
to = this.pagination.last_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (from <= to) {
|
||||||
|
pages.push(from);
|
||||||
|
from++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<aside class="column is-3 menu sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<img src="/images/logo.png" alt=""><strong>MDB</strong> Panel
|
||||||
|
</div>
|
||||||
|
<p class="menu-label">
|
||||||
|
General
|
||||||
|
</p>
|
||||||
|
<ul class="menu-list">
|
||||||
|
<li>
|
||||||
|
<a><span class="icon">
|
||||||
|
<i class="mdi mdi-18px mdi-monitor-dashboard"></i>
|
||||||
|
</span>Dashboard</a></li>
|
||||||
|
</ul>
|
||||||
|
<p class="menu-label">
|
||||||
|
Backups
|
||||||
|
</p>
|
||||||
|
<ul class="menu-list">
|
||||||
|
<li>
|
||||||
|
|
||||||
|
<router-link to="/schedules">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="mdi mdi-18px mdi-clock-outline"></i>
|
||||||
|
</span>
|
||||||
|
Schedules
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<router-link to="/backups">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="mdi mdi-18px mdi-upload-network"></i>
|
||||||
|
</span>
|
||||||
|
Backups
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p class="menu-label">
|
||||||
|
Clients
|
||||||
|
</p>
|
||||||
|
<ul class="menu-list">
|
||||||
|
<li><a>
|
||||||
|
<span class="icon">
|
||||||
|
<i class="mdi mdi-18px mdi-account-details"></i>
|
||||||
|
</span>
|
||||||
|
Client list</a></li>
|
||||||
|
<li><a>
|
||||||
|
<span class="icon">
|
||||||
|
<i class="mdi mdi-18px mdi-account-plus-outline"></i>
|
||||||
|
</span>
|
||||||
|
Add new client</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</aside>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template v-cloak>
|
||||||
|
<div>
|
||||||
|
<headernav :section="section" :subsection="subsection"></headernav>
|
||||||
|
<scheduletabs :statusCount="statusCount"></scheduletabs>
|
||||||
|
<table class="table is-fullwidth is-striped is-hoverable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>When <span class="icon"><i class="mdi mdi-18px mdi-chevron-up" aria-hidden="true"></i></span>
|
||||||
|
<span class="icon"><i class="mdi mdi-28px mdi-chevron-down" aria-hidden="true"></i></span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="schedule in schedules" :key="schedule.id">
|
||||||
|
<td><span class="icon tbl-icon"><i class="mdi mdi-24px mdi-close has-text-danger" aria-hidden="true"></i></span>
|
||||||
|
{{ schedule.client }}</td>
|
||||||
|
<td>{{ schedule.name }}</td>
|
||||||
|
<td>{{ schedule.date }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
schedules: null,
|
||||||
|
statusCount: {},
|
||||||
|
section: 'Schedules',
|
||||||
|
subsection: "errors"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
axios
|
||||||
|
.get('/api/v1/schedule/errors')
|
||||||
|
.then(response => (this.schedules = response.data.data, this.statusCount = response.data.count))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template v-cloak>
|
||||||
|
<div>
|
||||||
|
<headernav :section="section" :subsection="subsection"></headernav>
|
||||||
|
<scheduletabs :statusCount="statusCount"></scheduletabs>
|
||||||
|
<table class="table is-fullwidth is-striped is-hoverable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>When <span class="icon"><i class="mdi mdi-18px mdi-chevron-up" aria-hidden="true"></i></span>
|
||||||
|
<span class="icon"><i class="mdi mdi-28px mdi-chevron-down" aria-hidden="true"></i></span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="schedule in schedules" :key="schedule.id">
|
||||||
|
<td>
|
||||||
|
<span class="icon tbl-icon">
|
||||||
|
<i v-bind:class="{ 'has-text-success mdi-check': schedule.last_backup_status=='Success',
|
||||||
|
'has-text-warning mdi-exclamation': schedule.last_backup_status=='Warning',
|
||||||
|
'has-text-danger mdi-close': schedule.last_backup_status=='Error'
|
||||||
|
|
||||||
|
}" class="mdi mdi-24px" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
{{ schedule.client }}</td>
|
||||||
|
<td>{{ schedule.name }}</td>
|
||||||
|
<td>{{ schedule.date }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
schedules: null,
|
||||||
|
statusCount: {},
|
||||||
|
section: 'Schedules',
|
||||||
|
subsection: "no recent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
axios
|
||||||
|
.get('/api/v1/schedule/norecent')
|
||||||
|
.then(response => (this.schedules = response.data.data, this.statusCount = response.data.count))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<template v-cloak>
|
||||||
|
<div>
|
||||||
|
<headernav :section="section" :subsection="subsection"></headernav>
|
||||||
|
<scheduletabs :statusCount="statusCount"></scheduletabs>
|
||||||
|
<table class="table is-fullwidth is-striped is-hoverable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>When <span class="icon"><i class="mdi mdi-18px mdi-chevron-up" aria-hidden="true"></i></span>
|
||||||
|
<span class="icon"><i class="mdi mdi-28px mdi-chevron-down" aria-hidden="true"></i></span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="schedule in schedules" :key="schedule.id">
|
||||||
|
<td><span class="icon tbl-icon"><i class="mdi mdi-24px mdi-minus has-text-info" aria-hidden="true"></i></span>
|
||||||
|
{{ schedule.client_name }}</td>
|
||||||
|
<td>none</td>
|
||||||
|
<td>never</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
schedules: null,
|
||||||
|
statusCount: {},
|
||||||
|
section: 'Schedules',
|
||||||
|
subsection: "no schedules"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
axios
|
||||||
|
.get('/api/v1/schedule/noschedules')
|
||||||
|
.then(response => (this.schedules = response.data.data, this.statusCount = response.data.count))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
<template v-cloak>
|
||||||
|
<div>
|
||||||
|
<headernav :section="section" :subsection="subsection"></headernav>
|
||||||
|
<scheduletabs :statusCount="statusCount"></scheduletabs>
|
||||||
|
<table class="table is-fullwidth is-striped is-hoverable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>When <span class="icon"><i class="mdi mdi-18px mdi-chevron-up" aria-hidden="true"></i></span>
|
||||||
|
<span class="icon"><i class="mdi mdi-28px mdi-chevron-down" aria-hidden="true"></i></span>
|
||||||
|
</th>
|
||||||
|
<th><span class="is-pulled-right">Actions</span></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="schedule in schedules" :key="schedule.id">
|
||||||
|
<td><span class="icon tbl-icon"><i class="mdi mdi-24px mdi-check has-text-success" aria-hidden="true"></i></span>
|
||||||
|
{{ schedule.client }}</td>
|
||||||
|
<td>{{ schedule.name }}</td>
|
||||||
|
<td>{{ schedule.date }}</td>
|
||||||
|
<td><i class="mdi mdi-24px mdi-magnify is-pulled-right" aria-hidden="true"></i></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<pagination v-if="pagination.last_page > 1" :pagination="pagination" :offset="5" @paginate="fetchSchedules()"></pagination>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
schedules: null,
|
||||||
|
statusCount: {},
|
||||||
|
section: 'Schedules',
|
||||||
|
subsection: "success",
|
||||||
|
pagination: {
|
||||||
|
'current_page': 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchSchedules() {
|
||||||
|
axios.get('/api/v1/schedule/success?page=' + this.pagination.current_page)
|
||||||
|
.then(response => {
|
||||||
|
this.schedules = response.data.data,
|
||||||
|
this.statusCount = response.data.count,
|
||||||
|
this.pagination = response.data.meta;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error.response.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchSchedules();
|
||||||
|
setInterval(() => this.fetchSchedules(), 10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<template>
|
||||||
|
<div class="tabs is-fullwidth">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<router-link to="/schedules/successfull">
|
||||||
|
<span class="icon"><i class="mdi mdi-18px mdi-check-circle has-text-success" aria-hidden="true"></i></span>
|
||||||
|
<span>Successful <span class="tag">{{ statusCount.successful}}</span></span>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<router-link to="/schedules/norecent">
|
||||||
|
<span class="icon"><i class="mdi mdi-18px mdi-help-circle has-text-link" aria-hidden="true"></i></span>
|
||||||
|
<span>No Recent <span class="tag">{{ statusCount.norecent}}</span></span>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<router-link to="/schedules/warnings">
|
||||||
|
<span class="icon"><i class="mdi mdi-18px mdi-alert-circle has-text-warning" aria-hidden="true"></i></span>
|
||||||
|
<span>Warnings <span class="tag">{{ statusCount.warnings}}</span></span>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<router-link to="/schedules/errors">
|
||||||
|
<span class="icon"><i class="mdi mdi-18px mdi-close-circle has-text-danger" aria-hidden="true"></i></span>
|
||||||
|
<span>Errors <span class="tag">{{ statusCount.errors }}</span></span>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<router-link to="/schedules/noschedules">
|
||||||
|
<span class="icon"><i class="mdi mdi-18px mdi-minus-circle has-text-info" aria-hidden="true"></i></span>
|
||||||
|
<span>No Schedules <span class="tag">{{ statusCount.noschedules }}</span></span>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
statusCount: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template v-cloak>
|
||||||
|
<div>
|
||||||
|
<headernav :section="section" :subsection="subsection"></headernav>
|
||||||
|
<scheduletabs :statusCount="statusCount"></scheduletabs>
|
||||||
|
<table class="table is-fullwidth is-striped is-hoverable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Schedule</th>
|
||||||
|
<th>When <span class="icon"><i class="mdi mdi-18px mdi-chevron-up" aria-hidden="true"></i></span>
|
||||||
|
<span class="icon"><i class="mdi mdi-28px mdi-chevron-down" aria-hidden="true"></i></span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="schedule in schedules" :key="schedule.id">
|
||||||
|
<td><span class="icon tbl-icon"><i class="mdi mdi-24px mdi-exclamation has-text-warning" aria-hidden="true"></i></span>
|
||||||
|
{{ schedule.client }}</td>
|
||||||
|
<td>{{ schedule.name }}</td>
|
||||||
|
<td>{{ schedule.date }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
schedules: null,
|
||||||
|
statusCount: {},
|
||||||
|
section: 'Schedules',
|
||||||
|
subsection: "warnings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
axios
|
||||||
|
.get('/api/v1/schedule/warnings')
|
||||||
|
.then(response => (this.schedules = response.data.data, this.statusCount = response.data.count))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -1,20 +1,26 @@
|
||||||
|
|
||||||
// Body
|
// Links
|
||||||
$body-bg: #f8fafc;
|
// $link: white;
|
||||||
|
|
||||||
// Typography
|
|
||||||
$font-family-sans-serif: "Nunito", sans-serif;
|
|
||||||
$font-size-base: 0.9rem;
|
|
||||||
$line-height-base: 1.6;
|
|
||||||
|
|
||||||
// Colors
|
// // Body
|
||||||
$blue: #3490dc;
|
// $body-bg: #f8fafc;
|
||||||
$indigo: #6574cd;
|
|
||||||
$purple: #9561e2;
|
// // Typography
|
||||||
$pink: #f66D9b;
|
// $font-family-sans-serif: "Nunito", sans-serif;
|
||||||
$red: #e3342f;
|
// $font-size-base: 0.9rem;
|
||||||
$orange: #f6993f;
|
// $line-height-base: 1.6;
|
||||||
$yellow: #ffed4a;
|
|
||||||
$green: #38c172;
|
// // Colors
|
||||||
$teal: #4dc0b5;
|
// $blue: #3490dc;
|
||||||
$cyan: #6cb2eb;
|
// $indigo: #6574cd;
|
||||||
|
// $purple: #9561e2;
|
||||||
|
// $pink: #f66D9b;
|
||||||
|
// $red: #e3342f;
|
||||||
|
// $orange: #f6993f;
|
||||||
|
// $yellow: #ffed4a;
|
||||||
|
// $green: #38c172;
|
||||||
|
// $teal: #4dc0b5;
|
||||||
|
// $cyan: #6cb2eb;
|
||||||
|
$table-cell-border: 0px solid #dbdbdb;
|
||||||
|
$table-head-cell-border-width: 0 0 1px;
|
||||||
|
|
@ -5,10 +5,146 @@
|
||||||
// Variables
|
// Variables
|
||||||
@import 'variables';
|
@import 'variables';
|
||||||
|
|
||||||
// Bootstrap
|
// Bulma
|
||||||
@import '~bootstrap/scss/bootstrap';
|
@import '~bulma/bulma';
|
||||||
|
@import '~bulma-badge/dist/css/bulma-badge';
|
||||||
|
|
||||||
.navbar-laravel {
|
// html, body, #app {
|
||||||
background-color: #fff;
|
// height: 100%;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
// }
|
||||||
|
// #app {
|
||||||
|
// min-height: 100%;
|
||||||
|
// //display: flex;
|
||||||
|
// //flex-direction: column;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
tr{
|
||||||
|
line-height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar{
|
||||||
|
display: block;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
position: fixed;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: #32393F;
|
||||||
|
padding: 0px;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
.sidebar a{
|
||||||
|
color:#cacaca;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .icon{
|
||||||
|
padding-right: 20px;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-label {
|
||||||
|
padding-left: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-list a {
|
||||||
|
border-radius: 0px;
|
||||||
|
padding: 0.5em 4em;
|
||||||
|
}
|
||||||
|
.menu-list a:hover, .menu-list .router-link-exact-active, .menu-list .router-link-active{
|
||||||
|
background-color:#282e32;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs li .router-link-exact-active, .tabs li .router-link-active {
|
||||||
|
border-bottom-color: #3273dc !important;
|
||||||
|
color: #3273dc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
padding-left: 50px;
|
||||||
|
font-size: 1.7rem;
|
||||||
|
color: white;
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo strong{
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontent{
|
||||||
|
padding-left: 25%;
|
||||||
|
padding-top: 50px;
|
||||||
|
}
|
||||||
|
.feh-actions {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
padding-top:10px;
|
||||||
|
margin: 0;
|
||||||
|
// margin-top:-10px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
top: -5px;
|
||||||
|
height: 45px;
|
||||||
|
min-width: 45px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
z-index: 11;
|
||||||
|
transition: ease-in-out;
|
||||||
|
transition-duration: .3s;
|
||||||
|
background: whitesmoke;
|
||||||
|
}
|
||||||
|
.feh-actions:hover {
|
||||||
|
border: 0;
|
||||||
|
background: grey;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td, .table th {
|
||||||
|
padding-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tbl-icon {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-top: 2px;
|
||||||
|
margin-right: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
transition: background-color;
|
||||||
|
transition-duration: .25s;
|
||||||
|
}
|
||||||
|
tr:hover span.icon.tbl-icon:first-child {
|
||||||
|
/* code */
|
||||||
|
background-color:grey !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover i{
|
||||||
|
/* code */
|
||||||
|
color:white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
transition-property: opacity;
|
||||||
|
transition-timing-function: ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter,
|
||||||
|
.fade-leave-active {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
// .content{
|
||||||
|
// min-height:100%;
|
||||||
|
// float:left;
|
||||||
|
// overflow-y:auto;
|
||||||
|
// margin: 0 auto;
|
||||||
|
// position: relative;
|
||||||
|
// }
|
||||||
|
|
||||||
|
[v-cloak] {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="{{ asset('/css/app.css') }}">
|
||||||
|
<link rel="stylesheet" href="https://cdn.materialdesignicons.com/2.8.94/css/materialdesignicons.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<section>
|
||||||
|
<div class="columns">
|
||||||
|
<sidebar></sidebar>
|
||||||
|
<div class="column maincontent">
|
||||||
|
<div class="container is-fluid">
|
||||||
|
{{-- <headernav></headernav> --}}
|
||||||
|
<transition name="fade" mode="out-in">
|
||||||
|
<router-view></router-view>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<script src="{{ asset('/js/app.js') }}"></script>
|
||||||
|
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -22,4 +22,9 @@ Route::middleware('auth:api')->get('/user', function (Request $request) {
|
||||||
Route::apiResources(['v1/client' => 'API\v1\ClientController']);
|
Route::apiResources(['v1/client' => 'API\v1\ClientController']);
|
||||||
Route::post('v1/backup/{client_id}/{schedule_name}', 'API\v1\BackupController@store');
|
Route::post('v1/backup/{client_id}/{schedule_name}', 'API\v1\BackupController@store');
|
||||||
// Route::get('v1/test', 'API\v1\BackupController@test');
|
// Route::get('v1/test', 'API\v1\BackupController@test');
|
||||||
Route::get('v1/schedule', 'API\v1\ScheduleController@index');
|
Route::get('v1/schedule', 'API\v1\ScheduleController@index');
|
||||||
|
Route::get('v1/schedule/success', 'API\v1\ScheduleController@success');
|
||||||
|
Route::get('v1/schedule/warnings', 'API\v1\ScheduleController@warnings');
|
||||||
|
Route::get('v1/schedule/errors', 'API\v1\ScheduleController@errors');
|
||||||
|
Route::get('v1/schedule/noschedules', 'API\v1\ScheduleController@noschedules');
|
||||||
|
Route::get('v1/schedule/norecent', 'API\v1\ScheduleController@norecent');
|
||||||
|
|
@ -1,16 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
// Route::get('/', function () {
|
||||||
|--------------------------------------------------------------------------
|
// return view('index');
|
||||||
| Web Routes
|
// });
|
||||||
|--------------------------------------------------------------------------
|
Route::get('/{any}', function(){
|
||||||
|
|
return view('index');
|
||||||
| Here is where you can register web routes for your application. These
|
})->where('any', '.*');
|
||||||
| routes are loaded by the RouteServiceProvider within a group which
|
|
||||||
| contains the "web" middleware group. Now create something great!
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
Route::get('/', function () {
|
|
||||||
return view('welcome');
|
|
||||||
});
|
|
||||||
23
test.sh
23
test.sh
|
|
@ -1,23 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# call this with normal curl arguments, especially url argument, e.g.
|
|
||||||
# safecurl.sh "http://example.com:8080/something/"
|
|
||||||
# separating the (verbose) curl options into an array for readability
|
|
||||||
curl_args=(
|
|
||||||
-H 'Accept:application/json'
|
|
||||||
-H 'Content-Type:application/json'
|
|
||||||
--write '\n%{http_code}\n'
|
|
||||||
--fail
|
|
||||||
--silent
|
|
||||||
-k
|
|
||||||
)
|
|
||||||
echo "${curl_args[@]}"
|
|
||||||
# prepend some arguments, but pass on whatever arguments this script was called with
|
|
||||||
output=$(curl "${curl_args[@]}" "$@")
|
|
||||||
return_code=$?
|
|
||||||
if [ 0 -eq $return_code ]; then
|
|
||||||
# remove the "http_code" line from the end of the output, and parse it
|
|
||||||
echo "$output" | sed '$d' | jq .
|
|
||||||
else
|
|
||||||
# echo to stderr so further piping to jq will process empty output
|
|
||||||
>&2 echo "Failure: code=$output"
|
|
||||||
fi
|
|
||||||
Loading…
Reference in New Issue