Commit 21333f3b by Kálmán Viktor

dashboard: basic template and lease edit views

parent 739a1dec
from django import forms from django import forms
from vm.models import InstanceTemplate from vm.models import InstanceTemplate, Lease
from storage.models import Disk from storage.models import Disk
from firewall.models import Vlan from firewall.models import Vlan
# from django.core.urlresolvers import reverse_lazy # from django.core.urlresolvers import reverse_lazy
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import (Layout, Div, BaseInput, # Submit from crispy_forms.layout import (Layout, Div, BaseInput,
Field, HTML) Field, HTML, Submit)
from crispy_forms.layout import TEMPLATE_PACK from crispy_forms.layout import TEMPLATE_PACK
from crispy_forms.utils import render_field from crispy_forms.utils import render_field
from django.template import Context from django.template import Context
...@@ -290,6 +290,29 @@ class VmCreateForm(forms.Form): ...@@ -290,6 +290,29 @@ class VmCreateForm(forms.Form):
) )
class TemplateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(TemplateForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit('submit', 'Save changes'))
class Meta:
model = InstanceTemplate
class LeaseForm(forms.ModelForm):
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", "Save changes"))
return helper
class Meta:
model = Lease
class LinkButton(BaseInput): class LinkButton(BaseInput):
""" """
Used to create a link button descriptor for the {% crispy %} template tag:: Used to create a link button descriptor for the {% crispy %} template tag::
......
from django_tables2 import Table from django_tables2 import Table, A
from django_tables2.columns import TemplateColumn, Column, BooleanColumn from django_tables2.columns import (TemplateColumn, Column, BooleanColumn,
LinkColumn)
from vm.models import Instance, Node from vm.models import Instance, Node, InstanceTemplate, Lease
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -135,3 +136,64 @@ class NodeVmListTable(Table): ...@@ -135,3 +136,64 @@ class NodeVmListTable(Table):
attrs = {'class': ('table table-bordered table-striped table-hover ' attrs = {'class': ('table table-bordered table-striped table-hover '
'vm-list-table')} 'vm-list-table')}
fields = ('pk', 'name', 'state', 'time_of_suspend', 'time_of_delete', ) fields = ('pk', 'name', 'state', 'time_of_suspend', 'time_of_delete', )
class TemplateListTable(Table):
pk = LinkColumn(
'dashboard.views.template-detail',
args=[A('pk')],
verbose_name=_("ID"),
)
num_cores = Column(
verbose_name=_("Cores"),
)
ram_size = TemplateColumn(
"{{ record.ram_size }} Mb",
)
priority = TemplateColumn(
"{{ record.priority }}/100 ",
verbose_name=_("CPU priority"),
)
lease = TemplateColumn(
"{{ record.lease.name }}",
verbose_name=_("Lease"),
)
actions = TemplateColumn(
verbose_name=_("Actions"),
template_name="dashboard/template-list/column-template-actions.html"
)
class Meta:
model = InstanceTemplate
attrs = {'class': ('table table-bordered table-striped table-hover'
' template-list-table')}
fields = ('pk', 'name', 'num_cores', 'ram_size', 'arch',
'priority', 'system', 'access_method', 'lease', 'state',
'actions', )
class LeaseListTable(Table):
pk = LinkColumn(
'dashboard.views.lease-detail',
args=[A('pk')],
verbose_name=_("ID"),
)
suspend_in = TemplateColumn(
"{{ record.get_readable_suspend_time }}"
)
delete_in = TemplateColumn(
"{{ record.get_readable_delete_time }}"
)
actions = TemplateColumn(
verbose_name=_("Actions"),
template_name="dashboard/template-list/column-lease-actions.html"
)
class Meta:
model = Lease
attrs = {'class': ('table table-bordered table-striped table-hover'
' lease-list-table')}
fields = ('pk', 'name', 'suspend_in', 'delete_in', )
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
</a> </a>
<div href="#" class="list-group-item list-group-footer text-right"> <div href="#" class="list-group-item list-group-footer text-right">
<p> <p>
<a class="btn btn-primary btn-xs"><i class="icon-chevron-sign-right"></i> show more </a> <a href="{% url "dashboard.views.template-list" %}" class="btn btn-primary btn-xs"><i class="icon-chevron-sign-right"></i> show all </a>
<a class="btn btn-success btn-xs"><i class="icon-upload-alt"></i> upload </a> <a class="btn btn-success btn-xs"><i class="icon-upload-alt"></i> upload </a>
</p> </p>
</div> </div>
......
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.template-list" %}">Back</a>
<h3 class="no-margin"><i class="icon-desktop"></i> Edit lease</h3>
</div>
<div class="panel-body">
{% crispy form %}
</div>
</div>
</div>
</div>
{% endblock %}
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.template-list" %}">Back</a>
<h3 class="no-margin"><i class="icon-desktop"></i> Edit template</h3>
</div>
<div class="panel-body">
{% crispy form %}
</div>
</div>
</div>
</div>
{% endblock %}
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load render_table from django_tables2 %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a href="#" class="pull-right btn btn-success btn-xs">
<i class="icon-plus"></i> new template
</a>
<h3 class="no-margin"><i class="icon-desktop"></i> {% trans "Templates" %}</h3>
</div>
<div class="panel-body">
<div class="" style="max-width: 600px;">
{% render_table lease_table %}
</div>
{% render_table table %}
</div>
</div>
</div>
</div>
<style>
.template-list-table td, .template-list-table th,
.lease-list-table td, .lease-list-table th {
text-align: center;
}
.vm-list-table-thin {
width: 10px;
}
.vm-list-table-admin {
width: 130px;
}
</style>
{% endblock %}
{% load i18n %}
<a href="{% url "dashboard.views.lease-detail" pk=record.pk %}" id="template-list-edit-button" class="btn btn-default btn-xs" title data-original-title="{% trans "Edit" %}">
<i class="icon-edit"></i>
</a>
<a href="#" class="btn btn-danger btn-xs" title data-original-title="{% trans "Delete" %}">
<i class="icon-remove"></i>
</a>
{% load i18n %}
<a href="{% url "dashboard.views.template-detail" pk=record.pk%}" id="template-list-edit-button" class="btn btn-default btn-xs" title data-original-title="{% trans "Edit" %}">
<i class="icon-edit"></i>
</a>
<a href="#" class="btn btn-danger btn-xs" title data-original-title="{% trans "Delete" %}">
<i class="icon-remove"></i>
</a>
...@@ -5,13 +5,18 @@ from .views import ( ...@@ -5,13 +5,18 @@ from .views import (
IndexView, VmDetailView, VmList, VmCreate, TemplateDetail, AclUpdateView, IndexView, VmDetailView, VmList, VmCreate, TemplateDetail, AclUpdateView,
VmDelete, VmMassDelete, vm_activity, NodeList, NodeDetailView, PortDelete, VmDelete, VmMassDelete, vm_activity, NodeList, NodeDetailView, PortDelete,
TransferOwnershipView, TransferOwnershipConfirmView, NodeDelete, TransferOwnershipView, TransferOwnershipConfirmView, NodeDelete,
NodeCreate) TemplateList, LeaseDetail, NodeCreate,
)
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^$', IndexView.as_view(), name="dashboard.index"), url(r'^$', IndexView.as_view(), name="dashboard.index"),
url(r'^lease/(?P<pk>\d+)/$', LeaseDetail.as_view(),
name="dashboard.views.lease-detail"),
url(r'^template/(?P<pk>\d+)/$', TemplateDetail.as_view(), url(r'^template/(?P<pk>\d+)/$', TemplateDetail.as_view(),
name='dashboard.views.template-detail'), name='dashboard.views.template-detail'),
url(r"^template/list/$", TemplateList.as_view(),
name="dashboard.views.template-list"),
url(r'^vm/(?P<pk>\d+)/remove_port/(?P<rule>\d+)/$', PortDelete.as_view(), url(r'^vm/(?P<pk>\d+)/remove_port/(?P<rule>\d+)/$', PortDelete.as_view(),
name='dashboard.views.remove-port'), name='dashboard.views.remove-port'),
url(r'^vm/(?P<pk>\d+)/$', VmDetailView.as_view(), url(r'^vm/(?P<pk>\d+)/$', VmDetailView.as_view(),
......
...@@ -14,23 +14,43 @@ from django.http import HttpResponse, HttpResponseRedirect, Http404 ...@@ -14,23 +14,43 @@ from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from django.views.generic import TemplateView, DetailView, View, DeleteView from django.views.generic import (TemplateView, DetailView, View, DeleteView,
UpdateView)
from django.contrib import messages from django.contrib import messages
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from braces.views import LoginRequiredMixin from braces.views import LoginRequiredMixin
from .forms import VmCreateForm from .forms import VmCreateForm, TemplateForm, LeaseForm
from .tables import (VmListTable, NodeListTable, NodeVmListTable) from .tables import (VmListTable, NodeListTable, NodeVmListTable,
TemplateListTable, LeaseListTable)
from vm.models import (Instance, InstanceTemplate, InterfaceTemplate, from vm.models import (Instance, InstanceTemplate, InterfaceTemplate,
InstanceActivity, Node, instance_activity) InstanceActivity, Node, instance_activity, Lease)
from firewall.models import Vlan, Host, Rule from firewall.models import Vlan, Host, Rule
from storage.models import Disk from storage.models import Disk
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# github.com/django/django/blob/stable/1.6.x/django/contrib/messages/views.py
class SuccessMessageMixin(object):
"""
Adds a success message on successful form submission.
"""
success_message = ''
def form_valid(self, form):
response = super(SuccessMessageMixin, self).form_valid(form)
success_message = self.get_success_message(form.cleaned_data)
if success_message:
messages.success(self.request, success_message)
return response
def get_success_message(self, cleaned_data):
return self.success_message % cleaned_data
class IndexView(LoginRequiredMixin, TemplateView): class IndexView(LoginRequiredMixin, TemplateView):
template_name = "dashboard/index.html" template_name = "dashboard/index.html"
...@@ -331,8 +351,11 @@ class AclUpdateView(View, SingleObjectMixin): ...@@ -331,8 +351,11 @@ class AclUpdateView(View, SingleObjectMixin):
value, unicode(request.user)) value, unicode(request.user))
class TemplateDetail(DetailView): class TemplateDetail(SuccessMessageMixin, UpdateView):
model = InstanceTemplate model = InstanceTemplate
template_name = "dashboard/template-edit.html"
form_class = TemplateForm
success_message = _("Successfully modified template!")
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if request.is_ajax(): if request.is_ajax():
...@@ -357,8 +380,23 @@ class TemplateDetail(DetailView): ...@@ -357,8 +380,23 @@ class TemplateDetail(DetailView):
return HttpResponse(json.dumps(template), return HttpResponse(json.dumps(template),
content_type="application/json") content_type="application/json")
else: else:
# return super(TemplateDetail, self).get(request, *args, **kwargs) return super(TemplateDetail, self).get(request, *args, **kwargs)
return HttpResponse('soon')
def get_success_url(self):
return reverse_lazy("dashboard.views.template-detail",
kwargs=self.kwargs)
class TemplateList(SingleTableView):
template_name = "dashboard/template-list.html"
model = InstanceTemplate
table_class = TemplateListTable
table_pagination = False
def get_context_data(self, *args, **kwargs):
context = super(TemplateList, self).get_context_data(*args, **kwargs)
context['lease_table'] = LeaseListTable(Lease.objects.all())
return context
class VmList(LoginRequiredMixin, SingleTableView): class VmList(LoginRequiredMixin, SingleTableView):
...@@ -699,6 +737,16 @@ class VmMassDelete(View): ...@@ -699,6 +737,16 @@ class VmMassDelete(View):
return redirect(next if next else reverse_lazy('dashboard.index')) return redirect(next if next else reverse_lazy('dashboard.index'))
class LeaseDetail(SuccessMessageMixin, UpdateView):
model = Lease
form_class = LeaseForm
template_name = "dashboard/lease-edit.html"
success_message = _("Successfully modified lease!")
def get_success_url(self):
return reverse_lazy("dashboard.views.lease-detail", kwargs=self.kwargs)
@require_POST @require_POST
def vm_activity(request, pk): def vm_activity(request, pk):
object = Instance.objects.get(pk=pk) object = Instance.objects.get(pk=pk)
......
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from datetime import timedelta from datetime import timedelta, datetime
from django.db.models import Model, CharField, IntegerField from django.db.models import Model, CharField, IntegerField
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.timesince import timeuntil
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
...@@ -81,8 +82,18 @@ class Lease(Model): ...@@ -81,8 +82,18 @@ class Lease(Model):
def delete_interval(self, value): def delete_interval(self, value):
self.delete_interval_seconds = value.seconds self.delete_interval_seconds = value.seconds
def get_readable_suspend_time(self):
return timeuntil(datetime.utcnow() + self.suspend_interval,
datetime.utcnow())
def get_readable_delete_time(self):
return timeuntil(datetime.utcnow() + self.delete_interval,
datetime.utcnow())
def __unicode__(self): def __unicode__(self):
return self.name return "%s (%s) - (%s)" % (self.name,
self.get_readable_suspend_time(),
self.get_readable_delete_time())
class Trait(Model): class Trait(Model):
......
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