define([ "base/js/namespace", "base/js/dialog", "base/js/utils", "jquery" ], function(IPython, dialog, utils, $) { var currentConnection = '' 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(env, data, conn_table, onclick_cbf) { if (!currentDownloadPath) { currentDownloadPath = data.cwd } var table = document.createElement("TABLE") table.className = 'table-bordered table-striped table-condensed' var thead = table.createTHead() var thead_row = thead.insertRow(0) var titles = ['', 'Name', 'URL', 'Status', 'Username / Password'] for (title of titles) { thead_row.insertCell().textContent = title } tbody = table.createTBody() for (connection of data.connections) { var conn = document.createElement("INPUT") conn.type = "radio" conn.name = "connection_name" conn.value = connection.name conn.setAttribute("url", connection.url) conn.checked = connection.name === currentConnection; if (onclick_cbf === undefined) { conn.onclick = function() { currentConnection = this.value } } else { conn.onclick = onclick_cbf } var row = tbody.insertRow() row.insertCell().appendChild(conn) 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 = "username/password incorrect" } else if (response.status === 500) { message.textContent = "Connection error" } 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") table_title.textContent = "Please choose a connection" conn_table.appendChild(table_title) conn_table.appendChild(table) } function show_datasets_table( data, datasets_table) { var table = document.createElement("TABLE") table.className = "table-bordered table-striped table-condensed text-nowrap" var thead = table.createTHead() var t_row = thead.insertRow() var titles = ['', 'permId', 'Type', 'Experiment', 'Registration Date', 'Status', 'Size'] titles.forEach( function(title) { t_row.insertCell().textContent = title }) var tbody = table.createTBody() for (dataSet of data.dataSets) { var permId = document.createElement("INPUT") permId.type = "checkbox" permId.name = "permId" permId.value = dataSet.permId var row = tbody.insertRow() row.insertCell().appendChild(permId) row.insertCell().textContent = dataSet.permId row.insertCell().textContent = dataSet.type row.insertCell().textContent = dataSet.experiment row.insertCell().textContent = dataSet.registrationDate row.insertCell().textContent = dataSet.status row.insertCell().textContent = dataSet.size } while (datasets_table.firstChild) { datasets_table.removeChild(datasets_table.firstChild); } datasets_table.appendChild(table) } // gets the status of the avialable openBIS connections function getOpenBisConnections(env) { var connectionsUrl = env.notebook.base_url + 'openbis/conns' var settings = { url: connectionsUrl, processData: false, type: 'GET', dataType: 'json', contentType: 'application/json' } 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) var change_input_fields = 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")) } } dataset_types.onchange = change_input_fields // remove the old and add the new dataset-types 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) } // change the input fields, since we just received new datasetTypes change_input_fields() }) .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" close.setAttribute("data-dismiss", "alert") close.setAttribute("aria-label", "Close") var x = document.createElement("SPAN") x.setAttribute("aria-hidden", true) x.innerHTML = "×" close.appendChild(x) var feedbackBox = document.createElement( "DIV" ) feedbackBox.className = "openbis-feedback alert alert-dismissible alert-" + type feedbackBox.setAttribute("role","alert") feedbackBox.innerHTML = content feedbackBox.prepend(close) var nb_container = document.getElementById('notebook-container') nb_container.prepend(feedbackBox) } function writeMetaData(data) { var notebook = IPython.notebook if (typeof notebook.metadata.openbis_connections === 'undefined') { notebook.metadata.openbis_connections = {} } if (typeof notebook.metadata.openbis_connections[data.url] === 'undefined') { notebook.metadata.openbis_connections[data.url] = {} } // store metadata about the downloaded files into the notebook-metadata if (data.permId) { notebook.metadata.openbis_connections[data.url][data.permId] = { "permId": data.permId, "path": data.path, "dataStore": data.dataStore, "location": data.location, "size": data.size, "status": data.statusText } } } var fetchDatasetFromOpenBis = { help: 'Download openBIS datasets to your local harddrive', icon: 'fa-download', help_index: '', handler: function (env) { conn_table = document.createElement("DIV") conn_table.id = "openbis_connections" getOpenBisConnections(env) .done(function (data) { show_available_connections(env, data, conn_table) }) .fail(function (data) { alert(data.status) }) .always(function () { showDownloadDialog() }) function showDownloadDialog() { // This function gets called after loading the openBIS connections // to make sure we can display the download path provided by the server. // show DataSets for Sample identifier/permid var showDataSets = document.createElement("DIV") var title = document.createElement("STRONG") title.textContent = "Sample identfier/permId: " showDataSets.appendChild(title) showDataSets.style.marginTop = '10px' var sampleIdentifier = document.createElement("INPUT") sampleIdentifier.type = "text" sampleIdentifier.name = "sampleIdentifier" sampleIdentifier.size = 40 sampleIdentifier.placeholder = "sample identifier or permId" sampleIdentifier.value = currentSampleIdentifier var datasets_table = document.createElement("DIV") datasets_table.id = "dataset_table" datasets_table.className = "output output_scroll" datasets_table.style.maxHeight = "10em" var show_datasets_btn = document.createElement("BUTTON") show_datasets_btn.className = "btn-info btn-xs" show_datasets_btn.textContent = "show datasets" show_datasets_btn.onclick = function() { var selected_conn = document.querySelector('input[name=connection_name]:checked') if (!selected_conn) { alert('Please choose a connection') return false } connection_name = selected_conn.value currentConnection = connection_name currentSampleIdentifier = sampleIdentifier.value if (!currentSampleIdentifier) { alert('Please specify a sample identifier/permId') return false } var url = env.notebook.base_url + 'openbis/sample/' + connection_name + '/' + encodeURIComponent(currentSampleIdentifier) fetch(url) .then( function(response) { if (response.ok) { response.json() .then( function(data) { show_datasets_table(data, datasets_table) }) } else { response.json() .then( function(error) { console.log(error.reason) alert("Error: " + error.reason) }) } }) .catch( function(error) { console.error('A serious network problem occured:', error) }) } showDataSets.appendChild(sampleIdentifier) showDataSets.appendChild(show_datasets_btn) showDataSets.appendChild(datasets_table) // dataSetPermId only var dataset_direct = document.createElement("P") dataset_direct.style.marginTop='10px' dataset_direct.innerHTML = '<strong>enter DataSet permId directly: </strong>' //var dataset = $('<p>') // .css('margin-top', '10px') // .append($('<b>').text('... or enter DataSet permId directly: ')) var datasetPermId = document.createElement("INPUT") datasetPermId.type = "text" datasetPermId.name = "datasetPermId" datasetPermId.size = "40" datasetPermId.placeholder = "dataSet permId" dataset_direct.appendChild(datasetPermId) var downloadPath = document.createElement("INPUT") downloadPath.type = "text" downloadPath.name = "downloadPath" downloadPath.size = "90" downloadPath.value = currentDownloadPath var path = document.createElement("DIV") path.innerHTML = "<strong>download data to path: </strong>" path.appendChild(downloadPath) var download_dialog_box = document.createElement("DIV") download_dialog_box.appendChild(conn_table) download_dialog_box.appendChild(showDataSets) download_dialog_box.appendChild(dataset_direct) download_dialog_box.appendChild(path) function downloadDataset(selected_conn, selectedPermIds, downloadPath) { var connection_name = selected_conn.value for (permId of selectedPermIds) { var downloadUrl = env.notebook.base_url + 'openbis/dataset/' + connection_name + '/' + permId + '/' + encodeURIComponent(downloadPath) fetch(downloadUrl) .then( function(response) { if (response.ok) { response.json() .then( function(data) { createFeedback('success', data.statusText) // successful download: // write statusText from returned data to notebooks metadata writeMetaData(data) // keep current download path for later use currentDownloadPath = downloadPath }) } else { response.json() .then( function(error) { console.log(error.reason) alert("Error: " + error.reason) }) } }) .catch( function(error) { console.error('A serious network problem occured:', error) }) } } function onDownloadClick() { var selected_conn = document.querySelector('input[name=connection_name]:checked') if (! selected_conn) { alert('please choose a connection') return false } var selectedPermIds = [] for (row of document.querySelectorAll('input[name=permId]:checked') ) { selectedPermIds.push(row.value) } if (datasetPermId.value) { selectedPermIds.push(datasetPermId.value) } if (!selectedPermIds) { alert('please select a dataset or provide a permId') return false } if (!downloadPath.value) { alert('Please specify where you would like to download your files!') return false } downloadDataset(selected_conn, selectedPermIds, downloadPath.value) } dialog.modal({ body: download_dialog_box, title: 'Download openBIS DataSets', buttons: { 'Cancel': {}, 'Download': { class: 'btn-primary btn-large', click: onDownloadClick, } }, notebook: env.notebook, keyboard_manager: env.notebook.keyboard_manager }) } } } var uploadDatasetsToOpenBis = { help: 'upload Notebook and Data to openBIS', icon: 'fa-upload', help_index: '', handler: function (env) { 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(env, data, conn_table, onclick_cbf) }) .fail(function (data) { alert(data.status) }) 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') function onOk () { //var connection_name = $('input[name="connection_name"]:checked').val() var selected_connection = document.querySelector('input[name=connection_name]:checked') if (!selected_connection) { alert("No connection selected") return false } var connection_name = selected_connection.value var uploadUrl = env.notebook.base_url + 'openbis/dataset/' + connection_name var notebook = IPython.notebook var re = /\/notebooks\/(.*?)$/ var files = [] var filepath = window.location.pathname.match(re)[1] files.push(filepath) // FIXME //if (ds_files.val()) { // files.push(ds_files.value) //} var dataSetInfo = { "type" : dataset_types.value, "files" : files, "sampleIdentifier": sampleIdentifier.value } var settings = { url: uploadUrl, processData: false, type: 'POST', dataType: 'json', data: JSON.stringify(dataSetInfo), contentType: 'application/json', success: function (data) { // display feedback to user createFeedback('success', data.statusText) // write statusText from returned data to notebooks metadata if ( typeof notebook.metadata.openbis === 'undefined') { notebook.metadata.openbis = {} } if ( typeof notebook.metadata.openbis.permIds === 'undefined' ) { notebook.metadata.openbis.permIds = {} } if ( data.permId ) { notebook.metadata.openbis.permIds[data.permId] = data.statusText } }, error: function (data) { // display feedback to user var feedback = "<strong>Error: </strong>Dataset was not uploaded.<div>" + data.statusText + "</div>" createFeedback('danger', feedback) } } // 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">' // commit and push utils.ajax(settings) } if (IPython.notebook.dirty === true) { dialog.modal({ body: 'Please save the notebook before uploading it to openBIS.', title: 'Save notebook first', buttons: { 'Back': {} }, notebook: env.notebook, keyboard_manager: env.notebook.keyboard_manager }) } else { dialog.modal({ body: uploadDialogBox, title: 'Upload openBIS DataSet', buttons: { 'Cancel': {}, 'Upload': { class: 'btn-primary btn-large', click: onOk } }, notebook: env.notebook, keyboard_manager: env.notebook.keyboard_manager }) } } } var configureOpenBisConnections = { help: 'configure openBIS connections', icon: 'fa-sliders', help_index: '', handler: function (env) { 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(env, data, conn_table, onclick_cbf) }) .fail(function (data) { alert(data.status) }) var uploadDialogBox = $('<div/>').append(conn_table) // get the canvas for user feedback var container = $('#notebook-container') function onOk () { } dialog.modal({ body: uploadDialogBox, title: 'Choose openBIS connection', buttons: { 'Cancel': {}, 'Choose connection': { class: 'btn-primary btn-large', click: onOk } }, notebook: env.notebook, keyboard_manager: env.notebook.keyboard_manager }) } } function _onLoad () { // show connections var configure_openbis_connections = IPython.keyboard_manager.actions.register( configureOpenBisConnections, 'openbis-connections', 'jupyter-openBIS') // dnownload var download_datasets = IPython.keyboard_manager.actions.register( fetchDatasetFromOpenBis, 'openbis-dataset-download', 'jupyter-openBIS') // upload var upload_datasets = IPython.keyboard_manager.actions.register( uploadDatasetsToOpenBis, 'openbis-dataset-upload', 'jupyter-openBIS') // add button for new action IPython.toolbar.add_buttons_group([configure_openbis_connections, download_datasets, upload_datasets]) } return {load_ipython_extension: _onLoad} })