diff --git a/jupyter-openbis-extension/static/dialog.js b/jupyter-openbis-extension/static/dialog.js index 5ec77c3a2bd9f4863ad757c676f8e390b0174450..7baf6980de33a47e6552bb4d46d94f23a0791424 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)