No need to restart Web-server now to see changes in dynamic UI.
Workflow is simpler now: edit form definition YAML-file, save it,
reload the form it affects. Voila!
Implements: feature MRN-1147
Cherry-picked from dc78dc3b68
Change-Id: I72d68c17b829f9252560ecd01335656ffba0b262
This commit is contained in:
parent
98f506d0f4
commit
d9ee18a6d6
|
@ -20,7 +20,6 @@ from horizon import messages, exceptions
|
|||
from openstack_dashboard.api import glance
|
||||
import json
|
||||
|
||||
from muranodashboard.panel.services import iterate_over_service_forms
|
||||
from muranodashboard.panel.services import get_service_choices
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -31,10 +30,6 @@ class WizardFormServiceType(forms.Form):
|
|||
choices=get_service_choices())
|
||||
|
||||
|
||||
FORMS = [('service_choice', WizardFormServiceType)]
|
||||
FORMS.extend(iterate_over_service_forms())
|
||||
|
||||
|
||||
class MarkImageForm(SelfHandlingForm):
|
||||
_metadata = {
|
||||
'windows.2012': ' Windows Server 2012',
|
||||
|
|
|
@ -21,6 +21,7 @@ from ordereddict import OrderedDict
|
|||
import yaml
|
||||
from yaml.scanner import ScannerError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import copy
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
_all_services = OrderedDict()
|
||||
|
@ -65,12 +66,20 @@ def import_all_services():
|
|||
directory = getattr(settings, 'MURANO_SERVICES_DESC_PATH', None)
|
||||
if directory is None:
|
||||
directory = os.path.join(os.path.dirname(__file__), '../../services/')
|
||||
log.debug("Importing service definitions from '{0}'".format(directory))
|
||||
file_list = [f for f in os.listdir(directory) if f.endswith('.yaml')]
|
||||
|
||||
for filename in os.listdir(directory):
|
||||
if not filename.endswith('.yaml'):
|
||||
continue
|
||||
log.debug("Removing non-existing service definitions from cache")
|
||||
# TODO: this has O(n^2) complexity, should fix it if there are many defs
|
||||
for filename in _all_services.keys():
|
||||
try:
|
||||
file_list.index(filename)
|
||||
except ValueError:
|
||||
del _all_services[filename]
|
||||
log.info("Removed service '{0}' from cache".format(filename))
|
||||
|
||||
log.debug("Updating service definitions cache from '{0}'".format(
|
||||
directory))
|
||||
for filename in file_list:
|
||||
service_file = os.path.join(directory, filename)
|
||||
modified_on = os.path.getmtime(service_file)
|
||||
|
||||
|
@ -100,10 +109,14 @@ def iterate_over_services():
|
|||
yield service.type, service, service.forms
|
||||
|
||||
|
||||
def iterate_over_service_forms():
|
||||
for srv_type, service, forms in iterate_over_services():
|
||||
for step, form in enumerate(forms):
|
||||
yield '{0}-{1}'.format(srv_type, step), form
|
||||
def make_forms_getter(initial_forms=[]):
|
||||
def _get_forms():
|
||||
_forms = copy.copy(initial_forms)
|
||||
for srv_type, service, forms in iterate_over_services():
|
||||
for step, form in enumerate(forms):
|
||||
_forms.append(('{0}-{1}'.format(srv_type, step), form))
|
||||
return _forms
|
||||
return _get_forms
|
||||
|
||||
|
||||
def service_type_from_id(service_id):
|
||||
|
@ -150,6 +163,9 @@ def get_service_choices():
|
|||
iterate_over_services()]
|
||||
|
||||
|
||||
get_forms = make_forms_getter()
|
||||
|
||||
|
||||
def get_service_checkers():
|
||||
import_all_services()
|
||||
|
||||
|
@ -159,7 +175,7 @@ def get_service_checkers():
|
|||
return compare
|
||||
|
||||
return [(srv_id, make_comparator(srv_id)) for srv_id, form
|
||||
in iterate_over_service_forms()]
|
||||
in get_forms()]
|
||||
|
||||
|
||||
def get_service_descriptions():
|
||||
|
|
|
@ -21,8 +21,9 @@ from views import DetailServiceView
|
|||
from views import DeploymentsView
|
||||
from views import MarkedImagesView, MarkImageView
|
||||
from views import Wizard, EditEnvironmentView
|
||||
from forms import FORMS
|
||||
from muranodashboard.panel.services import get_service_checkers
|
||||
from forms import WizardFormServiceType
|
||||
from services import get_service_checkers
|
||||
from services import make_forms_getter
|
||||
from openstack_dashboard.dashboards.project.instances.views import DetailView
|
||||
|
||||
VIEW_MOD = 'openstack_dashboard.dashboards.project.murano.views'
|
||||
|
@ -33,8 +34,9 @@ urlpatterns = patterns(
|
|||
url(r'^environments$', IndexView.as_view(), name='index'),
|
||||
|
||||
url(r'^create/$',
|
||||
Wizard.as_view(FORMS,
|
||||
condition_dict=dict(get_service_checkers())),
|
||||
Wizard.as_view(make_forms_getter(
|
||||
initial_forms=[('service_choice', WizardFormServiceType)]),
|
||||
condition_dict=get_service_checkers),
|
||||
name='create'),
|
||||
|
||||
url(r'^create_environment$', CreateEnvironmentView.as_view(),
|
||||
|
|
|
@ -15,14 +15,13 @@
|
|||
import logging
|
||||
import re
|
||||
import json
|
||||
import copy
|
||||
|
||||
from django.core.urlresolvers import reverse, reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import smart_text
|
||||
from django.contrib.formtools.wizard.views import SessionWizardView
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
|
||||
from openstack_dashboard.api import glance
|
||||
|
||||
from horizon import exceptions
|
||||
|
@ -41,16 +40,62 @@ from workflows import CreateEnvironment, UpdateEnvironment
|
|||
from tabs import ServicesTabs, DeploymentTabs
|
||||
from forms import MarkImageForm
|
||||
|
||||
from muranodashboard.panel import api
|
||||
import api
|
||||
from muranoclient.common.exceptions import HTTPUnauthorized, \
|
||||
CommunicationError, HTTPInternalServerError, HTTPForbidden, HTTPNotFound
|
||||
from functools import update_wrapper
|
||||
from django.utils.decorators import classonlymethod
|
||||
from services import get_service_descriptions
|
||||
from services import get_service_name
|
||||
from services import get_service_field_descriptions
|
||||
|
||||
from muranodashboard.panel.services import get_service_descriptions, \
|
||||
get_service_name, get_service_field_descriptions
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Wizard(ModalFormMixin, SessionWizardView):
|
||||
class LazyWizard(SessionWizardView):
|
||||
"""The class which defers evaluation of form_list and condition_dict
|
||||
until view method is called. So, each time we load a page with a dynamic
|
||||
UI form, it will have markup/logic from the newest YAML-file definition.
|
||||
"""
|
||||
@classonlymethod
|
||||
def as_view(cls, initforms, *initargs, **initkwargs):
|
||||
"""
|
||||
Main entry point for a request-response process.
|
||||
"""
|
||||
# sanitize keyword arguments
|
||||
for key in initkwargs:
|
||||
if key in cls.http_method_names:
|
||||
raise TypeError(u"You tried to pass in the %s method name as a"
|
||||
u" keyword argument to %s(). Don't do that."
|
||||
% (key, cls.__name__))
|
||||
if not hasattr(cls, key):
|
||||
raise TypeError(u"%s() received an invalid keyword %r" % (
|
||||
cls.__name__, key))
|
||||
|
||||
def view(request, *args, **kwargs):
|
||||
forms = initforms
|
||||
if hasattr(initforms, '__call__'):
|
||||
forms = initforms()
|
||||
condition_dict = initkwargs.get('condition_dict', False)
|
||||
_kwargs = copy.copy(initkwargs)
|
||||
if condition_dict and hasattr(condition_dict, '__call__'):
|
||||
_kwargs.update({'condition_dict': dict(condition_dict())})
|
||||
_kwargs = cls.get_initkwargs(forms, *initargs, **_kwargs)
|
||||
self = cls(**_kwargs)
|
||||
if hasattr(self, 'get') and not hasattr(self, 'head'):
|
||||
self.head = self.get
|
||||
return self.dispatch(request, *args, **kwargs)
|
||||
|
||||
# take name and docstring from class
|
||||
update_wrapper(view, cls, updated=())
|
||||
|
||||
# and possible attributes set by decorators
|
||||
# like csrf_exempt from dispatch
|
||||
update_wrapper(view, cls.dispatch, assigned=())
|
||||
return view
|
||||
|
||||
|
||||
class Wizard(ModalFormMixin, LazyWizard):
|
||||
template_name = 'services/wizard_create.html'
|
||||
|
||||
def done(self, form_list, **kwargs):
|
||||
|
|
Loading…
Reference in New Issue