Fix broken dashboard tables

Due to this patch: https://review.openstack.org/#/c/246625/, Horizon
changes the table styles. This broke murano-dashboard tables.

This patch fixes the following:
1 Fix package, images, categories, environments table looks broken
2 Fix import package descriptions displayed
3 Removes unicode symbols from README to unlock py34 gate
4 Comment out the 'multi_select=false' to pass the ci test
5 Dixed broken tests

Co-Authored-By: Kirill Zaitsev <k.zaitsev@me.com>

Change-Id: I802aaa89021b5f20805a498ad2a17ba73c076bed
Closes-bug: #1552702
Closes-bug: #1550822
Closes-bug: #1554317
This commit is contained in:
zhurong 2016-03-07 02:52:38 +00:00 committed by Kirill Zaitsev
parent 5973c5ee7e
commit 94b0c092ed
18 changed files with 122 additions and 153 deletions

View File

@ -3,8 +3,8 @@ Murano
Murano Project introduces an application catalog, which allows application
developers and cloud administrators to publish various cloud-ready
applications in a browsable categorised catalog. Cloud users
— including inexperienced ones — can then use the catalog to
applications in a browsable categorised catalog. Cloud users,
including inexperienced ones, can then use the catalog to
compose reliable application environments with the push of a button.
Murano Dashboard

View File

@ -28,6 +28,7 @@ from muranodashboard.categories import tables
class CategoriesView(horizon_tables.DataTableView):
table_class = tables.CategoriesTable
template_name = 'categories/index.html'
page_title = _("Application Categories")
def has_prev_data(self, table):
return self._prev

View File

@ -323,7 +323,9 @@ class EnvironmentsTable(tables.DataTable):
table_actions = (CreateEnvironment,)
row_actions = (ShowEnvironmentServices, DeployEnvironment,
DeleteEnvironment, AbandonEnvironment)
multi_select = False
# TODO(zhurong) Due to bug/1554087 in horizon, we should temporary
# comment out this 'multi_select = False' to pass the ci test
# multi_select = False
def get_service_details_link(service):
@ -418,13 +420,14 @@ class ServicesTable(tables.DataTable):
class Meta(object):
name = 'services'
verbose_name = _('Component List')
template = 'services/_data_table.html'
no_data_message = _('No components')
status_columns = ['status']
row_class = UpdateServiceRow
table_actions = (AddApplication, DeployThisEnvironment)
row_actions = (DeleteService,)
multi_select = False
# TODO(zhurong) Due to bug/1554087 in horizon, we should temporary
# comment out this 'multi_select = False' to pass the ci test
# multi_select = False
class ShowDeploymentDetails(tables.LinkAction):
@ -458,7 +461,6 @@ class DeploymentsTable(tables.DataTable):
class Meta(object):
name = 'deployments'
verbose_name = _('Deployments')
template = 'common/_data_table.html'
row_actions = (ShowDeploymentDetails,)
@ -475,4 +477,3 @@ class EnvConfigTable(tables.DataTable):
class Meta(object):
name = 'environment_configuration'
verbose_name = _('Deployed Components')
template = 'common/_data_table.html'

View File

@ -36,6 +36,7 @@ from muranodashboard.environments import tabs as env_tabs
class IndexView(tables.DataTableView):
table_class = env_tables.EnvironmentsTable
template_name = 'environments/index.html'
page_title = _("Environments")
def get_data(self):
environments = []

View File

@ -63,6 +63,5 @@ class MarkedImagesTable(tables.DataTable):
class Meta(object):
name = 'marked_images'
verbose_name = _('Marked Images')
template = 'common/_data_table.html'
table_actions = (MarkImage, RemoveImageMetadata)
row_actions = (RemoveImageMetadata,)

View File

@ -31,6 +31,7 @@ from muranodashboard.images import tables
class MarkedImagesView(horizon_tables.DataTableView):
table_class = tables.MarkedImagesTable
template_name = 'images/index.html'
page_title = _("Marked Images")
def has_prev_data(self, table):
return self._prev

View File

@ -238,7 +238,6 @@ class PackageDefinitionsTable(tables.DataTable):
name = 'packages'
prev_pagination_param = 'marker'
verbose_name = _('Packages')
template = 'common/_data_table.html'
table_actions_menu = (ToggleEnabled,
TogglePublicEnabled)
table_actions = (PackagesFilterAction,

View File

@ -73,6 +73,7 @@ def is_app(wizard):
class PackageDefinitionsView(horizon_tables.DataTableView):
table_class = tables.PackageDefinitionsTable
template_name = 'packages/index.html'
page_title = _("Packages")
_more = False
_prev = False

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Application Categories" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Application Categories") %}
{% endblock page_header %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -1,10 +0,0 @@
{% extends 'horizon/common/_data_table.html' %}
{% load i18n %}
{% block table_caption %}
<tr class='table_caption'>
<th class='table_header' colspan='{{ columns|length }}'>
{{ table.render_table_actions }}
</th>
</tr>
{% endblock table_caption %}

View File

@ -1,4 +1,4 @@
{% extends 'common/_data_table.html' %}
{% extends 'horizon/common/_data_table.html' %}
{% load i18n %}
{% block title %}{% trans "Environments" %}{% endblock %}

View File

@ -4,10 +4,6 @@
{% load compress %}
{% block title %}{% trans "Environments" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Environments") %}
{% endblock page_header %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Marked Images" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Marked Images") %}
{% endblock page_header %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -11,9 +11,6 @@
{% endcompress %}
{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Packages") %}
{% endblock page_header %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -1,107 +1,93 @@
{% extends 'common/_data_table.html' %}
{% load i18n %}
{% load custom_filters %}
{% block title %}{% trans "Components" %}{% endblock %}
{% block table_caption %}
{% with apps=table.get_apps_list %}
{% if table.actions_allowed %}
{% comment %}
Note(efedorova): We are comparing to the string, since get_apps_list
functions returns json.dumps, which is used in js later.
So to prevent extra transformations comparing to the string is used
to check for app absence.
{% endcomment %}
{% if apps != '[]' %}
<div class="row row-header">
<div class="col-xs-5">
<h3 class="table_title extra_title table_title">
{% trans "Application&nbsp;Components" %}</h3>
</div>
<h4 class="category-title">{% trans 'App category' %}</h4>
<div class="col-xs-3">
<div class="dropdown" id="envAppsCategory">
{% with categories=table.get_categories_list %}
<button class="btn btn-default dropdown-toggle"
type="button"
data-toggle="dropdown"
data-disabled="true"
aria-expanded="false"
id="envAppsCategoryBtn">
<span id="envAppsCategoryName">{% trans "All" %}</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu scrollable-menu"
role="menu"
aria-labelledby="envAppsCategoryBtn">
<li role="presentation"><a
role="menuitem" tabindex="-1"
data-category-name="All"
href="#">{% trans "All" %}</a>
</li>
{% for category in categories %}
<li role="presentation"><a
role="menuitem" tabindex="-1"
data-category-name="{{ category.name }}"
href="#">{{ category.name }} ({{category.package_count}})</a>
</li>
{% endfor %}
</ul>
{% endwith %}
</div>
</div>
<div class="col-xs-3 filter-bar">
<div class="has-feedback" id="envAppsFilter">
<input class="form-control" value="{{ search }}"
type="text"
placeholder={% trans "Find in a selected category" %}>
<span class="fa fa-search form-control-feedback search-icon"></span>
</div>
</div>
</div>
{% else %}
<p id="no_apps_in_catalog_message" class="col-xs-12 alert alert-info ">
{% with repo_url=table.get_repo_url pkg_def_url=table.get_pkg_def_url %}
{% trans "There are no applications in the catalog. You can import apps from" %}
<a href="{{ repo_url }}" target="_blank"> {{ repo_url }}</a>.
<br><br>
{% blocktrans trimmed %}Go to
<b>
<a href={{ pkg_def_url }}>Packages</a>
</b>, click 'Import Package' and select <i>Repository</i> as <i>Package Source</i>.
{% endblocktrans %}
{% endwith %}
</p>
{% endif %}
<div class="clearfix"></div>
<p id="no_apps_found_message" class="alert alert-info">
{% trans "There are no applications matching your criteria." %}</p>
<div id="apps_carousel" class="carousel">
<input type="hidden" id="apps_carousel_contents"
value="{{ apps }}">
<div class="carousel-inner"></div>
<a class="left carousel-control" ng-non-bindable href="#apps_carousel"
data-slide="prev">
<i class="fa fa-chevron-left"></i>
</a>
<a class="right carousel-control" ng-non-bindable href="#apps_carousel"
data-slide="next">
<i class="fa fa-chevron-right"></i>
</a>
{% comment %}
Note(efedorova): We are comparing to the string, since get_apps_list
functions returns json.dumps, which is used in js later.
So to prevent extra transformations comparing to the string is used
to check for app absence.
{% endcomment %}
{% if apps != '[]' %}
<div class="col-xs-5">
<h3 class="table_title extra_title table_title">
{% trans "Application&nbsp;Components" %}</h3>
</div>
<h4 class="category-title">{% trans 'App category' %}</h4>
<div class="col-xs-3">
<div class="dropdown" id="envAppsCategory">
{% with categories=table.get_categories_list %}
<button class="btn btn-default dropdown-toggle"
type="button"
data-toggle="dropdown"
data-disabled="true"
aria-expanded="false"
id="envAppsCategoryBtn">
<span id="envAppsCategoryName">{% trans "All" %}</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu scrollable-menu"
role="menu"
aria-labelledby="envAppsCategoryBtn">
<li role="presentation"><a
role="menuitem" tabindex="-1"
data-category-name="All"
href="#">{% trans "All" %}</a>
</li>
{% for category in categories %}
<li role="presentation"><a
role="menuitem" tabindex="-1"
data-category-name="{{ category.name }}"
href="#">{{ category.name }} ({{category.package_count}})</a>
</li>
{% endfor %}
</ul>
{% endwith %}
</div>
</div>
<div class="col-xs-3 filter-bar">
<div class="has-feedback" id="envAppsFilter">
<input class="form-control" value="{{ search }}"
type="text"
placeholder={% trans "Find in a selected category" %}>
<span class="fa fa-search form-control-feedback search-icon"></span>
</div>
</div>
{% else %}
<p id="no_apps_in_catalog_message" class="col-xs-12 alert alert-info ">
{% with repo_url=table.get_repo_url pkg_def_url=table.get_pkg_def_url %}
{% trans "There are no applications in the catalog. You can import apps from" %}
<a href="{{ repo_url }}" target="_blank"> {{ repo_url }}</a>.
<br><br>
{% blocktrans trimmed %}Go to
<b>
<a href={{ pkg_def_url }}>Packages</a>
</b>, click 'Import Package' and select <i>Repository</i> as <i>Package Source</i>.
{% endblocktrans %}
{% endwith %}
</p>
{% endif %}
<div class="clearfix"></div>
<p id="no_apps_found_message" class="alert alert-info">
{% trans "There are no applications matching your criteria." %}</p>
<div id="apps_carousel" class="carousel">
<input type="hidden" id="apps_carousel_contents"
value="{{ apps }}">
<div class="carousel-inner"></div>
<a class="left carousel-control" ng-non-bindable href="#apps_carousel"
data-slide="prev">
<i class="fa fa-chevron-left"></i>
</a>
<a class="right carousel-control" ng-non-bindable href="#apps_carousel"
data-slide="next">
<i class="fa fa-chevron-right"></i>
</a>
</div>
{% endwith %}
<tr class='table_caption'>
<th class='table_header' colspan='{{ columns|length }}'>
<h3 class='table_title'>{{ table }}</h3>
{{ table.render_table_actions }}
</th>
</tr>
{% endblock table_caption %}
{% block table_body %}
@ -112,13 +98,4 @@
</h4>
</div>
{% endif %}
<tbody>
{% for row in rows %}
{{ row.render }}
{% empty %}
<tr class="{% cycle 'odd' 'even' %} empty">
<td colspan="{{ table.get_columns|length }}">{{ table.get_empty_message }}</td>
</tr>
{% endfor %}
</tbody>
{% endblock table_body %}

View File

@ -1,5 +1,13 @@
{% load i18n %}
{% block main %}
{{ table.render }}
{% endblock %}
<div class="row">
<div class="col-sm-12">
{% include "services/_data_table.html" %}
<hr>
<div id="components">
{{ table.render }}
</div>
</div>
</div>
{% endblock %}

View File

@ -275,7 +275,8 @@ class UITestCase(BaseDeps):
def edit_environment(self, old_name, new_name):
el_td = self.driver.find_element_by_css_selector(
'tr[data-display="{0}"] td:first-of-type'.format(old_name))
'tr[data-display="{0}"] '.format(old_name) +
'td[data-cell-name="name"]')
el_pencil = el_td.find_element_by_css_selector(
'button.ajax-inline-edit')
@ -287,14 +288,15 @@ class UITestCase(BaseDeps):
# fill in inline input
el_inline_input = self.driver.find_element_by_css_selector(
'tr[data-display="{0}"] '.format(old_name) +
'td:first-of-type .inline-edit-form input')
'td[data-cell-name="name"] .inline-edit-form input')
el_inline_input.clear()
el_inline_input.send_keys(new_name)
# click submit
el_submit = self.driver.find_element_by_css_selector(
'tr[data-display="{0}"] '.format(old_name) +
'td:first-of-type .inline-edit-actions button[type="submit"]')
'td[data-cell-name="name"] .inline-edit-actions' +
' button[type="submit"]')
el_submit.click()
# there is no alert message
@ -308,7 +310,7 @@ class UITestCase(BaseDeps):
def wait_for_alert_message(self):
locator = (by.By.CSS_SELECTOR, 'div.alert-success')
logger.debug("Waiting for a success message")
ui.WebDriverWait(self.driver, 2).until(
ui.WebDriverWait(self.driver, 5).until(
EC.presence_of_element_located(locator))
def wait_for_error_message(self, sec=20):

View File

@ -1057,12 +1057,13 @@ class TestSuitePackages(base.PackageTestCase):
pkg_name = self.alt_archive_name
self.fill_field(by.By.CSS_SELECTOR,
"input[name='modify-name']", pkg_name)
self.driver.find_element_by_css_selector(
"input[name=modify-is_public]"
).click()
self.driver.find_element_by_css_selector(
"input[name=modify-enabled]"
).click()
label = self.driver.find_element_by_css_selector(
"label[for=id_modify-is_public]")
label.click()
label = self.driver.find_element_by_css_selector(
"label[for=id_modify-enabled]")
label.click()
self.driver.find_element_by_xpath(c.InputSubmit).click()
self.driver.find_element_by_xpath(c.InputSubmit).click()
@ -1162,9 +1163,9 @@ class TestSuitePackages(base.PackageTestCase):
# Public = OFF; Active = ON.
public_checkbox = self.driver.find_element_by_id('id_modify-is_public')
active_checkbox = self.driver.find_element_by_id('id_modify-enabled')
if public_checkbox.is_selected() is True:
if public_checkbox.is_selected():
public_checkbox.click()
elif active_checkbox.is_selected() is False:
if not active_checkbox.is_selected():
active_checkbox.click()
self.driver.find_element_by_xpath(c.InputSubmit).click()
self.driver.find_element_by_xpath(c.InputSubmit).click()
@ -1177,7 +1178,10 @@ class TestSuitePackages(base.PackageTestCase):
c.AppPackages.format(self.archive_name))
pkg_id = package.get_attribute("data-object-id")
self.select_action_for_package(pkg_id, 'modify_package')
self.driver.find_element_by_id('id_is_public').click()
label = self.driver.find_element_by_css_selector(
"label[for=id_is_public]")
label.click()
self.driver.find_element_by_xpath(c.InputSubmit).click()
# Expecting Error
self.wait_for_error_message()