Commit dedc6495 authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint new geni-lib param code, working on making it selectable

via emulab features, for testing.
parent 749a51b9
#
# Copyright (c) 2000-2018 University of Utah and the Flux Group.
# Copyright (c) 2000-2019 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -163,6 +163,9 @@ APTCSSFILES = $(wildcard $(SRCDIR)/aptui/css/*.css)
APTFONTS = $(wildcard $(SRCDIR)/aptui/fonts/*)
APTIMAGES = $(wildcard $(SRCDIR)/aptui/images/*)
APTNEWJSFILES = $(wildcard $(SRCDIR)/aptui/js/new/*.js)
APTNEWTEMPLATES = $(wildcard $(SRCDIR)/aptui/template/new/*.html)
# need to make it *.gz; with simply "*",
# we end up sucking over "CVS"
DOWNLOADFILES = $(wildcard $(SRCDIR)/downloads/*.gz)
......@@ -228,6 +231,9 @@ ALLAPTCSS = $(notdir $(APTCSSFILES))
ALLAPTFONTS = $(notdir $(APTFONTS))
ALLAPTIMAGES = $(notdir $(APTIMAGES))
ALLAPTNEWJS = $(notdir $(APTNEWJSFILES))
ALLAPTNEWTEMPLATES = $(notdir $(APTNEWTEMPLATES))
INSTALLFILES = $(addprefix $(INSTALL_SBINDIR)/, htmlinstall) \
$(addprefix $(INSTALL_WWWDIR)/, $(ALLFILES)) \
$(addprefix $(INSTALL_WWWDIR)/floormap/, $(ALLFLOORMAPS)) \
......@@ -276,7 +282,9 @@ apt-install: $(addprefix $(INSTALL_WWWDIR)/apt/, $(ALLAPTUI)) \
$(addprefix $(INSTALL_WWWDIR)/apt/template/, $(ALLAPTTEMPLATES)) \
$(addprefix $(INSTALL_WWWDIR)/apt/css/, $(ALLAPTCSS)) \
$(addprefix $(INSTALL_WWWDIR)/apt/fonts/, $(ALLAPTFONTS)) \
$(addprefix $(INSTALL_WWWDIR)/apt/images/, $(ALLAPTIMAGES))
$(addprefix $(INSTALL_WWWDIR)/apt/images/, $(ALLAPTIMAGES)) \
$(addprefix $(INSTALL_WWWDIR)/apt/js/new/, $(ALLAPTNEWJS)) \
$(addprefix $(INSTALL_WWWDIR)/apt/template/new/, $(ALLAPTNEWTEMPLATES))
cd $(INSTALL_WWWDIR) && \
rm -f portal; \
ln -s apt portal;
......
......@@ -127,7 +127,8 @@ function Do_GetParameters()
}
list ($formfrag, $defaults) = $profile->GenerateFormFragment($paramdefs);
SPITAJAX_RESPONSE(array("formfrag" => htmlentities($formfrag),
"defaults" => $defaults));
"defaults" => $defaults,
"paramdefs"=> json_decode($paramdefs)));
}
#
......
......@@ -561,7 +561,8 @@ $(function ()
ppdivname : "pp-container",
registered : registered,
isadmin : isadmin,
callback : ConfigureDone,
config_callback : ConfigureDone,
modified_callback : function () { ppchanged = true; },
rspec : null,
multisite : multisite,
jacksGraphCallback: updateJacksGraph
......
// Start a Parameterized Profile
//
// TODO: visual grouping of group/structures and lists.
// grey out -/+ and use tooltips to tell people about min/max limits.
//
$(function () {
window.ppstart = (function()
{
'use strict';
var templates = APT_OPTIONS.fetchTemplateList(['ppform-wizard',
'image-picker-modal']);
var ppmodalString = templates['ppform-wizard'];
var imagePickerString = templates['image-picker-modal'];
var debug = 0;
var editor = null;
var editorLarge = null;
var defaults = null;
var ppdivname = null;
var uuid = "";
var registered = true;
var multisite = 0;
var RSPEC = null;
var configuredone_callback = null;
var modified_callback = null;
var warningsfatal = 1;
var imagePicker = null;
var debug = true;
// List of form elements (fields,groups), in order of appearance.
var formFields = [];
// Map groupId to info about the group, which includes fields in group.
var formGroups = {};
var groupTemplateString =
'<div class="row group-row" data-fieldid="<%- fieldid %>"> '+
' <div class="col-xs-offset-0">' +
' <div class="panel" ' +
' style="border-width: 0px; border: none;' +
' box-shadow: none; margin-bottom: 0px; padding-top: 0px;">' +
' <div class="panel-heading" ' +
' style="padding-top: 0px; padding-bottom: 0px;">' +
' <h5 style="display: inline-block;">' +
' <a href="#pp-param-group-subpanel-<%- name %>" ' +
' class="subpanel-collapse-chevron" ' +
' data-toggle="collapse">' +
' <span class="glyphicon glyphicon-chevron-right pull-left"' +
' style="font-weight: bold;"></span>' +
' <span style="font-weight: bold;">&nbsp;&nbsp; ' +
' <%- prompt %></span>' +
' </a>' +
' </h5>' +
' </div>' +
' <div id="pp-param-group-subpanel-<%- name %>" ' +
' class="panel-collapse collapse ' +
' pp-param-group-subpanel-collapse"' +
' style="height: auto;">' +
' <div id="pp-param-group-subpanel-body-<%- name %>" ' +
' style="padding-top: 0px; padding-bottom: 0px" ' +
' class="panel-body">' +
' </div>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
var emptyStructTemplateString =
'<div class="struct-row" data-fieldid="<%- fieldid %>"> ' +
' <div class="col-xs-offset-0">' +
' <div class="panel" ' +
' style="border-width: 0px; border: none;' +
' box-shadow: none; margin-bottom: 0px;">' +
' <div class="panel-heading" ' +
' style="padding-top: 0px; padding-bottom: 0px;">' +
' <h5 style="display: inline-block;">' +
' <span style="font-weight: bold;">&nbsp;&nbsp; ' +
' <%- prompt %></span>' +
' </h5>' +
' <span class="multivalue-struct-button-plus" ' +
' data-toggle="tooltip" ' +
' data-container="body" ' +
' data-trigger="hover" ' +
' title="Add another copy"> ' +
' <button type="button" ' +
' class="btn btn-small btn-default" ' +
' style="margin-left: 10px; padding: 3px;">' +
' <span class="glyphicon glyphicon-plus"></span>' +
' </button>' +
' </span>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
var structSetTemplateString =
'<div class="row structset" data-fieldid="<%- fieldid %>"> ' +
' <div class="col-xs-offset-0">' +
' <div class="panel" ' +
' style="border-width: 0px; border: none;' +
' box-shadow: none; margin-bottom: 0px;">' +
' <div class="panel-heading" ' +
' style="padding-top: 0px; padding-bottom: 0px;">' +
' <h5 style="display: inline-block;">' +
' <a href="#pp-param-structset-subpanel-<%- fieldid %>" ' +
' class="structset-subpanel-collapse-chevron" ' +
' data-toggle="collapse">' +
' <span class="glyphicon ' +
' glyphicon-chevron-right pull-left"' +
' style="font-weight: bold;"></span>' +
' <span style="font-weight: bold;"' +
' >&nbsp;&nbsp;<%- prompt %></span>' +
' </a>' +
' </h5>' +
' <% if (longhelp) { %> ' +
' <span class="pp-param-popover"> ' +
' <a href="#<%- longhelp_id %>" ' +
' data-toggle="collapse" ' +
' data-trigger="hover"> ' +
' <i class="glyphicon glyphicon-question-sign"></i>' +
' </a></span>' +
' <% } %> ' +
' </div>' +
' <% if (longhelp) { %> ' +
' <div id="<%- longhelp_id %>" ' +
' class="panel-collapse collapse panel panel-info ' +
' col-xs-10 col-xs-offset-1 pp-param-help-panel" '+
' style="background-color: #e6f6fa;height: auto;' +
' margin-top: 5px; margin-bottom: 5px;' +
' padding: 5px;" ' +
' data-toggle=collapse><%- longhelp %></div> ' +
' <% } %> ' +
' <div id="pp-param-structset-subpanel-<%- fieldid %>" ' +
' class="panel-collapse collapse ' +
' pp-param-structset-subpanel-collapse"' +
' style="height: auto;">' +
' <div id="pp-param-structset-subpanel-body-<%- fieldid %>" ' +
' style="padding-top: 0px; padding-bottom: 0px;" ' +
' class="panel-body structset-panel-body">' +
' </div>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
var structTemplateString =
'<div class="struct-row" data-fieldid="<%- fieldid %>" ' +
' data-copyindex="<%- index %>"> ' +
' <div class="col-xs-offset-0">' +
' <div class="panel" ' +
' style="border-width: 0px; border: none;' +
' box-shadow: none; margin-bottom: 0px;">' +
' <div class="panel-heading" ' +
' style="padding-top: 0px; padding-bottom: 0px;"> ' +
' <h5 style="display: inline-block;">' +
' <a href="#pp-param-group-subpanel-<%- name %>" ' +
' class="subpanel-collapse-chevron" ' +
' data-toggle="collapse">' +
' <span class="glyphicon ' +
' glyphicon-chevron-right pull-left"' +
' style="font-weight: bold;"></span>' +
' <span style="font-weight: bold;"' +
' >&nbsp;&nbsp;<%- prompt %></span>' +
' </a>' +
' </h5>' +
' <% if (longhelp) { %> ' +
' <span class="pp-param-popover"> ' +
' <a href="#<%- longhelp_id %>" ' +
' data-toggle="collapse" ' +
' data-trigger="hover"> ' +
' <i class="glyphicon glyphicon-question-sign"></i>' +
' </a></span>' +
' <% } %> ' +
' <% if (multivalue) { %> ' +
' <span data-toggle="tooltip" ' +
' data-container="body" ' +
' data-trigger="hover" ' +
' title="Delete this copy" ' +
' class="multivalue-struct-button-minus"> ' +
' <button type="button" ' +
' class="btn btn-small btn-default" ' +
' style="margin-left: 5px; padding: 2px;">' +
' <span class="glyphicon glyphicon-minus"></span>' +
' </button></span>' +
' <span data-toggle="tooltip" ' +
' data-container="body" ' +
' data-trigger="hover" ' +
' title="Add another copy" ' +
' class="multivalue-struct-button-plus"> ' +
' <button type="button" ' +
' class="btn btn-small btn-default" ' +
' style="margin-left: 0px; padding: 2px;">' +
' <span class="glyphicon glyphicon-plus"></span>' +
' </button></span>' +
' <span data-toggle="tooltip" ' +
' data-container="body" ' +
' data-trigger="hover" ' +
' title="Move up" ' +
' class="multivalue-struct-button-up"> ' +
' <button type="button" ' +
' class="btn btn-small btn-default" ' +
' style="margin-left: 0px; padding: 2px;">' +
' <span class="glyphicon glyphicon-arrow-up"></span>' +
' </button></span>' +
' <span data-toggle="tooltip" ' +
' data-container="body" ' +
' data-trigger="hover" ' +
' title="Move down" ' +
' class="multivalue-struct-button-down"> ' +
' <button type="button" ' +
' class="btn btn-small btn-default" ' +
' style="margin-left: 0px; padding: 2px;">' +
' <span class="glyphicon glyphicon-arrow-down"></span>' +
' </button></span>' +
' <% } %> ' +
' </div>' +
' <% if (longhelp) { %> ' +
' <div id="<%- longhelp_id %>" ' +
' class="panel-collapse collapse panel panel-info ' +
' col-xs-10 col-xs-offset-1 pp-param-help-panel" '+
' style="background-color: #e6f6fa;height: auto;' +
' margin-top: 5px; margin-bottom: 5px;' +
' padding: 5px;" ' +
' data-toggle=collapse><%- longhelp %></div> ' +
' <% } %> ' +
' <div id="pp-param-group-subpanel-<%- name %>" ' +
' class="panel-collapse collapse ' +
' pp-param-group-subpanel-collapse"' +
' style="height: auto;">' +
' <div id="pp-param-group-subpanel-body-<%- name %>" ' +
' style="padding-top: 0px; padding-bottom: 0px;" ' +
' class="panel-body">' +
' </div>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
var emptyInputTemplateString =
' <span class="multivalue-button-plus" ' +
' data-toggle="tooltip" ' +
' data-container="body" ' +
' data-trigger="hover" ' +
' title="Add value">' +
' <button type="button" ' +
' data-fieldid="<%- fieldid %>" ' +
' data-fieldname="<%- fieldname %>" ' +
' class="btn btn-small btn-default" ' +
' style="margin: 0px; padding: 3px; ' +
' margin-top: 5px; display: inline-block;">' +
' <span class="glyphicon glyphicon-plus"></span>' +
' </button>' +
' </span>';
var booleanTemplateString =
"<input data-fieldid='<%- fieldid %>' " +
" data-fieldname='<%- fieldname %>' " +
" <%- checked %> " +
" name='<%- name %>' " +
" style='margin: 0px; height: 34px; display: block;' " +
" class='format-me' " +
" data-label='<%- prompt %>' " +
" value='checked' " +
" type='checkbox'>";
var inputTemplateString =
"<input data-fieldid='<%- fieldid %>' " +
" data-fieldname='<%- fieldname %>' " +
" name='<%- name %>' " +
" <% if (multivalue) { %> "+
" style='display: inline-block; width: 75%' " +
" <% } %>" +
" value='<%- value %>' " +
" class='form-control format-me' " +
" data-label='<%- prompt %>' " +
" type='text'>";
var selectTemplateString =
"<select data-fieldid='<%- fieldid %>' " +
" data-fieldname='<%- fieldname %>' " +
" name='<%- name %>' " +
" <% if (multivalue) { %> "+
" style='display: inline-block; width: 75%' " +
" <% } %>" +
" class='form-control format-me' " +
" data-label='<%- prompt %>' " +
" placeholder='Please Select'>" +
" <% _.each(options, function(option, idx) { %> " +
" <% var val,key; %> " +
" <% if (Array.isArray(option)) { %> " +
" <% val = option[0]; %> " +
" <% key = option[1]; %> " +
" <% } else { %> " +
" <% val = key = option; %> "+
" <% } %> " +
" <option " +
" <% if (value && val == value) {%>selected<% } %> "+
" value='<%- val %>'><%- key %></option>" +
" <% }) %> " +
"</select>";
var imageSelectString =
"<div>" +
" <div class='input-group'> " +
" <input id='image-display' " +
" type='text' readonly " +
" class='form-control' " +
" value='<%- display %>'>" +
" <span class='input-group-btn'>" +
" <button class='btn btn-success' id='image-select' " +
" style='height: 34px' " +
" type='button'>" +
" <span class='glyphicon glyphicon-pencil'></span>" +
" </button>" +
" </span> " +
" </div>" +
" <input id='image-value' class='format-me' " +
" data-fieldid='<%- fieldid %>' " +
" data-fieldname='<%- fieldname %>' " +
" data-label='<%- prompt %>' " +
" name='<%- name %>' type='hidden' " +
" value='<%- value %>'>" +
"</div>";
var multivalueControlString =
"<div style='display: inline-block;'>" +
" <span class='hidden multivalue-button-minus' " +
" data-toggle='tooltip' " +
" data-container='body' " +
" data-trigger='hover' " +
" title='Delete this copy'> " +
" <button type='button' " +
" class='btn btn-small btn-default' " +
" style='margin-left: 5px; padding: 2px;'>"+
" <span class='glyphicon glyphicon-minus'></span>" +
"</button></span>" +
"<span class='multivalue-button-plus' " +
" data-toggle='tooltip' " +
" data-container='body' " +
" data-trigger='hover' " +
" title='Add another copy'> " +
" <button type='button' " +
" class='btn btn-small btn-default' " +
" style='margin-left: 0px; padding: 2px'>" +
" <span class='glyphicon glyphicon-plus'></span>" +
"</button></span>" +
"<span class='multivalue-button-up' " +
" data-toggle='tooltip' " +
" data-container='body' " +
" data-trigger='hover' " +
" title='Move up'> " +
" <button type='button' " +
" class='btn btn-small btn-default' " +
" style='margin-left: 0px; padding: 2px'>" +
" <span class='glyphicon glyphicon-arrow-up'></span>" +
"</button></span>" +
"<span class='multivalue-button-down' " +
" data-toggle='tooltip' " +
" data-container='body' " +
" data-trigger='hover' " +
" title='Move down'> " +
" <button type='button' " +
" class='btn btn-small btn-default' " +
" style='margin-left: 0px; padding: 2px'>" +
" <span class='glyphicon glyphicon-arrow-down'></span>" +
"</button></span></div>";
var helpPanelToggleString =
'<div id="pp-param-help-panel-toggle-state" ' +
' style="display: none">closed</div>' +
'<div class="row">' +
' <div class="col-sm-12">' +
' <div id="help_show_all_panel" class="panel" ' +
' style="border-width: 0px; border: none; box-shadow: none;">' +
' <h5>' +
' <a id="pp-param-help-panel-toggle-link" href="#">' +
' <span id="pp-param-help-panel-toggle-glyph-span" ' +
' class="glyphicon glyphicon-plus pull-left" ' +
' style="font-weight: bold; "></span>' +
' <span id="pp-param-help-panel-toggle-link-span" ' +
' style="font-weight: bold; ">' +
' &nbsp;&nbsp; Show All Parameter Help</span>' +
' </a>' +
' </h5>' +
' </div>' +
' </div>' +
'</div>';
var formString =
"<form id='pp-form' " +
" class='form-horizontal' role='form' method='post'>" +
" <div class='row'>" +
" <div id='pp-form-body' class='col-sm-12'></div>" +
" </div>" +
"</form>" +
"<div id='image-picker-body'></div>";
var emptyStructTemplate = _.template(emptyStructTemplateString);
var structSetTemplate = _.template(structSetTemplateString);
var emptyInputTemplate = _.template(emptyInputTemplateString);
var structTemplate = _.template(structTemplateString);
var groupTemplate = _.template(groupTemplateString);
var booleanTemplate = _.template(booleanTemplateString);
var inputTemplate = _.template(inputTemplateString);
var selectTemplate = _.template(selectTemplateString);
var mvalueTemplate = _.template(multivalueControlString);
var imageTemplate = _.template(imageSelectString);
/*
* Generate various type fragments.
*/
function GenerateEmptyField(fieldIndex, details)
{
var html = emptyInputTemplate({
"fieldid" : fieldIndex,
"fieldname" : details.name,
"prompt" : details.description,
});
return html;
}
function GenerateEmptyStruct(fieldIndex, details)
{
var html = emptyStructTemplate({
"fieldid" : details.name,
"fieldname" : details.name,
"prompt" : details.description,
});
return html;
}
function GenerateBoolean(name, fieldIndex, details, value)
{
var html = booleanTemplate({
"fieldid" : fieldIndex,
"fieldname" : details.name,
"name" : name,
"prompt" : details.description,
"checked" : (value ? "checked" : ""),
"multivalue" : details.multiValue,
});
if (details.multiValue) {
html += mvalueTemplate();
}
return html;
}
function GenerateSelect(name, fieldIndex, details, value)
{
var html = selectTemplate({
"fieldid" : fieldIndex,
"fieldname" : details.name,
"name" : name,
"options" : details.legalValues,
"prompt" : details.description,
"value" : value,
"multivalue" : details.multiValue,
});
if (details.multiValue) {
html += mvalueTemplate();
}
return html;
}
function GenerateImage(name, fieldIndex, details, value)
{
var display = imageDisplay(value);
var html = imageTemplate({
"fieldid" : fieldIndex,
"fieldname" : details.name,
"name" : name,
"prompt" : details.description,
"value" : value,
"display" : display,
"multivalue" : details.multiValue,
});
return html;
}
function GenerateInput(name, fieldIndex, details, value)
{
var html = inputTemplate({
"fieldid" : fieldIndex,
"fieldname" : details.name,
"name" : name,
"prompt" : details.description,
"value" : value,
"multivalue" : details.multiValue,
});
if (details.multiValue) {
html += mvalueTemplate();
}
return html;
}
/*
* Create initial value dict for a struct, which starts with the
* defaultValue array, and then lifts up per-field defaults.
*/
function initStructInitialValues(details, defaultValue)
{
var dict = {};
// If initialValues is not defined, then use itemDefaultValue
if (defaultValue === undefined) {
if (details.itemDefaultValue) {
defaultValue = details.itemDefaultValue;
}
else {
defaultValue = {};
}
}
_.each(details.parameterOrder, function (name) {
var pdetails = details.parameters[name];
// Easy case, a plain field.
if (!pdetails.multiValue) {
if (_.has(defaultValue, name)) {
dict[name] = defaultValue[name];
}
else {
dict[name] = pdetails.defaultValue;
}
return;
}
// multivalue fields get a dict too, of all the initial
// values. Just like what we do when the field is not in
// a struct. First an error check, we get a list in the
// paramdefs.
if (_.has(defaultValue, name) &&
!Array.isArray(defaultValue[name])) {
alert("Error in multivalue field in struct");
return;
}
dict[name] = {};
var i = 0;
var m = 0;
// Not sure I like this.
if (_.has(defaultValue, name)) {
m = defaultValue[name].length;
if (pdetails.min && pdetails.min > m) {
m = pdetails.min;
}
}
else if (pdetails.min) {
m = pdetails.min;
}
while (i < m) {
var tname = name;
if (i) {
tname = tname + "-" + i;
}
if (_.has(defaultValue, name) &&
_.size(defaultValue[name]) > i) {
dict[name][tname] = defaultValue[name][i];
}
else if (pdetails.defaultValue &&
pdetails.defaultValue.length > i) {
dict[name][tname] = pdetails.defaultValue[i];
}
else {
dict[name][tname] = pdetails.itemDefaultValue;
}
i++;
}
});
return dict;
}
// A standard (or group) multivalue field.
function initFieldInitialValues(details)
{
var i = 0;
var m = 0;
// Not sure I like this.
if (details.defaultValue) {
if (!Array.isArray(details.defaultValue)) {
console.info("Error in multivalue field in field", details);
return;
}
m = details.defaultValue.length;
if (details.min && details.min > m) {
m = details.min;
}
}
else if (details.min) {
m = details.min;
}
while (i < m) {
var tname = details.name;
if (i) {
tname = tname + "-" + i;
}
if (details.defaultValue &&
details.defaultValue.length > i) {
details.values[tname] = details.defaultValue[i];
}
else {
details.values[tname] = details.itemDefaultValue;
}
i++;
}
}
/*
* Generate the form parts from the paramdefs block.
*/
function InitializeForm(paramdefs)
{
console.info("InitializeForm", paramdefs);
/*
* First pass, associate form elements with their groups.
* This makes it easier to treat the groups as a unit later.
*/
_.each(paramdefs, function(details, name) {
var groupId = null;
var groupName = null;
// Backwards compatibility check for the "advanced" group.
if (_.has(details, "advanced") && details.advanced) {
details["groupId"] = "advanced";
details["groupName"] = "Advanced";
details["hide"] = true;
}
if (_.has(details, "groupId") && details.groupId) {
groupId = details.groupId;
if (_.has(details, "groupName")) {
groupName = details.groupName;
}
else {
groupName = groupId;
}
if (!groupName) {
details.groupName = groupName = groupId;
}
if (!_.has(formGroups, groupId)) {
var field = {
"isgroup" : true,
"groupId" : groupId,
"type" : details.type,
"hashelp" : false,
"visible" : details.hide ? false : true,
};
formGroups[groupId] = {
"id" : groupId,
"prompt" : groupName,
"fields" : {},
"formfield" : field,
};
formFields.push(field);
}
}
else if (details.type == "struct") {
// Convenience to match above.
details["isgroup"] = false;
details["values"] = {};
details["visible"] = {};
details["hashelp"] = false;
/*
* Regarding initial values. When non multivalue,