From d44a8755b8db4fb2b71d4fca6512abdd30aa0ea0 Mon Sep 17 00:00:00 2001
From: vermeul <swen@ethz.ch>
Date: Wed, 27 Feb 2019 10:59:41 +0100
Subject: [PATCH] complete connection management. Change of connection alters
 datasetTypes. Altering of datasetType will affect upload form

---
 jupyter-openbis-extension/static/dialog.js | 378 +++++++++++++++++----
 1 file changed, 317 insertions(+), 61 deletions(-)

diff --git a/jupyter-openbis-extension/static/dialog.js b/jupyter-openbis-extension/static/dialog.js
index 5ec77c3..7baf698 100644
--- a/jupyter-openbis-extension/static/dialog.js
+++ b/jupyter-openbis-extension/static/dialog.js
@@ -9,10 +9,12 @@ define([
         var currentSampleIdentifier = null
         var currentDownloadPath = null
         var ds_type = document.createElement("SELECT")
+        ds_type.size = '40'
         ds_type.className = "select-xs"
         ds_type.id = "dataset_type"
+        var conn_table = null
 
-        function show_available_connections (data, conn_table) {
+        function show_available_connections(env, data, conn_table, onclick_cbf) {
             if (!currentDownloadPath) {
                 currentDownloadPath = data.cwd
             }
@@ -21,47 +23,178 @@ define([
             table.className = 'table-bordered table-striped table-condensed'
             var thead = table.createTHead()
             var thead_row = thead.insertRow(0)
-            var titles = ['', 'Name', 'URL', 'Status']
+            var titles = ['', 'Name', 'URL', 'Status', 'Username / Password']
             for (title of titles) {
                 thead_row.insertCell().textContent = title
             }
-            //titles.forEach( function(item, index) {
-            //    thead_row.insertCell().textContent = item
-            //})
 
             tbody = table.createTBody()
-            for (item of data.connections) {
-            //data.connections.forEach( function(item) {
-                //console.log(item)
+            for (connection of data.connections) {
                 var conn = document.createElement("INPUT")
                 conn.type = "radio"
                 conn.name = "connection_name"
-                conn.value = item.name
-                conn.setAttribute("url", item.url)
-
-                // Change the list of available dataset types
-                conn.onchange = function() {
-                    currentConnection = item.name
-                    //ds_type.children().remove()
-                    while (ds_type.firstChild) {
-                        ds_type.removeChild(ds_type.firstChild);
-                    }
-                    if (item.ds_types != null) {
-                        for (ds_type of item.ds_types) {
-                            option = document.createElement("OPTION")
-                            option.textContent = ds_type.code
-                        }
+                conn.value = connection.name
+                conn.setAttribute("url", connection.url)
+
+                conn.checked = connection.name === currentConnection;
+                if (onclick_cbf === undefined) {
+                    conn.onclick = function() {
+                        currentConnection = this.value
                     }
                 }
-
-                conn.checked = item.name === currentConnection;
+                else {
+                    conn.onclick = onclick_cbf
+                }
 
                 var row = tbody.insertRow()
                 row.insertCell().appendChild(conn)
-                row.insertCell().textContent = item.name
-                row.insertCell().textContent = item.url
-                row.insertCell().textContent = item.status
+                row.insertCell().textContent = connection.name
+                row.insertCell().textContent = connection.url
+
+                var status_cell = row.insertCell()
+
+                var status_badge = document.createElement("SPAN")
+                status_badge.id = connection.name + "-badge"
+                status_badge.textContent = connection.status
+                if (connection.status === "connected") {
+                    status_badge.className = "label label-success"
+                }
+                else {
+                        status_badge.className = "label label-danger"
+                }
+                status_cell.appendChild(status_badge)
+
+                var username = document.createElement("INPUT")
+                username.type = "text"
+                username.name = "username"
+                username.autocomplete = "on"
+                username.value = connection.username
+                username.setAttribute("form", connection.name)
+
+                var password = document.createElement("INPUT")
+                password.type = "password"
+                password.name = "password"
+                password.autocomplete = "current-password"
+                password.value = connection.password
+                password.setAttribute("form", connection.name)
+
+                // Username / Password form
+                var pwform = document.createElement("FORM")
+                pwform.id = connection.name
+                pwform.onsubmit = function(event) {
+                    var form_data = new FormData(this)
+                    var status_badge = document.getElementById(this.id + "-badge")
+                    reconnect_connection(env, this.id,
+                        form_data.get("username"), form_data.get("password")
+                    )
+                        .then( function(response) {
+                            //console.log(response)
+                            if (status_badge.nextElementSibling !== null) {
+                                status_badge.parentNode.removeChild(status_badge.nextElementSibling)
+                            }
+                            if (response.ok) {
+                                status_badge.textContent = "connected"
+                                status_badge.className = "label label-success"
+                            }
+                            else {
+                                status_badge.textContent = "not connected"
+                                status_badge.className = "label label-danger"
+                                message = document.createElement("p")
+                                if (response.status === 401) {
+                                    message.textContent = "Wrong username/password"
+                                }
+                                else if (response.status === 500) {
+                                    message.textContent = "Cannot connect server"
+                                }
+                                else {
+                                    message.textContent = "General error"
+                                }
+                                status_badge.parentNode.insertBefore(message, status_badge.nextSibling)
+                            }
+                        })
+                        .catch( error => console.error("Error while attempting to reconnect: ",error) )
+
+                    return false
+                }
+
+
+                var connect_button = document.createElement("BUTTON")
+                connect_button.className = "btn btn-primary btn-xs"
+                connect_button.textContent  = "connect"
+
+                pwform.appendChild(username)
+                pwform.appendChild(password)
+                pwform.appendChild(connect_button)
+
+                var cell = row.insertCell()
+                cell.appendChild(pwform)
+            }
+
+            // add row for new connection
+            var row = tbody.insertRow()
+
+            var conn_form = document.createElement("FORM")
+            conn_form.id = "new_connection"
+            conn_form.onsubmit = function(event) {
+                var inputs = document.querySelectorAll("input[form=new_connection]")
+
+                data = {}
+                for (input of inputs) {
+                    data[input.name] = input.value
+                }
+                for (missing of ['connection_name','url', 'username', 'password']) {
+                    if (data[missing] === ""){
+                        alert("Please provide: " + missing)
+                        return false
+                    }
+                }
+                new_connection(
+                    env, data.connection_name, data.url, data.username, data.password
+                )
+                    .then( function(response){
+                        if (response.ok) {
+                            response.json()
+                                .then( function(data){
+                                    show_available_connections(env, data, conn_table)
+                                })
+                        }
+                    })
+                return false
             }
+            var conn_name = document.createElement("INPUT")
+            conn_name.type = "input"
+            conn_name.name = "connection_name"
+            conn_name.setAttribute("form", conn_form.id)
+            conn_name.placeholder = "openBIS instance name"
+            row.insertCell().appendChild(conn_form)
+            row.insertCell().appendChild(conn_name)
+
+            var conn_url = document.createElement("INPUT")
+            conn_url.type = "input"
+            conn_url.name = "url"
+            conn_url.setAttribute("form", conn_form.id)
+            conn_url.placeholder = "https://openbis.domain:port"
+            row.insertCell().appendChild(conn_url)
+            row.insertCell()
+
+            var username = document.createElement("INPUT")
+            username.autocomplete = "off"
+            username.type = "text"
+            username.name = "username"
+            username.setAttribute("form", conn_form.id)
+            username.placeholder = "username"
+            var password = document.createElement("INPUT")
+            password.type = "password"
+            password.name = "password"
+            password.autocomplete = "new-password"
+            password.setAttribute("form", conn_form.id)
+            var create_btn = document.createElement("BUTTON")
+            create_btn.setAttribute("form", conn_form.id)
+            create_btn.textContent = "create"
+            var uname_pw_cell = row.insertCell()
+            uname_pw_cell.appendChild(username)
+            uname_pw_cell.appendChild(password)
+            uname_pw_cell.appendChild(create_btn)
 
             conn_table.innerHTML = ""
             table_title = document.createElement("STRONG")
@@ -104,8 +237,10 @@ define([
             datasets_table.appendChild(table)
         }
 
+        // gets the status of the avialable openBIS connections
         function getOpenBisConnections(env) {
-             var connectionsUrl = env.notebook.base_url + 'openbis/conn'
+
+             var connectionsUrl = env.notebook.base_url + 'openbis/conns'
              var settings = {
                  url: connectionsUrl,
                  processData: false,
@@ -116,6 +251,106 @@ define([
              return utils.ajax(settings)
         }
 
+        function reconnect_connection(env, connection, username, password){
+            var url = env.notebook.base_url + 'openbis/conn/' + connection
+            body = {
+                "username": username,
+                "password": password
+            }
+
+            var cookie = decodeURIComponent(document.cookie)
+            var xsrf_token = cookie.split("_xsrf=")[1]
+
+            return fetch(url, {
+                method: "PUT",
+                headers: {
+                    "Content-Type": "application/json",
+                    "X-XSRFToken": xsrf_token,
+                },
+                body: JSON.stringify(body)
+            })
+        }
+
+        function new_connection(env, connection_name, connection_url, username, password){
+            var endpoint = env.notebook.base_url + 'openbis/conns'
+            body = {
+                "name"    : connection_name,
+                "url"     : connection_url,
+                "username": username,
+                "password": password
+            }
+
+            var cookie = decodeURIComponent(document.cookie)
+            var xsrf_token = cookie.split("_xsrf=")[1]
+
+            return fetch(endpoint, {
+                method: "POST",
+                headers: {
+                    "Content-Type": "application/json",
+                    "X-XSRFToken": xsrf_token,
+                },
+                body: JSON.stringify(body)
+            })
+        }
+
+        function getDatasetTypes(env, connection_name, dataset_types, input_fields) {
+            // get all DatasetTypes of a given connection
+
+            var url = env.notebook.base_url + 'openbis/datasetTypes/'+ connection_name
+            fetch(url)
+                .then( function(response) {
+                    if (response.ok) {
+                        response.json()
+                            .then( function(data) {
+                                //console.log(data.dataSetTypes)
+                                dts = data.dataSetTypes
+                                while (dataset_types.firstChild) {
+                                    dataset_types.removeChild(dataset_types.firstChild);
+                                }
+
+                                for (dt of dts) {
+                                    var option = document.createElement("OPTION")
+                                    option.value = dt.code
+                                    option.textContent = dt.description ? dt.code + ": " + dt.description : dt.code
+                                    dataset_types.appendChild(option)
+                                }
+                                dataset_types.onchange = function() {
+                                    // remove existing input fields
+                                    while (input_fields.firstChild) {
+                                        input_fields.removeChild(input_fields.firstChild)
+                                    }
+
+                                    // for every property assignment, create an input field.
+                                    for (pa of dts[dataset_type.selectedIndex].propertyAssignments) {
+                                        //var input_title = document.createTextNode(pa.label + ": ")
+                                        var input_field = document.createElement("INPUT")
+                                        input_field.type = "text"
+                                        input_field.name = pa.code
+                                        input_field.placeholder = pa.description ? pa.label + ": " + pa.description : pa.label
+                                        input_field.size = 90
+
+                                        //input_fields.appendChild(input_title)
+                                        input_fields.appendChild(input_field)
+                                        input_fields.appendChild(document.createElement("BR"))
+                                    }
+                                }
+                            })
+                            .catch( function(error){
+                                console.error("Error while parsing dataset types", error)
+                            })
+
+                    }
+                    else {
+                        while (dataset_types.firstChild) {
+                            dataset_types.removeChild(dataset_types.firstChild);
+                        }
+                    }
+                })
+                .catch (function(error) {
+                    console.error("Error while fetching dataset types:", error)
+                })
+        }
+
         function createFeedback(type, content) {
             var close = document.createElement("BUTTON")
             close.className = "close"
@@ -159,16 +394,15 @@ define([
         }
 
         var fetchDatasetFromOpenBis = {
-            help: 'Download a openBIS dataset to your local harddrive',
+            help: 'Download openBIS datasets to your local harddrive',
             icon: 'fa-download',
             help_index: '',
             handler: function (env) {
-                //var conn_table = $('<div id="openbis_connections"/>')
-                var conn_table = document.createElement("DIV")
+                conn_table = document.createElement("DIV")
                 conn_table.id = "openbis_connections"
                 getOpenBisConnections(env)
                     .done(function (data) {
-                        show_available_connections(data, conn_table)
+                        show_available_connections(env, data, conn_table)
                     })
                     .fail(function (data) {
                         alert(data.status)
@@ -341,7 +575,7 @@ define([
 
                     dialog.modal({
                         body: download_dialog_box,
-                        title: 'Download openBIS DataSet',
+                        title: 'Download openBIS DataSets',
                         buttons: {
                             'Cancel': {},
                             'Download': {
@@ -361,33 +595,59 @@ define([
             icon: 'fa-cloud-upload',
             help_index: '',
             handler: function (env) {
-                var conn_table = document.createElement("DIV")
+                conn_table = document.createElement("DIV")
+                var dst_title = document.createElement("STRONG")
+                dst_title.textContent = "DataSet type"
+                var dataset_types = document.createElement("SELECT")
+                dataset_types.id = "dataset_type"
+                dataset_types.className = "form-control select-xs"
+
+                var input_fields = document.createElement("DIV")
                 conn_table.id = "openbis_connections"
+
+                var onclick_cbf = function() {
+                    currentConnection = this.value
+                    getDatasetTypes(env, this.value, dataset_types, input_fields)
+                }
+
                 getOpenBisConnections(env)
                     .done(function (data) {
-                        show_available_connections(data, conn_table)
+                        show_available_connections(env, data, conn_table, onclick_cbf)
                     })
                     .fail(function (data) {
                         alert(data.status)
                     })
-                var ds_name = $('<input type="text" name="ds_name" size=40 placeholder="name">')
-                var ds_description = $('<input type="text" name="ds_description" size=40 placeholder="description">')
-                //var ds_type = $('<input type="text" name="ds_type" size=40 placeholder="type">')
-                //var ds_type = $('<select class="form-control select-xs" id="dataset_type">')
-                var sampleIdentifier = $('<input type="text" name="sampleIdentifier" size=40 placeholder="sample identifier">')
-                    .val(currentSampleIdentifier)
-                var ds_files = $('<input type="text" name="files" size=40 placeholder="filenames">')
-
-                var inputs = $('<div>')
-                    .css('margin-top', '10px')
-                    .append($('<p>').text('Name: ').append(ds_name))
-                    .append($('<p>').text('Description: ').append(ds_description))
-                    .append($('<p>').text('DatasetType: ').append(ds_type))
-                    .append($('<p>').text('Sample: ').append(sampleIdentifier))
-                    .append($('<p>').text('Files: ').append(ds_files))
+
+                var sample_title = document.createElement("STRONG")
+                sample_title.textContent = "Sample Identifier"
+                var sampleIdentifier = document.createElement("INPUT")
+                sampleIdentifier.type = "text"
+                sampleIdentifier.name = 'sampleIdentifier'
+                sampleIdentifier.placeholder = "Sample Identifier or permId"
+                sampleIdentifier.value = currentSampleIdentifier
+                sampleIdentifier.size  = "90"
+
+                var ds_title = document.createElement("STRONG")
+                ds_title.textContent = "DataSet files"
+                var ds_files         = document.createElement("INPUT")
+                ds_files.type        = "text"
+                ds_files.placeholder = "filenames"
+                ds_files.name        = "ds_files"
+                ds_files.size        = "90"
+
+                var inputs = document.createElement("DIV")
+                inputs.style.marginTop = '10px'
+                inputs.appendChild(dst_title)
+                inputs.appendChild(dataset_types)
+                inputs.appendChild(input_fields)
+                inputs.appendChild(sample_title)
+                inputs.appendChild(sampleIdentifier)
+                inputs.appendChild(ds_title)
+                inputs.appendChild(ds_files)
 
                 var uploadDialogBox = $('<div/>').append(conn_table).append(inputs)
 
+
                 // get the canvas for user feedback
                 var container = $('#notebook-container')
 
@@ -407,18 +667,16 @@ define([
                     var files = []
                     var filepath = window.location.pathname.match(re)[1]
                     files.push(filepath)
-                    if (ds_files.val()) {
-                        files.push(ds_files.val())
-                    }
+                    // FIXME
+                    //if (ds_files.val()) {
+                    //    files.push(ds_files.value)
+                    //}
 
                     var dataSetInfo = {
-                        "name"            : ds_name.val(),
-                        "description"     : ds_description.val(),
-                        "type"            : ds_type.val(),
+                        "type"            : dataset_types.value,
                         "files"           : files,
-                        "sampleIdentifier": sampleIdentifier.val()
+                        "sampleIdentifier": sampleIdentifier.value
                     }
-                    //console.log(dataSetInfo);
 
                     var settings = {
                         url: uploadUrl,
@@ -454,8 +712,6 @@ define([
 
                     // display preloader during commit and push
                     var preloader = '<img class="openbis-feedback" src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.5.8/ajax-loader.gif">'
-                    container.prepend(preloader)
-                    $('.openbis-feedback').remove()
 
                     // commit and push
                     utils.ajax(settings)
-- 
GitLab