diff options
author | Radomir Dopieralski <openstack@sheep.art.pl> | 2015-02-25 13:20:38 +0100 |
---|---|---|
committer | Jiri Tomasek <jtomasek@redhat.com> | 2015-03-03 11:18:02 +0100 |
commit | cb28034ac66f40396db8f7f5743f0f06d0092d0b (patch) | |
tree | 250be9bb42f1ba457f2dd48374a3d4054671efb9 | |
parent | 1ec94e28738cdf643368f8a5ccaff265122e4e78 (diff) | |
download | tuskar-ui-cb28034ac66f40396db8f7f5743f0f06d0092d0b.tar.gz |
Change the validation message list into checklist
Change-Id: I0205fb1e3df64a8c0d94a3f3538603e50540de92
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> |