Merge branch 'feature-run-query' into dev
This commit is contained in:
Коммит
00a6b47483
|
@ -1,7 +1,9 @@
|
|||
import logging
|
||||
import os
|
||||
import datetime
|
||||
import re
|
||||
|
||||
import requests
|
||||
from flask import Flask, render_template, redirect, url_for, request, session
|
||||
from flask_login import LoginManager, login_required, login_user, logout_user
|
||||
|
||||
|
@ -77,9 +79,13 @@ def runs():
|
|||
page = int(request.args.get('page', 1))
|
||||
query = Run.query.order_by(Run.creation.desc()).offset(page_size * (page - 1)).limit(20)
|
||||
|
||||
return render_template('runs.html', runs=query, page=page,
|
||||
previous_page=url_for('runs', page=max(page - 1, 1)),
|
||||
next_page=url_for('runs', page=page + 1))
|
||||
page_previous = url_for('runs', page=page - 1) if page > 1 else None
|
||||
page_next = url_for('runs', page=page + 1)
|
||||
|
||||
return render_template('runs.html', runs=query,
|
||||
page=page,
|
||||
page_previous=page_previous,
|
||||
page_next=page_next)
|
||||
|
||||
|
||||
@app.route('/run/<int:run_id>')
|
||||
|
@ -89,10 +95,24 @@ def run(run_id: int):
|
|||
if not this_run:
|
||||
return 404
|
||||
|
||||
show_log = request.args.get('logs', 'False') == 'true'
|
||||
query = request.args.get('query', '')
|
||||
|
||||
tasks = [t for t in this_run.tasks if t.result != 'Passed']
|
||||
|
||||
if query:
|
||||
tasks = [t for t in tasks if re.search(query, t.identifier)]
|
||||
|
||||
logs = dict()
|
||||
if show_log:
|
||||
for t in tasks:
|
||||
resp = requests.get(t.log_path)
|
||||
if resp.status_code < 300:
|
||||
logs[t.id] = resp.text
|
||||
|
||||
tasks = sorted(tasks, key=lambda t: t.name)
|
||||
|
||||
return render_template('run.html', tasks=tasks)
|
||||
return render_template('run.html', tasks=tasks, logs=logs, query=query)
|
||||
|
||||
|
||||
@app.route('/help', methods=['GET'])
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# pylint: disable=unused-import, too-few-public-methods
|
||||
|
||||
import json
|
||||
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
from .user import User
|
||||
|
||||
|
||||
db = SQLAlchemy() # pylint: disable=invalid-name
|
||||
|
||||
|
||||
|
@ -62,3 +63,29 @@ class Task(db.Model):
|
|||
# relationship
|
||||
run_id = db.Column(db.Integer, db.ForeignKey('run.id'), nullable=False)
|
||||
run = db.relationship('Run', backref=db.backref('tasks', cascade='all, delete-orphan', lazy=True))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Task, self).__init__(*args, **kwargs)
|
||||
self._settings = None
|
||||
|
||||
@property
|
||||
def identifier(self) -> str:
|
||||
return self.settings_in_json['classifier']['identifier'] # pylint: disable=unsubscriptable-object
|
||||
|
||||
@property
|
||||
def log_path(self) -> str:
|
||||
return self.result_in_json['a01.reserved.tasklogpath'] # pylint: disable=unsubscriptable-object
|
||||
|
||||
@property
|
||||
def settings_in_json(self) -> dict:
|
||||
if not hasattr(self, '_settings'):
|
||||
setattr(self, '_settings', json.loads(self.settings))
|
||||
|
||||
return getattr(self, '_settings')
|
||||
|
||||
@property
|
||||
def result_in_json(self) -> dict:
|
||||
if not hasattr(self, '_result'):
|
||||
setattr(self, '_result', json.loads(self.result_details))
|
||||
|
||||
return getattr(self, '_result')
|
||||
|
|
|
@ -11,4 +11,12 @@ main {
|
|||
table.condense {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
pre code {
|
||||
font-size: 0.5rem;
|
||||
}
|
||||
|
||||
div.log {
|
||||
background-color: beige;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
<div>
|
||||
<a class="waves-effect waves-light btn-large" href="{{ url_for('runs') }}">Runs</a>
|
||||
<div class="jumbotron">
|
||||
<h1 class="display-4">Welcome to the A01 Automation Dashboard.</h1>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -3,37 +3,59 @@
|
|||
<head>
|
||||
{% block head %}
|
||||
<meta charset="UTF-8">
|
||||
<title>A01 Automation</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css"
|
||||
integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB"
|
||||
crossorigin="anonymous">
|
||||
<link rel="stylesheet"
|
||||
href="{{ url_for('static', filename='styles/main.css') }}">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
|
||||
<title>A01 Automation</title>
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<div class="nav-wrapper container">
|
||||
<a href="/" class="brand-logo">A01 Automation</a>
|
||||
<ul class="right">
|
||||
{% if current_user.is_authenticated %}
|
||||
<li><a href="{{ url_for('profile') }}">{{ current_user.user_name }}</a></li>
|
||||
{% else %}
|
||||
<a href="{{ url_for('login') }}">Log in</a>
|
||||
{% endif %}
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<a class="navbar-brand" href="#">A01 Automation</a>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('runs') }}">Runs</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
{% if current_user.is_authenticated %}
|
||||
<a class="nav-link" href="{{ url_for('profile') }}">{{ current_user.user_name }}</a>
|
||||
{% else %}
|
||||
<a class="nav-link" href="{{ url_for('login') }}">Log in</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
{% if current_user.is_authenticated %}
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
{% else %}
|
||||
<p class="lead">You are not authenticated. Please use the log in link in the upper right of the page to navigate
|
||||
to the log in page.</p>
|
||||
<p class="lead">This page may redirect to the log in page, automatically in 3 seconds.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if current_user.is_authenticated %}
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
{% else %}
|
||||
<div class="container">
|
||||
<div class="jumbotron">
|
||||
<h1 class="display-4">Please log in.</h1>
|
||||
<p class="lead">You are not authenticated. Please use the log in link in the upper right of the page to
|
||||
navigate to the log in page.</p>
|
||||
<hr class="my-4">
|
||||
<p class="lead">This page may redirect to the log in page automatically in 10 seconds.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
|
||||
integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"
|
||||
integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T"
|
||||
crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<meta http-equiv="refresh" content="3;{{ auth_link }}"/>
|
||||
<meta http-equiv="refresh" content="10;{{ auth_link }}"/>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,29 +1,63 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
<p class="lead center-align">Only failures are shown</p>
|
||||
<table class="condense">
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
{% for task in tasks %}
|
||||
<tr>
|
||||
<td> {{ task.id }} </td>
|
||||
<td style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 40rem"> {{ task.name }} </td>
|
||||
<td> {{ task.result }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{# <div class="center-align">#}
|
||||
{# <ul class="pagination">#}
|
||||
{# <li><a href="{{ previous_page }}"><i class="material-icons">chevron_left</i></a></li>#}
|
||||
{# <li class="active"><a href="#!">{{ page }}</a></li>#}
|
||||
{# <li><a href="{{ next_page }}"><i class="material-icons">chevron_right</i></a></li>#}
|
||||
{# </ul>#}
|
||||
{# </div>#}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<form class="mt-1 ml-1 col-12" method="get">
|
||||
<div class="form-row">
|
||||
<div class="col">
|
||||
<label class="sr-only" for="query">Query</label>
|
||||
<input type="text" class="form-control mb-2 mr-sm-2"
|
||||
id="query" name="query"
|
||||
placeholder="Current query: {{ query or 'Empty' }}.">
|
||||
</div>
|
||||
<div class="col-auto mt-1 mb-2 mr-sm-2">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="inlineFormCheck" name="logs"
|
||||
value="true">
|
||||
<label class="form-check-label" for="inlineFormCheck">
|
||||
Logs
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn btn-primary mb-2">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<table class="table table-sm table-hover ml-1 mb-1 mr-1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Identifier</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for task in tasks %}
|
||||
<tr>
|
||||
<td>{{ task.id }}</td>
|
||||
<td style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 40rem">
|
||||
{{ task.identifier }}
|
||||
</td>
|
||||
<td>{{ task.result }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="row mt-5">
|
||||
{% for t in tasks %}
|
||||
{% if t.id in logs %}
|
||||
<div class="col ml-1 mt-1">
|
||||
<p class="lead">{{ t.identifier }}</p>
|
||||
<div class="log">
|
||||
<pre><code>{{ logs[t.id] }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,28 +1,36 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
<table class="condense">
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
{% for run in runs %}
|
||||
<div class="container-fluid">
|
||||
<table class="table table-hover table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<td><a href="{{ url_for('run', run_id=run.id) }}">{{ run.id }}</a></td>
|
||||
<td>{{ run.name }}</td>
|
||||
<td>{{ run.status }}</td>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="center-align">
|
||||
<ul class="pagination">
|
||||
<li><a href="{{ previous_page }}"><i class="material-icons">chevron_left</i></a></li>
|
||||
<li class="active"><a href="#!">{{ page }}</a></li>
|
||||
<li><a href="{{ next_page }}"><i class="material-icons">chevron_right</i></a></li>
|
||||
</ul>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for run in runs %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('run', run_id=run.id) }}">{{ run.id }}</a></td>
|
||||
<td>{{ run.name }}</td>
|
||||
<td>{{ run.status }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<nav>
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_previous %}
|
||||
<li class="page-item"><a class="page-link" href="{{ page_previous }}">Previous</a></li>
|
||||
{% else %}
|
||||
<li class="page-item disabled"><a class="page-link" href="#" tabindex="-1">Previous</a></li>
|
||||
{% endif %}
|
||||
<li class="page-item"><a class="page-link" href="#">{{ page }}</a></li>
|
||||
<li class="page-item"><a class="page-link" href="{{ page_next }}">Next</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,5 +1,7 @@
|
|||
pip>=10.0.0
|
||||
|
||||
requests==2.18.4
|
||||
|
||||
flask==1.0.2
|
||||
flask-login==0.4.1
|
||||
flask-sqlalchemy==2.3.1
|
||||
|
|
Загрузка…
Ссылка в новой задаче