Fetch class descendants in the dynamic_ui from glare
Before this change whenever a murano-class dependency was specified in the ui definition of a package, only packages that contained those specific fqns were fetched from API, even though the information about inheritance is available in the glare back-end. With this change dashboard also fetches all the packages, that have classes, that inherit from the specified package. This change also alters the way absence of a package is handled. It's now specified as an empty field with explanation, rather then a django message. This allows having only partial dependencies and skipping optional dependencies altogether Change-Id: I6632f72ca260c26a116b3aa4608d9592d0f1cbce Closes-Bug: #1585812
This commit is contained in:
parent
a2b39319c2
commit
2857c8f4a3
@ -54,6 +54,14 @@ def package_list(request, marker=None, filters=None, paginate=False,
|
||||
return packages, has_more_data
|
||||
|
||||
|
||||
def apps_that_inherit(request, fqn):
|
||||
glare = getattr(settings, 'MURANO_USE_GLARE', False)
|
||||
if not glare:
|
||||
return []
|
||||
apps = api.muranoclient(request).packages.filter(inherits=fqn)
|
||||
return apps
|
||||
|
||||
|
||||
def app_by_fqn(request, fqn, catalog=True):
|
||||
apps = api.muranoclient(request).packages.filter(fqn=fqn, catalog=catalog)
|
||||
try:
|
||||
|
@ -20,7 +20,7 @@ import re
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core import validators as django_validator
|
||||
from django import forms
|
||||
from django.http import Http404
|
||||
from django.forms import widgets
|
||||
from django.template import defaultfilters
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils import html
|
||||
@ -524,24 +524,37 @@ class DatabaseListField(CharField):
|
||||
self.validate_mssql_identifier(db_name)
|
||||
|
||||
|
||||
class ErrorWidget(widgets.Widget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.message = kwargs.pop(
|
||||
'message', _("There was an error initialising this field."))
|
||||
super(ErrorWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
return "<div name={name}>{message}</div>".format(
|
||||
name=name, message=self.message)
|
||||
|
||||
|
||||
class MuranoTypeWidget(hz_forms.fields.DynamicSelectWidget):
|
||||
def __init__(self, attrs=None, **kwargs):
|
||||
if attrs is None:
|
||||
attrs = {'class': 'murano_add_select'}
|
||||
else:
|
||||
attrs.setdefault('class', '')
|
||||
attrs['class'] += ' murano_add_select'
|
||||
super(MuranoTypeWidget, self).__init__(attrs=attrs, **kwargs)
|
||||
|
||||
class Media(object):
|
||||
js = ('muranodashboard/js/add-select.js',)
|
||||
|
||||
|
||||
def make_select_cls(fqns):
|
||||
if not isinstance(fqns, (tuple, list)):
|
||||
fqns = (fqns,)
|
||||
|
||||
class Widget(hz_forms.fields.DynamicSelectWidget):
|
||||
def __init__(self, attrs=None, **kwargs):
|
||||
if attrs is None:
|
||||
attrs = {'class': 'murano_add_select'}
|
||||
else:
|
||||
attrs.setdefault('class', '')
|
||||
attrs['class'] += ' murano_add_select'
|
||||
super(Widget, self).__init__(attrs=attrs, **kwargs)
|
||||
|
||||
class Media(object):
|
||||
js = ('muranodashboard/js/add-select.js',)
|
||||
|
||||
class DynamicSelect(hz_forms.DynamicChoiceField, CustomPropertiesField):
|
||||
widget = Widget
|
||||
widget = MuranoTypeWidget
|
||||
|
||||
def __init__(self, empty_value_message=None, *args, **kwargs):
|
||||
super(DynamicSelect, self).__init__(*args, **kwargs)
|
||||
@ -552,21 +565,52 @@ def make_select_cls(fqns):
|
||||
|
||||
@with_request
|
||||
def update(self, request, environment_id, **kwargs):
|
||||
matching_classes = []
|
||||
fqns_seen = set()
|
||||
# NOTE(kzaitsev): it's possible to have a private
|
||||
# and public apps with the same fqn, however the engine would
|
||||
# currently favor private package. Therefore we should squash
|
||||
# these until we devise a better way to work with this
|
||||
# situation and versioning
|
||||
|
||||
for class_fqn in fqns:
|
||||
app_found = pkg_api.app_by_fqn(request, class_fqn)
|
||||
if app_found:
|
||||
fqns_seen.add(app_found.fully_qualified_name)
|
||||
matching_classes.append(app_found)
|
||||
|
||||
apps_found = pkg_api.apps_that_inherit(request, class_fqn)
|
||||
for app in apps_found:
|
||||
if app.fully_qualified_name in fqns_seen:
|
||||
continue
|
||||
fqns_seen.add(app.fully_qualified_name)
|
||||
matching_classes.append(app)
|
||||
|
||||
if not matching_classes:
|
||||
msg = _(
|
||||
"Couldn't find any apps, required for this field.\n"
|
||||
"Tried: {fqns}").format(fqns=', '.join(fqns))
|
||||
self.widget = ErrorWidget(message=msg)
|
||||
|
||||
# NOTE(kzaitsev): this closure is needed to allow us have custom
|
||||
# logic when clicking add button
|
||||
def _make_link():
|
||||
ns_url = 'horizon:murano:catalog:add'
|
||||
ns_url_args = (environment_id, False, True)
|
||||
|
||||
def _reverse(_fqn):
|
||||
_app = pkg_api.app_by_fqn(request, _fqn)
|
||||
if _app is None:
|
||||
msg = "Application with FQN='{0}' doesn't exist"
|
||||
messages.error(request, msg.format(_fqn))
|
||||
raise Http404(msg.format(_fqn))
|
||||
args = (_app.id, environment_id, False, True)
|
||||
return _app.name, reverse(ns_url, args=args)
|
||||
return json.dumps([_reverse(cls) for cls in fqns])
|
||||
# This will prevent horizon from adding an extra '+' button
|
||||
if not matching_classes:
|
||||
return ''
|
||||
|
||||
return json.dumps([
|
||||
(app.name, reverse(ns_url, args=((app.id,) + ns_url_args)))
|
||||
for app in matching_classes])
|
||||
|
||||
self.widget.add_item_link = _make_link
|
||||
apps = env_api.service_list_by_fqns(request, environment_id, fqns)
|
||||
|
||||
apps = env_api.service_list_by_fqns(
|
||||
request, environment_id,
|
||||
[app.fully_qualified_name for app in matching_classes])
|
||||
choices = [('', self.empty_value_message)]
|
||||
choices.extend([(app['?']['id'],
|
||||
html.escape(app.name)) for app in apps])
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
fixes:
|
||||
- Specifying a base class in the ui definition now also fetches all the packages with classes
|
||||
that inherit from that class, when glare is used.
|
Loading…
Reference in New Issue
Block a user