More advanced task details with graph !
This commit is contained in:
parent
a78320344f
commit
4067a8448b
7 changed files with 482 additions and 31 deletions
|
@ -3,7 +3,9 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use \Carbon\Carbon;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
|
use App\Models\TaskHistory;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
@ -69,14 +71,93 @@ class ApiController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getTaskDetails($id) {
|
public function getTaskGraph(Request $request, $id) {
|
||||||
|
$days = ($request->input('days', 15) - 1);
|
||||||
|
|
||||||
|
// First, we get the first date of the stats
|
||||||
|
// In this case, one month ago
|
||||||
|
$date = $last_days = Carbon::now()->subDays($days);
|
||||||
|
|
||||||
|
// Then we get all history for the past month
|
||||||
|
$results = TaskHistory::orderBy('created_at', 'asc')
|
||||||
|
->where('created_at', '>', $last_days->toDateString())
|
||||||
|
->where('task_id', '=', $id)
|
||||||
|
->selectRaw('date(created_at) as date, status')
|
||||||
|
->get()
|
||||||
|
;
|
||||||
|
|
||||||
|
// Then we start building an array for the entire month
|
||||||
|
$stats = [];
|
||||||
|
do {
|
||||||
|
$stats[$date->toDateString()] = [
|
||||||
|
'up' => 0,
|
||||||
|
'down' => 0
|
||||||
|
];
|
||||||
|
$date = $date->addDay();
|
||||||
|
}
|
||||||
|
while ($date->lt(Carbon::now()));
|
||||||
|
|
||||||
|
// Finally we populate the data
|
||||||
|
if (! is_null($results)) {
|
||||||
|
foreach ($results as $r) {
|
||||||
|
if (empty($stats[$r->date])) {
|
||||||
|
$stats[$r->date] = [
|
||||||
|
'up' => 0,
|
||||||
|
'down' => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($r->status == 1) {
|
||||||
|
++$stats[$r->date]['up'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++$stats[$r->date]['down'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response()->json($stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getTaskDetails(Request $request, $id) {
|
||||||
|
$days = ($request->input('days', 15) - 1);
|
||||||
|
|
||||||
$task = Task::with(['group', 'history'])
|
$task = Task::with(['group', 'history'])
|
||||||
->find($id)
|
->find($id)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (! is_null($task)) {
|
if (! is_null($task)) {
|
||||||
$limit = 100;
|
|
||||||
|
$results = $task
|
||||||
|
->history()
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->where('created_at', '>', \Carbon\Carbon::now()->subDay($days)->toDateString())
|
||||||
|
->selectRaw('date(created_at) as `date`, created_at, status, output')
|
||||||
|
->get()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (! is_null($results)) {
|
||||||
|
$prev = null;
|
||||||
|
$history = $averages = [];
|
||||||
|
|
||||||
|
foreach ($results as $h) {
|
||||||
|
if ($h->status != $prev) {
|
||||||
|
array_push($history, $h);
|
||||||
|
}
|
||||||
|
$prev = $h->status;
|
||||||
|
|
||||||
|
if (empty($averages[$h->date])) {
|
||||||
|
$averages[$h->date] = [
|
||||||
|
'sum' => 0,
|
||||||
|
'count' => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if ($h->status == 1) {
|
||||||
|
$averages[$h->date]['sum'] ++;
|
||||||
|
}
|
||||||
|
$averages[$h->date]['count'] ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json(array_merge($task->toArray(), [
|
return response()->json(array_merge($task->toArray(), [
|
||||||
$task,
|
$task,
|
||||||
|
@ -84,9 +165,9 @@ class ApiController extends Controller
|
||||||
'host' => $task->host,
|
'host' => $task->host,
|
||||||
'status' => $task->status,
|
'status' => $task->status,
|
||||||
'type' => $task->type,
|
'type' => $task->type,
|
||||||
'history' => $task->history()->limit($limit)->orderBy('created_at', 'DESC')->get(),
|
'history' => $history,
|
||||||
'group' => $task->group,
|
'averages' => $averages,
|
||||||
'limit' => $limit
|
'group' => $task->group
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
191
package-lock.json
generated
191
package-lock.json
generated
|
@ -1,13 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "web",
|
"name": "monitolite",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"apexcharts": "^3.32.0",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
|
"vue-apexcharts": "^1.6.2",
|
||||||
"vue-router": "^3.5.3",
|
"vue-router": "^3.5.3",
|
||||||
"vuex": "^3.6.2"
|
"vuex": "^3.6.2"
|
||||||
},
|
},
|
||||||
|
@ -2396,6 +2398,19 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/apexcharts": {
|
||||||
|
"version": "3.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.32.0.tgz",
|
||||||
|
"integrity": "sha512-9VUyiTR2RgD4NIJOOdKxxi8tjzrKCBMr7HjWxsw+5lDPu/tZJLVudpgFhlNTIy3CbhxQ4edaiTttmbo6eDDgiA==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.draggable.js": "^2.2.2",
|
||||||
|
"svg.easing.js": "^2.0.0",
|
||||||
|
"svg.filter.js": "^2.0.2",
|
||||||
|
"svg.pathmorphing.js": "^0.1.3",
|
||||||
|
"svg.resize.js": "^1.4.3",
|
||||||
|
"svg.select.js": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/array-flatten": {
|
"node_modules/array-flatten": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||||
|
@ -8539,6 +8554,89 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svg.draggable.js": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.easing.js": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": ">=2.3.x"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.filter.js": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
|
||||||
|
"integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.js": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
|
||||||
|
},
|
||||||
|
"node_modules/svg.pathmorphing.js": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.resize.js": {
|
||||||
|
"version": "1.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
|
||||||
|
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.6.5",
|
||||||
|
"svg.select.js": "^2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.resize.js/node_modules/svg.select.js": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.select.js": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.6.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/svgo": {
|
"node_modules/svgo": {
|
||||||
"version": "2.8.0",
|
"version": "2.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
|
||||||
|
@ -8906,6 +9004,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
|
||||||
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
|
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-apexcharts": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-apexcharts/-/vue-apexcharts-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-9HS3scJwWgKjmkcWIf+ndNDR0WytUJD8Ju0V2ZYcjYtlTLwJAf2SKUlBZaQTkDmwje/zMgulvZRi+MXmi+WkKw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"apexcharts": "^3.26.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-hot-reload-api": {
|
"node_modules/vue-hot-reload-api": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
||||||
|
@ -11290,6 +11396,19 @@
|
||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"apexcharts": {
|
||||||
|
"version": "3.32.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.32.0.tgz",
|
||||||
|
"integrity": "sha512-9VUyiTR2RgD4NIJOOdKxxi8tjzrKCBMr7HjWxsw+5lDPu/tZJLVudpgFhlNTIy3CbhxQ4edaiTttmbo6eDDgiA==",
|
||||||
|
"requires": {
|
||||||
|
"svg.draggable.js": "^2.2.2",
|
||||||
|
"svg.easing.js": "^2.0.0",
|
||||||
|
"svg.filter.js": "^2.0.2",
|
||||||
|
"svg.pathmorphing.js": "^0.1.3",
|
||||||
|
"svg.resize.js": "^1.4.3",
|
||||||
|
"svg.select.js": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"array-flatten": {
|
"array-flatten": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||||
|
@ -15953,6 +16072,70 @@
|
||||||
"has-flag": "^4.0.0"
|
"has-flag": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"svg.draggable.js": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.easing.js": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": ">=2.3.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.filter.js": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
|
||||||
|
"integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.js": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
|
||||||
|
},
|
||||||
|
"svg.pathmorphing.js": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.resize.js": {
|
||||||
|
"version": "1.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
|
||||||
|
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.6.5",
|
||||||
|
"svg.select.js": "^2.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"svg.select.js": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.select.js": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.6.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"svgo": {
|
"svgo": {
|
||||||
"version": "2.8.0",
|
"version": "2.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
|
||||||
|
@ -16228,6 +16411,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
|
||||||
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
|
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
|
||||||
},
|
},
|
||||||
|
"vue-apexcharts": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-apexcharts/-/vue-apexcharts-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-9HS3scJwWgKjmkcWIf+ndNDR0WytUJD8Ju0V2ZYcjYtlTLwJAf2SKUlBZaQTkDmwje/zMgulvZRi+MXmi+WkKw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"vue-hot-reload-api": {
|
"vue-hot-reload-api": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
"vue-template-compiler": "^2.6.14"
|
"vue-template-compiler": "^2.6.14"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"apexcharts": "^3.32.0",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
|
"vue-apexcharts": "^1.6.2",
|
||||||
"vue-router": "^3.5.3",
|
"vue-router": "^3.5.3",
|
||||||
"vuex": "^3.6.2"
|
"vuex": "^3.6.2"
|
||||||
}
|
}
|
||||||
|
|
118
public/js/app.js
118
public/js/app.js
File diff suppressed because one or more lines are too long
|
@ -14,6 +14,9 @@ Vue.prototype.$http = axios
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
Vue.prototype.moment = moment
|
Vue.prototype.moment = moment
|
||||||
|
|
||||||
|
import VueApexCharts from 'vue-apexcharts'
|
||||||
|
Vue.use(VueApexCharts)
|
||||||
|
Vue.component('apexchart', VueApexCharts)
|
||||||
|
|
||||||
import Home from '../views/app.vue'
|
import Home from '../views/app.vue'
|
||||||
import TaskDetails from '../views/taskdetails.vue'
|
import TaskDetails from '../views/taskdetails.vue'
|
||||||
|
|
|
@ -8,14 +8,19 @@
|
||||||
<!-- <p class="context-menu"><img src="/img/menu.svg" width="40" /></p> -->
|
<!-- <p class="context-menu"><img src="/img/menu.svg" width="40" /></p> -->
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<h3>Uptime: past {{ chart.days }} days</h3>
|
||||||
|
<div id="chart">
|
||||||
|
<apexchart v-if="chart.render" type="bar" height="350" :options="chartOptions" :series="series"></apexchart>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3>History log</h3>
|
<h3>Last {{ chart.days }} days history log</h3>
|
||||||
<p>Showing the latest {{ task.limit }} history records</p>
|
<div v-if="task.history.length > 0">
|
||||||
|
<p><i>Showing only records where status has changed</i></p>
|
||||||
<table id="tasks_tbl">
|
<table id="tasks_tbl">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="20%">Date</th>
|
<th width="20%">Date</th>
|
||||||
|
<th width="20%">Time</th>
|
||||||
<th width="*">Output</th>
|
<th width="*">Output</th>
|
||||||
<th width="10%">Status</th>
|
<th width="10%">Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -24,9 +29,9 @@
|
||||||
<tr
|
<tr
|
||||||
v-for="history in task.history"
|
v-for="history in task.history"
|
||||||
v-bind:key="history.id"
|
v-bind:key="history.id"
|
||||||
:class="task.active == 0 ? 'inactive' : ''"
|
|
||||||
>
|
>
|
||||||
<td>{{ moment(history.created_at).format('YYYY-MM-DD HH:mm:ss') }}</td>
|
<td>{{ moment(history.date).format('YYYY-MM-DD') }}</td>
|
||||||
|
<td>{{ moment(history.created_at).format('HH:mm:ss') }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="history.output">
|
<span v-if="history.output">
|
||||||
{{ history.output }}
|
{{ history.output }}
|
||||||
|
@ -41,6 +46,8 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
<p v-else>No history to display here</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -50,7 +57,48 @@
|
||||||
export default{
|
export default{
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
task: null
|
task: null,
|
||||||
|
|
||||||
|
chart: {
|
||||||
|
render: false,
|
||||||
|
days: 15
|
||||||
|
},
|
||||||
|
|
||||||
|
series: [{
|
||||||
|
data: []
|
||||||
|
}],
|
||||||
|
noData: {
|
||||||
|
text: 'Loading...'
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
chart: {
|
||||||
|
type: 'bar',
|
||||||
|
height: 350,
|
||||||
|
stacked: true,
|
||||||
|
stackType: '100%'
|
||||||
|
},
|
||||||
|
responsive: [{
|
||||||
|
breakpoint: 480,
|
||||||
|
options: {
|
||||||
|
legend: {
|
||||||
|
position: 'bottom',
|
||||||
|
offsetX: -10,
|
||||||
|
offsetY: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
xaxis: {
|
||||||
|
categories: [],
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
opacity: .9
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'right',
|
||||||
|
offsetX: 0,
|
||||||
|
offsetY: 50
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -71,9 +119,48 @@
|
||||||
let task_id = this.$route.params.id ?? null
|
let task_id = this.$route.params.id ?? null
|
||||||
|
|
||||||
if (task_id != null) {
|
if (task_id != null) {
|
||||||
this.$http.get('/api/getTask/'+task_id)
|
this.$http.post('/api/getTask/'+task_id, {
|
||||||
|
days: this.chart.days
|
||||||
|
})
|
||||||
.then(response => this.task = response.data)
|
.then(response => this.task = response.data)
|
||||||
|
.then(() => {
|
||||||
|
this.$http.post('/api/getTaskGraph/'+task_id, {
|
||||||
|
days: this.chart.days
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
let xaxis = [];
|
||||||
|
let new_data_a = [];
|
||||||
|
let new_data_b = [];
|
||||||
|
console.log(response.data)
|
||||||
|
|
||||||
|
for (let date in response.data) {
|
||||||
|
xaxis.push(date)
|
||||||
|
new_data_a.push(response.data[date]['up'])
|
||||||
|
new_data_b.push(response.data[date]['down'])
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chartOptions.xaxis.categories = xaxis;
|
||||||
|
this.series = [{
|
||||||
|
name: 'UP',
|
||||||
|
data: new_data_a,
|
||||||
|
color: '#00955c'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'DOWN',
|
||||||
|
data: new_data_b,
|
||||||
|
color: '#ef3232'
|
||||||
|
}]
|
||||||
|
|
||||||
|
this.chart.render = true
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#chart {
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -15,7 +15,8 @@
|
||||||
|
|
||||||
$router->group(['prefix' => 'api/'], function () use ($router) {
|
$router->group(['prefix' => 'api/'], function () use ($router) {
|
||||||
$router->get('getTasks/', ['uses' => 'ApiController@getTasks']);
|
$router->get('getTasks/', ['uses' => 'ApiController@getTasks']);
|
||||||
$router->get('getTask/{id}', ['uses' => 'ApiController@getTaskDetails']);
|
$router->post('getTask/{id}', ['uses' => 'ApiController@getTaskDetails']);
|
||||||
|
$router->post('getTaskGraph/{id}', ['uses' => 'ApiController@getTaskGraph']);
|
||||||
$router->patch('toggleTaskStatus/{id}', ['uses' => 'ApiController@toggleTaskStatus']);
|
$router->patch('toggleTaskStatus/{id}', ['uses' => 'ApiController@toggleTaskStatus']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue