polardbxengine/storage/ndb/mcc/frontend/welcome.html

412 lines
22 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!--
Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-->
<html dir="ltr" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
<title>MySQL Cluster</title>
<link rel="icon" type="image/x-icon" href="/img/favicon.ico"/>
<link rel="stylesheet" type="text/css"
href="dojo/dijit/themes/claro/claro.css"/>
<link rel="stylesheet" type="text/css" href="css/welcome.css"/>
<style type="text/css">
@import "dojo/dojox/form/resources/CheckedMultiSelect.css";
</style>
<script type="text/javascript" src="dojo/dojo/dojo.js" djConfig="parseOnLoad: true, locale: 'en'"></script>
<script type="text/javascript">
// Path to top level mcc module
dojo.registerModulePath("mcc", "../../js/mcc");
dojo.require("dijit.form.Button");
dojo.require("dojo.dom");
dojo.require("dojo.dom-construct");
dojo.require("dojo.domReady!");
dojo.require("dojox.widget.Standby");
// MCC modules immediately required
if (!!window.MSInputMethodContext && !!document.documentMode) {
dojo.require("mcc.userconfigIE");
} else {
dojo.require("mcc.userconfig");
}
function parseURLParams(url) {
var queryStart = url.indexOf("?") + 1,
queryEnd = url.indexOf("#") + 1 || url.length + 1,
query = url.slice(queryStart, queryEnd - 1),
pairs = query.replace(/\+/g, " ").split("&"),
parms = {}, i, n, v, nv;
if (query === url || query === "") return;
//Actually there are no K/V pairs in this concrete example.
//The output is in form of [config1.mcc, config2.mcc,...].
return pairs;
}
var url = window.location.href;
var cfgList = parseURLParams(url);
console.debug('[DBG]cfgList: ' + cfgList);
let picked = 'New configuration';
var standby = new dojox.widget.Standby({target: "configure-box"});
function doStuff() {
standby.show();
function do_post(msg) {
// Convert to json string
var jsonMsg = JSON.stringify(msg); //dojo.toJson(msg);
//var dbgMsg = JSON.stringify(msg); //dojo.toJson(msg);
// Return deferred from xhrPost
return dojo.xhrPost({
url: "/cmd",
headers: { "Content-Type": "application/json" },
postData: jsonMsg,
handleAs: "json"
});
}
// Generic error handler closure
function errorHandler(req, onError) {
if (onError) {
return onError;
} else {
return function (error) {
console.error("An error occurred while executing '" + req.cmd +
" (" + req.seq + ")': " + error);
};
}
}
// Generic reply handler closure
function replyHandler(onReply, onError) {
return function (reply) {
if (reply && reply.stat && reply.stat.errMsg != "OK") {
if (onError) {
onError(reply.stat.errMsg, reply);
} else {
alert(reply.stat.errMsg);
}
} else {
try{
onReply(reply);
} catch (E) {
alert("Error in formatting reply.");
}
}
};
}
function cffileExistsReq(mesg, onReply, onError) {
console.debug("[DBG]Composing cffileExistsReq message for host localhost.");
var ms = mesg;
// Call do_post, provide callbacks
do_post(ms).then(replyHandler(onReply, onError),
errorHandler(ms.head, onError));
}
function createCfgFileReq(mesg, onReply, onError) {
console.debug("[DBG]Composing createCfgFileReq message for host localhost.");
var ms = mesg;
// Call do_post, provide callbacks
do_post(ms).then(replyHandler(onReply, onError),
errorHandler(ms.head, onError));
}
function readCfgFileReq(mesg, onReply, onError) {
console.debug("[DBG]Composing readCfgFileReq message for host localhost.");
var ms = mesg;
// Call do_post, provide callbacks
do_post(ms).then(replyHandler(onReply, onError),
errorHandler(ms.head, onError));
}
var cf = picked;
if (cf) {
if (cf == 'New configuration') {
cf = "NewConfig";
cf = prompt("Please provide the name for new configuration file: ");
if (cf == null || cf == "") {
//Cancelled or empty.
console.warn("window.location.reload() - CF name NULL or EMPTY");
standby.hide();
window.location.reload();
return;
}
}
// We are no longer sending cfgname.MCC from back end!
if ( /\.(mcc)$/i.test(cf) === false ) {
cf += '.mcc';
}
mcc.userconfig.setConfigFile(cf);
var defCfg = mcc.userconfig.getDefaultCfg();
var fileExists = false;
var res = new dojo.Deferred();
var msg = {
head: {cmd: "cffileExistsReq", seq: 0},
body: {
ssh: {keyBased: false, user: "", pwd: ""},
hostName: 'localhost',
path: "~",
fname: cf
}
};
cffileExistsReq(
msg,
function (reply) {
//File with that name already exists. Will load that later on.
console.debug("[DBG]reply.body.hostRes.exists is: " + reply.body.hostRes.exists);
fileExists = reply.body.hostRes.exists == 1;
res.resolve(true);
return res;
},
function (errMsg, reply) {
console.error("Error happened while checking for existence of " + cf + ' file!'+
"Error message is: " + errMsg);
alert("Error happened while checking for existence of " + cf + ' file!'+
"Error message is: " + errMsg);
res.resolve(false);
return res;
}
);
res.then(function(success){
console.debug("[DBG]cffileExistsReq success: ", success);
return true;
}, function(error){
console.error("cffileExistsReq error: ", error);
return false;
}).then(function(info){
console.debug("[DBG]cffileExistsReq has finished with success status: " + info);
if (info) {
//var cfNoExt = cf.substr(0, cf.lastIndexOf('.')) || cf;
console.debug("[DBG]FileExists is NOT " + (!fileExists));
if (!fileExists) {
var res2 = new dojo.Deferred();
console.debug("[DBG]Config doesn't exit. Creating file, writing defaults.");
//Fill new config with predefined defaults:
msg = {
head: {cmd: "createCfgFileReq", seq: 1},
body: {
ssh: {keyBased: false, user: "", pwd: ""},
hostName: 'localhost',
path: "~",
fname: cf,
contentString: defCfg,
phr: ""
}
};
createCfgFileReq(
msg,
function (resFNC) {
console.debug("[DBG]Configuration didn't exits. Created.");
res2.resolve(true);
return res2;
},
function (errMsgFNC) {
console.error("Unable to create config file " + cf+ " in HOME directory: " + errMsgFNC);
//This is bad, bail out and just work from tree.
cf = "";
res2.resolve(false);
return res2;
}
);
res2.then(function(success1){
console.debug("[DBG]createCfgFileReq success: ", success1);
return true;
}, function(error1){
console.error("createCfgFileReq error: ", error1);
return false;
}).then(function(info1){
console.debug("[DBG]createCfgFileReq has finished with success status: ", info1);
if (info1) {
console.debug("[DBG]Setting global conf file.");
mcc.userconfig.setConfigFile(cf);
mcc.userconfig.setConfigFileContents(defCfg);
window.name = JSON.stringify({
"CFC": mcc.userconfig.getConfigFileContents(),
"CF": cf,
"CFPP": ""});
standby.hide();
window.open('content.html', '_self');
}
});
} else {
console.debug("[DBG]Reading from existing config file.");
console.debug("[DBG]Setting global conf file.");
mcc.userconfig.setConfigFile(cf);
msg = {
head: {cmd: "readCfgFileReq", seq: 1},
body: {
ssh: {keyBased: false, user: "", pwd: ""},
hostName: 'localhost',
path: "~",
fname: cf,
phr: ""
}
};
readCfgFileReq(
msg,
function (reply) {
console.debug("[DBG]readCfgFileReq has finished with success.");
// Just in case someone thinks it's funny to create empty mcc file...
if (reply.body.hostRes.contentString.length > 10) {
// "Someone" thought _on_ would be nice value for Boolean.
// Now have to convert to _true_.
mcc.userconfig.setConfigFileContents(
reply.body.hostRes.contentString.replace(/"on"/g, 'true'));
} else {
mcc.userconfig.setConfigFileContents(defCfg);
}
window.name = JSON.stringify({
"CFC": mcc.userconfig.getConfigFileContents(),
"CF": cf,
"CFPP": ""});
standby.hide();
window.open('content.html', '_self');
},
function (errMsgFNC) {
console.error("window.location.reload() - errMsgFNC");
standby.hide();
alert("Unable to read config file " + cf +
" in HOME directory: " + errMsgFNC);
//This is bad, bail out and just work from tree.
cf = "";
window.location.reload();
return;
}
);
}
}
});
} else {
console.debug("[DBG]window.location.reload() - LAST");
standby.hide();
window.location.reload();
return;
}
} //doStuff()
dojo.ready(function() {
// Check browser type
var supportedUa = navigator.userAgent.match(/firefox|safari|chrome|msie/gi);
console.debug("[DBG]Browser application name is " + navigator.appName);
console.debug("[DBG]Browser application version is " + navigator.appVersion);
console.debug("[DBG]User agent string is: " + navigator.userAgent);
console.debug("[DBG]User agent " + supportedUa + " is supported");
if (!supportedUa) {
alert("You seem to be using a " + navigator.appName +
" browser, which is currently not supported by the " +
"MySQL Cluster configuration tool. You may choose to " +
"continue anyway, but beware that the tool may not " +
"work as intended.");
}
document.body.appendChild(standby.domNode);
standby.startup();
// No need to send path along as it is always HOME.
function populateMultiSelect(optionData){
require([
"dojox/form/CheckedMultiSelect",
"dojo/dom", "dojo/_base/window", "dojo/domReady!"
], function(CheckedMultiSelect, dom, win){
var sel = dojo.byId('sid1');
var ss1 = new CheckedMultiSelect({
name: 'sid1',
options: optionData,
onChange: function(val){
picked = val;
console.debug("[DBG]PICKED: " + picked);
},
multiple: false,
class: "narrow wrap",
style: "white-space: normal; height: 85%;"
}, sel);
ss1.startup();
document.getElementById("sid1").focus();
ss1.on("keydown", function(e) {
console.debug("[DBG]CMS.keydown");
switch(e.keyCode) {
case dojo.keys.ENTER:
dojo.stopEvent(e);
console.debug("[DBG]CMS.keydown ENTER");
break;
case dojo.keys.TAB:
dojo.stopEvent(e);
console.debug("[DBG]CMS.keydown TAB");
break;
default:
}
});
});
}
var opts = new Array();
opts.push(
{value: "New configuration",
label: "New configuration",
selected: true}
);
if (cfgList) {
console.debug("[DBG]Found " + cfgList.length + " configurations.");
console.info('List of configurations found: %s', cfgList);
for (var i = 0; i < cfgList.length; i++) {
opts.push({value:cfgList[i], label:cfgList[i]});
}
} else {
console.warn("No existing configurations found.");
}
populateMultiSelect(opts);
});
</script>
</head>
<body class="claro">
<!-- Welcome title image -->
<div id="title"><img alt="Oracle logo" src="img/welcome-title.png"></div>
<!-- Big MySQL Logo image in the background -->
<div id="mysql-logo"><img alt="MySQL logo" src="img/welcome-mysql-logo.png"></div>
<!-- Configuration box: Start from scratch or continue -->
<div id="configure-box-wrapper" style="display: flex; flex-wrap: nowrap;top: 300px">
<div id="intro-box" style="width: -webkit-fill-available; display: flow-root; margin-right: 2%; height: 400px; font-size: large;color: wheat;">
<h2>&emsp;MCC quick reference:</h2>
<p>&emsp;&#10148;&emsp;Create <b>New configuration</b> or resume work on existing one by picking it from the list.</p>
<p>&emsp;&#10148;&emsp;RUN configuration will load it from disk to MCC and allow you to continue working on/with it.</p>
<p>&emsp;&#10148;&emsp;SECURITY: The configuration files are located in your HOME/.mcc directory and stored in plain text. Configuration files do not store sensitive information, like passwords, but do store user names and External/Internal IP addresses of hosts.</p>
<p>&emsp;&#10148;&emsp;SECURITY: Please use properly signed certificate to encrypt communication between front and back end.</p>
<p>&emsp;&#10148;&emsp;Make sure to allow pop-up windows in the browser where MCC runs as we communicate important things using that mechanism.</p>
</div>
<div id="configure-box" style="margin: 5px auto; height: 400px; float: right;position: relative">
<div id = "configListContainer" style="width: 95%; height: 85%;margin: 10 auto;float: left;text-align: left;border: 0;">
<select id="sid1" class="narrow wrap"></select>
</div>
<div id = "configBtnContainer" style="width: 95%; margin: 10 auto; position: absolute; bottom: 0;">
<button
type="button"
id="createNewCluster"
style="width: 100%;height: 80%;margin: 5 auto;float: left;text-align: center;border: 2px solid;background-color: #011D33;font-size: large;"
>RUN configuration
</button>
<script type="text/javascript">
function clickRunB() {
doStuff();
}
document.getElementById("createNewCluster").addEventListener("click", clickRunB);
</script>
</div>
</div><!--CONFIGUREBOX-->
</div> <!--CONFIGUREBOX WRAPPER-->
</body>
</html>