Commit 764d9bf6 by Czémán Arnold

dashboard: add endpoint list and edit view

parent 33ff6a60
...@@ -1670,6 +1670,16 @@ class CephDataStoreForm(DataStoreForm): ...@@ -1670,6 +1670,16 @@ class CephDataStoreForm(DataStoreForm):
is_stacked=True)} is_stacked=True)}
class StorageListSearchForm(forms.Form):
s = forms.CharField(widget=forms.TextInput(attrs={
'class': "form-control input-tags",
'placeholder': _("Search...")
}))
def __init__(self, *args, **kwargs):
super(StorageListSearchForm, self).__init__(*args, **kwargs)
class EndpointForm(ModelForm): class EndpointForm(ModelForm):
@property @property
...@@ -1691,6 +1701,8 @@ class EndpointForm(ModelForm): ...@@ -1691,6 +1701,8 @@ class EndpointForm(ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(EndpointForm, self).__init__(*args, **kwargs) super(EndpointForm, self).__init__(*args, **kwargs)
# NOTE: may this is not necessary, this is the default value in
# libvirt's ceph backend
self.fields['port'].initial = 6789 self.fields['port'].initial = 6789
class Meta: class Meta:
...@@ -1698,14 +1710,14 @@ class EndpointForm(ModelForm): ...@@ -1698,14 +1710,14 @@ class EndpointForm(ModelForm):
fields = ("name", "address", "port") fields = ("name", "address", "port")
class StorageListSearchForm(forms.Form): class EndpointListSearchForm(forms.Form):
s = forms.CharField(widget=forms.TextInput(attrs={ s = forms.CharField(widget=forms.TextInput(attrs={
'class': "form-control input-tags", 'class': "form-control input-tags",
'placeholder': _("Search...") 'placeholder': _("Search...")
})) }))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(StorageListSearchForm, self).__init__(*args, **kwargs) super(EndpointListSearchForm, self).__init__(*args, **kwargs)
class DiskForm(ModelForm): class DiskForm(ModelForm):
......
...@@ -87,6 +87,7 @@ $(function () { ...@@ -87,6 +87,7 @@ $(function () {
return false; return false;
}); });
// NOTE: modal for create endpoint, might use in future
$('.datastore_endpoint-create').click(function(e) { $('.datastore_endpoint-create').click(function(e) {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
......
...@@ -410,3 +410,30 @@ class StorageListTable(Table): ...@@ -410,3 +410,30 @@ class StorageListTable(Table):
fields = ('name', 'type', 'path', 'hostname', 'used_percent') fields = ('name', 'type', 'path', 'hostname', 'used_percent')
prefix = "storage-" prefix = "storage-"
class EndpointListTable(Table):
name = TemplateColumn(
verbose_name=_("Name"),
template_name="dashboard/endpoint-list/column-endpoint-name.html",
attrs={'th': {'data-sort': "string"}}
)
address = Column(
verbose_name=_("Address"),
attrs={'th': {'data-sort': "string"}}
)
port = Column(
verbose_name=_("Port"),
attrs={'th': {'data-sort': "string"}}
)
class Meta:
model = DataStore
attrs = {'class': ('table table-bordered table-striped table-hover'
'endpoint-list-table')}
fields = ('name', 'address', 'port',)
prefix = "endpoint-"
...@@ -23,6 +23,10 @@ ...@@ -23,6 +23,10 @@
</div> </div>
</div> </div>
<input type="submit" value="{% trans "Create new endpoint" %}" class="btn btn-success" id="datastore_endpoint_host-create-btn"> <input type="submit" value="{% trans "Create new endpoint" %}" class="btn btn-success" id="datastore_endpoint_host-create-btn">
<a href="{% url "dashboard.views.storage-endpoint-list" %}" class="btn btn-primary">
{% trans "Back" %}
</a>
</form> </form>
......
{% extends "dashboard/base.html" %}
{% load staticfiles %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title-page %}{% trans "Endpoint" %}{% endblock %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="no-margin"><i class="fa fa-database"></i> {% trans "Endpoint" %}</h3>
</div>
<div class="panel-body">
<form id="datastore_endpoint_form" action="" method="POST">
{% with form=form %}
{% include "display-form-errors.html" %}
{% endwith %}
{% csrf_token %}
<div class="row">
<div class="col-xs-12">{{ form.name|as_crispy_field }}</div>
</div>
<div class="row">
<div class="col-xs-9">
{{ form.address|as_crispy_field }}
</div>
<div class="col-xs-3">
{{ form.port|as_crispy_field }}
</div>
</div>
<input type="submit" value="{% trans "Save" %}" class="btn btn-primary">
<a href="{% url "dashboard.views.storage-endpoint-list" %}" class="btn btn-primary">
{% trans "Back" %}
</a>
</form>
</div><!-- .panel-body -->
</div>
{% endblock %}
{% extends "dashboard/base.html" %}
{% load staticfiles %}
{% load i18n %}
{% load render_table from django_tables2 %}
{% block title-page %}{% trans "Endpoints" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a href="{% url "dashboard.views.storage-endpoint-create" %}" class="pull-right btn btn-success btn-xs">
<i class="fa fa-plus"></i> {% trans "new endpoint" %}
</a>
<h3 class="no-margin"><i class="fa fa-database"></i> {% trans "Endpoints" %}</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-offset-8 col-md-4" id="endpoint-list-search">
<form action="" method="GET">
<div class="input-group">
{{ search_form.s }}
<div class="input-group-btn">
<button type="submit" class="btn btn-primary input-tags">
<i class="fa fa-search"></i>
</button>
</div>
</div><!-- .input-group -->
</form>
</div><!-- .col-md-4 #storage-list-search -->
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
{% render_table table %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
<a href="{% url "dashboard.views.storage-endpoint-edit" pk=record.pk %}" title="{{ record.description }}">
{{ record.name }}
</a>
...@@ -11,9 +11,14 @@ ...@@ -11,9 +11,14 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<a href="{% url "dashboard.views.storage-choose" %}" class="pull-right btn btn-success btn-xs storage-choose"> <div class="pull-right">
<i class="fa fa-plus"></i> {% trans "new data store" %} <a href="{% url "dashboard.views.storage-endpoint-list" %}" class="btn btn-success btn-xs" id="endpoint-list-btn">
</a> {% trans "endpoint list" %}
</a>
<a href="{% url "dashboard.views.storage-choose" %}" class="btn btn-success btn-xs storage-choose">
<i class="fa fa-plus"></i> {% trans "new data store" %}
</a>
</div>
<h3 class="no-margin"><i class="fa fa-database"></i> {% trans "Data stores" %}</h3> <h3 class="no-margin"><i class="fa fa-database"></i> {% trans "Data stores" %}</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "Select or add new Ceph monitor endpoints(s)" %}</legend> <legend>{% trans "Select or add new Ceph monitor endpoints(s)" %}</legend>
<a href="{% url "dashboard.views.storage-endpoint-create" %}" class="btn btn-success datastore_endpoint-create"> <a href="{% url "dashboard.views.storage-endpoint-create" %}" class="btn btn-success">
<i class="fa fa-plus"></i> <i class="fa fa-plus"></i>
{% trans "new endpoint" %} {% trans "new endpoint" %}
</a> </a>
......
...@@ -54,7 +54,7 @@ from .views import ( ...@@ -54,7 +54,7 @@ from .views import (
NodeActivityView, NodeActivityView,
UserList, UserList,
StorageDetail, StorageList, StorageChoose, StorageCreate, DiskDetail, StorageDetail, StorageList, StorageChoose, StorageCreate, DiskDetail,
EndpointCreate, EndpointCreate, EndpointList, EndpointEdit,
MessageList, MessageDetail, MessageCreate, MessageDelete, MessageList, MessageDetail, MessageCreate, MessageDelete,
) )
from .views.vm import vm_ops, vm_mass_ops from .views.vm import vm_ops, vm_mass_ops
...@@ -247,6 +247,10 @@ urlpatterns = patterns( ...@@ -247,6 +247,10 @@ urlpatterns = patterns(
url(r'^storage/endpoint/create/$', EndpointCreate.as_view(), url(r'^storage/endpoint/create/$', EndpointCreate.as_view(),
name="dashboard.views.storage-endpoint-create"), name="dashboard.views.storage-endpoint-create"),
url(r'^storage/endpoint/list/$', EndpointList.as_view(),
name="dashboard.views.storage-endpoint-list"),
url(r'^storage/endpoint/(?P<pk>\d+)/$', EndpointEdit.as_view(),
name='dashboard.views.storage-endpoint-edit'),
url(r'^disk/(?P<pk>\d+)/$', DiskDetail.as_view(), url(r'^disk/(?P<pk>\d+)/$', DiskDetail.as_view(),
name="dashboard.views.disk-detail"), name="dashboard.views.disk-detail"),
......
...@@ -34,10 +34,10 @@ from sizefield.utils import filesizeformat ...@@ -34,10 +34,10 @@ from sizefield.utils import filesizeformat
from common.models import WorkerNotFound from common.models import WorkerNotFound
from storage.models import DataStore, Disk, Endpoint from storage.models import DataStore, Disk, Endpoint
from ..tables import DiskListTable, StorageListTable from ..tables import DiskListTable, StorageListTable, EndpointListTable
from ..forms import ( from ..forms import (
DataStoreForm, CephDataStoreForm, DiskForm, StorageListSearchForm, DataStoreForm, CephDataStoreForm, DiskForm, StorageListSearchForm,
EndpointForm EndpointForm, EndpointListSearchForm
) )
from .util import FilterMixin from .util import FilterMixin
import json import json
...@@ -295,7 +295,7 @@ class EndpointCreate(SuccessMessageMixin, CreateView): ...@@ -295,7 +295,7 @@ class EndpointCreate(SuccessMessageMixin, CreateView):
context.update({ context.update({
'box_title': _("Create a new endpoint"), 'box_title': _("Create a new endpoint"),
'ajax_title': True, 'ajax_title': True,
'template': "dashboard/_datastore_endpoint-create.html", 'template': "dashboard/endpoint-create.html",
}) })
return context return context
...@@ -342,4 +342,52 @@ class EndpointCreate(SuccessMessageMixin, CreateView): ...@@ -342,4 +342,52 @@ class EndpointCreate(SuccessMessageMixin, CreateView):
return error_str return error_str
def get_success_url(self): def get_success_url(self):
return reverse_lazy("dashboard.views.storage-list") return reverse_lazy("dashboard.views.storage-endpoint-list")
class EndpointList(SuperuserRequiredMixin, FilterMixin, SingleTableView):
template_name = "dashboard/endpoint-list.html"
model = Endpoint
table_class = EndpointListTable
table_pagination = False
allowed_filters = {
'name': "name__icontains",
'address': "address__icontains",
}
def get_context_data(self, *args, **kwargs):
context = super(EndpointList, self).get_context_data(*args, **kwargs)
context['search_form'] = self.search_form
return context
def get(self, *args, **kwargs):
self.search_form = EndpointListSearchForm(self.request.GET)
self.search_form.full_clean()
return super(EndpointList, self).get(*args, **kwargs)
def get_queryset(self):
logger.debug('StorageList.get_queryset() called. User: %s',
unicode(self.request.user))
qs = Endpoint.objects.all()
self.create_fake_get()
try:
filters, excludes = self.get_queryset_filters()
qs = qs.filter(**filters).exclude(**excludes).distinct()
except ValueError:
messages.error(self.request, _("Error during filtering."))
return qs
class EndpointEdit(SuperuserRequiredMixin, UpdateView):
model = Endpoint
fields = ("name", "address", "port")
template_name = "dashboard/endpoint-edit.html"
def get_success_url(self):
ds = self.get_object()
return reverse("dashboard.views.storage-endpoint-edit",
kwargs={"pk": ds.id})
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