summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRadomir Dopieralski <openstack@sheep.art.pl>2015-02-25 13:20:38 +0100
committerJiri Tomasek <jtomasek@redhat.com>2015-03-03 11:18:02 +0100
commitcb28034ac66f40396db8f7f5743f0f06d0092d0b (patch)
tree250be9bb42f1ba457f2dd48374a3d4054671efb9
parent1ec94e28738cdf643368f8a5ccaff265122e4e78 (diff)
downloadtuskar-ui-cb28034ac66f40396db8f7f5743f0f06d0092d0b.tar.gz
Change the validation message list into checklist
Change-Id: I0205fb1e3df64a8c0d94a3f3538603e50540de92
-rw-r--r--tuskar_ui/infrastructure/overview/forms.py176
-rw-r--r--tuskar_ui/infrastructure/overview/tests.py32
-rw-r--r--tuskar_ui/infrastructure/overview/views.py13
-rw-r--r--tuskar_ui/infrastructure/static/infrastructure/js/tuskar.edit_plan.js1
-rw-r--r--tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_plan.html38
5 files changed, 156 insertions, 104 deletions
diff --git a/tuskar_ui/infrastructure/overview/forms.py b/tuskar_ui/infrastructure/overview/forms.py
index b69169f9..bb040611 100644
--- a/tuskar_ui/infrastructure/overview/forms.py
+++ b/tuskar_ui/infrastructure/overview/forms.py
@@ -14,7 +14,6 @@
import logging
-from django.core.urlresolvers import reverse_lazy
import django.forms
from django.utils.translation import ugettext_lazy as _
import horizon.exceptions
@@ -34,96 +33,79 @@ import tuskar_ui.infrastructure.flavors.utils as flavors_utils
MATCHING_DEPLOYMENT_MODE = flavors_utils.matching_deployment_mode()
LOG = logging.getLogger(__name__)
+MESSAGE_ICONS = {
+ 'ok': 'fa-check-square-o text-success',
+ 'pending': 'fa-square-o text-info',
+ 'error': 'fa-exclamation-circle text-danger',
+ 'warning': 'fa-exclamation-triangle text-warning',
+ None: 'fa-exclamation-triangle text-warning',
+}
def validate_plan(request, plan):
"""Validates the plan and returns a list of dicts describing the issues."""
messages = []
- try:
- controller_role = plan.get_role_by_name("controller")
- except KeyError:
+ requested_nodes = 0
+ for role in plan.role_list:
+ node_count = plan.get_role_node_count(role)
+ requested_nodes += node_count
+ available_flavors = len(api.flavor.Flavor.list(request))
+ if available_flavors == 0:
messages.append({
- 'text': _(u"No controller role."),
+ 'text': _(u"Define Flavors."),
'is_critical': True,
+ 'status': 'pending',
})
else:
- if plan.get_role_node_count(controller_role) not in (1, 3):
- messages.append({
- 'text': _(u"You should have either 1 or 3 controller nodes."),
- 'is_critical': True,
- })
- try:
- compute_role = plan.get_role_by_name("compute")
- except KeyError:
messages.append({
- 'text': _(u"No compute role."),
+ 'text': _(u"Define Flavors."),
+ 'status': 'ok',
+ })
+ available_nodes = len(api.node.Node.list(request, associated=False,
+ maintenance=False))
+ if available_nodes == 0:
+ messages.append({
+ 'text': _(u"Register Nodes."),
'is_critical': True,
+ 'status': 'pending',
+ })
+ elif requested_nodes > available_nodes:
+ messages.append({
+ 'text': _(u"Not enough registered nodes for this plan. "
+ u"You need {0} more.").format(
+ requested_nodes - available_nodes),
+ 'is_critical': True,
+ 'status': 'error',
})
else:
- if plan.get_role_node_count(compute_role) < 1:
- messages.append({
- 'text': _(u"You need at least 1 compute node."),
- 'is_critical': True,
- })
- requested_nodes = 0
+ messages.append({
+ 'text': _(u"Register Nodes."),
+ 'status': 'ok',
+ })
previous_snmp_password = None
for role in plan.role_list:
node_count = plan.get_role_node_count(role)
- if node_count and role.image(plan) is None:
- messages.append({
- 'text': _(u"Role {0} has no image.").format(role.name),
- 'is_critical': True,
- 'link_url': reverse_lazy('horizon:infrastructure:roles:index'),
- 'link_label': _(u"Associate this role with an image."),
- })
- if node_count and role.flavor(plan) is None:
- messages.append({
- 'text': _(u"Role {0} has no flavor.").format(role.name),
- 'is_critical': False,
- 'link_url': reverse_lazy('horizon:infrastructure:roles:index'),
- 'link_label': _(u"Associate this role with a flavor."),
- })
- requested_nodes += node_count
snmp_password = plan.parameter_value(
role.parameter_prefix + 'SnmpdReadonlyUserPassword')
- if (not snmp_password or
+ if node_count and (
+ role.image(plan) is None or
+ role.flavor(plan) is None or
+ (not snmp_password or
previous_snmp_password and
- previous_snmp_password != snmp_password):
+ previous_snmp_password != snmp_password)
+ ):
messages.append({
- 'text': _(
- u"Set your SNMP password for role {0}.").format(role.name),
+ 'text': _(u"Configure Roles."),
'is_critical': True,
- 'link_url': reverse_lazy(
- 'horizon:infrastructure:parameters:index'),
- 'link_label': _(u"Configure."),
+ 'status': 'pending',
})
+ break
previous_snmp_password = snmp_password
- available_flavors = len(api.flavor.Flavor.list(request))
- if available_flavors == 0:
+ else:
messages.append({
- 'text': _(u"You have no flavors defined."),
- 'is_critical': True,
- 'link_url': reverse_lazy('horizon:infrastructure:flavors:index'),
- 'link_label': _(u"Define flavors."),
+ 'text': _(u"Configure Roles."),
+ 'status': 'ok',
})
- available_nodes = len(api.node.Node.list(request, associated=False,
- maintenance=False))
- if available_nodes == 0:
- messages.append({
- 'text': _(u"You have no nodes available."),
- 'is_critical': True,
- 'link_url': reverse_lazy('horizon:infrastructure:nodes:index'),
- 'link_label': _(u"Register nodes."),
- })
- elif requested_nodes > available_nodes:
- messages.append({
- 'text': _(u"Not enough registered nodes for this plan. "
- u"You need {0} more.").format(
- requested_nodes - available_nodes),
- 'is_critical': True,
- 'link_url': reverse_lazy('horizon:infrastructure:nodes:index'),
- 'link_label': _(u"Register more nodes."),
- })
if not MATCHING_DEPLOYMENT_MODE:
# All roles have to have the same flavor.
default_flavor_name = api.flavor.Flavor.list(request)[0].name
@@ -134,7 +116,69 @@ def validate_plan(request, plan):
role.name,
),
'is_critical': False,
+ 'statis': 'error',
})
+ roles_assigned = True
+ messages.append({
+ 'text': _(u"Assign roles."),
+ 'status': lambda: 'ok' if roles_assigned else 'pending',
+ })
+ try:
+ controller_role = plan.get_role_by_name("controller")
+ except KeyError:
+ messages.append({
+ 'text': _(u"Controller Role Needed."),
+ 'is_critical': True,
+ 'status': 'error',
+ 'indent': 1,
+ })
+ roles_assigned = False
+ else:
+ if plan.get_role_node_count(controller_role) not in (1, 3):
+ messages.append({
+ 'text': _(u"1 or 3 Controllers Needed."),
+ 'is_critical': True,
+ 'status': 'pending',
+ 'indent': 1,
+ })
+ roles_assigned = False
+ else:
+ messages.append({
+ 'text': _(u"1 or 3 Controllers Needed."),
+ 'status': 'ok',
+ 'indent': 1,
+ })
+
+ try:
+ compute_role = plan.get_role_by_name("compute")
+ except KeyError:
+ messages.append({
+ 'text': _(u"Compute Role Needed."),
+ 'is_critical': True,
+ 'status': 'error',
+ 'indent': 1,
+ })
+ roles_assigned = False
+ else:
+ if plan.get_role_node_count(compute_role) < 1:
+ messages.append({
+ 'text': _(u"1 Compute Needed."),
+ 'is_critical': True,
+ 'status': 'pending',
+ 'indent': 1,
+ })
+ roles_assigned = False
+ else:
+ messages.append({
+ 'text': _(u"1 Compute Needed."),
+ 'status': 'ok',
+ 'indent': 1,
+ })
+ for message in messages:
+ status = message.get('status')
+ if callable(status):
+ message['status'] = status = status()
+ message['classes'] = MESSAGE_ICONS.get(status, MESSAGE_ICONS[None])
return messages
diff --git a/tuskar_ui/infrastructure/overview/tests.py b/tuskar_ui/infrastructure/overview/tests.py
index ace9122d..729a2eda 100644
--- a/tuskar_ui/infrastructure/overview/tests.py
+++ b/tuskar_ui/infrastructure/overview/tests.py
@@ -342,22 +342,38 @@ class OverviewTests(test.BaseAdminViewTests):
patch('tuskar_ui.api.flavor.Flavor.list', return_value=[])
):
ret = forms.validate_plan(None, plan)
+ for m in ret:
+ m['text'] = unicode(m['text'])
self.assertEqual(ret, [
{
'is_critical': True,
- 'text': u'No controller role.',
+ 'text': u'Define Flavors.',
+ 'status': 'pending',
+ 'classes': 'fa-square-o text-info',
}, {
'is_critical': True,
- 'text': u'No compute role.',
+ 'text': u'Register Nodes.',
+ 'status': 'pending',
+ 'classes': 'fa-square-o text-info',
+ }, {
+ 'status': 'ok',
+ 'text': u'Configure Roles.',
+ 'classes': 'fa-check-square-o text-success',
+ }, {
+ 'status': 'pending',
+ 'text': u'Assign roles.',
+ 'classes': 'fa-square-o text-info',
}, {
'is_critical': True,
- 'link_label': u'Define flavors.',
- 'link_url': '/infrastructure/flavors/',
- 'text': u'You have no flavors defined.',
+ 'text': u'Controller Role Needed.',
+ 'status': 'error',
+ 'indent': 1,
+ 'classes': 'fa-exclamation-circle text-danger',
}, {
'is_critical': True,
- 'link_label': u'Register nodes.',
- 'link_url': '/infrastructure/nodes/',
- 'text': u'You have no nodes available.',
+ 'text': u'Compute Role Needed.',
+ 'status': 'error',
+ 'indent': 1,
+ 'classes': 'fa-exclamation-circle text-danger',
},
])
diff --git a/tuskar_ui/infrastructure/overview/views.py b/tuskar_ui/infrastructure/overview/views.py
index 6a3ed38a..6cc09546 100644
--- a/tuskar_ui/infrastructure/overview/views.py
+++ b/tuskar_ui/infrastructure/overview/views.py
@@ -30,6 +30,12 @@ from tuskar_ui.infrastructure import views
INDEX_URL = 'horizon:infrastructure:overview:index'
+def _steps_message(messages):
+ total_steps = len(messages)
+ completed_steps = len([m for m in messages if not m.get('is_critical')])
+ return _("{0} of {1} Steps Completed").format(completed_steps, total_steps)
+
+
def _get_role_data(plan, stack, form, role):
"""Gathers data about a single deployment role.
@@ -217,6 +223,7 @@ class IndexView(horizon.forms.ModalFormView, views.StackMixin):
context['plan_messages'] = messages
context['plan_invalid'] = any(message.get('is_critical')
for message in messages)
+ context['steps_message'] = _steps_message(messages)
return context
def post(self, request, *args, **kwargs):
@@ -243,15 +250,15 @@ class IndexView(horizon.forms.ModalFormView, views.StackMixin):
messages.extend({
'text': repr(error),
} for field in form.fields for error in field.errors)
-
# We need to unlazify all the lazy urls and translations.
return http.HttpResponse(json.dumps({
'plan_invalid': any(m.get('is_critical') for m in messages),
+ 'steps_message': _steps_message(messages),
'messages': [{
'text': unicode(m.get('text', '')),
'is_critical': m.get('is_critical', False),
- 'link_url': unicode(m.get('link_url', '')),
- 'link_label': unicode(m.get('link_label', '')),
+ 'indent': m.get('indent', 0),
+ 'classes': m['classes'],
} for m in messages],
}), mimetype='application/json')
diff --git a/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.edit_plan.js b/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.edit_plan.js
index 1c832adb..96ab5459 100644
--- a/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.edit_plan.js
+++ b/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.edit_plan.js
@@ -66,6 +66,7 @@ tuskar.edit_plan = (function () {
module.title_template.render(data));
$('div.deployment-box ul').replaceWith(
module.message_template.render(data));
+ $('div.deployment-box a#collapse-steps').text(data.steps_message);
};
horizon.addInitFunction(module.init);
diff --git a/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_plan.html b/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_plan.html
index 6bad88f9..d1cd7c81 100644
--- a/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_plan.html
+++ b/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_plan.html
@@ -9,24 +9,16 @@
{% endblock %}
{% block deployment-title %}
-{% if plan_invalid %}
- {% trans "Design your deployment" %}
-{% else %}
- {% trans "Ready to get deployed" %}
-{% endif %}
+ {% trans "Deployment Checklist" %}
{% endblock %}
{% block deployment-info %}
-<ul class="fa-ul">
+<a data-toggle="collapse" href="#messages" aria-expanded="false" aria-controls="messages" id="collapse-steps">{{ steps_message }}</a>
+<ul class="fa-ul collapse" id="messages">
{% for message in plan_messages %}
- <li>
- <i class="fa-li fa {% if message.is_critical %}fa-exclamation-circle text-danger{% else %}fa-exclamation-triangle text-warning{% endif %}"></i>
+ <li style="margin-left:{{ message.indent|default:0 }}em">
+ <i class="fa-li fa {{ message.classes }}" ></i>
{{ message.text }}
- {% if message.link_url %}
- (<a href="{{ message.link_url }}">
- {{ message.link_label|default:message.link_url }}
- </a>)
- {% endif %}
</li>
{% endfor %}
</ul>
@@ -42,24 +34,16 @@ class="btn btn-primary ajax-modal btn-default {% if plan_invalid %}disabled{% en
{% block templates %}
<script type="text/html" id="title-template">{% spaceless %}{% jstemplate %}
<h4>
-[[#validating]]{% trans "Validating the plan..." %}[[/validating]]
-[[^validating]]
- [[#plan_invalid]]{% trans "Design your deployment" %}[[/plan_invalid]]
- [[^plan_invalid]]{% trans "Ready to get deployed" %}[[/plan_invalid]]
-[[/validating]]
+[[#validating]]{% trans "Validating the Plan..." %}[[/validating]]
+[[^validating]]{% trans "Deployment Checklist" %}[[/validating]]
</h4>
{% endjstemplate %}{% endspaceless %}</script>
<script type="text/html" id="message-template">{% spaceless %}{% jstemplate %}
-<ul class="fa-ul">
-[[#messages ]]
- <li><i class="fa-li fa
- [[#is_critical]]fa-exclamation-circle text-danger[[/is_critical]]
- [[^is_critical]]fa-exclamation-triangle text-warning[[/is_critical]]
- "></i>
+<ul class="fa-ul collapse" id="messages">
+[[#messages]]
+ <li style="margin-left: [[indent]]em">
+ <i class="fa-li fa [[classes]]"></i>
[[text]]
- [[#link_label]]
- (<a href="[[link_url]]">[[link_label]]</a>)
- [[/link_label]]
</li>
[[/messages]]
</ul>