Service configuration read only form
This replaces current service configuration view with form view that is consistent with wireframes and editable form view which is to be implemented. Change-Id: Ic4ea20fb6c2b3dc261af30c0d23e695d546ccae8
This commit is contained in:
parent
fc4946b816
commit
1897d28726
@ -22,14 +22,15 @@ import netaddr
|
||||
SEPARATOR_RE = re.compile('[\s,;|]+', re.UNICODE)
|
||||
|
||||
|
||||
def fieldset(self, *args, **kwargs):
|
||||
def fieldset(form, *args, **kwargs):
|
||||
"""A helper function for grouping fields based on their names."""
|
||||
|
||||
prefix = kwargs.pop('prefix', None)
|
||||
names = args or self.fields.keys()
|
||||
prefix = kwargs.pop('prefix', '.*')
|
||||
names = args or form.fields.keys()
|
||||
|
||||
for name in names:
|
||||
if prefix is None or name.startswith(prefix):
|
||||
yield forms.forms.BoundField(self, self.fields[name], name)
|
||||
if prefix is not None and re.match(prefix, name):
|
||||
yield forms.forms.BoundField(form, form.fields[name], name)
|
||||
|
||||
|
||||
class MACDialect(netaddr.mac_eui48):
|
||||
@ -133,3 +134,24 @@ class LabelWidget(forms.Widget):
|
||||
if value:
|
||||
return html.escape(value)
|
||||
return ''
|
||||
|
||||
|
||||
class StaticTextWidget(forms.Widget):
|
||||
def render(self, name, value, attrs=None):
|
||||
if value is None:
|
||||
value = ''
|
||||
return html.format_html('<p class="form-control-static">{0}</p>',
|
||||
value)
|
||||
|
||||
|
||||
class StaticTextPasswordWidget(forms.Widget):
|
||||
def render(self, name, value, attrs=None):
|
||||
if value is None or value == '':
|
||||
return html.format_html(u'<p class="form-control-static"></p>')
|
||||
else:
|
||||
return html.format_html(
|
||||
u'<p class="form-control-static">'
|
||||
u'<a href="" class="btn btn-default btn-xs password-button"'
|
||||
u' data-content="{0}"><i class="fa fa-eye"></i> {1}</a>'
|
||||
u'</p>', value, _(u"Reveal")
|
||||
)
|
||||
|
@ -16,13 +16,15 @@ import json
|
||||
import logging
|
||||
|
||||
import django.forms
|
||||
from django.utils import html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon.exceptions
|
||||
import horizon.forms
|
||||
import horizon.messages
|
||||
|
||||
|
||||
from tuskar_ui import api
|
||||
import tuskar_ui.forms
|
||||
from tuskar_ui.utils import utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -44,6 +46,58 @@ CINDER_ISCSI_HELPER_CHOICES = [
|
||||
]
|
||||
|
||||
|
||||
def name_with_tooltip(parameter):
|
||||
humanized_name = utils.de_camel_case(parameter.stripped_name)
|
||||
if not parameter.description:
|
||||
return humanized_name
|
||||
return html.format_html(
|
||||
u'{0} <a class="help-icon fa fa-question-circle" '
|
||||
u'data-content="{1}" tabindex="0" href="#" '
|
||||
u'title="{2}"></a>',
|
||||
html.escape(humanized_name),
|
||||
html.escape(parameter.description),
|
||||
html.escape(humanized_name)
|
||||
)
|
||||
|
||||
|
||||
class ServiceConfig(horizon.forms.SelfHandlingForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ServiceConfig, self).__init__(*args, **kwargs)
|
||||
|
||||
plan = api.tuskar.Plan.get_the_plan(self.request)
|
||||
parameters = plan.parameter_list(include_key_parameters=False)
|
||||
|
||||
for p in parameters:
|
||||
if p.hidden:
|
||||
self.fields[p.name] = django.forms.CharField(
|
||||
required=False,
|
||||
widget=tuskar_ui.forms.StaticTextPasswordWidget(),
|
||||
label=name_with_tooltip(p))
|
||||
else:
|
||||
self.fields[p.name] = django.forms.CharField(
|
||||
required=False,
|
||||
widget=tuskar_ui.forms.StaticTextWidget(),
|
||||
label=name_with_tooltip(p))
|
||||
|
||||
def global_fieldset(self):
|
||||
return tuskar_ui.forms.fieldset(self, prefix='^(?!.*::)')
|
||||
|
||||
def controller_fieldset(self):
|
||||
return tuskar_ui.forms.fieldset(self, prefix='controller-1')
|
||||
|
||||
def compute_fieldset(self):
|
||||
return tuskar_ui.forms.fieldset(self, prefix='compute-1')
|
||||
|
||||
def block_storage_fieldset(self):
|
||||
return tuskar_ui.forms.fieldset(self, prefix='cinder-storage-1')
|
||||
|
||||
def object_storage_fieldset(self):
|
||||
return tuskar_ui.forms.fieldset(self, prefix='swift-storage-1')
|
||||
|
||||
def handle():
|
||||
pass
|
||||
|
||||
|
||||
class EditServiceConfig(horizon.forms.SelfHandlingForm):
|
||||
virt_type = django.forms.ChoiceField(
|
||||
label=_("Deployment Type"),
|
||||
|
@ -1,97 +0,0 @@
|
||||
# -*- coding: utf8 -*-
|
||||
#
|
||||
# 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.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 <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> %s</span>' % (
|
||||
escape(parameter.value),
|
||||
escape(_(u"Reveal")),
|
||||
),
|
||||
)
|
||||
return parameter.value
|
||||
|
||||
|
||||
class ParametersTable(tables.DataTable):
|
||||
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
|
||||
|
||||
class Meta:
|
||||
name = "parameters"
|
||||
verbose_name = _("Service Configuration")
|
||||
table_actions = ()
|
||||
row_actions = ()
|
||||
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")
|
@ -1,56 +1,70 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% extends "infrastructure/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
{% block title %}{% trans 'Service Configuration' %}{% endblock %}
|
||||
{% block title %}{% trans "Service Configuration" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include 'horizon/common/_items_count_domain_page_header.html' with title=_('Service Configuration') %}
|
||||
{% endblock page_header %}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<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 class="row">
|
||||
<form class="form-horizontal">
|
||||
{% include 'horizon/common/_form_errors.html' with form=form %}
|
||||
<div class="col-md-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-md-10">
|
||||
<div class="tab-content panel panel-default configuration-panel">
|
||||
<div class="tab-pane active" id="global">
|
||||
{% for field in form.global_fieldset %}
|
||||
{% include 'horizon/common/_horizontal_field.html' with field=field %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="tab-pane" id="controller">
|
||||
{% for field in form.controller_fieldset %}
|
||||
{% include 'horizon/common/_horizontal_field.html' with field=field %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="tab-pane" id="compute">
|
||||
{% for field in form.compute_fieldset %}
|
||||
{% include 'horizon/common/_horizontal_field.html' with field=field %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="tab-pane" id="block-storage">
|
||||
{% for field in form.block_storage_fieldset %}
|
||||
{% include 'horizon/common/_horizontal_field.html' with field=field %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="tab-pane" id="object-storage">
|
||||
{% for field in form.object_storage_fieldset %}
|
||||
{% include 'horizon/common/_horizontal_field.html' with field=field %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</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').click(function () {
|
||||
return false;
|
||||
}).popover({
|
||||
trigger: 'focus',
|
||||
placement: 'right'
|
||||
<script type="text/javascript">
|
||||
(window.$ || window.addHorizonLoadEvent)(function () {
|
||||
$(document).tooltip('hide'); // prevent horizon from adding tooltip
|
||||
$('a.help-icon').click(function () {
|
||||
return false;
|
||||
}).popover({
|
||||
trigger: 'focus',
|
||||
placement: 'right'
|
||||
});
|
||||
$('a.password-button').popover({
|
||||
trigger: 'click',
|
||||
placement: 'right'
|
||||
});
|
||||
});
|
||||
$('span.password-button').popover({
|
||||
trigger: 'click',
|
||||
placement: 'top'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -20,7 +20,6 @@ import horizon.tables
|
||||
|
||||
from tuskar_ui import api
|
||||
from tuskar_ui.infrastructure.parameters import forms
|
||||
from tuskar_ui.infrastructure.parameters import tables
|
||||
|
||||
|
||||
class ServiceConfigView(horizon.forms.ModalFormView):
|
||||
@ -60,42 +59,15 @@ class ServiceConfigView(horizon.forms.ModalFormView):
|
||||
'virt_type': virt_type}
|
||||
|
||||
|
||||
class IndexView(horizon.tables.MultiTableView):
|
||||
table_classes = (
|
||||
tables.GlobalParametersTable,
|
||||
tables.ControllerParametersTable,
|
||||
tables.ComputeParametersTable,
|
||||
tables.BlockStorageParametersTable,
|
||||
tables.ObjectStorageParametersTable,
|
||||
)
|
||||
class IndexView(horizon.forms.ModalFormView):
|
||||
form_class = forms.ServiceConfig
|
||||
template_name = "infrastructure/parameters/index.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.plan = api.tuskar.Plan.get_the_plan(request)
|
||||
def get_initial(self):
|
||||
self.plan = api.tuskar.Plan.get_the_plan(self.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')
|
||||
return {p.name: p.value for p in self.parameters}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(IndexView, self).get_context_data(**kwargs)
|
||||
|
@ -219,29 +219,50 @@ table.definition-list-table > thead {
|
||||
table.definition-list-table > tbody > tr > td {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
||||
ul.nav-arrow {
|
||||
padding-top: 30px;
|
||||
& > 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;
|
||||
z-index: 1000;
|
||||
position: relative;
|
||||
margin-right: -30px;
|
||||
& > a {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
&.active {
|
||||
margin-right: -31px;
|
||||
&:after {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: -12px;
|
||||
border-top: 19px solid transparent;
|
||||
border-bottom: 19px solid transparent;
|
||||
border-left: 12px solid $link-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.configuration-panel {
|
||||
min-height: 40em;
|
||||
padding: 15px 15px 15px 30px !important;
|
||||
border: none;
|
||||
border-left: 1px solid $border-color;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.password-button + div.popover {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.form-horizontal label .popover {
|
||||
min-width: 250px;
|
||||
.popover-content {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user