Commit 6973d80e authored by Keith Downie's avatar Keith Downie Committed by Leigh B Stoller

Merged in wizard with multisite

parent 88e0ecb5
......@@ -266,7 +266,8 @@ function SPITFORM($formfields, $newuser, $errors)
SPITHEADER(1);
echo "<div id='ppviewmodal_div'></div>\n";
echo "<div class='row'>
echo "<div id='stepsContainer' class='row'>
<h3>Select a Profile</h3>
<div class='col-lg-6 col-lg-offset-3
col-md-6 col-md-offset-3
col-sm-8 col-sm-offset-2
......@@ -282,15 +283,22 @@ function SPITFORM($formfields, $newuser, $errors)
echo "<div class='panel panel-default'>
<div class='panel-heading'>
<h3 class='panel-title'>\n";
}
else {
echo "<h3 style='margin-top: 0px;'>";
}
echo "<center>Start Experiment";
if (isset($profilename)) {
echo " using profile &quot;$profilename&quot";
}
echo "</center></h3>\n";
}
else {
# Will only show header when linked to a profile
if (isset($profilename)) {
echo "<h3 style='margin: 0px;'>";
echo "<center>Start Experiment";
echo " using profile &quot;$profilename&quot";
echo "</center></h3>\n";
}
}
if (!$this_user) {
echo " </div>
<div class='panel-body'>\n";
......@@ -453,35 +461,11 @@ function SPITFORM($formfields, $newuser, $errors)
$thisuuid = $profile->uuid();
echo "<input type='hidden' name='profile' value='$thisuuid'>\n";
}
if (isset($this_user) && !$this_user->webonly()) {
echo "<div class='panel panel-info'>\n";
echo " <div class='panel-body bg-info' style='padding: 5px;'>\n";
#
# Local users, show a link to the ssh keys page.
# Nonlocal users, remind them ssh keys go into their portal.
#
if ($this_user->IsNonLocal()) {
echo "<div>";
echo " <div>
GENI Users; be sure to add ssh keys at <b>your</b> portal if
you want to log in from your desktop, else you
will be limited to using a shell window in your browser.
</div>
</div>\n";
}
else {
echo "<div>";
echo " <div>
<a href='ssh-keys.php'>Manage your SSH keys</a> if
you want to log in from your desktop, else you
will be limited to using a shell window in your browser.
</div>
</div>\n";
}
echo " </div>\n";
echo "</div>\n";
}
#
# Container for the inputs that get copied to the last step of the wizard
#
echo "<div id='experiment_options' class='hidden'>\n";
#
# Spit out an experient name box, which is optional and prefilled
# with a default.
......@@ -491,15 +475,15 @@ function SPITFORM($formfields, $newuser, $errors)
if ($errors && array_key_exists("name", $errors)) {
$thisclass .= " has-error";
}
echo "<div class='form-horizontal'>
echo "<div id='name_selector' class='form-horizontal experiment_option'>
<div class='$thisclass'>
<label class='col-sm-4 control-label'
style='text-align: right;'>Name:</label>
<div class='col-sm-6'
data-toggle='popover'
data-delay='{hide:1500, show:500}'
data-html='true'
data-content='Provide a unique name to identity your
data-delay='{hide:1500, show:500}'
data-html='true'
data-content='Provide a unique name to identity your
new experiment. If you are in
the habit of starting more then one experiment at
a time this is really handy when trying to tell
......@@ -522,7 +506,8 @@ function SPITFORM($formfields, $newuser, $errors)
# Spit out a project selection list if more then one project membership
#
if ($this_user && !$this_user->webonly()) {
if (count($projlist) == 1) {
# Changed to 0 for testing, change back
if (count($projlist) == 0) {
echo "<input id='profile_pid' type='hidden'
name='formfields[pid]'
value='" . $formfields["pid"] . "'>\n";
......@@ -538,7 +523,7 @@ function SPITFORM($formfields, $newuser, $errors)
"<option $selected value='$pid'>$pid</option>\n";
}
$html =
"<div class='form-horizontal'><div class='form-group'>
"<div class='form-horizontal experiment_option' id='profile_selector'><div class='form-group'>
<label class='col-sm-4 control-label'
style='text-align: right;'>Project:</label>
<div class='col-sm-6'>
......@@ -561,8 +546,9 @@ function SPITFORM($formfields, $newuser, $errors)
$am_options .=
"<option $selected value='$am'>$am</option>\n";
}
$html = "<div id='aggregate_selector'>
<div class='form-horizontal' id='nosite_selector'>
<div class='form-horizontal experiment_option' id='nosite_selector'>
<div class='form-group'>
<label class='col-sm-4 control-label'
style='text-align: right;'>
......@@ -576,22 +562,59 @@ function SPITFORM($formfields, $newuser, $errors)
$html = $html . "<div id='site_selector' class='hidden'></div></div>";
echo $html;
}
echo "</div>\n";
echo "</fieldset>
<div class='form-group row'>
<div class='form-group row hidden'>
<div class='col-sm-6 col-sm-offset-3'>
<button class='btn btn-primary btn-block hidden'
id='configurator_button'
type='button'>Configure
</button>
<button class='btn btn-success btn-block' id='instantiate_submit'
<button class='btn btn-success btn-block hidden' id='instantiate_submit'
type='submit' name='create'>Create!
</button>
</div>
</div>
</div>\n";
</div>\n";
# This is for a PP rspec.
echo "<textarea name='formfields[pp_rspec]'
id='pp_rspec_textarea'
class='form-control hidden'
type='textarea'></textarea>\n";
echo "</form>\n
</div>\n";
if (!isset($this_user)) {
echo "</div>
</div>\n";
}
echo "<h3>Parameterize</h3><div class='col-lg-6 col-lg-offset-3
col-md-6 col-md-offset-3
col-sm-8 col-sm-offset-2
col-xs-12 col-xs-offset-0'></div>\n";
echo "<h3>Finalize</h3><div class='col-lg-6 col-lg-offset-3
col-md-6 col-md-offset-3
col-sm-8 col-sm-offset-2
col-xs-12 col-xs-offset-0'>
<div id='finalize_container' class='col-lg-8 col-md-8 col-sm-8 col-xs-12'>
<div class='panel panel-default'>
<div class='panel-heading'>Please review the selections below and then click Finish.</div>
<div class='panel-body'>
<div id='finalize_options'></div>
</div>
</div>
</div>
<div id='inline_container' class='col-lg-4 col-md-4 col-sm-4 col-xs-12'>
<a id='inline_overlay' href='#'></a>
<div id='inline_jacks'></div>
</div>
</div>\n";
echo "</div>\n";
echo "<button class='btn btn-primary btn-sm'
style='display:block;visibility:hidden;'
id='modal_profile_continue_button'
type='button' name='create'>Continue</button>\n";
if (!isset($this_user)) {
SpitVerifyModal("verify_modal", "Create");
if ($newuser) {
......@@ -610,13 +633,6 @@ function SPITFORM($formfields, $newuser, $errors)
echo "<input type='hidden' name='stuffing' value='$stuffing' />";
}
}
echo "</div>\n";
# This is for a PP rspec.
echo "<textarea name='formfields[pp_rspec]'
id='pp_rspec_textarea'
class='form-control hidden'
type='textarea'></textarea>\n";
echo "</form>\n";
SpitTopologyViewModal("quickvm_topomodal", $profile_array);
echo "<div id='waitwait_div'></div>\n";
......
define(['underscore', 'js/lib/text!template/edit-modal.html'],
function (_, editModalString)
define(['underscore', 'js/lib/text!template/edit-modal.html', 'js/lib/text!template/edit-inline.html'],
function (_, editModalString, editInlineString)
{
'use strict';
......@@ -67,7 +67,7 @@ function (_, editModalString)
alert('Failed to fetch Jacks context from ' + contextUrl);
}
function JacksEditor (root, isViewer)
function JacksEditor (root, isViewer, isInline, withoutSelection, withoutMenu)
{
this.root = root;
this.instance = null;
......@@ -75,24 +75,45 @@ function (_, editModalString)
this.output = null;
this.xml = null;
this.mode = 'editor';
this.selectionPane = true;
this.menu = true;
if (isViewer)
{
this.mode = 'viewer';
}
this.shown = false;
this.render();
this.shown = false;
if (isInline) {
this.inline = 'inline';
}
// A little backward, but I didn't want the addition of these parameters to
// mess up code elsewhere. The previous values for these parts of the context was true.
if (withoutSelection) {
this.selectionPane = false;
}
if (withoutMenu) {
this.menu = false;
}
this.render();
}
JacksEditor.prototype = {
render: function ()
{
this.root.html(editModalString);
if (this.inline == 'inline')
{
this.root.html(editInlineString);
}
else
{
this.root.html(editModalString);
this.root.find('#quickvm_editmodal').on('shown.bs.modal', _.bind(this.handleShown, this));
}
if (this.mode !== 'editor')
{
this.root.find('.modal-header h3').html('Topology Viewer');
}
this.root.find('#quickvm_editmodal').on('shown.bs.modal', _.bind(this.handleShown, this));
this.root.find('#edit-save').click(_.bind(this.fetchXml, this));
this.root.find('#edit-cancel, #edit-dismiss')
.click(_.bind(this.cancelEdit, this));
......@@ -102,14 +123,14 @@ function (_, editModalString)
source: 'rspec',
root: '#edit_nopicker',
multiSite: true,
nodeSelect: true,
nodeSelect: this.selectionPane,
readyCallback: _.bind(this.jacksReady, this),
show: {
rspec: false,
tour: false,
version: false,
menu: true,
selectInfo: true
menu: this.menu,
selectInfo: this.selectionPane
},
canvasOptions: context.canvasOptions,
constraints: context.constraints
......@@ -144,7 +165,12 @@ function (_, editModalString)
}
if (this.input)
{
this.root.find('#quickvm_editmodal').modal('show');
if (this.inline == 'inline') {
this.handleShown();
}
else {
this.root.find('#quickvm_editmodal').modal('show');
}
}
},
......
......@@ -5,6 +5,7 @@ window.APT_OPTIONS.configObject = {
paths: {
'jquery-ui': 'js/lib/jquery-ui',
'jquery-grid':'js/lib/jquery.appendGrid-1.3.1.min',
'jquery-steps': 'js/lib/jquery.steps.min',
'formhelpers': 'js/lib/bootstrap-formhelpers',
'dateformat': 'js/lib/date.format',
'd3': 'js/lib/d3.v3',
......@@ -20,6 +21,7 @@ window.APT_OPTIONS.configObject = {
shim: {
'jquery-ui': { },
'jquery-grid': { deps: ['jquery-ui'] },
'jquery-steps': { },
'formhelpers': { },
'dateformat': { exports: 'dateFormat' },
'd3': { exports: 'd3' },
......
require(window.APT_OPTIONS.configObject,
['underscore', 'constraints', 'js/quickvm_sup', 'js/ppstart',
['underscore', 'constraints', 'js/quickvm_sup', 'js/ppwizardstart', 'js/JacksEditor',
'js/lib/text!template/aboutapt.html',
'js/lib/text!template/aboutcloudlab.html',
'js/lib/text!template/waitwait-modal.html',
'formhelpers', 'filestyle', 'marked', 'jacks'],
function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwaitString)
'formhelpers', 'filestyle', 'marked', 'jacks', 'jquery-steps'],
function (_, Constraints, sup, ppstart, JacksEditor, aboutaptString, aboutcloudString, waitwaitString)
{
'use strict';
......@@ -23,21 +23,140 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
input: null,
output: null
};
var editor = null;
var loaded_uuid = null;
var ppchanged = false;
function initialize()
{
// Get context for constraints
// Get context for constraints
var contextUrl = 'https://www.emulab.net/protogeni/jacks-context/cloudlab-utah.json';
$('#profile_where').prop('disabled', true);
$('#instantiate_submit').prop('disabled', true);
$.get(contextUrl).then(contextReady, contextFail);
window.APT_OPTIONS.initialize(sup);
registered = window.REGISTERED;
window.APT_OPTIONS.initialize(sup);
window.APT_OPTIONS.initialize(ppstart);
registered = window.REGISTERED;
webonly = window.WEBONLY;
portal = window.PORTAL;
ajaxurl = window.AJAXURL;
ajaxurl = window.AJAXURL;
$('#stepsContainer').steps({
headerTag: "h3",
bodyTag: "div",
transitionEffect: "slideLeft",
autoFocus: true,
onStepChanging: function(event, currentIndex, newIndex) {
if (currentIndex == 0 && newIndex == 1) {
if (ispprofile) {
if (selected_uuid != loaded_uuid) {
$('#stepsContainer-p-1 > div').attr('style','display:block');
ppstart.StartPP({uuid : selected_uuid,
registered : registered,
amlist : amlist,
amdefault : amdefault,
callback : ConfigureDone,
button_label : "Accept"});
loaded_uuid = selected_uuid;
ppchanged = true;
}
}
else {
$('#stepsContainer-p-1 > div').attr('style','display:none');
}
}
else if (currentIndex == 1 && newIndex == 2) {
// Set up the Finalize tab
$('#stepsContainer-p-2 #finalize_options').html('');
// Each .experiment_option in the form is copied to the last page.
// When the finish button is pressed, these values are copied back.
$('#experiment_options .experiment_option').each(function() {
if (!$(this).hasClass('hidden')) {
var fieldId = $(this).attr('id');
var fieldHTML = $(this).html();
$('#stepsContainer-p-2 #finalize_options').append(''
+'<div class="'+fieldId+'">'
+'<div class="form-horizontal">'
+fieldHTML
+'</div></div>');
}
});
}
if (currentIndex == 2) {
SwitchJacks('small');
}
if (currentIndex == 0 && selected_uuid == null) {
return false;
}
return true;
},
onStepChanged: function(event, currentIndex, priorIndex) {
var cIndex = currentIndex;
if (currentIndex == 1) {
// If the profile isn't parameterized, skip the second step
if (!ispprofile) {
if (priorIndex < currentIndex) {
// Generate the profile on the third tab
ShowProfileSelectionInline($('#profile_name .current'), $('#stepsContainer-p-2 #inline_jacks'), true);
$(this).steps('next');
$('#stepsContainer-t-1').parent().removeClass('done').addClass('disabled');
}
if (priorIndex > currentIndex) {
$(this).steps('previous');
cIndex--;
}
}
$('#pp_form input').change(function() {
ppchanged = true;
});
$('#pp_form select').change(function() {
ppchanged = true;
});
}
else if (currentIndex == 2 && priorIndex == 1) {
// Keep the two panes the same height
$('#inline_container').css('height', $('#finalize_container').outerHeight());
if (ispprofile && ppchanged) {
ppstart.HandleSubmit();
ppchanged = false;
}
}
if (currentIndex < priorIndex) {
// Disable going forward by clicking on the labels
for (var i = cIndex+1; i < $('.steps > ul > li').length; i++) {
$('#stepsContainer-t-'+i).parent().removeClass('done').addClass('disabled');
}
}
}
});
// Set up wizard final page formatting
$('#stepsContainer .steps').addClass('col-lg-6 col-lg-offset-3 col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2 col-xs-12 col-xs-offset-0');
$('#stepsContainer .actions').addClass('col-lg-6 col-lg-offset-3 col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2 col-xs-12 col-xs-offset-0');
// Set up jacks swap
$('#stepsContainer #inline_overlay').click(function() {
SwitchJacks('large');
});
// Set up the Finish button to submit the form
$('#stepsContainer .actions a[href="#finish"]').click(function() {
$('#stepsContainer-p-2 #finalize_options > div').each(function() {
var fieldId = $(this).attr('class');
$('#'+fieldId+' .form-control').val($('.'+fieldId+' .form-control').val());
});
if (!ispprofile) {
$('#instantiate_submit').click();
}
});
if ($('#amlist-json').length) {
amlist = JSON.parse(_.unescape($('#amlist-json')[0].textContent));
}
......@@ -64,7 +183,7 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
$('#verify_modal').modal('show');
}
$('#quickvm_topomodal').on('shown.bs.modal', function() {
ShowProfileSelection($('.current'))
ShowProfileSelection($('#profile_name .current'))
});
$('button#reset-form').click(function (event) {
......@@ -81,8 +200,9 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
});
$('button#showtopo_select').click(function (event) {
event.preventDefault();
ChangeProfileSelection($('.selected'));
ChangeProfileSelection($('#quickvm_topomodal .selected'));
$('#quickvm_topomodal').modal('hide');
$('.steps .error').removeClass('error');
});
$('#instantiate_submit').click(function (event) {
if (webonly != 0) {
......@@ -99,18 +219,6 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
$("#waitwait-modal").modal('show');
return true;
});
$('#configurator_button').click(function (event) {
if (ispprofile) {
event.preventDefault();
ppstart({uuid : selected_uuid,
registered : registered,
amlist : amlist,
amdefault : amdefault,
callback : ConfigureDone,
button_label : "Accept"});
}
return false;
});
$('#profile_copy_button').click(function (event) {
event.preventDefault();
if (!registered) {
......@@ -165,6 +273,48 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
_.delay(function () {$('.dropdown-toggle').dropdown();}, 500);
}
function SwitchJacks(which) {
if (which == 'small' && $('#stepsContainer-p-2 #inline_jacks').html() == '') {
$('#stepsContainer #finalize_container').removeClass('col-lg-12 col-md-12 col-sm-12');
$('#stepsContainer #finalize_container').addClass('col-lg-8 col-md-8 col-sm-8');
$('#stepsContainer #inline_large_jacks').html('');
$('#inline_large_container').addClass('hidden');
if (ispprofile) {
ppstart.ChangeJacksRoot($('#stepsContainer-p-2 #inline_jacks'), true);
}
else {
ShowProfileSelectionInline($('#profile_name .current'), $('#stepsContainer-p-2 #inline_jacks'), true);
}
$('#stepsContainer-p-2 #inline_container').removeClass('hidden');
}
else if (which == 'large') {
// Sometimes the steps library will clean up the added elements
if ($('#inline_large_container').length === 0) {
$('<div id="inline_large_container" class="hidden"></div>').insertAfter('#stepsContainer .content');
$('#inline_large_container').html(''
+'<button id="closeLargeInline" type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>'
+'<div id="inline_large_jacks"></div>');
$('#stepsContainer #inline_large_container').addClass('col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12 col-xs-offset-0');
$('#closeLargeInline').click(function() {
SwitchJacks('small');
});
}
$('#stepsContainer #finalize_container').removeClass('col-lg-8 col-md-8 col-sm-8');
$('#stepsContainer #finalize_container').addClass('col-lg-12 col-md-12 col-sm-12');
$('#stepsContainer-p-2 #inline_jacks').html('');
$('#stepsContainer-p-2 #inline_container').addClass('hidden');
if (ispprofile) {
ppstart.ChangeJacksRoot($('#stepsContainer #inline_large_jacks'), false);
}
else {
ShowProfileSelectionInline($('#profile_name .current'), $('#stepsContainer #inline_large_jacks'), false);
}
$('#inline_large_container').removeClass('hidden');
}
}
function resetForm($form) {
$form.find('input:text, input:password, select, textarea').val('');
}
......@@ -184,6 +334,15 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
};
GetProfile($(selectedElement).attr('value'), continuation);
}
// Used to generate the topology on Tab 3 of the wizard for non-pp profiles
function ShowProfileSelectionInline(selectedElement, root, selectionPane) {
editor = new JacksEditor(root, true, true, selectionPane, true);
var continuation = function(rspec, description, name, amdefault, ispp) {
editor.show(rspec);
};
GetProfile($(selectedElement).attr('value'), continuation);
}
function ChangeProfileSelection(selectedElement) {
if (!$(selectedElement).hasClass('current')) {
......@@ -210,11 +369,9 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
// Show the configuration button, disable the create button.
if (ispprofile) {
$("#configurator_button").removeClass("hidden");
$('#instantiate_submit').attr('disabled', true);
}
else {
$("#configurator_button").addClass("hidden");
$('#instantiate_submit').attr('disabled', false);
}
......@@ -355,7 +512,7 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
for (var siteid in sites) {
html = html +
"<div class='form-horizontal'>" +
"<div id='site"+siteid+"cluster' class='form-horizontal experiment_option'>" +
" <div class='form-group'>" +
" <label class='col-sm-4 control-label' " +
" style='text-align: right;'>"+
......@@ -366,9 +523,8 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
" <select name=\"formfields[sites][" + siteid + "]\"" +
" class='form-control'>" + options +
" </select>" +
"</div></div><div>";
"</div></div></div>";
}
html = html + "<br>";
console.info(html);
$("#nosite_selector").addClass("hidden");
$("#site_selector").removeClass("hidden");
......
......@@ -167,6 +167,7 @@ $PAGEHEADER_FUNCTION = function($thinheader = 0, $ignore1 = NULL,
<link rel='stylesheet' href='css/$APTSTYLE'>";
echo "<script>APT_CACHE_TOKEN='" . Instance::CacheToken() . "';</script>";
echo "<script src='js/common.js'></script>
<link rel='stylesheet' href='css/jquery-steps.css'>
<script src='https://www.emulab.net/emulab_sup.js'></script>