diff --git a/app/factory.py b/app/factory.py index b6116574e9bf654af6c8cc95e78b6ce9bf886567..566091da294e7289707d61a5de5d3dca18733b39 100644 --- a/app/factory.py +++ b/app/factory.py @@ -21,6 +21,7 @@ from .admin.views import (AdminModelView, ItemAdmin, UserAdmin, TokenAdmin, from .main.views import bp as main from .inventory.views import bp as inventory from .network.views import bp as network +from .task.views import bp as task from .user.views import bp as user from .api.user import bp as user_api from .api.inventory import bp as inventory_api @@ -112,11 +113,12 @@ def create_app(config=None): admin.add_view(AdminModelView(models.Mac, db.session)) admin.add_view(AdminModelView(models.Cname, db.session)) admin.add_view(AdminModelView(models.Tag, db.session)) - admin.add_view(TaskAdmin(models.Task, db.session)) + admin.add_view(TaskAdmin(models.Task, db.session, endpoint='tasks')) app.register_blueprint(main) app.register_blueprint(inventory, url_prefix='/inventory') app.register_blueprint(network, url_prefix='/network') + app.register_blueprint(task, url_prefix='/task') app.register_blueprint(user, url_prefix='/user') app.register_blueprint(user_api, url_prefix='/api/v1/user') app.register_blueprint(inventory_api, url_prefix='/api/v1/inventory') diff --git a/app/static/js/tasks.js b/app/static/js/tasks.js new file mode 100644 index 0000000000000000000000000000000000000000..de87469f32c944321721453f913107df9d3893c4 --- /dev/null +++ b/app/static/js/tasks.js @@ -0,0 +1,30 @@ +$(document).ready(function() { + + var tasks_table = $("#tasks_table").DataTable({ + "ajax": function(data, callback, settings) { + $.getJSON( + $SCRIPT_ROOT + "/task/_retrieve_tasks", + function(json) { + callback(json); + }); + }, + "pagingType": "full_numbers", + "pageLength": 20, + "lengthMenu": [[20, 50, 100, -1], [20, 50, 100, "All"]], + "order": [[2, 'desc']], + "columnDefs": [ + { + "targets": [0], + "render": function(data, type, row) { + // render funtion to create link to Task view page + if ( data === null ) { + return data; + } + var url = $SCRIPT_ROOT + "/task/tasks/view/" + data; + return '<a href="'+ url + '">' + data + '</a>'; + } + } + ] + }); + +}); diff --git a/app/task/__init__.py b/app/task/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/task/views.py b/app/task/views.py new file mode 100644 index 0000000000000000000000000000000000000000..ad3f42758d05763277cf0626b1ecae45d0eb9f69 --- /dev/null +++ b/app/task/views.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +""" +app.task.views +~~~~~~~~~~~~~~ + +This module implements the task blueprint. + +:copyright: (c) 2018 European Spallation Source ERIC +:license: BSD 2-Clause, see LICENSE for more details. + +""" +from flask import Blueprint, render_template, jsonify +from flask_login import login_required, current_user +from .. import utils, models + +bp = Blueprint('task', __name__) + + +@bp.route('/tasks') +@login_required +def list_tasks(): + return render_template('task/tasks.html') + + +@bp.route('/tasks/view/<id_>') +@login_required +def view_task(id_): + task = models.Task.query.get_or_404(id_) + return render_template('task/view_task.html', task=task) + + +@bp.route('/_retrieve_tasks') +@login_required +def retrieve_tasks(): + data = [(task.id, + task.name, + utils.format_field(task.created_at), + task.status.name, + task.command, + str(task.user)) + for task in current_user.get_tasks()] + return jsonify(data=data) diff --git a/app/templates/base-fluid.html b/app/templates/base-fluid.html index b425f067f81b27cb9aabdebe7be148eab3076b48..44b29d3d7861d46bcf4cafc6d470c76a1407e125 100644 --- a/app/templates/base-fluid.html +++ b/app/templates/base-fluid.html @@ -25,6 +25,9 @@ href="{{ url_for('network.list_scopes') }}">Network Scopes</a> <a class="list-group-item list-group-item-action {{ is_active(path.startswith("/network/domains")) }}" href="{{ url_for('network.list_domains') }}">Domains</a> + {% elif path.startswith("/task") %} + <a class="list-group-item list-group-item-action {{ is_active(path.startswith("/task/tasks")) }}" + href="{{ url_for('task.list_tasks') }}">Tasks</a> {% endif %} </div> </div> diff --git a/app/templates/base.html b/app/templates/base.html index 158126adb6f30fe29ebed9c174a21928a8133763..4b2426f49ca064bf15c493cd45e38c9af32c6563 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -28,6 +28,7 @@ {% set path = request.path %} <a class="nav-item nav-link {{ is_active(path.startswith("/inventory")) }}" href="{{ url_for('inventory.list_items') }}">Inventory</a> <a class="nav-item nav-link {{ is_active(path.startswith("/network")) }}" href="{{ url_for('network.list_hosts') }}">Network</a> + <a class="nav-item nav-link {{ is_active(path.startswith("/task")) }}" href="{{ url_for('task.list_tasks') }}">Task</a> {% if current_user.is_authenticated and current_user.is_admin %} <a class="nav-item nav-link" href="{{ url_for('admin.index') }}">Admin</a> <a class="nav-item nav-link" href="{{ url_for('rq_dashboard.overview') }}">RQ Dashboard</a> diff --git a/app/templates/task/tasks.html b/app/templates/task/tasks.html new file mode 100644 index 0000000000000000000000000000000000000000..d6a4159c8572cdebaf67818b83517b031a99a505 --- /dev/null +++ b/app/templates/task/tasks.html @@ -0,0 +1,35 @@ +{% extends "base-fluid.html" %} +{% from "_helpers.html" import is_active %} + +{% block title %}Tasks - CSEntry{% endblock %} + +{% block main %} + {% set path = request.path %} + <ul class="nav nav-tabs"> + <li class="nav-item"> + <a class="nav-link {{ is_active(path.endswith("/task/tasks")) }}" href="{{ url_for('task.list_tasks') }}">List tasks</a> + </li> + {% block tasks_nav %}{% endblock %} + </ul> + + <br> + + {% block tasks_main %} + <table id="tasks_table" class="table table-bordered table-hover table-sm" cellspacing="0" width="100%"> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + <th>Created at</th> + <th>Status</th> + <th>Command</th> + <th>User</th> + </tr> + </thead> + </table> + {%- endblock %} +{%- endblock %} + +{% block csentry_scripts %} + <script src="{{ url_for('static', filename='js/tasks.js') }}"></script> +{% endblock %} diff --git a/app/templates/task/view_task.html b/app/templates/task/view_task.html new file mode 100644 index 0000000000000000000000000000000000000000..ff1bee2abfcbbd64ff1538f52b88d639d4bf0449 --- /dev/null +++ b/app/templates/task/view_task.html @@ -0,0 +1,30 @@ +{% extends "task/tasks.html" %} + +{% block title %}View Task - CSEntry{% endblock %} + +{% block tasks_nav %} + <li class="nav-item"> + <a class="nav-link active" href="{{ url_for('task.view_task', id_=task.id) }}">View task</a> + </li> +{% endblock %} + +{% block tasks_main %} + <div class="row"> + <div class="col-sm-9"> + <dl class="row"> + <dt class="col-sm-3">Id</dt> + <dd class="col-sm-9">{{ task.id }}</dd> + <dt class="col-sm-3">Name</dt> + <dd class="col-sm-9">{{ task.name }}</dd> + <dt class="col-sm-3">Created at</dt> + <dd class="col-sm-9">{{ task.created_at }}</dd> + <dt class="col-sm-3">Status</dt> + <dd class="col-sm-9">{{ task.status.name }}</dd> + <dt class="col-sm-3">Command</dt> + <dd class="col-sm-9">{{ task.command }}</dd> + <dt class="col-sm-3">User</dt> + <dd class="col-sm-9">{{ task.user }}</dd> + </dl> + </div> + </div> +{%- endblock %}