NEW FEATURE: overview of runs

This commit is contained in:
Jeroen De Meerleer 2021-05-27 11:46:30 +02:00
parent b80e834f68
commit 03365a1fc8
Signed by: JeroenED
GPG Key ID: 28CCCB8F62BFADD6
10 changed files with 101 additions and 19 deletions

1
assets/job/view.js Normal file
View File

@ -0,0 +1 @@
import 'bootstrap';

1
assets/job/view.scss Normal file
View File

@ -0,0 +1 @@
@import "~bootstrap/dist/css/bootstrap.css";

View File

@ -25,10 +25,11 @@ job_index:
_controller: JeroenED\Webcron\Controller\JobController::defaultAction
job_view:
path: '/job/{id}'
path: '/job/{id}/{all}'
methods: [ 'GET' ]
defaults:
_controller: JeroenED\Webcron\Controller\JobController::jobAction
all: false
requirements:
id: \d+

View File

@ -0,0 +1,17 @@
<?php
namespace JeroenED\Framework;
use Doctrine\DBAL\Connection;
class Repository
{
protected Connection $dbcon;
public function __construct(Connection $dbcon)
{
$this->dbcon = $dbcon;
}
}

View File

@ -5,6 +5,7 @@ namespace JeroenED\Webcron\Controller;
use JeroenED\Framework\Controller;
use JeroenED\Webcron\Repository\Job;
use JeroenED\Webcron\Repository\Run;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
@ -21,16 +22,18 @@ class JobController extends Controller
return $this->render('job/index.html.twig', ['jobs' => $jobs]);
}
public function jobAction($id)
public function jobAction($id, $all = false)
{
if(!isset($_SESSION['isAuthenticated']) || !$_SESSION['isAuthenticated']) {
return new RedirectResponse($this->generateRoute('login'));
}
$jobRepo = new Job($this->getDbCon());
$runRepo = new Run($this->getDbCon());
if($this->getRequest()->getMethod() == 'GET') {
$job = $jobRepo->getJob($id);
return new Response('Not implemented, yet', Response::HTTP_NOT_IMPLEMENTED);
$runs = $runRepo->getRunsForJob($id, $all != 'all' ? [$job['data']['response']] : []);
return $this->render('job/view.html.twig', ['job' => $job, 'runs' => $runs, 'allruns' => $all == 'all']);
} elseif($this->getRequest()->getMethod() == 'DELETE') {
$success = $jobRepo->deleteJob($id);
$this->addFlash('success', $success['message']);

View File

@ -5,20 +5,13 @@ namespace JeroenED\Webcron\Repository;
use DateTime;
use Doctrine\DBAL\Connection;
use GuzzleHttp\Client;
use JeroenED\Framework\Repository;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Net\SSH2;
class Job
class Job extends Repository
{
private Connection $dbcon;
public function __construct(Connection $dbcon)
{
$this->dbcon = $dbcon;
}
public function getAllJobs()
{
$jobsSql = "SELECT * FROM job";

29
src/Repository/Run.php Normal file
View File

@ -0,0 +1,29 @@
<?php
namespace JeroenED\Webcron\Repository;
use JeroenED\Framework\Repository;
class Run extends Repository
{
public function getRunsForJob(int $id, $excludedexitcodes = [], $ordered = true): array
{
$runsSql = "SELECT * FROM run WHERE job_id = :job";
$params = [':job' => $id];
if (!empty($excludedexitcodes)) {
$runsSql .= ' AND exitcode NOT in (';
foreach($excludedexitcodes as $key => $exitcode) {
$runsSql .= ':code' . $key;
$params[':code' . $key] = $exitcode;
}
$runsSql .= ')';
}
if ($ordered) $runsSql .= ' ORDER by timestamp DESC';
$runsStmt = $this->dbcon->prepare($runsSql);
$runsRslt = $runsStmt->executeQuery($params);
$runs = $runsRslt->fetchAllAssociative();
return $runs;
}
}

View File

@ -5,15 +5,10 @@ namespace JeroenED\Webcron\Repository;
use Doctrine\DBAL\Connection;
use JeroenED\Framework\Repository;
class User
class User extends Repository
{
private Connection $dbcon;
public function __construct(Connection $dbcon)
{
$this->dbcon = $dbcon;
}
/**
* @param string $user

View File

@ -0,0 +1,41 @@
{% extends "base.html.twig" %}
{% block title %}Overview of run for {{ job.name }}{% endblock %}
{% block content %}
<h2>Overview of runs for {{ job.name }}</h2>
<p>
<a href="{{ path('job_edit', { id: job.id }) }}">Edit job</a>
{% if allruns %} | <a href="{{ path('job_view', { id: job.id })}}">Only show failed runs</a>
{% elseif not allruns %} | <a href="{{ path('job_view', { id: job.id, all: 'all' })}}">Show all runs</a>
{% endif %}
</p>
<div id="runs" class="accordion">
{% for run in runs %}
<div class="card">
<div class="card-header" id="run-{{ run.id }}-header">
<h2 class="mb-0">
<button class="btn btn-link btn-block d-flex justify-content-between" type="button" data-toggle="collapse" data-target="#run-{{ run.id }}" aria-expanded="true" aria-controls="run-{{ run.id }}">
<span>{{ run.timestamp | date("d/m/Y H:i:s") }}</span>
<span>{{ run.exitcode }}</span>
</button>
</h2>
</div>
<div id="run-{{ run.id }}" class="collapse{% if loop.index == 1%} show{% endif %}" aria-labelledby="run-{{ run.id }}-header" data-parent="#runs">
<div class="card-body">
<pre>{{ run.output }}</pre>
</div>
</div>
</div>
{% else %}
<h4>No {% if not allruns %}failed {% endif %}runs found</h4>
<p><a href="{{ path('job_view', { id: job.id, all: 'all' })}}">Show all runs</a></p>
{% endfor %}
</div>
{% endblock %}
{% block styles %}
{{ encore_entry_link_tags('job.view') }}
{% endblock %}
{% block scripts %}
{{ encore_entry_script_tags('job.view') }}
{% endblock %}

View File

@ -25,6 +25,7 @@ Encore
*/
.addEntry('security.login', ['./assets/security/login.js', './assets/security/login.scss'])
.addEntry('job.index', ['./assets/job/index.js', './assets/job/index.scss'])
.addEntry('job.view', ['./assets/job/view.js', './assets/job/view.scss'])
.addEntry('job.add', ['./assets/job/add.js', './assets/job/add.scss'])
//.addEntry('page1', './assets/page1.js')
//.addEntry('page2', './assets/page2.js')