[Launch Instance Fix] Launch Instance from Various Screens
Using the 'launch' options from Image Table/Detail or Network Topology fires off the Launch Instance workflow. Each firing-off point describes where the user should be relocated to when successfully done with the wizard (when a launch request has been successfully submitted). Co-Authored-By: Shaoquan Chen <sean.chen2@hp.com> Closes-Bug: #1433113 Change-Id: Id7bfad80781195c6311ef37e3ef32077947d8e62
This commit is contained in:
parent
224e992237
commit
688b2d57d4
1
horizon/static/angular/wizard/wizard.js
vendored
1
horizon/static/angular/wizard/wizard.js
vendored
@ -152,6 +152,7 @@
|
||||
// this is a simple workaround.
|
||||
function always() {
|
||||
$scope.ready = true;
|
||||
$scope.initTask.resolve();
|
||||
switchToFirstReadyStep();
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,28 @@ class LaunchImage(tables.LinkAction):
|
||||
return False
|
||||
|
||||
|
||||
class LaunchImageNG(LaunchImage):
|
||||
name = "launch_image_ng"
|
||||
verbose_name = _("Launch")
|
||||
classes = ("btn-launch")
|
||||
ajax = False
|
||||
|
||||
def __init__(self,
|
||||
attrs={
|
||||
"ng-controller": "LaunchInstanceModalCtrl"
|
||||
},
|
||||
**kwargs):
|
||||
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
|
||||
return "javascript:void(0);"
|
||||
|
||||
|
||||
class DeleteImage(tables.DeleteAction):
|
||||
# NOTE: The bp/add-batchactions-help-text
|
||||
# will add appropriate help text to some batch/delete actions.
|
||||
@ -268,6 +290,11 @@ class ImagesTable(tables.DataTable):
|
||||
status_columns = ["status"]
|
||||
verbose_name = _("Images")
|
||||
table_actions = (OwnerFilter, CreateImage, DeleteImage,)
|
||||
row_actions = (LaunchImage, CreateVolumeFromImage,
|
||||
EditImage, DeleteImage,)
|
||||
launch_actions = ()
|
||||
if getattr(settings, 'LAUNCH_INSTANCE_LEGACY_ENABLED', True):
|
||||
launch_actions = (LaunchImage,) + launch_actions
|
||||
if getattr(settings, 'LAUNCH_INSTANCE_NG_ENABLED', False):
|
||||
launch_actions = (LaunchImageNG,) + launch_actions
|
||||
row_actions = launch_actions + (CreateVolumeFromImage,
|
||||
EditImage, DeleteImage,)
|
||||
pagination_param = "image_marker"
|
||||
|
@ -28,6 +28,9 @@
|
||||
</div>
|
||||
<div class="launchButtons">
|
||||
{% if launch_instance_allowed %}
|
||||
{% if show_ng_launch %}
|
||||
<a ng-controller="LaunchInstanceModalCtrl" 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>
|
||||
{% 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 %}
|
||||
{% if create_network_allowed %}
|
||||
|
@ -130,6 +130,8 @@ class NetworkTopologyView(views.HorizonTemplateView):
|
||||
context['router_quota_exceeded'] = self._quota_exceeded('routers')
|
||||
context['console_type'] = getattr(
|
||||
settings, 'CONSOLE_TYPE', 'AUTO')
|
||||
context['show_ng_launch'] = getattr(
|
||||
settings, 'LAUNCH_INSTANCE_NG_ENABLED', False)
|
||||
return context
|
||||
|
||||
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
function LaunchInstanceModalCtrl($scope, $modal, $window, modalSpec) {
|
||||
$scope.openLaunchInstanceWizard = function (launchContext) {
|
||||
var localSpec = {
|
||||
|
||||
var localSpec = {
|
||||
resolve: {
|
||||
launchContext: function() { return launchContext; }
|
||||
}
|
||||
@ -105,11 +106,16 @@
|
||||
|
||||
var launchInstanceModal = $modal.open(localSpec);
|
||||
|
||||
launchInstanceModal.result.then(function () {
|
||||
if (launchContext && launchContext.successUrl) {
|
||||
$window.location.href = launchContext.successUrl;
|
||||
}
|
||||
});
|
||||
var handleModalClose = function(redirectPropertyName) {
|
||||
return function() {
|
||||
if (launchContext && launchContext[redirectPropertyName]) {
|
||||
$window.location.href = launchContext[redirectPropertyName];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
launchInstanceModal.result.then(handleModalClose('successUrl'),
|
||||
handleModalClose('dismissUrl'));
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -83,7 +83,7 @@
|
||||
popover-trigger="hover"></span>
|
||||
<select name="boot-source-type" class="form-control input-sm"
|
||||
ng-options="src.label for src in bootSourcesOptions track by src.type"
|
||||
ng-change="updateBootSourceSelection(model.newInstanceSpec.source_type)"
|
||||
ng-change="updateBootSourceSelection(model.newInstanceSpec.source_type.type)"
|
||||
ng-model="model.newInstanceSpec.source_type">
|
||||
</select>
|
||||
</div>
|
||||
@ -199,7 +199,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-repeat-start="row in tableData.displayAllocated track by row.id">
|
||||
<tr ng-repeat-start="row in selection">
|
||||
<td class="expander">
|
||||
<span class="fa fa-chevron-right"
|
||||
hz-expand-detail
|
||||
|
@ -1,6 +1,9 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var push = [].push,
|
||||
forEach = angular.forEach;
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name hz.dashboard.launch-instance
|
||||
@ -103,17 +106,17 @@
|
||||
//
|
||||
|
||||
$scope.bootSourcesOptions = [
|
||||
{ type: 'image', label: gettext('Image') },
|
||||
{ type: 'snapshot', label: gettext('Instance Snapshot') },
|
||||
{ type: 'volume', label: gettext('Volume') },
|
||||
{ type: 'volume_snapshot', label: gettext('Volume Snapshot') }
|
||||
{ type: bootSourceTypes.IMAGE, label: gettext('Image') },
|
||||
{ type: bootSourceTypes.INSTANCE_SNAPSHOT, label: gettext('Instance Snapshot') },
|
||||
{ type: bootSourceTypes.VOLUME, label: gettext('Volume') },
|
||||
{ type: bootSourceTypes.VOLUME_SNAPSHOT, label: gettext('Volume Snapshot') }
|
||||
];
|
||||
|
||||
$scope.updateBootSourceSelection = function (selectedSource) {
|
||||
$scope.currentBootSource = selectedSource.type;
|
||||
$scope.currentBootSource = selectedSource;
|
||||
$scope.model.newInstanceSpec.vol_create = false;
|
||||
$scope.model.newInstanceSpec.vol_delete_on_terminate = false;
|
||||
changeBootSource(selectedSource.type);
|
||||
changeBootSource(selectedSource);
|
||||
validateBootSourceType();
|
||||
};
|
||||
|
||||
@ -129,7 +132,7 @@
|
||||
$scope.sourceDetails =
|
||||
'/static/dashboard/launch-instance/source/source-details.html';
|
||||
|
||||
var selection = $scope.model.newInstanceSpec.source;
|
||||
var selection = $scope.selection = $scope.model.newInstanceSpec.source;
|
||||
|
||||
var bootSources = {
|
||||
image: {
|
||||
@ -229,8 +232,8 @@
|
||||
};
|
||||
|
||||
// dynamically update page based on boot source selection
|
||||
function changeBootSource(key) {
|
||||
updateDataSource(key);
|
||||
function changeBootSource(key, preSelection) {
|
||||
updateDataSource(key, preSelection);
|
||||
updateHelpText(key);
|
||||
updateTableHeadCells(key);
|
||||
updateTableBodyCells(key);
|
||||
@ -238,9 +241,12 @@
|
||||
updateMaxInstanceCount();
|
||||
}
|
||||
|
||||
function updateDataSource(key) {
|
||||
angular.extend($scope.tableData, bootSources[key]);
|
||||
function updateDataSource(key, preSelection) {
|
||||
selection.length = 0;
|
||||
if (preSelection) {
|
||||
push.apply(selection, preSelection);
|
||||
}
|
||||
angular.extend($scope.tableData, bootSources[key]);
|
||||
}
|
||||
|
||||
function updateHelpText(key) {
|
||||
@ -418,6 +424,40 @@
|
||||
.$setValidity('bootSourceType', isValid);
|
||||
}
|
||||
|
||||
function findSourceById(sources, id) {
|
||||
var i = 0, len = sources.length, source;
|
||||
for (; i < len; i++) {
|
||||
source = sources[i];
|
||||
if (source.id === id) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setSourceImageWithId(id) {
|
||||
var pre = findSourceById($scope.model.images, id);
|
||||
if (pre) {
|
||||
changeBootSource(bootSourceTypes.IMAGE, [pre]);
|
||||
$scope.model.newInstanceSpec.source_type = $scope.bootSourcesOptions[0];
|
||||
$scope.currentBootSource = $scope.bootSourcesOptions[0].type;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watchCollection(
|
||||
function () {
|
||||
return $scope.model.images;
|
||||
},
|
||||
function (newValue, oldValue) {
|
||||
$scope.initPromise.then(function () {
|
||||
$scope.$applyAsync(function () {
|
||||
if ($scope.launchContext.imageId) {
|
||||
setSourceImageWithId($scope.launchContext.imageId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
//
|
||||
// initialize
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user