Newer
Older
anttil
committed
define([
"base/js/dialog",
"base/js/utils",
"jquery",
"./state",
"./common",
anttil
committed
],
function (dialog, utils, $, state, common, entitySearcher) {
var errorElements = { }
function createErrorElement(name) {
var element = document.createElement("STRONG")
element.textContent = ""
element.style.marginLeft = "8px"
element.style.color = "red"
errorElements[name.toLowerCase()] = element
return element
}
function cleanErrors() {
Object.keys(errorElements).forEach(key => errorElements[key].textContent="")
}
var spinner = document.createElement("IMG")
spinner.className="openbis-feedback"
spinner.src=""
function showSpinner(env) {
var userName = window.location.pathname.split("/")[2];
spinner.src = '/user/' + userName+ '/nbextensions/jupyter-openbis-extension/spinner.gif'
function hideSpinner(env) {
spinner.src=""
}
function get_file_list(env, container, path) {
var url = env.notebook.base_url + 'api/contents'
if (path !== "") {
url = url + '/' + path
}
fetch(url)
.then( function(response) {
if (response.ok) {
response.json()
.then(function(data){
state.fileCheckboxes = createFileTable(env, data, container, false, state.selectedFiles)
})
}
else {
console.error(response.status)
}
})
}
function get_dataset_list(env, container) {
var datasets = env.notebook.metadata.datasets
if (datasets != null) {
var values = Object.keys(datasets)
values.sort()
state.datasetCheckboxes = createSelectTable(values, container, true, state.unselectedDatasets)
Juan Fuentes
committed
function getOpenBISHistoryId() {
Juan Fuentes
committed
// Default empty history id
Juan Fuentes
committed
var resultDatasetHistoryId = "";
Juan Fuentes
committed
// Search for the history id on the metadata, new format, hidden from the user
Juan Fuentes
committed
if(Jupyter &&
Jupyter.notebook &&
Jupyter.notebook.metadata &&
Jupyter.notebook.metadata.openbisHistoryId) {
resultDatasetHistoryId = Jupyter.notebook.metadata.openbisHistoryId;
}
Juan Fuentes
committed
// Search for the history id on the cells, older format
Juan Fuentes
committed
if (!resultDatasetHistoryId) {
var resultDatasetHistoryIdIdx = 0;
while(Jupyter.notebook.get_cell(resultDatasetHistoryIdIdx) != null) {
var cell = Jupyter.notebook.get_cell(resultDatasetHistoryIdIdx);
var cellText = cell.get_text();
if(cell.get_text().startsWith("resultDatasetHistoryId='")) {
var firstIndexOf = cell.get_text().indexOf("'");
var lastIndexOf = cell.get_text().indexOf("'", firstIndexOf + 1);
resultDatasetHistoryId = cell.get_text().substring(firstIndexOf + 1, lastIndexOf);
}
resultDatasetHistoryIdIdx++;
}
}
Juan Fuentes
committed
return resultDatasetHistoryId; // We always return at least the empty one
Juan Fuentes
committed
}
anttil
committed
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) {
var change_input_fields = function () {
cleanErrors()
anttil
committed
var oldType = state.uploadDataSetType
if (oldType != null && !(oldType in state.uploadDataSetTypes)) {
state.uploadDataSetTypes[oldType] = {}
}
state.uploadDataSetType = dataset_types.options[dataset_types.selectedIndex].value
anttil
committed
// remove existing input fields
while (input_fields.firstChild) {
anttil
committed
var element = input_fields.firstChild
if (element.nodeName === "INPUT" && state.uploadDataSetType != null) {
state.uploadDataSetTypes[oldType][element.name] = element.value
}
input_fields.removeChild(element)
anttil
committed
}
// for every property assignment, create an input field.
for (pa of dts[dataset_types.selectedIndex].propertyAssignments) {
var input_title = document.createElement("STRONG")
input_title.textContent = pa.mandatory ? pa.label + " (mandatory)" : pa.label
var input_error = createErrorElement('prop.'+pa.code)
anttil
committed
var input_field = document.createElement("INPUT")
input_field.type = "text"
input_field.name = pa.code
input_field.placeholder = pa.description ? pa.description : pa.label
anttil
committed
input_field.size = 90
input_field.style.width="100%"
anttil
committed
anttil
committed
var mem = state.uploadDataSetTypes[dts[dataset_types.selectedIndex].code]
if (mem == null) {
Juan Fuentes
committed
mem = {
Juan Fuentes
committed
"$HISTORY_ID" : getOpenBISHistoryId() // History Id should get automatically populated if available
Juan Fuentes
committed
}
anttil
committed
}
input_field.value = pa.code in mem ? mem[pa.code] : ""
input_fields.appendChild(input_title)
input_fields.appendChild(input_error)
anttil
committed
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);
}
anttil
committed
var index = 0
var selectedIndex = -1
anttil
committed
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)
anttil
committed
if (dt.code === state.uploadDataSetType) {
selectedIndex = index
}
index++
anttil
committed
}
anttil
committed
dataset_types.selectedIndex = selectedIndex === -1 ? 0 : selectedIndex
anttil
committed
// 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 createSelectTable(values, container, checked, overrides) {
var table = document.createElement("TABLE")
table.className = 'table-bordered table-striped table-condensed'
table.style.width = "100%"
var body = table.createTBody()
var checkboxes = []
values.forEach( value => {
var row = body.insertRow()
var checkbox = document.createElement("INPUT")
checkbox.type = "checkbox"
checkbox.value = value
checkbox.checked = overrides.includes(value) ? !checked : checked
checkboxes.push(checkbox)
row.insertCell().appendChild(checkbox)
var valueCell = row.insertCell()
valueCell.textContent = value
valueCell.style.width = "100%"
})
container.appendChild(table)
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
function createFileTable(env, data, container, checked, overrides) {
var table = document.createElement("TABLE")
table.className = 'table-bordered table-striped table-condensed'
table.style.width = "100%"
var body = table.createTBody()
if (data.path !== "") {
var row = body.insertRow()
row.insertCell()
var iconCell = row.insertCell()
iconCell.className = "item_icon folder_icon icon-fixed-width"
var filenameCell = row.insertCell()
filenameCell.textContent = ".."
filenameCell.style.width = "80%"
filenameCell.onclick = function(){
var elems = data.path.split('/')
elems.pop()
get_file_list(env, container, elems.join('/'))
}
var sizeCell = row.insertCell()
sizeCell.style.textAlign = "right"
sizeCell.style.width = "15%"
}
var checkboxes = []
data.content.sort( (a, b) => a.name.localeCompare(b.name, undefined, {sensitivity: 'base'}) ).forEach( file => {
var row = body.insertRow()
var checkboxCell = row.insertCell()
checkboxCell.style.width="5%"
var iconCell = row.insertCell()
var filenameCell = row.insertCell()
filenameCell.textContent = file.name
filenameCell.style.width = "100%"
if (file.type === "directory") {
iconCell.className = "item_icon folder_icon icon-fixed-width"
filenameCell.onclick = function () {
get_file_list(env, container, file.path)
}
}
else {
var checkbox = document.createElement("INPUT")
checkbox.type = "checkbox"
checkbox.value = file.path
checkbox.checked = overrides.includes(file.name) ? !checked : checked
checkboxes.push(checkbox)
checkboxCell.appendChild(checkbox)
if (file.type === "notebook") {
iconCell.className = "item_icon notebook_icon icon-fixed-width"
}
else {
iconCell.className = "item_icon file_icon icon-fixed-width"
}
filenameCell.onclick = function () {
this.parentElement.firstElementChild.firstElementChild.checked = !this.parentElement.firstElementChild.firstElementChild.checked
}
}
var sizeCell = row.insertCell()
sizeCell.textContent = file.size
sizeCell.style.textAlign = "right"
sizeCell.style.width = "15%"
})
container.innerHTML = ""
container.appendChild(table)
return checkboxes
}
anttil
committed
return {
help: 'upload Notebook and Data to openBIS',
icon: 'fa-upload',
help_index: '',
handler: function (env) {
var main_error = createErrorElement('main')
anttil
committed
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"
dataset_types.style.marginLeft = 0
Swen Vermeul
committed
dataset_types.style.padding = 0
anttil
committed
var input_fields = document.createElement("DIV")
input_fields.setAttribute("id", "upload-input-fields");
anttil
committed
getDatasetTypes(env, state.connection.name, dataset_types, input_fields)
var sample_title = document.createElement("STRONG")
sample_title.textContent = "Entity"
Swen Vermeul
committed
var sample_error = createErrorElement('entityIdentifier')
var entityIdentifier = entitySearcher.getEntitySearcherForUpload(state)
anttil
committed
var ds_title = document.createElement("STRONG")
var dataSetListContainer = document.createElement("DIV")
if (env.notebook.metadata.datasets) {
ds_title.textContent = "Parent DataSets"
dataSetListContainer.style.maxHeight="150px"
dataSetListContainer.style.overflow="auto"
get_dataset_list(env, dataSetListContainer)
}
var files_title = document.createElement("STRONG")
files_title.textContent = "Files"
var fileListContainer = document.createElement("DIV")
fileListContainer.style.maxHeight="150px"
fileListContainer.style.overflow="auto"
anttil
committed
var inputs = document.createElement("DIV")
inputs.style.marginTop = '10px'
inputs.appendChild(main_error)
inputs.appendChild(spinner)
inputs.appendChild(document.createElement("BR"))
anttil
committed
inputs.appendChild(dst_title)
inputs.appendChild(dataset_types)
inputs.appendChild(input_fields)
inputs.appendChild(sample_title)
inputs.appendChild(sample_error)
Swen Vermeul
committed
inputs.appendChild(entityIdentifier)
anttil
committed
inputs.appendChild(ds_title)
inputs.appendChild(dataSetListContainer)
inputs.appendChild(files_title)
inputs.appendChild(fileListContainer)
anttil
committed
var uploadDialogBox = $('<div/>').append(inputs)
anttil
committed
anttil
committed
function saveState() {
state.uploadDataSetTypes[state.uploadDataSetType] = {}
for (element of input_fields.children) {
if (element.nodeName === "INPUT" && state.uploadDataSetType != null) {
state.uploadDataSetTypes[state.uploadDataSetType][element.name] = element.value
}
}
state.unselectedDatasets = state.datasetCheckboxes.filter(cb => !cb.checked).map(cb => cb.value)
state.selectedFiles = state.fileCheckboxes.filter(cb => cb.checked).map(cb => cb.value)
anttil
committed
}
anttil
committed
function onOk() {
var connection_name = state.connection.name
if (!connection_name) {
alert("No connection selected")
return false
}
var uploadUrl = env.notebook.base_url + 'openbis/dataset/' + connection_name
var notebook = IPython.notebook
var files = state.fileCheckboxes.filter(cb => cb.checked).map(cb => cb.value)
anttil
committed
var re = /\/notebooks\/(.*?)$/
var filepath = window.location.pathname.match(re)[1]
files.push(filepath)
var props = {}
for (input of $('#upload-input-fields').find('input')) {
props[input.name] = input.value
}
anttil
committed
var dataSetInfo = {
"type": dataset_types.value,
"files": files,
"parents": state.datasetCheckboxes.filter(cb => cb.checked).map(cb => cb.value),
"entityIdentifier": entityIdentifier.firstChild.value,
"props": props
anttil
committed
}
var settings = {
url: uploadUrl,
processData: false,
type: 'POST',
dataType: 'json',
data: JSON.stringify(dataSetInfo),
contentType: 'application/json',
success: function (data) {
anttil
committed
saveState()
$('div.modal').remove()
$('div.modal-backdrop').remove()
anttil
committed
common.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) {
hideSpinner()
if ("errors" in data.responseJSON) {
var errors = data.responseJSON.errors
for (error of errors) {
let key, value
Object.keys(error).forEach(k => {
key = k.toLowerCase()
value = error[k]
})
anttil
committed
errorElements[key in errorElements ? key : "main"].textContent = value
anttil
committed
} else {
errorElements["main"].textContent = "Server error"
anttil
committed
}
}
cleanErrors()
anttil
committed
utils.ajax(settings)
return false
anttil
committed
}
anttil
committed
function onCancel() {
saveState()
return true
}
anttil
committed
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: {
anttil
committed
'Cancel': {
click: onCancel
},
anttil
committed
'Upload': {
class: 'btn-primary btn-large',
click: onOk
}
},
notebook: env.notebook,
keyboard_manager: env.notebook.keyboard_manager
})
}
}
}
}