Commit 871de94e by Kálmán Viktor

dashboard: add node activity detail view

closes #432
parent d8a9c4ef
...@@ -232,6 +232,14 @@ class ActivityModel(TimeStampedModel): ...@@ -232,6 +232,14 @@ class ActivityModel(TimeStampedModel):
else: else:
return code return code
def get_status_id(self):
if self.succeeded is None:
return 'wait'
elif self.succeeded:
return 'success'
else:
return 'failed'
@celery.task() @celery.task()
def compute_cached(method, instance, memcached_seconds, def compute_cached(method, instance, memcached_seconds,
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
<i class="fa {% if not a.finished %}fa-refresh fa-spin {% else %}fa-{{a.icon}}{% endif %}"></i> <i class="fa {% if not a.finished %}fa-refresh fa-spin {% else %}fa-{{a.icon}}{% endif %}"></i>
</span> </span>
<strong title="{{ a.result.get_admin_text }}"> <strong title="{{ a.result.get_admin_text }}">
{{ a.readable_name.get_admin_text|capfirst }} <a href="{{ a.get_absolute_url }}">
{{ a.readable_name.get_admin_text|capfirst }}</a>
</strong> </strong>
<span title="{{ a.started }}">{{ a.started|arrowfilter:LANGUAGE_CODE }}</span>{% if a.user %}, {{ a.user }}{% endif %} <span title="{{ a.started }}">{{ a.started|arrowfilter:LANGUAGE_CODE }}</span>{% if a.user %}, {{ a.user }}{% endif %}
...@@ -19,7 +20,8 @@ ...@@ -19,7 +20,8 @@
<div data-activity-id="{{ s.pk }}" <div data-activity-id="{{ s.pk }}"
class="sub-activity{% if s.has_failed %} sub-activity-failed{% endif %}"> class="sub-activity{% if s.has_failed %} sub-activity-failed{% endif %}">
<span title="{{ s.result.get_admin_text }}"> <span title="{{ s.result.get_admin_text }}">
{{ s.readable_name|get_text:user }} <a href="{{ s.get_absolute_url }}">
{{ s.readable_name|get_text:user }}</a>
</span> </span>
&ndash; &ndash;
{% if s.finished %} {% if s.finished %}
......
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load hro %}
{% block content %}
<div class="body-content">
<div class="page-header">
<h1>
<div class="pull-right" id="vm-activity-state">
<span class="label label-{% if object.get_status_id == 'wait' %}info{% else %}{% if object.succeeded %}success{% else %}danger{% endif %}{% endif %}">
<span>{{ object.get_status_id|upper }}</span>
</span>
</div>
<i class="fa fa-{{icon}}"></i>
{{ object.node.name }}: {{object.readable_name|get_text:user}}
</h1>
</div>
<div class="row">
<div class="col-md-6" id="vm-info-pane">
{% include "dashboard/vm-detail/_activity-timeline.html" with active=object %}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-body">
<dl>
<dt>{% trans "activity code" %}</dt>
<dd>{{object.activity_code}}</dd>
<dt>{% trans "node" %}</dt>
<dd><a href="{{object.node.get_absolute_url}}">{{object.node}}</a></dd>
<dt>{% trans "time" %}</dt>
<dd>{{object.started|default:'n/a'}} → {{object.finished|default:'n/a'}}</dd>
<dt>{% trans "user" %}</dt>
<dd>
<a href="{{ object.user.profile.get_absolute_url }}">
{{object.user|default:'(system)'}}</a></dd>
<dt>{% trans "type" %}</dt>
<dd>
{% if object.parent %}
{% blocktrans with url=object.parent.get_absolute_url name=object.parent %}
subactivity of <a href="{{url}}">{{name}}</a>
{% endblocktrans %}
{% else %}{% trans "top level activity" %}{% endif %}
</dd>
<dt>{% trans "task uuid" %}</dt>
<dd>{{ object.task_uuid|default:'n/a' }}</dd>
<dt>{% trans "status" %}</dt>
<dd id="activity_status">{{ object.get_status_id }}</dd>
<dt>{% trans "result" %}</dt>
<dd><textarea class="form-control" id="activity_result_text">{{object.result|get_text:user}}</textarea></dd>
<dt>{% trans "subactivities" %}</dt>
{% for s in object.children.all %}
<dd>
<span{% if s.result %} title="{{ s.result|get_text:user }}"{% endif %}>
<a href="{{ s.get_absolute_url }}">
{{ s.readable_name|get_text:user|capfirst }}</a></span> &ndash;
{% if s.finished %}
{{ s.finished|time:"H:i:s" }}
{% else %}
<i class="fa fa-refresh fa-spin" class="sub-activity-loading-icon"></i>
{% endif %}
{% if s.has_failed %}
<div class="label label-danger">{% trans "failed" %}</div>
{% endif %}
</dd>
{% empty %}
<dd>{% trans "none" %}</dd>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
...@@ -25,7 +25,7 @@ from .views import ( ...@@ -25,7 +25,7 @@ from .views import (
GroupDetailView, GroupList, IndexView, GroupDetailView, GroupList, IndexView,
InstanceActivityDetail, LeaseCreate, LeaseDelete, LeaseDetail, InstanceActivityDetail, LeaseCreate, LeaseDelete, LeaseDetail,
MyPreferencesView, NodeAddTraitView, NodeCreate, NodeDelete, MyPreferencesView, NodeAddTraitView, NodeCreate, NodeDelete,
NodeDetailView, NodeList, NodeDetailView, NodeList, NodeActivityDetail,
NotificationView, TemplateAclUpdateView, TemplateCreate, NotificationView, TemplateAclUpdateView, TemplateCreate,
TemplateDelete, TemplateDetail, TemplateList, TemplateDelete, TemplateDetail, TemplateList,
vm_activity, VmCreate, VmDetailView, vm_activity, VmCreate, VmDetailView,
...@@ -133,6 +133,8 @@ urlpatterns = patterns( ...@@ -133,6 +133,8 @@ urlpatterns = patterns(
name='dashboard.views.node-activity-list'), name='dashboard.views.node-activity-list'),
url(r'^node/create/$', NodeCreate.as_view(), url(r'^node/create/$', NodeCreate.as_view(),
name='dashboard.views.node-create'), name='dashboard.views.node-create'),
url(r'^node/activity/(?P<pk>\d+)/$', NodeActivityDetail.as_view(),
name='dashboard.views.node-activity'),
url(r'^favourite/$', FavouriteView.as_view(), url(r'^favourite/$', FavouriteView.as_view(),
name='dashboard.views.favourite'), name='dashboard.views.favourite'),
......
...@@ -330,3 +330,18 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View): ...@@ -330,3 +330,18 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View):
json.dumps(response), json.dumps(response),
content_type="application/json" content_type="application/json"
) )
class NodeActivityDetail(LoginRequiredMixin, SuperuserRequiredMixin,
DetailView):
model = NodeActivity
context_object_name = 'nodeactivity' # much simpler to mock object
template_name = 'dashboard/nodeactivity_detail.html'
def get_context_data(self, **kwargs):
ctx = super(NodeActivityDetail, self).get_context_data(**kwargs)
ctx['activities'] = _format_activities(NodeActivity.objects.filter(
node=self.object.node, parent=None
).order_by('-started').select_related())
ctx['icon'] = _get_activity_icon(self.object)
return ctx
...@@ -135,14 +135,6 @@ class InstanceActivity(ActivityModel): ...@@ -135,14 +135,6 @@ class InstanceActivity(ActivityModel):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('dashboard.views.vm-activity', args=[self.pk]) return reverse('dashboard.views.vm-activity', args=[self.pk])
def get_status_id(self):
if self.succeeded is None:
return 'wait'
elif self.succeeded:
return 'success'
else:
return 'failed'
def has_percentage(self): def has_percentage(self):
op = self.instance.get_operation_from_activity_code(self.activity_code) op = self.instance.get_operation_from_activity_code(self.activity_code)
return (self.task_uuid and op and op.has_percentage and return (self.task_uuid and op and op.has_percentage and
...@@ -219,6 +211,9 @@ class NodeActivity(ActivityModel): ...@@ -219,6 +211,9 @@ class NodeActivity(ActivityModel):
return self.node.get_operation_from_activity_code( return self.node.get_operation_from_activity_code(
self.activity_code) self.activity_code)
def get_absolute_url(self):
return reverse('dashboard.views.node-activity', args=[self.pk])
def __unicode__(self): def __unicode__(self):
if self.parent: if self.parent:
return '{}({})->{}'.format(self.parent.activity_code, return '{}({})->{}'.format(self.parent.activity_code,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment