Restyle the service configuration

* Roll it back into a single page
* Style the table like it's not a table
* Have several tables on a single page
* With vertical tabs
* With arrow-like selected tab
* Hide passwords

Change-Id: Idead718e40f9b5efa5a37a6f87604a3f498577fc
This commit is contained in:
Radomir Dopieralski
2014-10-29 13:35:18 +01:00
parent d7410126fd
commit 4a1b94e24f
6 changed files with 192 additions and 76 deletions

View File

@@ -11,18 +11,50 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django.utils.html import escape # noqa
from django.utils.safestring import mark_safe # noqa
from django.utils.translation import ugettext_lazy as _
from horizon import tables
def name_with_tooltip(parameter):
if not parameter.description:
return parameter.stripped_name
return mark_safe(
u'%s&nbsp;<a class="help-icon fa fa-question-circle" '
u'data-content="%s" tabindex="0" href="#" '
u'title="%s"></a>' % (
escape(parameter.stripped_name),
escape(parameter.description),
escape(parameter.stripped_name),
),
)
def value_or_hidden(parameter):
if parameter.hidden:
return mark_safe(
u'<span class="btn btn-xs btn-default password-button" '
u'data-content="%s"'
u'><i class="fa fa-eye"></i>&nbsp;%s</span>' % (
escape(parameter.value),
escape(_(u"Reveal")),
),
)
return parameter.value
class ParametersTable(tables.DataTable):
name = tables.Column('stripped_name',
verbose_name=_("Parameter Name"))
value = tables.Column('value',
verbose_name=_("Value"))
description = tables.Column('description',
verbose_name=_("Detailed Description"))
name = tables.Column(
name_with_tooltip,
verbose_name=_("Parameter Name"),
classes=['data-table-config-label'],
)
value = tables.Column(
value_or_hidden,
verbose_name=_("Value"),
classes=['data-table-config-value'],
)
def get_object_id(self, datum):
return datum.name
@@ -32,4 +64,34 @@ class ParametersTable(tables.DataTable):
verbose_name = _("Service Configuration")
table_actions = ()
row_actions = ()
template = "horizon/common/_enhanced_data_table.html"
template = "horizon/common/_definition_list_data_table.html"
class GlobalParametersTable(ParametersTable):
class Meta(ParametersTable.Meta):
name = "global_parameters"
verbose_name = _("Global")
class ControllerParametersTable(ParametersTable):
class Meta(ParametersTable.Meta):
name = "controller_parameters"
verbose_name = _("Controller")
class ComputeParametersTable(ParametersTable):
class Meta(ParametersTable.Meta):
name = "compute_parameters"
verbose_name = _("Compute")
class BlockStorageParametersTable(ParametersTable):
class Meta(ParametersTable.Meta):
name = "block_storage_parameters"
verbose_name = _("Block Storage")
class ObjectStorageParametersTable(ParametersTable):
class Meta(ParametersTable.Meta):
name = "object_storage_parameters"
verbose_name = _("Object Storage")

View File

@@ -1,62 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_lazy as _
from horizon import tabs
from tuskar_ui import api
from tuskar_ui.infrastructure.parameters import tables
class ParametersTab(tabs.TableTab):
table_classes = (tables.ParametersTable,)
template_name = "horizon/common/_detail_table.html"
def __init__(self, group, request, name, slug, parameters):
self.name = name
self.slug = slug
self.parameters = parameters
super(ParametersTab, self).__init__(group, request)
def get_parameters_data(self):
return self.parameters
class ParametersTabs(tabs.TabGroup):
slug = "parameters"
tabs = ()
sticky = True
template_name = "horizon/common/_items_count_tab_group.html"
def __init__(self, request, **kwargs):
super(ParametersTabs, self).__init__(request, **kwargs)
plan = api.tuskar.Plan.get_the_plan(request)
params = plan.parameter_list(include_key_parameters=False)
tab_instances = []
general_params = [p for p in params if p.role is None]
if general_params:
tab_instances.append((
'global',
ParametersTab(self, request,
_('Global'), 'global', general_params),
))
for role in plan.role_list:
role_params = [p for p in params
if p.role and p.role.uuid == role.uuid]
if role_params:
tab_instances.append((
role.name,
ParametersTab(self, request,
role.name.title(), role.name, role_params),
))
self._tabs = SortedDict(tab_instances)

View File

@@ -9,9 +9,46 @@
{% block main %}
<div class="row">
<div class="col-xs-12">
{{ tab_group.render }}
<div class="col-xs-2">
<ul class="nav nav-pills nav-stacked nav-arrow" role="tablist">
<li class="active"><a href="#global" role="tab" data-toggle="tab">{% trans "Global" %}</a></li>
<li><a href="#controller" role="tab" data-toggle="tab">{% trans "Controller" %}</a></li>
<li><a href="#compute" role="tab" data-toggle="tab">{% trans "Compute" %}</a></li>
<li><a href="#block-storage" role="tab" data-toggle="tab">{% trans "Block Storage" %}</a></li>
<li><a href="#object-storage" role="tab" data-toggle="tab">{% trans "Object Storage" %}</a></li>
</ul>
</div>
<div class="col-xs-10">
<div class="tab-content panel panel-default configuration-panel">
<div class="tab-pane active" id="global">
{{ global_parameters_table.render }}
</div>
<div class="tab-pane" id="controller">
{{ controller_parameters_table.render }}
</div>
<div class="tab-pane" id="compute">
{{ compute_parameters_table.render }}
</div>
<div class="tab-pane" id="block-storage">
{{ block_storage_parameters_table.render }}
</div>
<div class="tab-pane" id="object-storage">
{{ object_storage_parameters_table.render }}
</div>
</div>
</div>
</div>
<script type="text/javascript">
(window.$ || window.addHorizonLoadEvent)(function () {
$('a.help-icon').popover({
trigger: 'focus',
placement: 'right'
});
$('span.password-button').popover({
trigger: 'click',
placement: 'top'
});
});
</script>
{% endblock %}

View File

@@ -16,11 +16,11 @@ from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
import horizon.forms
from horizon import tabs as horizon_tabs
import horizon.tables
from tuskar_ui import api
from tuskar_ui.infrastructure.parameters import forms
from tuskar_ui.infrastructure.parameters import tabs
from tuskar_ui.infrastructure.parameters import tables
class ServiceConfigView(horizon.forms.ModalFormView):
@@ -60,10 +60,43 @@ class ServiceConfigView(horizon.forms.ModalFormView):
'virt_type': virt_type}
class IndexView(horizon_tabs.TabbedTableView):
tab_group_class = tabs.ParametersTabs
class IndexView(horizon.tables.MultiTableView):
table_classes = (
tables.GlobalParametersTable,
tables.ControllerParametersTable,
tables.ComputeParametersTable,
tables.BlockStorageParametersTable,
tables.ObjectStorageParametersTable,
)
template_name = "infrastructure/parameters/index.html"
def get(self, request, *args, **kwargs):
self.plan = api.tuskar.Plan.get_the_plan(request)
self.parameters = self.plan.parameter_list(
include_key_parameters=False)
return super(IndexView, self).get(request, *args, **kwargs)
def _get_parameters(self, role_name=None):
if not role_name:
return [p for p in self.parameters if p.role is None]
return [p for p in self.parameters
if p.role and p.role.name == role_name]
def get_global_parameters_data(self):
return self._get_parameters(None)
def get_controller_parameters_data(self):
return self._get_parameters('controller')
def get_compute_parameters_data(self):
return self._get_parameters('compute')
def get_block_storage_parameters_data(self):
return self._get_parameters('cinder-storage')
def get_object_storage_parameters_data(self):
return self._get_parameters('swift-storage')
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
edit_action = {

View File

@@ -194,3 +194,44 @@ $link-color: #428bca;
#suggested-flavors-header {
margin-bottom: 0px;
}
/* Configuration parameters */
table .data-table-config-label {
width: 20em;
vertical-align: top;
}
table .data-table-config-value {
font-weight: bold;
}
table.definition-list-table > thead {
display: none;
}
table.definition-list-table > tbody > tr > td {
border: 0;
}
ul.nav-arrow {
& > li {
z-index: 1000;
position: relative;
margin-right: -32px;
}
& > li.active:after {
display: block;
content: '';
position: absolute;
top: 1px;
right: -7px;
border-top: 18px solid transparent;
border-bottom: 18px solid transparent;
border-left: 8px solid $link-color;
}
}
.configuration-panel {
min-height: 40em;
}
.password-button + div.popover {
white-space: pre-wrap;
word-wrap: break-word;
}

View File

@@ -0,0 +1,5 @@
{% extends "horizon/common/_enhanced_data_table.html" %}
{% block table_css_classes %}table table-condensed definition-list-table {{ table.css_classes }}{% endblock %}
{% block table_footer %}{% endblock %}