You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 16:37:07 UTC
[07/49] incubator-taverna-server git commit: taverna-* module names
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/admin.js
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/admin.js b/taverna-server-webapp/src/main/resources/static/admin.js
new file mode 100644
index 0000000..c2c41bf
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/static/admin.js
@@ -0,0 +1,549 @@
+// Wrappers round AJAX calls to simplify *most* of this stuff
+
+/** How to retrieve text asynchronously. */
+function getText(u, done) {
+ $.ajax({
+ type : "GET",
+ url : u,
+ async : true,
+ cache : false,
+ accept : "text/plain",
+ dataType : "text",
+ success : done
+ });
+}
+/** How to retrieve JSON asynchronously. */
+function getJSON(u, done) {
+ $.ajax({
+ type : "GET",
+ url : u,
+ async : true,
+ cache : false,
+ dataType : "json",
+ accept : "application/json",
+ success : done
+ });
+}
+/** How to send a PUT of text asynchronously. */
+function putText(u, val, done) {
+ $.ajax({
+ type : "PUT",
+ url : u,
+ async : false,
+ cache : false,
+ data : val,
+ contentType : "text/plain",
+ dataType : "text",
+ processData : false,
+ success : done,
+ error : function(jqXHR, textStatus, errorThrown) {
+ alert(errorThrown);
+ }
+ });
+}
+/** How to send a PUT of XML asynchronously. */
+function putXML(u, xml, done) {
+ $.ajax({
+ type : "PUT",
+ url : u,
+ async : false,
+ cache : false,
+ contentType : "application/xml",
+ data : new XMLSerializer().serializeToString(xml),
+ success : done,
+ error : function(jqXHR, textStatus, errorThrown) {
+ alert(errorThrown);
+ }
+ });
+}
+/** How to send a POST of XML asynchronously. */
+function postXML(u, xml, done) {
+ $.ajax({
+ type : "POST",
+ url : u,
+ async : false,
+ cache : false,
+ contentType : "application/xml",
+ data : new XMLSerializer().serializeToString(xml),
+ success : done,
+ error : function(jqXHR, textStatus, errorThrown) {
+ alert(errorThrown);
+ }
+ });
+}
+/** How to send a DELETE asynchronously. */
+function deleteUrl(u, done) {
+ $.ajax({
+ type : "DELETE",
+ url : u,
+ async : true,
+ cache : false,
+ success : done,
+ error : function(jqXHR, textStatus, errorThrown) {
+ alert(errorThrown);
+ }
+ });
+}
+
+/** Locates a URL with respect to the administrative REST interface. */
+function where(tail) {
+ return $("#admin")[0].href + "/" + tail;
+}
+
+// Make an XML element structure
+// Derived from hack on Stack Overflow, but with extra tinkering
+/** Function called to create a node in an XML structure. */
+var Node;
+/** Function called to create nodes in an XML structure from an array. */
+var NodeAll;
+(function() {
+ var doc = document.implementation.createDocument(null, null, null);
+ var adminNS = "http://ns.taverna.org.uk/2010/xml/server/admin/";
+ Node = function() {
+ var node = doc.createElementNS(adminNS, arguments[0]), child;
+ for ( var i = 1; i < arguments.length; i++) {
+ child = arguments[i];
+ if (child == undefined)
+ continue;
+ if (typeof child != 'object')
+ child = doc.createTextNode(child.toString());
+ node.appendChild(child);
+ }
+ return node;
+ };
+ NodeAll = function(wrapperElem, wrappedElem, elements) {
+ var node = doc.createElementNS(adminNS, wrapperElem);
+ for ( var i = 0; i < elements.length; i++) {
+ var child = doc.createElementNS(adminNS, wrappedElem);
+ var text = doc.createTextNode(elements[i]);
+ child.appendChild(text);
+ node.appendChild(child);
+ }
+ return node;
+ };
+})();
+
+/** The IDs of boolean-coupled buttons. */
+var buttonlist = [ "allowNew", "logFaults", "logWorkflows", "generateProvenance" ];
+/** The IDs of values that track server variables without setting things. */
+var readonlies = [ "invokationCount", "lastExitCode", "runCount", "startupTime", "operatingCount" ];
+/** The IDs of text/numeric-coupled entries. */
+var entries = [ "defaultLifetime", "executeWorkflowScript", "javaBinary",
+ "registrationPollMillis", "registrationWaitSeconds", "registryHost",
+ "registryPort", "runLimit", "runasPasswordFile", "serverForkerJar",
+ "serverWorkerJar", "usageRecordDumpFile", "operatingLimit",
+ "registryJar" ];
+/** Cached information about users. */
+var userinfo = [];
+/** Extra arguments to pass to the runtime. */
+var extraAry = [];
+
+/** How to update the read-only fields; will be called periodically */
+function updateRO() {
+ $.each(readonlies, function(idx, val) {
+ var widget = $("#" + val);
+ getText(where(val), function(data) {
+ widget.html(data);
+ });
+ });
+ getJSON(where("factoryProcessMapping"),
+ function(data) {
+ var ary = data.stringList.string;
+ var tbl = $("#factoryProcessMapping");
+ tbl.html("<tr><th>User<th>ID</tr>");
+ if (ary != undefined)
+ for ( var i = 0; i < ary.length - 1; i += 2)
+ tbl.append("<tr><td>" + ary[i] + "<td>" + ary[i + 1]
+ + "</tr>");
+ });
+}
+
+/**
+ * Generate a user row with suitable indices, but no content (it will be pushed
+ * into the row later).
+ */
+function userRowHTML(idx) {
+ // USER NAME
+ var content = "<td><span id='username" + idx
+ + "' title='The login name of the user.'></span></td>";
+ // SYSTEM ID MAPPING
+ content += "<td><input id='userlocal"
+ + idx
+ + "' title='The system username to run workflows as, or blank for default.' /></td>";
+ // ENABLED
+ content += "<td><label title='Is this user allowed to log in?' for='useron"
+ + idx + "'>Enabled</label>" + "<input type='checkbox' id='useron"
+ + idx + "' /></td>";
+ // ADMIN
+ content += "<td><label title='Is this user an admin (allowed to access this page)?' for='useradmin"
+ + idx
+ + "'>Admin</label>"
+ + "<input type='checkbox' id='useradmin"
+ + idx + "' /></td>";
+ // SET PASSWORD
+ content += "<td><button title='Set the password for this user.' id='userpass"
+ + idx + "'>Set Password</button></td>";
+ // DELETE
+ content += "<td><button title='Delete this user. Take care to not delete yourself!' id='userdel"
+ + idx + "'>Delete</button></td>";
+
+ return "<tr id='usersep" + idx + "' class='userrows'>"
+ + "<td colspan=6><hr></td></tr>" + "<tr id='userrow" + idx
+ + "' class='userrows'>" + content + "</tr>";
+}
+
+/** How to get the list of permitted workflows; called on demand */
+function refreshWorkflows() {
+ var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows"), wfref = $("#refreshWorkflows");
+ wfbut.button("disable");
+ wfbut1.button("disable");
+ wfref.button("disable");
+ getJSON(where("permittedWorkflowURIs"), function(data) {
+ var s = "";
+ $.each(data.stringList.string || [], function(idx, str) {
+ s += $.trim(str) + "\n";
+ });
+ wftable.val($.trim(s));
+ wfbut.button("enable");
+ wfbut1.button("enable");
+ wfref.button("enable");
+ });
+}
+/** How to set the list of permitted workflows; called when the user clicks */
+function saveWorkflows() {
+ var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows");
+ var xml = NodeAll("stringList", "string", wftable.val().split("\n"));
+ wfbut.button("disable");
+ wfbut1.button("disable");
+ putXML(where("permittedWorkflowURIs"), xml, function() {
+ refreshWorkflows();
+ });
+}
+
+/** How to empty the list of permitted workflows; called when the user clicks */
+function emptyWorkflows() {
+ var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows");
+ var xml = NodeAll("stringList", "string", "");
+ wfbut.button("disable");
+ wfbut1.button("disable");
+ putXML(where("permittedWorkflowURIs"), xml, function() {
+ refreshWorkflows();
+ });
+}
+
+/** How to update the table of users; called on demand */
+function refreshUsers() {
+ var usertable = $("#userList");
+ getJSON(where("users"), function(data) {
+ $(".userrows").remove();
+ userinfo = [];
+ $.each(data.userList.user, function(idx, url) {
+ usertable.append(userRowHTML(idx));
+ var i = idx;
+ userinfo[i] = {
+ url : url
+ };
+ getJSON(url, function(data) {
+ var model = userinfo[i].model = data.userDesc;
+ $("#username" + i).html(model.username);
+ $("#userlocal" + i).val(model.localUserId).change(function() {
+ updateUser(i, "localUserId", $(this).val());
+ });
+ $("#useron" + i).button().attr("checked", model.enabled)
+ .button("refresh").click(
+ function() {
+ updateUser(i, "enabled", $(this).attr(
+ "checked") == "checked");
+ });
+ $("#useradmin" + i).button().attr("checked", model.admin)
+ .button("refresh").click(
+ function() {
+ updateUser(i, "admin", $(this).attr(
+ "checked") == "checked");
+ });
+ $("#userpass" + i).button({
+ icons : {
+ primary : "ui-icon-alert"
+ }
+ }).click(function() {
+ updatePasswordUser(i);
+ });
+ $("#userdel" + i).button({
+ icons : {
+ primary : "ui-icon-trash"
+ },
+ text : false
+ }).click(function() {
+ deleteUser(i);
+ });
+ });
+ return true;
+ });
+ });
+}
+
+/** How to delete a user by index (with dialog) */
+function deleteUser(idx) {
+ $("#dialog-confirm").dialog({
+ modal : true,
+ autoOpen : false,
+ buttons : {
+ "OK" : function() {
+ $(this).dialog("close");
+ deleteUrl(userinfo[idx].url, function() {
+ refreshUsers();
+ });
+ },
+ "Cancel" : function() {
+ $(this).dialog("close");
+ }
+ }
+ });
+ $("#dialog-confirm").dialog("open");
+}
+
+/** How to update a user's password by index (with dialog) */
+function updatePasswordUser(idx) {
+ $("#change-password").val("");
+ $("#change-password2").val("");
+ $("#dialog-password").dialog({
+ modal : true,
+ autoOpen : false,
+ buttons : {
+ "OK" : function() {
+ $(this).dialog("close");
+ var pass = $("#change-password").val();
+ var pass2 = $("#change-password2").val();
+ $("#change-password").val("");
+ $("#change-password2").val("");
+ if (pass.equals(pass2))
+ updateUser(idx, "password", pass);
+ },
+ "Cancel" : function() {
+ $(this).dialog("close");
+ $("#change-password").val("");
+ }
+ }
+ });
+ $("#dialog-password").dialog("open");
+}
+
+/** How to set a specific field of a user record */
+function updateUser(idx, field, value) {
+ var model = userinfo[idx].model;
+ var xml = Node("userDesc", Node("username", model.username),
+ field == "password" ? Node("password", value) : undefined,
+ field == "localUserId" ? Node("localUserId", value)
+ : model.localUserId == undefined ? undefined : Node(
+ "localUserId", model.localUserId), Node("enabled",
+ field == "enabled" ? value : model.enabled), Node("admin",
+ field == "admin" ? value : model.admin));
+ putXML(userinfo[idx].url, xml, function() {
+ refreshUsers();
+ });
+}
+
+/** How to configure all the buttons and entries */
+function connectButtonsAndEntries() {
+ $.each(buttonlist, function(idx, val) {
+ var widget = $("#" + val);
+ var u = where(val);
+ widget.button();
+ getText(u, function(data) {
+ widget.attr('checked', (data + "") != "false");
+ widget.button("refresh");
+ });
+ widget.change(function() {
+ putText(u, widget.attr("checked") == "checked", function(data) {
+ widget.attr('checked', (data + "") != "false");
+ widget.button("refresh");
+ return true;
+ });
+ });
+ });
+ $.each(entries, function(idx, val) {
+ var widget = $("#" + val);
+ var u = where(val);
+ getText(u, function(data) {
+ widget.val(data);
+ });
+ widget.change(function() {
+ putText(u, widget.val(), function(data) {
+ widget.val(data);
+ return true;
+ });
+ });
+ });
+}
+
+/** What happens when the user tries to make a new user */
+function makeNewUser() {
+ var sysid = $("#newSysID").val();
+ var newuserinfo = {
+ admin : $("#newAdmin").attr("checked") == "checked",
+ enabled : $("#newEnabled").attr("checked") == "checked",
+ username : $("#newUsername").val(),
+ password : $("#newPassword").val()
+ };
+ // Blank out the password immediately!
+ $("#newPassword").val("");
+ if (sysid.length > 0) {
+ newuserinfo.localUserId = sysid;
+ }
+ if (newuserinfo.username == "" || newuserinfo.password == "") {
+ alert("Won't create user; need a username and a password!");
+ return;
+ }
+ var xml = newuserinfo = Node("userDesc", Node("username",
+ newuserinfo.username), Node("password", newuserinfo.password),
+ newuserinfo.localUserId == undefined ? undefined : Node(
+ "localUserId", newuserinfo.localUserId), Node("enabled",
+ newuserinfo.enabled), Node("admin", newuserinfo.admin));
+ postXML(where("users"), xml, function() {
+ refreshUsers();
+ });
+}
+
+/** Handle the extra arguments */
+function loadExtraArgs() {
+ getJSON(where("extraArguments"),
+ function(data) {
+ var rows = data.stringList.string || [];
+ if ((typeof rows) == "string")
+ rows = [ rows ];
+ $(".extraargrow").remove();
+ extraAry = rows;
+ var i;
+ function row() {
+ var buf = "<tr class='extraargrow'>";
+ for ( var i = 1; i < arguments.length; i++)
+ buf += "<td>" + arguments[i] + "</td>";
+ return $(arguments[0]).append(buf + "</tr>");
+ }
+ function delbutn(id, what) {
+ return "<button id='" + id + "' title='Delete this " + what
+ + ".'>Del</button>";
+ }
+ for (i = 0; i < extraAry.length; i++) {
+ var rowid = "extradel" + i;
+ if (rows[i].match("^-D")) {
+ var m = rows[i].match("^-D([^=]*)=(.*)$");
+ row("#extraArguments-prop", delbutn(rowid,
+ "property assignment"), "<tt><b>-D</b>" + m[1]
+ + "<b>=</b>" + m[2] + "</tt>");
+ } else if (rows[i].match("-E")) {
+ var m = rows[i].match("^-E([^=]*)=(.*)$");
+ row("#extraArguments-env", delbutn(rowid,
+ "environment assignment"), "<tt><b>-E</b>"
+ + m[1] + "<b>=</b>" + m[2] + "</tt>");
+ } else {
+ var m = rows[i].match("^-J(.*)$");
+ row("#extraArguments-runtime", delbutn(rowid,
+ "runtime parameter"), "<tt><b>-J</b>" + m[1]
+ + "</tt>");
+ }
+ $("#" + rowid).button({
+ icons : {
+ primary : "ui-icon-trash"
+ },
+ text : false
+ }).click(
+ (function(row) {
+ return function() {
+ extraAry.splice(row, 1);
+ var xml = NodeAll("stringList", "string",
+ extraAry);
+ putXML(where("extraArguments"), xml,
+ function() {
+ loadExtraArgs();
+ });
+ };
+ })(i));
+ }
+ });
+}
+
+/** Run a dialog for creating an extra argument. */
+function addExtraArg(dialogId, prefix, part1id, part2id) {
+ $(dialogId).dialog({
+ modal : true,
+ autoOpen : false,
+ buttons : {
+ "OK" : function() {
+ $(this).dialog("close");
+ var str = prefix + $(part1id).val();
+ if (part2id != undefined)
+ str += "=" + $(part2id).val();
+ extraAry.push(str);
+ var xml = NodeAll("stringList", "string", extraAry);
+ putXML(where("extraArguments"), xml, function() {
+ loadExtraArgs();
+ });
+ },
+ "Cancel" : function() {
+ $(this).dialog("close");
+ }
+ }
+ });
+ $(dialogId).dialog("open");
+}
+
+/** Start everything going on page load */
+$(function() {
+ // Must be done in this order because the accordion is inside a tab
+ $("#a-worker").accordion({
+ collapsible : true,
+ fillSpace : true,
+ autoHeight : false
+ });
+ $("#body").tabs({
+ selected : 0
+ });
+ $("#saveWorkflows").button({
+ disabled : true
+ }).click(function(event) {
+ saveWorkflows();
+ event.preventDefault();
+ });
+ $("#refreshWorkflows").button({
+ disabled : true
+ }).click(function(event) {
+ refreshWorkflows();
+ event.preventDefault();
+ });
+ $("#emptyWorkflows").button({
+ disabled : true
+ }).click(function(event) {
+ emptyWorkflows();
+ event.preventDefault();
+ });
+
+ // Make the link to the list of usage records point correctly
+ // Original plan called for browsable table, but that's too slow
+ $("#ur").attr("href", where("usageRecords"));
+
+ connectButtonsAndEntries();
+ updateRO();
+ setInterval(updateRO, 30000);
+ refreshUsers();
+ refreshWorkflows();
+ $("#newEnabled").button();
+ $("#newAdmin").button({
+ icons : {
+ primary : "ui-icon-alert"
+ }
+ });
+ $("#makeNewUser").button().click(function() {
+ makeNewUser();
+ });
+ $("#extra-prop-add").button().click(function() {
+ addExtraArg("#dialog-property", "-D", "#prop-key", "#prop-value");
+ });
+ $("#extra-env-add").button().click(function() {
+ addExtraArg("#dialog-environment", "-E", "#env-key", "#env-value");
+ });
+ $("#extra-run-add").button().click(function() {
+ addExtraArg("#dialog-runtime", "-J", "#runtime-value");
+ });
+ loadExtraArgs();
+});