diff --git a/atdb/taskdatabase/serializers.py b/atdb/taskdatabase/serializers.py index 30762cd46b840887fe2dddae531b6f7839bfc4ba..a200d6b9761c76c5a0bab08cd30eadee7a28682d 100644 --- a/atdb/taskdatabase/serializers.py +++ b/atdb/taskdatabase/serializers.py @@ -92,7 +92,7 @@ class TaskReadSerializer(serializers.ModelSerializer): class Meta: model = Task - fields = ('id','task_type','filter','predecessor','successors', + fields = ('id','task_type','creationTime','filter','predecessor','successors', 'project','sas_id','priority','purge_policy','resume', 'workflow', 'stage_request_id', diff --git a/atdb/taskdatabase/templates/taskdatabase/base.html b/atdb/taskdatabase/templates/taskdatabase/base.html index 913a91e764f84e14afe0e9bb9ecfb300ab7b556b..fa34728027e41f484f9d375f5f7c232036336337 100644 --- a/atdb/taskdatabase/templates/taskdatabase/base.html +++ b/atdb/taskdatabase/templates/taskdatabase/base.html @@ -39,7 +39,7 @@ ATDB-LDV Dashboard</a> </li> <li><a class="nav-link" href="{% url 'homepage' %}">Tasks</a></li> - <li><a class="nav-link" href="{% url 'task-details' 0 0 %}">Details</a></li> + <li><a class="nav-link" href="{% url 'task-details'%}">Details</a></li> <li><a class="nav-link" href="{% url 'tables2' %}">Query</a></li> <li><a class="nav-link" href="{% url 'diagram' %}">State Diagram</a></li> {% if user.is_staff %} diff --git a/atdb/taskdatabase/templates/taskdatabase/filter/filter_buttons.html b/atdb/taskdatabase/templates/taskdatabase/filter/filter_buttons.html index ad46ef746bbc00378688242584c74b3499233ab8..640c5219a2722132e5cbbda4731d1286719319f5 100644 --- a/atdb/taskdatabase/templates/taskdatabase/filter/filter_buttons.html +++ b/atdb/taskdatabase/templates/taskdatabase/filter/filter_buttons.html @@ -2,8 +2,7 @@ <div class="card-body"> <table> <tr><td>Click to Filter</td></tr> - <tr> - + <tr> <td> <a href="{% url 'task-set-filter' 'all' %}" class="btn btn-success btn-sm" role="button">ALL</a> <a href="{% url 'task-set-filter' 'defined' %}" class="btn btn-primary btn-sm" role="button">defined</a> diff --git a/atdb/taskdatabase/templates/taskdatabase/index.html b/atdb/taskdatabase/templates/taskdatabase/index.html index 9afc83048178b9bc9a029d38047d75610822414c..ce8f1ac7774a1faa98e52ad629c76995fe9af3ce 100644 --- a/atdb/taskdatabase/templates/taskdatabase/index.html +++ b/atdb/taskdatabase/templates/taskdatabase/index.html @@ -46,7 +46,7 @@ {% include 'taskdatabase/pagination.html' %} </div> </div> - <p class="footer"> Version 1.0.0 (5 mar 2021 - 12:00) + <p class="footer"> Version 1.0.0 (5 mar 2021 - 15:00) </div> diff --git a/atdb/taskdatabase/templates/taskdatabase/task/details_card.html b/atdb/taskdatabase/templates/taskdatabase/task/details_card.html new file mode 100644 index 0000000000000000000000000000000000000000..bb9913901fa9f7f7f8d5741fb3748a69ba26aa9d --- /dev/null +++ b/atdb/taskdatabase/templates/taskdatabase/task/details_card.html @@ -0,0 +1,50 @@ + +<div class="card"> + <div class="card-body"> + <h4>Task: {{ task.id }}</h4> + <table class="table table-striped"> + <tbody> + <tr><td><b>id</b></td><td><a href="{% url 'task-detail-view-api' task.pk %}" target="_blank">{{ task.id }} </a></td></tr> + <tr><td><b>priority</b></td><td>{{ task.priority }}</td></tr> + <tr class="{{ task.status }}"><td><b>status</b></td><td>{{ task.status }}</td></tr> + <tr><td><b>workflow</b></td><td> + <a class="open-modal btn btn-primary btn-sm" + href="{% url 'workflow-details' task.workflow %}" + data-popup-url="{% url 'workflow-details' task.workflow %}" + target="_blank"> {{ task.workflow }} + </a></td> + <tr> + <td colspan="2"> + <a class="open-modal btn btn-primary btn-sm" + href="{% url 'show-inputs' task.id %}" + data-popup-url="{% url 'show-inputs' task.id %}" + target="_blank"><i class="fas fa-angle-double-down"></i> inputs + </a> + <a class="open-modal btn btn-primary btn-sm" + href="{% url 'show-outputs' task.id %}" + data-popup-url="{% url 'show-outputs' task.id %}" + target="_blank"><i class="fas fa-angle-double-up"></i> outputs + </a> + <a class="open-modal btn btn-primary btn-sm" + href="{% url 'show-metrics' task.id %}" + data-popup-url="{% url 'show-metrics' task.id %}" + target="_blank"><i class="fas fa-clock"></i> metrics + </a> + </td> + </tr> + + <tr><td><b>project</b></td><td>{{ task.project }}</td></tr> + <tr><td><b>sas_id</b></td><td>{{ task.sas_id }}</td></tr> + <tr><td><b>creationTime</b></td><td>{{ task.creationTime }}</td></tr> + + <tr><td><b>purge_policy</b></td><td>{{ task.purge_policy }}</td></tr> + <tr><td><b>resume</b></td><td>{{ task.resume }}</td></tr> + <tr><td><b>stage_request_id</b></td><td>{{ task.stage_request_id }}</td></tr> + <tr><td><b>size_to_process</b></td><td>{{ task.size_to_process|filesizeformat }}</td></tr> + <tr><td><b>size_processed</b></td><td>{{ task.size_processed|filesizeformat }}</td></tr> + <tr><td><b>total_processing_time</b></td><td>{{ task.total_processing_time }}</td></tr> + + </tbody> + </table> + </div> +</div> \ No newline at end of file diff --git a/atdb/taskdatabase/templates/taskdatabase/task/logentries_card.html b/atdb/taskdatabase/templates/taskdatabase/task/logentries_card.html new file mode 100644 index 0000000000000000000000000000000000000000..11e37a07f21c1ebd4ba0c6afed5c6ff772874b12 --- /dev/null +++ b/atdb/taskdatabase/templates/taskdatabase/task/logentries_card.html @@ -0,0 +1,8 @@ +<div class="card"> + <div class="card-body"> + <h4>Log Entries</h4> + <table class="table table-striped"> + {{ logentries | safe }} + </table> + </div> +</div> \ No newline at end of file diff --git a/atdb/taskdatabase/templates/taskdatabase/task/status_panel.html b/atdb/taskdatabase/templates/taskdatabase/task/status_panel.html new file mode 100644 index 0000000000000000000000000000000000000000..ecb103b915c6f798bcf6d52000020a5094881e35 --- /dev/null +++ b/atdb/taskdatabase/templates/taskdatabase/task/status_panel.html @@ -0,0 +1,33 @@ + + <div class="row"> + <div class="col-sm"> + <div class="card"> + + <div class="card-body"> + + {% if user.is_staff %} + <p>Click to change Status</p> + <table> + + <tr> + {% if task.status != "defining" %} + <a href="{% url 'task-details-setstatus' task.pk 'defining' %}" class="btn btn-warning btn-sm" role="button"><i class="fas fa-undo"></i> Reset</a> + {% endif %} + {% if task.status == "defining" %} + <a href="{% url 'task-details-setstatus' task.pk 'defined' %}" class="btn btn-success btn-sm" role="button"><i class="fas fa-sync-alt"></i> Stage</a> + {% endif %} + <a href="{% url 'task-details-setstatus' task.pk 'staged' %}" class="btn btn-secondary btn-sm" role="button"><i class="fas fa-sync-alt"></i> staged</a> + <a href="{% url 'task-details-setstatus' task.pk 'processed' %}" class="btn btn-secondary btn-sm" role="button"><i class="fas fa-sync-alt"></i> processed</a></td> + <a href="{% url 'task-details-setstatus' task.pk 'validated' %}" class="btn btn-secondary btn-sm" role="button"><i class="fas fa-sync-alt"></i> validated</a> + <a href="{% url 'task-details-setstatus' task.pk 'scrubbed' %}" class="btn btn-secondary btn-sm" role="button"><i class="fas fa-sync-alt"></i> scrubbed</a> + <a href="{% url 'task-details-setstatus' task.pk 'archived' %}" class="btn btn-secondary btn-sm" role="button"><i class="fas fa-sync-alt"></i> archived</a> + <a href="{% url 'task-details-setstatus' task.pk 'finished' %}" class="btn btn-secondary btn-sm" role="button"><i class="fas fa-sync-alt"></i> finished</a> + + </tr> + </table> + {% endif %} + </div> + </div> + </div> + </div> + diff --git a/atdb/taskdatabase/templates/taskdatabase/task/task_details.html b/atdb/taskdatabase/templates/taskdatabase/task/task_details.html index d59accf9997a1d5078e94a2fa0f4ff504aee2333..feb3d32ad6c88b275ac2227a7bd7cb6b1ae3ba5f 100644 --- a/atdb/taskdatabase/templates/taskdatabase/task/task_details.html +++ b/atdb/taskdatabase/templates/taskdatabase/task/task_details.html @@ -3,40 +3,22 @@ {% block myBlock %} <div class="container"> + {% include "taskdatabase/task/status_panel.html" %} + + <div class="row"> - <div class="col-sm"> - <div class="card"> - <div class="card-body"> - <h3>Task: {{ task.id }}</h3> - <table class="table table-striped"> - <tbody> - <tr><td><b>id</b></td><td><a href="{% url 'task-detail-view-api' task.pk %}" target="_blank">{{ task.id }} </a></td></tr> - <tr><td><b>status</b></td><td>{{ task.status }}</td></tr> - <td><b>tasks list</b></td><td><a href="{% url 'tasks-api' %}" class="btn btn-secondary btn-sm" role="button" target="_blank">REST API</a></td> - </tr> - </tbody> - </table> - </div> - </div> + <div class="col-sm"> + {% include "taskdatabase/task/details_card.html" %} </div> <div class="col-sm"> - <div class="card"> - <div class="card-body"> - <h3>Logentries: {{ task.id }}</h3> - <table class="table table-striped"> - <tbody> - <tr><td><b>id</b></td><td><a href="{% url 'task-detail-view-api' task.pk %}" target="_blank">{{ task.id }} </a></td></tr> - <tr><td><b>status</b></td><td>{{ task.status }}</td></tr> - <td><b>tasks list</b></td><td><a href="{% url 'tasks-api' %}" class="btn btn-secondary btn-sm" role="button" target="_blank">REST API</a></td> - </tr> - </tbody> - </table> - </div> - </div> + {% include "taskdatabase/task/logentries_card.html" %} </div> </div> </div> +{% include "taskdatabase/modal/modal_script.html" %} +{% include "taskdatabase/modal/modal.html" %} + +{% endblock %} -{% endblock %} \ No newline at end of file diff --git a/atdb/taskdatabase/templates/taskdatabase/tasks.html b/atdb/taskdatabase/templates/taskdatabase/tasks.html index 2f43ac11155e2d2ca121d69a0e8e5c89d0bd995f..81f9b18e9520c100476b88f00b901220b12d81d2 100644 --- a/atdb/taskdatabase/templates/taskdatabase/tasks.html +++ b/atdb/taskdatabase/templates/taskdatabase/tasks.html @@ -34,7 +34,7 @@ <a class="btn btn-primary btn-sm" href="{% url 'task-details' task.id my_tasks.number %}" data-popup-url="{% url 'task-details' task.id my_tasks.number %}" - > Task + > Details </a> <a class="open-modal btn btn-primary btn-sm" @@ -85,12 +85,6 @@ {% if task.status == "defining" %} <a href="{% url 'task-setstatus-view' task.pk 'defined' my_tasks.number %}" class="btn btn-success btn-sm" role="button">Stage</a> {% endif %} - <a href="{% url 'task-setstatus-view' task.pk 'staged' my_tasks.number %}" class="btn btn-secondary btn-sm" role="button"></i> staged</a> - <a href="{% url 'task-setstatus-view' task.pk 'processed' my_tasks.number %}" class="btn btn-secondary btn-sm" role="button">processed</a> - <a href="{% url 'task-setstatus-view' task.pk 'validated' my_tasks.number %}" class="btn btn-secondary btn-sm" role="button">validated</a> - <a href="{% url 'task-setstatus-view' task.pk 'scrubbed' my_tasks.number %}" class="btn btn-secondary btn-sm" role="button">scrubbed</a> - <a href="{% url 'task-setstatus-view' task.pk 'archived' my_tasks.number %}" class="btn btn-secondary btn-sm" role="button">archived</a> - <a href="{% url 'task-setstatus-view' task.pk 'finished' my_tasks.number %}" class="btn btn-secondary btn-sm" role="button">finished</a> {% endif %} {% if task.status == "processed" %} diff --git a/atdb/taskdatabase/urls.py b/atdb/taskdatabase/urls.py index eff28fbd2ed91ac3f50ffadd3d75b092d71b2ceb..1f7f431bbc8aa30c58a77e9a081985edd0491108 100644 --- a/atdb/taskdatabase/urls.py +++ b/atdb/taskdatabase/urls.py @@ -6,7 +6,9 @@ urlpatterns = [ # --- GUI --- path('', views.IndexView.as_view(), name='homepage'), path('/<page>', views.IndexView.as_view(), name='homepage_page'), + path('task_details/<int:id>/<page>', views.TaskDetails, name='task-details'), + path('task_details', views.TaskDetails, name='task-details'), path('show-inputs/<int:id>/', views.ShowInputs, name='show-inputs'), path('show-outputs/<int:id>/', views.ShowOutputs, name='show-outputs'), @@ -42,6 +44,8 @@ urlpatterns = [ # --- controller resources --- path('tasks/<int:pk>/setstatus/<new_status>/<page>', views.TaskSetStatus, name='task-setstatus-view'), + path('tasks/<int:pk>/setstatus/<new_status>', views.TaskSetStatus, name='task-details-setstatus'), + path('tasks/<int:pk>/change_priority/<priority_change>/<page>', views.TaskChangePriority, name='task-change-priority'), path('tasks/set_filter/<filter>', views.TaskSetFilter, name='task-set-filter'), diff --git a/atdb/taskdatabase/views.py b/atdb/taskdatabase/views.py index 732d6030274ccbdf89a74e772f5400c6b3a06918..d654c50681024477d942dec52a0f488f985ee5b6 100644 --- a/atdb/taskdatabase/views.py +++ b/atdb/taskdatabase/views.py @@ -81,7 +81,9 @@ class LogEntryFilter(filters.FilterSet): model = LogEntry fields = { + 'task__id': ['exact'], 'step_name': ['exact', 'icontains', 'in', 'startswith'], + 'status': ['exact','in'], } class ConfigurationFilter(filters.FilterSet): @@ -191,45 +193,34 @@ class TaskTables2View(SingleTableView): table_class = TaskTable template_name = 'tables2/tables2.html' -# ---------- REST API views ----------- - -# example: /atdb/tasks/ -class TaskListViewAPI(generics.ListCreateAPIView): - """ - A pagination list of tasks, unsorted. - """ - model = Task - queryset = Task.objects.all() - #serializer_class = TaskSerializer - # using the Django Filter Backend - https://django-filter.readthedocs.io/en/latest/index.html - filter_backends = (filters.DjangoFilterBackend,) - filter_class = TaskFilter - - def get_serializer_class(self): - if self.request.method in ['GET']: - return TaskReadSerializer - else: - return TaskWriteSerializer +def convert_logentries_to_html(log_entries): + results = "" -# example: /atdb/tasks/5/ -# calling this view serializes a task in the REST API -class TaskDetailsViewAPI(generics.RetrieveUpdateDestroyAPIView): - """ - Detailed view of a task. - """ - model = Task - queryset = Task.objects.all() - # serializer_class = TaskSerializer + try: + results += "<th>step</th><th>status</th><th>timestamp</th><th>cpu_cycles</th><th>wall_clock_time</th><th>logfile</th>" + results += "<tbody>" + for log in log_entries: + line = "<tr><td><b>" + log.step_name + '</b></td>' + line +='<td class="' + log.status + '" >' + log.status + "</td>" + line += "<td>" + str(log.timestamp) + "</td>" + line += "<td>" + str(log.cpu_cycles) + "</td>" + line += "<td>" + str(log.wall_clock_time) + "</td>" + if log.url_to_log_file!=None: + link = "<a href=" + '"' + str(log.url_to_log_file) + '">' + "logfile" + "</a>" + else: + link = "-" + line += "<td>" + link + "</td>" + results += line + + results += "</tbody>" + except: + results = "<tr><td>no data</td></tr>" - def get_serializer_class(self): - if self.request.method in ['GET']: - return TaskReadSerializer - else: - return TaskWriteSerializer + return results -def TaskDetails(request, id, page): +def TaskDetails(request, id=0, page=0): try: task = Task.objects.get(id=id) @@ -249,7 +240,11 @@ def TaskDetails(request, id, page): # store the current page on the session request.session['page'] = page - return render(request, "taskdatabase/task/task_details.html", {'task': task }) + + log_entries = LogEntry.objects.filter(task=task) + logentries_html = convert_logentries_to_html(log_entries) + + return render(request, "taskdatabase/task/task_details.html", {'task': task, 'logentries': logentries_html }) def convert_list_of_dicts_to_html(my_list): @@ -296,6 +291,49 @@ def ShowMetrics(request, id): return render(request, "taskdatabase/details/metrics.html", {'results': results}) +def WorkflowDetails(request, id): + workflow = Workflow.objects.get(id=id) + return render(request, "taskdatabase/workflow/workflow_details.html", {'workflow': workflow}) + + +# ---------- REST API views ----------- + +# example: /atdb/tasks/ +class TaskListViewAPI(generics.ListCreateAPIView): + """ + A pagination list of tasks, unsorted. + """ + model = Task + queryset = Task.objects.all() + #serializer_class = TaskSerializer + + # using the Django Filter Backend - https://django-filter.readthedocs.io/en/latest/index.html + filter_backends = (filters.DjangoFilterBackend,) + filter_class = TaskFilter + + def get_serializer_class(self): + if self.request.method in ['GET']: + return TaskReadSerializer + else: + return TaskWriteSerializer + +# example: /atdb/tasks/5/ +# calling this view serializes a task in the REST API +class TaskDetailsViewAPI(generics.RetrieveUpdateDestroyAPIView): + """ + Detailed view of a task. + """ + model = Task + queryset = Task.objects.all() + # serializer_class = TaskSerializer + + def get_serializer_class(self): + if self.request.method in ['GET']: + return TaskReadSerializer + else: + return TaskWriteSerializer + + # example: /atdb/workflows/ class WorkflowListViewAPI(generics.ListCreateAPIView): model = Workflow @@ -312,11 +350,6 @@ class WorkflowDetailsViewAPI(generics.RetrieveUpdateDestroyAPIView): serializer_class = WorkflowSerializer -def WorkflowDetails(request, id): - workflow = Workflow.objects.get(id=id) - return render(request, "taskdatabase/workflow/workflow_details.html", {'workflow': workflow}) - - # example: /atdb/logentries/ class LogEntryListViewAPI(generics.ListCreateAPIView): model = LogEntry @@ -382,12 +415,18 @@ def Hold(request,pk,hold_it,page): return redirect('/atdb/?page='+page) -def TaskSetStatus(request,pk,new_status,page): +def TaskSetStatus(request,pk,new_status,page=0): model = Task task = Task.objects.get(pk=pk) task.new_status = new_status task.save() - return redirect('/atdb/?page='+page) + + if page==0: + # redirect to details screen + return redirect('/atdb/task_details/0/0') + else: + # redirect to tasks list + return redirect('/atdb/?page='+page) def TaskSetFilter(request,filter): @@ -411,6 +450,7 @@ def TaskSetStatusTables2(request,pk,new_status,page): task.save() return redirect('/atdb/tables2/?page='+page) + # /atdb/get_size?status__in=defined,staged class GetSizeView(generics.ListAPIView): queryset = Task.objects.all()