Commit 47ec24be authored by Erik Tute's avatar Erik Tute
Browse files

Implemented basic support for ehrbase

parent a58c9f47
namespace HaMSTR_ETLBuilder_Forms
using System;
namespace HaMSTR_ETLBuilder_Forms
{
partial class ETLBuilder_Initial
{
......@@ -1182,6 +1184,21 @@
}
private void tabPageMapping_Click(object sender, EventArgs e)
{
}
private void cmbBoxThinkAddress_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void cmbBoxTemplateId_SelectedIndexChanged(object sender, EventArgs e)
{
}
#endregion
private System.Windows.Forms.DataGridView gridRelData;
......
......@@ -54,6 +54,12 @@ namespace HaMSTR_ETLBuilder_Forms
//Dictionary für die Einstellungen bzgl Think-Plattform vorbefüllen
initializeThinkParams();
//just some lazy dev stuff
/*Thread.Sleep(1000);
load_project_file(Directory.GetCurrentDirectory()+ "\\project.json", Directory.GetCurrentDirectory());
Thread.Sleep(1000);
btnExecQuery_Click(null, null);*/
//myBrowser.ShowDevTools();
}
//Verhalten beim Schließen der Form (tritt ein, bevor die Form tatsächlich geschlossen wird)
......@@ -159,7 +165,7 @@ namespace HaMSTR_ETLBuilder_Forms
dbConnect conStoreErrors = new dbConnect();
ServerResponseHandling responseHandle = null;
ThinkHandle thinkHandle = null;
RepoHandle repoHandle = null;
ContributionsHandler contributionsHandler = null;
ChromiumWebBrowser myBrowser = new ChromiumWebBrowser(String.Format("file:///{0}/HTML/index.html", Directory.GetCurrentDirectory()));
......@@ -690,19 +696,19 @@ namespace HaMSTR_ETLBuilder_Forms
//have to be a global variables, so they will not be destroyed when method is done but requests are pending
responseHandle = new ServerResponseHandling(int.Parse(tBoxNrRequestStats.Text));
thinkHandle = new ThinkHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, logEvents, responseHandle);
responseHandle.thinkHandle = thinkHandle;
repoHandle = new RepoHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, logEvents, responseHandle);
responseHandle.repoHandle = repoHandle;
contributionsHandler = new ContributionsHandler(thinkHandle);
contributionsHandler = new ContributionsHandler(repoHandle);
responseHandle.contributionsHandler = contributionsHandler;
contributionsHandler.namespaceTag = txtBoxNamespaceTag.Text.ToString();
#endregion
//try to retrieve existing ehrIds in namespace with one query (to avoid the two queries for each single existing ehrId)
string aql = "SELECT e / ehr_id / value AS ehrId, e/ ehr_status / subject / external_ref / id / value AS subjectId FROM EHR e " +
"WHERE e / ehr_status / subject / external_ref /namespace = \""+ txtBoxNamespaceTag.Text +"\"";
dynamic res = JsonConvert.DeserializeObject<ExpandoObject>(thinkHandle.httpRequest("query?aql=" + aql, false, null, null), new ExpandoObjectConverter());
string aql = "SELECT e/ehr_id/value AS ehrId, e/ehr_status/subject/external_ref/id/value AS subjectId FROM EHR e " +
"WHERE e/ehr_status/subject/external_ref/namespace = '"+ txtBoxNamespaceTag.Text +"'";
dynamic res = JsonConvert.DeserializeObject<ExpandoObject>(repoHandle.httpRequest("query?aql=" + aql, false, null, null), new ExpandoObjectConverter());
if (res != null)
{
foreach (dynamic row in res.resultSet)
......@@ -710,7 +716,6 @@ namespace HaMSTR_ETLBuilder_Forms
contributionsHandler.subjectIdsToEhrIds[row.subjectId] = row.ehrId;
}
}
//create contributions from data
createContributions(contributionsHandler, dbConnection.dt);
logEvents.inputText = DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt") +
......@@ -732,29 +737,6 @@ namespace HaMSTR_ETLBuilder_Forms
{
contributionsHandler.skipInstructionsJSON = (!cBoxIncludeInstructionsJSON.Checked);
//get new InstructionsString
/*string returnedInstructions = "";
myBrowser.ExecuteScriptAsync("iVM.toJSON();");
var task = myBrowser.EvaluateScriptAsync("(function() {return iVM.newInstructions;})();");
var complete = task.ContinueWith(t =>
{
if (!t.IsFaulted)
{
var response = t.Result;
if (response.Success && response.Result != null)
{
returnedInstructions = response.Result.ToString();
}
}
});
complete.Wait();
returnedInstructions = returnedInstructions.Replace("\\n", "");
if (returnedInstructions != "")
{
txtBoxInstructionsString.Text = returnedInstructions;
}*/
//set handlers
InstructionsHandler instructionsHandler = new InstructionsHandler(txtBoxInstructionsString.Text, contributionsHandler);
......@@ -802,11 +784,11 @@ namespace HaMSTR_ETLBuilder_Forms
private void button1_Click_1(object sender, EventArgs e)
{
//string tmpStr = "";
foreach (KeyValuePair<string, bool> tmp in thinkHandle.openRequests)
foreach (KeyValuePair<string, bool> tmp in repoHandle.openRequests)
{
problematicRequests.TryAdd(tmp.Key, "no response");
}
thinkHandle.openRequests = new ConcurrentDictionary<string, bool>();
repoHandle.openRequests = new ConcurrentDictionary<string, bool>();
foreach (KeyValuePair<string, string> tmp in responseHandle.tmpProblematicRequests)
{
......@@ -913,7 +895,7 @@ namespace HaMSTR_ETLBuilder_Forms
{
if (txtBoxInstructionsString.Text == null) { txtBoxInstructionsString.Text = ""; }
ThinkHandle thinkHandle = new ThinkHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, null, null);//responseHande is just needed for async usage
RepoHandle repoHandle = new RepoHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, null, null);//responseHande is just needed for async usage
if (string.IsNullOrWhiteSpace(cmbBoxTemplateId.SelectedItem.ToString())) {
MessageBox.Show("Please select TemplateId.");
......@@ -921,17 +903,16 @@ namespace HaMSTR_ETLBuilder_Forms
}
//assemble infos for ETL-Builder-Tool and log them as JSON-String
EtlBuilderInfo etlBuilderInfo = new EtlBuilderInfo(dbConnection.previewDataTable(dbConnection.dt, 100), txtBoxInstructionsString.Text, cmbBoxTemplateId.SelectedItem.ToString(), thinkHandle);
EtlBuilderInfo etlBuilderInfo = new EtlBuilderInfo(dbConnection.previewDataTable(dbConnection.dt, 100), txtBoxInstructionsString.Text, cmbBoxTemplateId.SelectedItem.ToString(), repoHandle);
myBrowser.Reload(true);
Thread.Sleep(200);
Thread.Sleep(500);
myBrowser.ExecuteScriptAsync("var iVM = new InstructionsVM(); ko.applyBindings(iVM);");
Thread.Sleep(300);
myBrowser.ExecuteScriptAsync("iVM.addExampleData(" + etlBuilderInfo.exampleDataJSON + ");");
myBrowser.ExecuteScriptAsync("iVM.addInstructions("+ etlBuilderInfo.columnInstructionsJSON.Replace("\n", " ") + ");");
myBrowser.ExecuteScriptAsync("iVM.addPaths(" + etlBuilderInfo.templatePathesJSON.Replace("\n", " ") + ");");
myBrowser.ExecuteScriptAsync("iVM.addOPT(" + etlBuilderInfo.templateOPTJSON.Replace("\n", " ") + ");");
//myBrowser.ShowDevTools();
}
catch (Exception ex)
{
......@@ -952,48 +933,52 @@ namespace HaMSTR_ETLBuilder_Forms
if (openFileTxtInstructions.ShowDialog() == DialogResult.OK)
{
var converter = new ExpandoObjectConverter();
StreamReader stream = new StreamReader(openFileTxtInstructions.FileName);
dynamic project = JsonConvert.DeserializeObject<ExpandoObject>(stream.ReadToEnd(), converter);
stream.Close();
load_project_file(openFileTxtInstructions.FileName, curDir);
}
}
cBoxExcelfile.Checked = project.excel;
cBoxPostgres.Checked = project.postgresDB;
cBoxSqlServer.Checked = project.msSQL;
txtBoxConnString.Text = project.connString;
txtBoxSqlQuery.Text = project.sqlQuery;
cBoxErrorLog.Checked = project.logErr;
cBoxErrorDbPg.Checked = project.postgresErr;
cBoxErrorDbSqlServer.Checked = project.mssqlErr;
txtBoxErrorConnString.Text = project.connStrErr;
txtBoxErrorSqlStatement.Text = project.sqlErr;
try { cmbBoxThinkAddress.Text = project.thinkAddress; } catch (RuntimeBinderException) { cmbBoxThinkAddress.SelectedIndex = 0; }
try { cmbBoxTemplateId.Text = project.templateId; } catch (RuntimeBinderException) { cmbBoxTemplateId.SelectedIndex = 0; }
txtBoxThinkUser.Text = project.repoUser;
try { txtBoxThinkPwd.Text = project.repoPwd; } catch (RuntimeBinderException) { } //option for manually set password in testsettings
txtBoxNamespaceTag.Text = project.repoNamespace;
txtBoxInstructionsString.Text = project.instructions;
try { tBoxNrRequestStats.Text = project.nrRequestStats; } catch (RuntimeBinderException) { tBoxNrRequestStats.Text = "4"; }
try { tBoxDummyEHRId.Text = project.dummyEHRId; } catch (RuntimeBinderException) { tBoxDummyEHRId.Text = "null"; }
try { cBoxIncludeInstructionsJSON.Checked = project.includeInstructionsJSON; } catch (RuntimeBinderException) { cBoxIncludeInstructionsJSON.Checked = false; }
cBoxStoreProblematicRequests.Checked = project.storeProblematic;
cBoxStoreLastWaitingContributions.Checked = project.storeRemainingContributions;
if (txtBoxThinkPwd.Text == "") //just a dev convenience thing, try to load pw from another file
private void load_project_file(string filename, string curDir)
{
var converter = new ExpandoObjectConverter();
StreamReader stream = new StreamReader(filename);
dynamic project = JsonConvert.DeserializeObject<ExpandoObject>(stream.ReadToEnd(), converter);
stream.Close();
cBoxExcelfile.Checked = project.excel;
cBoxPostgres.Checked = project.postgresDB;
cBoxSqlServer.Checked = project.msSQL;
txtBoxConnString.Text = project.connString;
txtBoxSqlQuery.Text = project.sqlQuery;
cBoxErrorLog.Checked = project.logErr;
cBoxErrorDbPg.Checked = project.postgresErr;
cBoxErrorDbSqlServer.Checked = project.mssqlErr;
txtBoxErrorConnString.Text = project.connStrErr;
txtBoxErrorSqlStatement.Text = project.sqlErr;
try { cmbBoxThinkAddress.Text = project.thinkAddress; } catch (RuntimeBinderException) { cmbBoxThinkAddress.SelectedIndex = 0; }
try { cmbBoxTemplateId.Text = project.templateId; } catch (RuntimeBinderException) { cmbBoxTemplateId.SelectedIndex = 0; }
txtBoxThinkUser.Text = project.repoUser;
try { txtBoxThinkPwd.Text = project.repoPwd; } catch (RuntimeBinderException) { } //option for manually set password in testsettings
txtBoxNamespaceTag.Text = project.repoNamespace;
txtBoxInstructionsString.Text = project.instructions;
try { tBoxNrRequestStats.Text = project.nrRequestStats; } catch (RuntimeBinderException) { tBoxNrRequestStats.Text = "4"; }
try { tBoxDummyEHRId.Text = project.dummyEHRId; } catch (RuntimeBinderException) { tBoxDummyEHRId.Text = "null"; }
try { cBoxIncludeInstructionsJSON.Checked = project.includeInstructionsJSON; } catch (RuntimeBinderException) { cBoxIncludeInstructionsJSON.Checked = false; }
cBoxStoreProblematicRequests.Checked = project.storeProblematic;
cBoxStoreLastWaitingContributions.Checked = project.storeRemainingContributions;
if (txtBoxThinkPwd.Text == "") //just a dev convenience thing, try to load pw from another file
{
try
{
try
{
stream = new StreamReader(curDir + "\\project.json");
project = JsonConvert.DeserializeObject<ExpandoObject>(stream.ReadToEnd(), converter);
stream.Close();
txtBoxThinkPwd.Text = project.repoPwd;
}
catch
{
}
stream = new StreamReader(curDir + "\\project.json");
project = JsonConvert.DeserializeObject<ExpandoObject>(stream.ReadToEnd(), converter);
stream.Close();
txtBoxThinkPwd.Text = project.repoPwd;
}
catch
{
}
}
}
......@@ -1073,25 +1058,36 @@ namespace HaMSTR_ETLBuilder_Forms
private void btnAQLForCompositions_Click(object sender, EventArgs e)
{
rTxtBoxDeleting.Text = "select a/uid/value as compositionId" + Environment.NewLine +
if ((cmbBoxThinkAddress.SelectedItem.ToString()).IndexOf("/ehrbase/")>-1)
{
rTxtBoxDeleting.Text = "select a/uid/value as compositionId, "+ Environment.NewLine +
" e/ehr_id/value as ehrId" + Environment.NewLine +
"from EHR e" + Environment.NewLine +
"contains COMPOSITION a" + Environment.NewLine +
"WHERE a/ archetype_details / template_id / value = '" + cmbBoxTemplateId.SelectedItem.ToString() + "'" + Environment.NewLine;
}
else
{
rTxtBoxDeleting.Text = "select a/uid/value as compositionId" + Environment.NewLine +
"from EHR e" + Environment.NewLine +
"contains COMPOSITION a" + Environment.NewLine +
"WHERE a/ archetype_details / template_id / value = '"+ cmbBoxTemplateId.SelectedItem.ToString() + "'" + Environment.NewLine;
"WHERE a/ archetype_details / template_id / value = '" + cmbBoxTemplateId.SelectedItem.ToString() + "'" + Environment.NewLine;
}
}
private void btnRetrieveIds_Click(object sender, EventArgs e)
{
try
{
thinkHandle = new ThinkHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, null, null);
dynamic res = JsonConvert.DeserializeObject<ExpandoObject>(thinkHandle.httpRequest("query?aql=" + rTxtBoxDeleting.Text.Replace('\n', ' '), false, null, null), new ExpandoObjectConverter());
repoHandle = new RepoHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, null, null);
dynamic res = JsonConvert.DeserializeObject<ExpandoObject>(repoHandle.httpRequest("query?aql=" + rTxtBoxDeleting.Text.Replace('\n', ' '), false, null, null), new ExpandoObjectConverter());
rTxtBoxDeleting.Text = JsonConvert.SerializeObject(res.resultSet, Formatting.Indented);
txtBoxDeleteAmount.Text = res.resultSet.Count.ToString();
if (rTxtBoxDeleting.Text.IndexOf("ehrId") != -1)
{
lblDeleteType.Text = "EHRs";
}
else if (rTxtBoxDeleting.Text.IndexOf("compositionId") != -1)
if (rTxtBoxDeleting.Text.IndexOf("compositionId") != -1)
{
lblDeleteType.Text = "compositions";
}
......@@ -1106,6 +1102,7 @@ namespace HaMSTR_ETLBuilder_Forms
class compositionItem
{
public string compositionId { get; set; }
public string ehrId { get; set; }
}
class ehrItem
{
......@@ -1115,17 +1112,17 @@ namespace HaMSTR_ETLBuilder_Forms
{
try
{
thinkHandle = new ThinkHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, null, null);
repoHandle = new RepoHandle(cmbBoxThinkAddress.SelectedItem.ToString(), txtBoxThinkUser.Text, txtBoxThinkPwd.Text, null, null);
loggingBox logEvents = new loggingBox(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt") + " Deleting " + lblDeleteType.Text + " started..." + Environment.NewLine);
logEvents.Show(); //Show the log
repoHandle.log = logEvents;
//depending on type of deletion parse JSON and iterate through list sending DELETE-request for each element
if (lblDeleteType.Text == "EHRs")
{
List<ehrItem> res = JsonConvert.DeserializeObject<List<ehrItem>>(rTxtBoxDeleting.Text);
foreach (ehrItem entry in res)
{
thinkHandle.httpRequest("ehrs/" + entry.ehrId, false, "", "DELETE-ADMIN");
repoHandle.httpRequest("ehrs/" + entry.ehrId, false, "", "DELETE-ADMIN");
}
}
else
......@@ -1133,7 +1130,14 @@ namespace HaMSTR_ETLBuilder_Forms
List<compositionItem> res = JsonConvert.DeserializeObject<List<compositionItem>>(rTxtBoxDeleting.Text);
foreach (compositionItem entry in res)
{
thinkHandle.httpRequest("compositions/" + entry.compositionId, false, "", "DELETE-ADMIN");
if (repoHandle.isEhrbase)
{
repoHandle.httpRequest("compositions/" + entry.compositionId, false, entry.ehrId, "DELETE-ADMIN");
}
else
{
repoHandle.httpRequest("compositions/" + entry.compositionId, false, "", "DELETE-ADMIN");
}
}
}
......@@ -1153,36 +1157,5 @@ namespace HaMSTR_ETLBuilder_Forms
responseHandle.maybeLog(true);
}
}
private void label5_Click(object sender, EventArgs e)
{
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void cmbBoxTemplateId_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void cmbBoxThinkAddress_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void tabPageMapping_Click(object sender, EventArgs e)
{
}
}
}
\ No newline at end of file
......@@ -9,14 +9,15 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link rel=stylesheet href=style.css>
<!-- Only use locally stored libraries here. Else slow loading can screw up whole webapp -->
<script language=javascript type=text/javascript src="jquery-2.2.0.min.js"></script>
<script language=javascript type=text/javascript src="jquery-ui.min.js"></script>
<script language=javascript type=text/javascript src="knockout-3.4.0.js"></script>
<script language=javascript type=text/javascript src="instructionsVM.js"></script>
<script language=javascript type=text/javascript src="utils.js"></script>
<script language=javascript type=text/javascript src="staticData.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.14.5/xlsx.full.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.14.5/jszip.js"></script>
<script language=javascript type=text/javascript src="xlsx.full.min.js"></script>
<script language=javascript type=text/javascript src="jszip.js"></script>
<title>ETLBuilder</title>
</head>
<body>
......@@ -28,112 +29,109 @@
<!--Add dictionary from Excel Button-->
<button data-bind='click: openModal, enable: columns().length > 0'>Add dictionary entry from Excel</button>
</div>
</div>
<!--Modal-->
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close" data-bind='click: closeModal'>&times;</span>
<input type="file" id="fileUpload" />
<p>
<small>
Please specify the path to the excel file (.xls or .xlsx).<br/>
The excel file must contain the column names <strong>StringToReplace</strong> and <strong>StringToReplaceWith</strong>.
</small>
</p>
<button data-bind='click: uploadExcel'>Upload</button>
</div>
</div>
</div>
<div class="overlayWindow probableParams" data-bind="visible: probableConditions().length>0">
<button data-bind='click: clearProbableValues'>Hide</button><br>
<table class="probableParams">
<tbody data-bind="foreach: probableConditions">
<tr class="probableParam">
<td data-bind="text: $data, click: $root.changeConditionValue" class="probableParams"></td>
</tr>
</tbody>
</table>
<!--Modal-->
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close" data-bind='click: closeModal'>&times;</span>
<input type="file" id="fileUpload" />
<p>
<small>
Please specify the path to the excel file (.xls or .xlsx).<br/>
The excel file must contain the column names <strong>StringToReplace</strong> and <strong>StringToReplaceWith</strong>.
</small>
</p>
<button data-bind='click: uploadExcel'>Upload</button>
</div>
</div>
<div class="overlayWindow probableParams" data-bind="visible: probableActions().length>0">
<button data-bind='click: clearProbableValues'>Hide</button><br>
<table class="probableParams">
<tbody data-bind="foreach: probableActions">
<tr class="probableParam">
<td data-bind="text: $data, click: $root.changeActionValue" class="probableParams"></td>
</tr>
</tbody>
</table>
</div>
<div class="overlayWindow probableParams" data-bind="visible: probableParams().length>0" title="Probable Parameters">
<button data-bind='click: clearProbableValues'>Hide</button><br>
<table class="probableParams">
<tbody data-bind="foreach: probableParams">
<tr class="probableParam">
<td data-bind="text: $data, click: $root.changeParameterValue" class="probableParams"></td>
</tr>
</tbody>
</table>
</div>
<div class="instructions" data-bind="visible: columns().length>0">
<a href='#' class="add column" data-bind='click: $root.addColumn'>+</a>
<ul id="columns" class="columns" data-bind="foreach: columns">
<li class="column">
For column: <input class="label column" data-bind="value: colName"/>
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "columns")'>X</a>
<ul class="cAndAs" data-bind="foreach: cAndAs">
<li class="condition">
on condition: <input class="label" data-bind="value: condition, click: $root.editCondition.bind($data, $parent)"/>
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "cAndAs")'>X</a><br>
<a href='#' class="add action" data-bind='click: $root.addActionAtBegin'>+</a>
<ul class="actions" data-bind="foreach: actions">
<li class="action">
invoke method: <input class="label action" data-bind="value: method, click: $root.editAction.bind($data, $parent)"/>
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "actions")'>X</a><br>
<a class="action">with parameters:</a>
<table class="parameters" data-bind="foreach: parameters">
<tr class="parameter">
<td data-bind="text: parameterName" class="label"></td>
<td style="width:100%">
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "parameters")'>X</a>
<input class="label parameter parameterInput" data-bind="value: parameter, click: $root.editParameter.bind($data, $parent)"/>
</td>
</tr>
</table>
<a href='#' class="add parameter" data-bind='click: $root.addParameter'>+</a>
</li>
</ul>
<a href='#' class="add action" data-bind='click: $root.addAction'>+</a>
</li>
</ul>
<a href='#' class="add condition" data-bind='click: $root.addCondition'>+</a> <a href='#' class="clone column" data-bind='click: $root.cloneColumn'>C</a>
</li>
</ul>
</div>
<div class="overlayWindow probableParams" data-bind="visible: probableConditions().length>0">
<button data-bind='click: clearProbableValues'>Hide</button><br>
<table class="probableParams">
<tbody data-bind="foreach: probableConditions">
<tr class="probableParam">
<td data-bind="text: $data, click: $root.changeConditionValue" class="probableParams"></td>
</tr>
</tbody>
</table>
</div>
<div class="overlayWindow probableParams" data-bind="visible: probableActions().length>0">
<button data-bind='click: clearProbableValues'>Hide</button><br>
<table class="probableParams">
<tbody data-bind="foreach: probableActions">
<tr class="probableParam">
<td data-bind="text: $data, click: $root.changeActionValue" class="probableParams"></td>
</tr>
</tbody>
</table>
</div>
<script language="JavaScript">
$(function () {
$(".overlayWindow").draggable();
});
<div class="overlayWindow probableParams" data-bind="visible: probableParams().length>0" title="Probable Parameters">
<button data-bind='click: clearProbableValues'>Hide</button><br>
<table class="probableParams">
<tbody data-bind="foreach: probableParams">
<tr class="probableParam">
<td data-bind="text: $data, click: $root.changeParameterValue" class="probableParams"></td>
</tr>
</tbody>
</table>
</div>
<div class="instructions" data-bind="visible: columns().length>0">
<a href='#' class="add column" data-bind='click: $root.addColumn'>+</a>
<ul id="columns" class="columns" data-bind="foreach: columns">
<li class="column">
For column: <input class="label column" data-bind="value: colName" />
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "columns")'>X</a>
<ul class="cAndAs" data-bind="foreach: cAndAs">
<li class="condition">
on condition: <input class="label" data-bind="value: condition, click: $root.editCondition.bind($data, $parent)" />
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "cAndAs")'>X</a><br>
<a href='#' class="add action" data-bind='click: $root.addActionAtBegin'>+</a>
<ul class="actions" data-bind="foreach: actions">
<li class="action">
invoke method: <input class="label action" data-bind="value: method, click: $root.editAction.bind($data, $parent)" />
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "actions")'>X</a><br>
<a class="action">with parameters:</a>
<table class="parameters" data-bind="foreach: parameters">
<tr class="parameter">
<td data-bind="text: parameterName" class="label"></td>
<td style="width:100%">
<a href='#' class="delete" data-bind='click: $root.deleteItem.bind($data, $parent, "parameters")'>X</a>
<input class="label parameter parameterInput" data-bind="value: parameter, click: $root.editParameter.bind($data, $parent)" />
</td>
</tr>
</table>
<a href='#' class="add parameter" data-bind='click: $root.addParameter'>+</a>
</li>
</ul>
<a href='#' class="add action" data-bind='click: $root.addAction'>+</a>
</li>
</ul>
<a href='#' class="add condition" data-bind='click: $root.addCondition'>+</a> <a href='#' class="clone column" data-bind='click: $root.cloneColumn'>C</a>
</li>
</ul>
</div>
<script language="JavaScript">
$(function () {
$(".overlayWindow").draggable();
});
$(".inputData").focus();
$(".inputData").select();
$(".inputData").focus();
$(".inputData").select();
//GUI-Interaktionen
//GUI-Interaktionen
//Drag and Drop für Parameter-Vorschläge
$(".probableParams").on("dragstart", ".probableParams", function (e) {