Commit da2b020d by Kálmán Viktor

Merge branch 'feature-vm-list' into 'master'

Feature better VM list

Closes #232
parents b5653fec 3d552c81
......@@ -39,7 +39,7 @@ from django.contrib.auth.forms import UserCreationForm as OrgUserCreationForm
from django.forms.widgets import TextInput, HiddenInput
from django.template import Context
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy as _
from sizefield.widgets import FileSizeWidget
from django.core.urlresolvers import reverse_lazy
......@@ -1138,3 +1138,29 @@ class VmResourcesForm(forms.ModelForm):
class Meta:
model = Instance
fields = ('num_cores', 'priority', 'ram_size', )
vm_search_choices = (
(0, _("owned")),
(1, _("shared")),
(2, _("all")),
)
class VmListSearchForm(forms.Form):
s = forms.CharField(widget=forms.TextInput(attrs={
'class': "form-control input-tags",
'placeholder': _("Search...")
}))
stype = forms.ChoiceField(vm_search_choices, widget=forms.Select(attrs={
'class': "btn btn-default input-tags",
}))
def __init__(self, *args, **kwargs):
super(VmListSearchForm, self).__init__(*args, **kwargs)
# set initial value, otherwise it would be overwritten by request.GET
if not self.data.get("stype"):
data = self.data.copy()
data['stype'] = 2
self.data = data
......@@ -258,14 +258,15 @@ $(function () {
html += '<div class="list-group-item list-group-item-last">' + gettext("No result") + '</div>';
$("#dashboard-vm-list").html(html);
$('.title-favourite').tooltip({'placement': 'right'});
});
// if there is only one result and ENTER is pressed redirect
if(e.keyCode == 13 && search_result.length == 1) {
window.location.href = "/dashboard/vm/" + search_result[0].pk + "/";
}
if(e.keyCode == 13 && search_result.length > 1 && input.length > 0) {
window.location.href = "/dashboard/vm/list/?s=" + input;
$("#dashboard-vm-search-form").submit(function() {
var vm_list_items = $("#dashboard-vm-list .list-group-item");
if(vm_list_items.length == 1) {
window.location.href = vm_list_items.first().prop("href");
return false;
}
return true;
});
/* search for nodes */
......
......@@ -46,12 +46,15 @@
</style>
<div href="#" class="list-group-item list-group-footer">
<div class="row">
<form action="{% url "dashboard.views.vm-list" %}" method="GET" id="dashboard-vm-search-form">
<div class="col-sm-6 col-xs-6 input-group input-group-sm">
<input id="dashboard-vm-search-input" type="text" class="form-control" placeholder="{% trans "Search..." %}" />
<input id="dashboard-vm-search-input" type="text" class="form-control" name="s"
placeholder="{% trans "Search..." %}" />
<div class="input-group-btn">
<button type="submit" class="form-control btn btn-primary"><i class="fa fa-search"></i></button>
</div>
</div>
</form>
<div class="col-sm-6 text-right">
<a class="btn btn-primary btn-xs" href="{% url "dashboard.views.vm-list" %}">
<i class="fa fa-chevron-circle-right"></i>
......
......@@ -15,22 +15,37 @@
</div>
<h3 class="no-margin"><i class="fa fa-desktop"></i> {% trans "Virtual machines" %}</h3>
</div>
<div class="pull-right" style="max-width: 250px; margin-top: 15px; margin-right: 15px;">
<form action="" method="GET" class="input-group">
<input type="text" name="s"{% if request.GET.s %} value="{{ request.GET.s }}"{% endif %} class="form-control input-tags" placeholder="{% trans "Search..."%}" />
<div class="pull-right" style="max-width: 300px; margin-top: 15px; margin-right: 15px;">
<form action="" method="GET">
<div class="input-group">
{{ search_form.s }}
<div class="input-group-btn">
<button type="submit" class="form-control btn btn-primary input-tags" title="search"><i class="fa fa-search"></i></button>
{{ search_form.stype }}
<button type="submit" class="btn btn-primary input-tags">
<i class="fa fa-search"></i>
</button>
</div>
</div>
</form>
</div>
<div class="panel-body vm-list-group-control">
<p>
<strong>{% trans "Group actions" %}</strong>
<!--
<button id="vm-list-group-select-all" class="btn btn-info btn-xs">{% trans "Select all" %}</button>
<a class="btn btn-default btn-xs" id="vm-list-group-migrate" disabled><i class="fa fa-truck"></i> {% trans "Migrate" %}</a>
<a disabled href="#" class="btn btn-default btn-xs"><i class="fa fa-refresh"></i> {% trans "Reboot" %}</a>
<a disabled href="#" class="btn btn-default btn-xs"><i class="fa fa-off"></i> {% trans "Shutdown" %}</a>
<a id="vm-list-group-delete" disabled href="#" class="btn btn-danger btn-xs"><i class="fa fa-times"></i> {% trans "Destroy" %}</a>
<a href="#" class="btn btn-default btn-xs" title="{% trans "Migrate" %}" disabled>
<i class="fa fa-truck"></i>
</a>
<a href="#" class="btn btn-default btn-xs" title="{% trans "Reboot" %}" disabled>
<i class="fa fa-refresh"></i>
</a>
<a href="#" class="btn btn-default btn-xs" title="{% trans "Shutdown" %}" disabled>
<i class="fa fa-power-off"></i>
</a>
-->
<a title="{% trans "Destroy" %}" id="vm-list-group-delete" disabled href="#" class="btn btn-danger btn-xs" disabled>
<i class="fa fa-times"></i>
</a>
</p>
</div>
<div class="panel-body">
......@@ -87,6 +102,9 @@
</div>
</div>
<div class="alert alert-info">
You can filter the list by certain attributes (owner, name, status, tags) in the following way: "owner:John Doe name:my little server". If you don't specify any attribute names the filtering will be done by name.
</div>
<div class="alert alert-info">
{% trans "You can select multiple vm instances while holding down the <strong>CTRL</strong> key." %}
......
......@@ -70,7 +70,7 @@ from .forms import (
VmSaveForm, UserKeyForm, VmRenewForm,
CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm,
TraitsForm, RawDataForm, GroupPermissionForm, AclUserAddForm,
VmResourcesForm, VmAddInterfaceForm,
VmResourcesForm, VmAddInterfaceForm, VmListSearchForm
)
from .tables import (
......@@ -1563,6 +1563,11 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
'template': "template__pk",
}
def get_context_data(self, *args, **kwargs):
context = super(VmList, self).get_context_data(*args, **kwargs)
context['search_form'] = self.search_form
return context
def get(self, *args, **kwargs):
if self.request.is_ajax():
favs = Instance.objects.filter(
......@@ -1582,13 +1587,14 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
content_type="application/json",
)
else:
self.search_form = VmListSearchForm(self.request.GET)
self.search_form.full_clean()
return super(VmList, self).get(*args, **kwargs)
def get_queryset(self):
logger.debug('VmList.get_queryset() called. User: %s',
unicode(self.request.user))
queryset = Instance.get_objects_with_level(
'user', self.request.user).filter(destroyed_at=None)
queryset = self.create_default_queryset()
self.create_fake_get()
sort = self.request.GET.get("sort")
......@@ -1603,6 +1609,18 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
**self.get_queryset_filters()).select_related('owner', 'node'
).distinct()
def create_default_queryset(self):
cleaned_data = self.search_form.cleaned_data
stype = cleaned_data.get('stype', 2)
superuser = stype == 2
shared = stype == 1
level = "owner" if stype == 0 else "user"
queryset = Instance.get_objects_with_level(
level, self.request.user,
group_also=shared, disregard_superuser=not superuser,
).filter(destroyed_at=None)
return queryset
def create_fake_get(self):
"""
Updates the request's GET dict to filter the vm list
......
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