diff --git a/horizon/templates/horizon/jasmine/jasmine.html b/horizon/templates/horizon/jasmine/jasmine.html index 77940d8311..584471d64f 100644 --- a/horizon/templates/horizon/jasmine/jasmine.html +++ b/horizon/templates/horizon/jasmine/jasmine.html @@ -8,24 +8,15 @@ window.STATIC_URL = '/static/'; window.WEBROOT = '/'; + - - - - - + {% for file in HORIZON_CONFIG.xstatic_lib_files %} + + {% endfor %} - - - - - - - - - - - - - +{% for file in HORIZON_CONFIG.xstatic_lib_files %} + +{% endfor %} {% endcompress %} diff --git a/openstack_dashboard/templates/horizon/_scripts.html b/openstack_dashboard/templates/horizon/_scripts.html index f211f80dbc..ba400aa542 100644 --- a/openstack_dashboard/templates/horizon/_scripts.html +++ b/openstack_dashboard/templates/horizon/_scripts.html @@ -11,28 +11,13 @@ {% include "horizon/_script_i18n.html" %} -{% comment %} Compress jQuery, Angular, Plugins, Bootstrap, Hogan.js and Horizon-specific JS. {% endcomment %} +{% comment %} Compress Horizon-specific JS. {% endcomment %} {% compress js %} - - - - - - - - - - - - - - - @@ -60,15 +45,10 @@ - - - - - {% for file in HORIZON_CONFIG.js_files %} diff --git a/openstack_dashboard/test/settings.py b/openstack_dashboard/test/settings.py index 40866b72ee..298703e3fe 100644 --- a/openstack_dashboard/test/settings.py +++ b/openstack_dashboard/test/settings.py @@ -16,8 +16,6 @@ from django.utils.translation import pgettext_lazy from horizon.test.settings import * # noqa from horizon.utils import secret_key from openstack_dashboard import exceptions -from openstack_dashboard.static_settings import find_static_files # noqa -from openstack_dashboard.static_settings import get_staticfiles_dirs # noqa from horizon.utils.escape import monkeypatch_escape @@ -25,7 +23,7 @@ from horizon.utils.escape import monkeypatch_escape # enabling in our test setup to find any issues it might cause monkeypatch_escape() -STATICFILES_DIRS = get_staticfiles_dirs() +from openstack_dashboard.utils import settings as settings_utils TEST_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_PATH = os.path.abspath(os.path.join(TEST_DIR, "..")) @@ -102,14 +100,19 @@ ANGULAR_FEATURES = { 'images_panel': False # Use the legacy panel so unit tests are still run } +STATICFILES_DIRS = settings_utils.get_xstatic_dirs( + settings_utils.BASE_XSTATIC_MODULES, HORIZON_CONFIG +) + # Load the pluggable dashboard settings import openstack_dashboard.enabled -from openstack_dashboard.utils import settings +import openstack_dashboard.local.enabled INSTALLED_APPS = list(INSTALLED_APPS) # Make sure it's mutable -settings.update_dashboards( +settings_utils.update_dashboards( [ openstack_dashboard.enabled, + openstack_dashboard.local.enabled ], HORIZON_CONFIG, INSTALLED_APPS, @@ -119,8 +122,8 @@ settings.update_dashboards( # the stacks MappingsTests are updated with the new URL path. HORIZON_CONFIG['swift_panel'] = 'legacy' -find_static_files(HORIZON_CONFIG, AVAILABLE_THEMES, - THEME_COLLECTION_DIR, ROOT_PATH) +settings_utils.find_static_files(HORIZON_CONFIG, AVAILABLE_THEMES, + THEME_COLLECTION_DIR, ROOT_PATH) # Set to 'legacy' or 'direct' to allow users to upload images to glance via # Horizon server. When enabled, a file form field will appear on the create diff --git a/openstack_dashboard/themes/material/static/bootstrap/_styles.scss b/openstack_dashboard/themes/material/static/bootstrap/_styles.scss index 4c1f60264d..5085450102 100644 --- a/openstack_dashboard/themes/material/static/bootstrap/_styles.scss +++ b/openstack_dashboard/themes/material/static/bootstrap/_styles.scss @@ -1,7 +1,7 @@ // Based on Paper // Bootswatch // ----------------------------------------------------- -@import "/bootstrap/scss/bootstrap/mixins/vendor-prefixes"; +@import "/horizon/lib/bootstrap_scss/scss/bootstrap/mixins/vendor-prefixes"; @import "/horizon/lib/bootswatch/paper/bootswatch"; @import "/horizon/lib/roboto_fontface/css/roboto-fontface.scss"; diff --git a/openstack_dashboard/utils/settings.py b/openstack_dashboard/utils/settings.py index b21ffd2767..a4abaec5f5 100644 --- a/openstack_dashboard/utils/settings.py +++ b/openstack_dashboard/utils/settings.py @@ -17,7 +17,8 @@ import os import pkgutil import six -from horizon.utils import file_discovery as fd +from horizon.utils import file_discovery +from openstack_dashboard import theme_settings def import_submodules(module): @@ -121,7 +122,8 @@ def update_dashboards(modules, horizon_config, installed_apps): for _app in _apps: module = import_module(_app) base_path = os.path.join(module.__path__[0], 'static/') - fd.populate_horizon_config(horizon_config, base_path) + file_discovery.populate_horizon_config(horizon_config, + base_path) add_exceptions = six.iteritems(config.get('ADD_EXCEPTIONS', {})) for category, exc_list in add_exceptions: @@ -168,3 +170,173 @@ def update_dashboards(modules, horizon_config, installed_apps): # so we save the reference to it before we append to installed_apps horizon_config.setdefault('plugins', []).extend(apps) installed_apps[0:0] = apps + + +# Order matters, list the xstatic module name and the entry point file(s) for +# that module (this is often defined as the "main" in bower.json, and +# as the xstatic module MAIN variable in the very few compliant xstatic +# modules). If the xstatic module does define a MAIN then set the files +# list to None. +# This list is to be used as the base list which is potentially added to in +# local_settings.py before being passed to get_xstatic_dirs() +BASE_XSTATIC_MODULES = [ + ('xstatic.pkg.jquery', ['jquery.js']), + ('xstatic.pkg.jquery_migrate', ['jquery-migrate.js']), + ('xstatic.pkg.angular', [ + 'angular.js', + 'angular-cookies.js', + 'angular-sanitize.js', + 'angular-route.js' + ]), + ('xstatic.pkg.angular_bootstrap', ['angular-bootstrap.js']), + ('xstatic.pkg.angular_gettext', ['angular-gettext.js']), + ('xstatic.pkg.angular_lrdragndrop', None), + ('xstatic.pkg.angular_smart_table', None), + ('xstatic.pkg.angular_fileupload', ['ng-file-upload-all.js']), + ('xstatic.pkg.d3', ['d3.js']), + ('xstatic.pkg.jquery_quicksearch', ['jquery.quicksearch.js']), + ('xstatic.pkg.jquery_tablesorter', ['jquery.tablesorter.js']), + ('xstatic.pkg.spin', ['spin.js', 'spin.jquery.js']), + ('xstatic.pkg.jquery_ui', ['jquery-ui.js']), + ('xstatic.pkg.bootstrap_scss', ['js/bootstrap.js']), + ('xstatic.pkg.bootstrap_datepicker', ['bootstrap-datepicker.js']), + ('xstatic.pkg.hogan', ['hogan.js']), + ('xstatic.pkg.rickshaw', ['rickshaw.js']), + ('xstatic.pkg.jsencrypt', ['jsencrypt.js']), + ('xstatic.pkg.objectpath', ['ObjectPath.js']), + ('xstatic.pkg.tv4', ['tv4.js']), + ('xstatic.pkg.angular_schema_form', ['schema-form.js']), + + # @imported in scss files diectly + ('xstatic.pkg.font_awesome', []), + ('xstatic.pkg.bootswatch', []), + ('xstatic.pkg.roboto_fontface', []), + ('xstatic.pkg.mdi', []), + + # testing only, not included in application + ('xstatic.pkg.jasmine', []), + ('xstatic.pkg.termjs', []), +] + + +def get_xstatic_dirs(XSTATIC_MODULES, HORIZON_CONFIG): + """Discover static file configuration of the xstatic modules. + + For each entry in the XSTATIC_MODULES list we determine the entry + point files (which may come from the xstatic MAIN var) and then + determine where in the Django static tree the xstatic package's contents + should be placed. + + For jquery.bootstrap.wizard.js the module name is None the static file is + actually a 3rd-party file but resides in the Horizon source tree and not + an xstatic package. + + The xstatic.pkg.jquery_ui package had its contents moved by packagers so + it must be handled as a special case. + """ + STATICFILES_DIRS = [] + HORIZON_CONFIG['xstatic_lib_files'] = [] + for module_name, files in XSTATIC_MODULES: + module = import_module(module_name) + if module_name == 'xstatic.pkg.jquery_ui': + # determine the correct path for jquery-ui which packagers moved + if module.VERSION.startswith('1.10.'): + # The 1.10.x versions already contain 'ui' directory. + files = ['ui/' + files[0]] + + STATICFILES_DIRS.append( + ('horizon/lib/' + module.NAME, module.BASE_DIR) + ) + + # pull the file entry points from the xstatic package MAIN if possible + if hasattr(module, 'MAIN'): + files = module.MAIN + if not isinstance(files, list): + files = [files] + + # just the Javascript files, please (don't