Fix bug where WEBROOT is not respected
The WEB_ROOT setting needs to be respected rather than assuming / as the root of the application. Simiarly, we can not assume that STATIC_URL is a sub url of the WEB_ROOT. They can be configured as two indepedent url. Angular templates are loaded dynamically with Ajax, which requires an absolute base path. We define those base paths as angular constants for template use and future routing. TO TEST, follow directions at: http://docs.openstack.org/developer/horizon/topics/settings.html#webroot Co-Authored-By: Matt Borland <matt.borland@hp.com> Co-Authored-By: Shaoquan Chen <sean.chen2@hp.com> Co-Authored-By: Thai Tran <tqtran@us.ibm.com> Change-Id: Ifcd459633682edc94b270019ce77e17d64bea22d Closes-Bug: #1451681
This commit is contained in:
parent
ede7402604
commit
35e47358f0
@ -7,16 +7,20 @@
|
||||
'horizon.framework.util',
|
||||
'horizon.framework.widgets'
|
||||
])
|
||||
.constant('horizon.framework.basePath', '/static/framework/')
|
||||
.config(frameworkConfiguration);
|
||||
.config(config);
|
||||
|
||||
frameworkConfiguration.$inject = [
|
||||
config.$inject = [
|
||||
'$provide',
|
||||
'$interpolateProvider',
|
||||
'$httpProvider',
|
||||
'$windowProvider'
|
||||
];
|
||||
|
||||
function frameworkConfiguration($interpolateProvider, $httpProvider, $windowProvider) {
|
||||
function config($provide, $interpolateProvider, $httpProvider, $windowProvider) {
|
||||
|
||||
var path = $windowProvider.$get().STATIC_URL + 'framework/';
|
||||
$provide.constant('horizon.framework.basePath', path);
|
||||
|
||||
// Replacing the default angular symbol
|
||||
// allow us to mix angular with django templates
|
||||
$interpolateProvider.startSymbol('{$');
|
||||
|
@ -21,11 +21,17 @@ limitations under the License.
|
||||
.module('horizon.framework.util.http', [])
|
||||
.service('horizon.framework.util.http.service', ApiService);
|
||||
|
||||
ApiService.$inject = ['$http'];
|
||||
ApiService.$inject = ['$http', '$window'];
|
||||
|
||||
function ApiService($http) {
|
||||
function ApiService($http, $window) {
|
||||
|
||||
var httpCall = function (method, url, data, config) {
|
||||
/* eslint-disable angular/ng_window_service */
|
||||
url = $window.WEBROOT + url;
|
||||
/* eslint-enable angular/ng_window_service */
|
||||
|
||||
url = url.replace(/\/+/g, '/');
|
||||
|
||||
if (angular.isUndefined(config)) {
|
||||
config = {};
|
||||
}
|
||||
|
@ -1,14 +1,21 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('horizon.framework.util', [
|
||||
'horizon.framework.util.bind-scope',
|
||||
'horizon.framework.util.filters',
|
||||
'horizon.framework.util.http',
|
||||
'horizon.framework.util.i18n',
|
||||
'horizon.framework.util.tech-debt',
|
||||
'horizon.framework.util.workflow',
|
||||
'horizon.framework.util.validators'
|
||||
])
|
||||
.constant('horizon.framework.util.basePath', '/static/framework/util/');
|
||||
angular
|
||||
.module('horizon.framework.util', [
|
||||
'horizon.framework.util.bind-scope',
|
||||
'horizon.framework.util.filters',
|
||||
'horizon.framework.util.http',
|
||||
'horizon.framework.util.i18n',
|
||||
'horizon.framework.util.tech-debt',
|
||||
'horizon.framework.util.workflow',
|
||||
'horizon.framework.util.validators'
|
||||
])
|
||||
.config(config);
|
||||
|
||||
function config($provide, $windowProvider) {
|
||||
var path = $windowProvider.$get().STATIC_URL + 'framework/util/';
|
||||
$provide.constant('horizon.framework.util.basePath', path);
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -79,11 +79,14 @@
|
||||
}
|
||||
];
|
||||
|
||||
var markup = '<magic-search ' +
|
||||
'template="/static/framework/widgets/magic-search/magic-search.html" ' +
|
||||
'strings="filterStrings" ' +
|
||||
'facets="{{ filterFacets }}">' +
|
||||
'</magic-search>';
|
||||
/* eslint-disable angular/ng_window_service */
|
||||
var markup =
|
||||
'<magic-search ' +
|
||||
'template="' + window.STATIC_URL + 'framework/widgets/magic-search/magic-search.html" ' +
|
||||
'strings="filterStrings" ' +
|
||||
'facets="{{ filterFacets }}">' +
|
||||
'</magic-search>';
|
||||
/* eslint-enable angular/ng_window_service */
|
||||
|
||||
$element = $compile(angular.element(markup))($scope);
|
||||
|
||||
|
@ -1,19 +1,25 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('horizon.framework.widgets', [
|
||||
'horizon.framework.widgets.help-panel',
|
||||
'horizon.framework.widgets.wizard',
|
||||
'horizon.framework.widgets.table',
|
||||
'horizon.framework.widgets.modal',
|
||||
'horizon.framework.widgets.modal-wait-spinner',
|
||||
'horizon.framework.widgets.transfer-table',
|
||||
'horizon.framework.widgets.charts',
|
||||
'horizon.framework.widgets.action-list',
|
||||
'horizon.framework.widgets.metadata-tree',
|
||||
'horizon.framework.widgets.metadata-display',
|
||||
'horizon.framework.widgets.toast'
|
||||
])
|
||||
.constant('horizon.framework.widgets.basePath', '/static/framework/widgets/');
|
||||
angular
|
||||
.module('horizon.framework.widgets', [
|
||||
'horizon.framework.widgets.help-panel',
|
||||
'horizon.framework.widgets.wizard',
|
||||
'horizon.framework.widgets.table',
|
||||
'horizon.framework.widgets.modal',
|
||||
'horizon.framework.widgets.modal-wait-spinner',
|
||||
'horizon.framework.widgets.transfer-table',
|
||||
'horizon.framework.widgets.charts',
|
||||
'horizon.framework.widgets.action-list',
|
||||
'horizon.framework.widgets.metadata-tree',
|
||||
'horizon.framework.widgets.metadata-display',
|
||||
'horizon.framework.widgets.toast'
|
||||
])
|
||||
.config(config);
|
||||
|
||||
function config($provide, $windowProvider) {
|
||||
var path = $windowProvider.$get().STATIC_URL + 'framework/widgets/';
|
||||
$provide.constant('horizon.framework.widgets.basePath', path);
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* global STATIC_URL, console */
|
||||
/* Namespace for core functionality related to DataTables. */
|
||||
horizon.datatables = {
|
||||
update: function () {
|
||||
@ -70,7 +69,8 @@ horizon.datatables = {
|
||||
var imagePath = $new_row.find('.btn-action-required').length > 0 ?
|
||||
"dashboard/img/action_required.png":
|
||||
"dashboard/img/loading.gif";
|
||||
imagePath = STATIC_URL + imagePath;
|
||||
|
||||
imagePath = window.STATIC_URL + imagePath;
|
||||
spinner_elm.prepend(
|
||||
$("<div>")
|
||||
.addClass("loading_gif")
|
||||
|
@ -5,6 +5,10 @@
|
||||
<title>Jasmine Spec Runner</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}horizon/lib/jasmine/jasmine.css">
|
||||
|
||||
<script>
|
||||
window.STATIC_URL = '/static/';
|
||||
window.WEBROOT = '/';
|
||||
</script>
|
||||
<script src="{% url 'horizon:jsi18n' 'horizon' %}"></script>
|
||||
<script src="{{ STATIC_URL }}horizon/lib/jasmine/jasmine.js"></script>
|
||||
<script src="{{ STATIC_URL }}horizon/lib/jasmine/jasmine-html.js"></script>
|
||||
|
@ -53,4 +53,7 @@ def openstack(request):
|
||||
region in available_regions]}
|
||||
context['regions'] = regions
|
||||
|
||||
# Adding webroot access
|
||||
context['WEBROOT'] = getattr(settings, "WEBROOT", "/")
|
||||
|
||||
return context
|
||||
|
@ -29,15 +29,11 @@
|
||||
'hz.dashboard.identity.users',
|
||||
'hz.dashboard.identity.projects'
|
||||
])
|
||||
.config(config);
|
||||
|
||||
/**
|
||||
* @name hz.dashboard.identity.basePath
|
||||
* @description Base path for the identity dashboard
|
||||
*/
|
||||
.constant('hz.dashboard.identity.basePath', getBasePath());
|
||||
|
||||
function getBasePath() {
|
||||
return (window.WEBROOT || '') + '/static/dashboard/identity/';
|
||||
function config($provide, $windowProvider) {
|
||||
var path = $windowProvider.$get().STATIC_URL + 'dashboard/identity/';
|
||||
$provide.constant('hz.dashboard.identity.basePath', path);
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -24,10 +24,11 @@
|
||||
*/
|
||||
angular
|
||||
.module('hz.dashboard.identity.projects', [])
|
||||
.constant('hz.dashboard.identity.projects.basePath', basePath());
|
||||
.config(config);
|
||||
|
||||
function basePath() {
|
||||
return (window.WEBROOT || '') + '/static/dashboard/identity/projects/';
|
||||
function config($provide, $windowProvider) {
|
||||
var path = $windowProvider.$get().STATIC_URL + 'dashboard/identity/projects/';
|
||||
$provide.constant('hz.dashboard.identity.projects.basePath', path);
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -44,6 +44,7 @@
|
||||
var toastService;
|
||||
var policyAPI;
|
||||
var keystoneAPI;
|
||||
var staticUrl;
|
||||
|
||||
///////////////////////
|
||||
|
||||
@ -61,6 +62,7 @@
|
||||
policyAPI = $injector.get('horizon.openstack-service-api.policy');
|
||||
keystoneAPI = $injector.get('horizon.openstack-service-api.keystone');
|
||||
controller = $injector.get('$controller');
|
||||
staticUrl = $injector.get('$window').STATIC_URL;
|
||||
|
||||
spyOn(toastService, 'add').and.callFake(fakeToast);
|
||||
spyOn(policyAPI, 'check').and.callFake(fakePolicy);
|
||||
@ -77,7 +79,7 @@
|
||||
}
|
||||
|
||||
it('should set path properly', function() {
|
||||
var path = '/static/dashboard/identity/users/table/';
|
||||
var path = staticUrl + 'dashboard/identity/users/table/';
|
||||
expect(createController().path).toEqual(path);
|
||||
});
|
||||
|
||||
@ -99,4 +101,4 @@
|
||||
});
|
||||
|
||||
});
|
||||
})();
|
||||
})();
|
||||
|
@ -60,20 +60,20 @@ class LaunchImage(tables.LinkAction):
|
||||
class LaunchImageNG(LaunchImage):
|
||||
name = "launch_image_ng"
|
||||
verbose_name = _("Launch")
|
||||
url = "horizon:project:images:index"
|
||||
classes = ("btn-launch")
|
||||
ajax = False
|
||||
|
||||
def __init__(self, attrs=None, **kwargs):
|
||||
if attrs is None:
|
||||
attrs = {"ng-controller": "LaunchInstanceModalController"}
|
||||
kwargs['preempt'] = True
|
||||
super(LaunchImage, self).__init__(attrs, **kwargs)
|
||||
|
||||
def get_link_url(self, datum):
|
||||
imageId = self.table.get_object_id(datum)
|
||||
clickValue = "openLaunchInstanceWizard({successUrl: " +\
|
||||
"'/project/images/', imageId: '%s'})" % (imageId)
|
||||
self.attrs['ng-click'] = clickValue
|
||||
url = reverse(self.url)
|
||||
ngclick = "openLaunchInstanceWizard({successUrl: '%s', imageId: '%s'})"
|
||||
self.attrs.update({"ng-controller": "LaunchInstanceModalController",
|
||||
"ng-click": ngclick % (url, imageId)})
|
||||
return "javascript:void(0);"
|
||||
|
||||
|
||||
|
@ -349,18 +349,16 @@ class LaunchLink(tables.LinkAction):
|
||||
|
||||
class LaunchLinkNG(LaunchLink):
|
||||
name = "launch-ng"
|
||||
url = "horizon:project:instances:index"
|
||||
ajax = False
|
||||
classes = ("btn-launch")
|
||||
|
||||
def __init__(self,
|
||||
attrs={
|
||||
"ng-controller": "LaunchInstanceModalController",
|
||||
"ng-click": "openLaunchInstanceWizard(" +
|
||||
"{successUrl: '/project/instances/'})"
|
||||
},
|
||||
**kwargs):
|
||||
kwargs['preempt'] = True
|
||||
super(LaunchLink, self).__init__(attrs, **kwargs)
|
||||
def get_default_attrs(self):
|
||||
url = urlresolvers.reverse(self.url)
|
||||
ngclick = "openLaunchInstanceWizard({ successUrl: '%s' })" % url
|
||||
self.attrs.update({'ng-controller': 'LaunchInstanceModalController',
|
||||
'ng-click': ngclick})
|
||||
return super(LaunchLinkNG, self).get_default_attrs()
|
||||
|
||||
def get_link_url(self, datum=None):
|
||||
return "javascript:void(0);"
|
||||
|
@ -29,7 +29,8 @@
|
||||
<div class="launchButtons">
|
||||
{% if launch_instance_allowed %}
|
||||
{% if show_ng_launch %}
|
||||
<a ng-controller="LaunchInstanceModalController" ng-click="openLaunchInstanceWizard({successUrl: '/project/network_topology/', dismissUrl: '/project/network_topology/'})" id="instances__action_launch" class="btn btn-default btn-sm btn-launch ajax-modal {% if instance_quota_exceeded %}disabled{% endif %}"><span class="fa fa-cloud-upload"></span> {% if instance_quota_exceeded %}{% trans "Launch Instance (Quota exceeded)"%}{% else %}{% trans "Launch Instance"%}{% endif %}</a>
|
||||
{% url 'horizon:project:network_topology:index' as networkUrl %}
|
||||
<a ng-controller="LaunchInstanceModalController" ng-click="openLaunchInstanceWizard({successUrl: '{{networkUrl}}', dismissUrl: '{{networkUrl}}'})" id="instances__action_launch" class="btn btn-default btn-sm btn-launch ajax-modal {% if instance_quota_exceeded %}disabled{% endif %}"><span class="fa fa-cloud-upload"></span> {% if instance_quota_exceeded %}{% trans "Launch Instance (Quota exceeded)"%}{% else %}{% trans "Launch Instance"%}{% endif %}</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'horizon:project:network_topology:launchinstance' %}" id="instances__action_launch" class="btn btn-default btn-sm btn-launch ajax-modal {% if instance_quota_exceeded %}disabled{% endif %}"><span class="fa fa-cloud-upload"></span> {% if instance_quota_exceeded %}{% trans "Launch Instance (Quota exceeded)"%}{% else %}{% trans "Launch Instance"%}{% endif %}</a>
|
||||
{% endif %}
|
||||
|
@ -364,6 +364,7 @@ POLICY_CHECK_FUNCTION = policy_backend.check
|
||||
|
||||
# Add HORIZON_CONFIG to the context information for offline compression
|
||||
COMPRESS_OFFLINE_CONTEXT = {
|
||||
'WEBROOT': WEBROOT,
|
||||
'STATIC_URL': STATIC_URL,
|
||||
'HORIZON_CONFIG': HORIZON_CONFIG,
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('hz.dashboard', [
|
||||
'hz.dashboard.launch-instance',
|
||||
'hz.dashboard.tech-debt'
|
||||
])
|
||||
angular
|
||||
.module('hz.dashboard', [
|
||||
'hz.dashboard.launch-instance',
|
||||
'hz.dashboard.tech-debt'
|
||||
])
|
||||
.config(config);
|
||||
|
||||
.constant('dashboardBasePath', '/static/dashboard/');
|
||||
function config($provide, $windowProvider) {
|
||||
var path = $windowProvider.$get().STATIC_URL + 'dashboard/';
|
||||
$provide.constant('dashboardBasePath', path);
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -24,18 +24,20 @@
|
||||
|
||||
describe('hz.dashboard:constant:dashboardBasePath', function () {
|
||||
var dashboardBasePath;
|
||||
var staticUrl;
|
||||
|
||||
beforeEach(module('hz.dashboard'));
|
||||
beforeEach(inject(function ($injector) {
|
||||
dashboardBasePath = $injector.get('dashboardBasePath');
|
||||
staticUrl = $injector.get('$window').STATIC_URL;
|
||||
}));
|
||||
|
||||
it('should be defined', function () {
|
||||
expect(dashboardBasePath).toBeDefined();
|
||||
});
|
||||
|
||||
it('should equal to "/static/dashboard/"', function () {
|
||||
expect(dashboardBasePath).toEqual('/static/dashboard/');
|
||||
it('should get set correctly', function () {
|
||||
expect(dashboardBasePath).toEqual(staticUrl + 'dashboard/');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -8,7 +8,10 @@
|
||||
|
||||
{% comment %} Compress jQuery, Angular, Plugins, Bootstrap, Hogan.js and Horizon-specific JS. {% endcomment %}
|
||||
{% compress js %}
|
||||
<script type="text/javascript">var STATIC_URL = "{{ STATIC_URL }}";</script>
|
||||
<script type="text/javascript">
|
||||
var STATIC_URL = "{{ STATIC_URL }}";
|
||||
var WEBROOT = "{{ WEBROOT }}";
|
||||
</script>
|
||||
<script src='{{ STATIC_URL }}horizon/lib/angular/angular-cookies.js'></script>
|
||||
<script src='{{ STATIC_URL }}horizon/lib/angular/angular-sanitize.js'></script>
|
||||
<script src="{{ STATIC_URL }}horizon/lib/angular/lrdragndrop.js"></script>
|
||||
|
@ -90,9 +90,7 @@ var horizonPlugInModules = [];
|
||||
globals.npgettext = django.npgettext;
|
||||
globals.interpolate = django.interpolate;
|
||||
globals.get_format = django.get_format;
|
||||
globals.STATIC_URL = '/static/';
|
||||
globals.WEBROOT = '/';
|
||||
|
||||
}(this));
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user