"README.md" did not exist on "c1d6299afae3b99cf299b93860bbfd78bd41fd9e"
Newer
Older
piotr.kupczyk@id.ethz.ch
committed
delete newMultiselectedRows[row.id]
} else {
newMultiselectedRows[row.id] = true
}
await this.multiselectRows(Object.keys(newMultiselectedRows))
}
}
piotr.kupczyk@id.ethz.ch
committed
async handleMultiselectAllRowsChange() {
piotr.kupczyk@id.ethz.ch
committed
const { rows, multiselectedRows } = this.context.getState()
piotr.kupczyk@id.ethz.ch
committed
const rowIds = rows.map(row => String(row.id))
piotr.kupczyk@id.ethz.ch
committed
const multiselectedRowIds = Object.keys(multiselectedRows)
let newMultiselectedRowIds = null
if (_.difference(rowIds, multiselectedRowIds).length === 0) {
newMultiselectedRowIds = _.difference(multiselectedRowIds, rowIds)
} else {
newMultiselectedRowIds = _.union(multiselectedRowIds, rowIds)
}
this.multiselectRows(newMultiselectedRowIds)
}
piotr.kupczyk@id.ethz.ch
committed
async handleMultiselectionClear() {
this.multiselectRows([])
}
piotr.kupczyk@id.ethz.ch
committed
async handleExecuteAction(action) {
if (action && action.execute) {
const { multiselectedRows } = this.context.getState()
action.execute({ multiselectedRows })
}
}
piotr.kupczyk@id.ethz.ch
committed
async handleExport() {
piotr.kupczyk@id.ethz.ch
committed
const exportable = this.getExportable()
piotr.kupczyk@id.ethz.ch
committed
if (!exportable) {
return
piotr.kupczyk@id.ethz.ch
committed
} else if (exportable.fileFormat === GridExportOptions.FILE_FORMAT.TSV) {
piotr.kupczyk@id.ethz.ch
committed
await this.handleExportTSV(exportable)
piotr.kupczyk@id.ethz.ch
committed
} else if (exportable.fileFormat === GridExportOptions.FILE_FORMAT.XLS) {
piotr.kupczyk@id.ethz.ch
committed
await this.handleExportXLS(exportable)
piotr.kupczyk@id.ethz.ch
committed
}
}
piotr.kupczyk@id.ethz.ch
committed
async handleExportTSV(exportable) {
piotr.kupczyk@id.ethz.ch
committed
const _this = this
const state = this.context.getState()
const props = this.context.getProps()
piotr.kupczyk@id.ethz.ch
committed
function _stringToUtf16ByteArray(str) {
var bytes = []
bytes.push(255, 254)
for (var i = 0; i < str.length; ++i) {
var charCode = str.charCodeAt(i)
bytes.push(charCode & 0xff) //low byte
bytes.push((charCode & 0xff00) >>> 8) //high byte (might be 0)
}
return bytes
}
piotr.kupczyk@id.ethz.ch
committed
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
function _getFileName(prefix) {
const now = new Date()
const year = String(now.getFullYear()).padStart(4, '0')
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
const hours = String(now.getHours()).padStart(2, '0')
const minutes = String(now.getMinutes()).padStart(2, '0')
const seconds = String(now.getSeconds()).padStart(2, '0')
const millis = String(now.getMilliseconds()).padStart(3, '0')
return (
prefix +
'.' +
year +
'-' +
month +
'-' +
day +
'-' +
hours +
'-' +
minutes +
'-' +
seconds +
'-' +
millis +
'.tsv'
)
}
piotr.kupczyk@id.ethz.ch
committed
async function _getExportedRows() {
const { exportOptions } = state
var exportedRows = []
piotr.kupczyk@id.ethz.ch
committed
if (exportOptions.rows === GridExportOptions.ROWS.ALL_PAGES) {
piotr.kupczyk@id.ethz.ch
committed
if (state.local) {
exportedRows = state.sortedRows
} else if (props.loadRows) {
const loadedResult = await props.loadRows({
filters: state.filters,
globalFilter: state.globalFilter,
page: 0,
pageSize: 1000000,
sortings: state.sortings
})
exportedRows = loadedResult.rows
}
piotr.kupczyk@id.ethz.ch
committed
} else if (exportOptions.rows === GridExportOptions.ROWS.CURRENT_PAGE) {
piotr.kupczyk@id.ethz.ch
committed
exportedRows = state.rows
piotr.kupczyk@id.ethz.ch
committed
} else if (exportOptions.rows === GridExportOptions.ROWS.SELECTED_ROWS) {
piotr.kupczyk@id.ethz.ch
committed
exportedRows = Object.values(state.multiselectedRows).map(
selectedRow => selectedRow.data
)
} else {
throw Error('Unsupported rows option: ' + exportOptions.rows)
}
return exportedRows
}
async function _getExportedColumns(exportedRows) {
const { exportOptions } = state
var exportedColumns = []
piotr.kupczyk@id.ethz.ch
committed
if (exportOptions.columns === GridExportOptions.COLUMNS.ALL) {
piotr.kupczyk@id.ethz.ch
committed
exportedColumns = _this.getAllColumns()
piotr.kupczyk@id.ethz.ch
committed
} else if (exportOptions.columns === GridExportOptions.COLUMNS.VISIBLE) {
piotr.kupczyk@id.ethz.ch
committed
const { newAllColumns, newColumnsVisibility, newColumnsSorting } =
await _this._loadColumns(
exportedRows,
state.columnsVisibility,
state.columnsSorting
)
piotr.kupczyk@id.ethz.ch
committed
_this._sortColumns(newAllColumns, newColumnsSorting)
piotr.kupczyk@id.ethz.ch
committed
exportedColumns = newAllColumns.filter(
column => newColumnsVisibility[column.name]
)
piotr.kupczyk@id.ethz.ch
committed
} else {
throw Error('Unsupported columns option: ' + exportOptions.columns)
}
return exportedColumns.filter(column => column.exportable)
}
function _exportTSV(rows, columns) {
const { exportOptions } = state
piotr.kupczyk@id.ethz.ch
committed
const headers = columns.map(column => column.name)
piotr.kupczyk@id.ethz.ch
committed
const arrayOfRowArrays = []
piotr.kupczyk@id.ethz.ch
committed
arrayOfRowArrays.push(headers)
rows.forEach(row => {
var rowAsArray = []
columns.forEach(column => {
var rowValue = column.getValue({
row,
column,
operation: 'export',
exportOptions
})
if (!rowValue) {
rowValue = ''
} else {
var specialCharsRemover = document.createElement('textarea')
specialCharsRemover.innerHTML = rowValue
rowValue = specialCharsRemover.value //Removes special HTML Chars
rowValue = String(rowValue).replace(/\r?\n|\r|\t/g, ' ') //Remove carriage returns and tabs
piotr.kupczyk@id.ethz.ch
committed
if (exportOptions.values === GridExportOptions.VALUES.RICH_TEXT) {
piotr.kupczyk@id.ethz.ch
committed
// do nothing with the value
piotr.kupczyk@id.ethz.ch
committed
} else if (
exportOptions.values === GridExportOptions.VALUES.PLAIN_TEXT
) {
piotr.kupczyk@id.ethz.ch
committed
rowValue = String(rowValue).replace(/<(?:.|\n)*?>/gm, '')
} else {
throw Error('Unsupported values option: ' + exportOptions.values)
}
}
rowAsArray.push(rowValue)
})
arrayOfRowArrays.push(rowAsArray)
})
piotr.kupczyk@id.ethz.ch
committed
{
header: false,
delimiter: '\t',
quoted: false
},
arrayOfRowArrays,
function (err, tsv) {
var utf16bytes = _stringToUtf16ByteArray(tsv)
var utf16bytesArray = new Uint8Array(utf16bytes.length)
utf16bytesArray.set(utf16bytes, 0)
var blob = new Blob([utf16bytesArray], {
type: 'text/tsv;charset=UTF-16LE;'
})
piotr.kupczyk@id.ethz.ch
committed
FileSaver.saveAs(blob, _getFileName(exportable.filePrefix))
piotr.kupczyk@id.ethz.ch
committed
}
)
}
piotr.kupczyk@id.ethz.ch
committed
try {
this.context.setState({
exportState: {
loading: true
}
})
piotr.kupczyk@id.ethz.ch
committed
const exportedRows = await _getExportedRows()
const exportedColumns = await _getExportedColumns(exportedRows)
_exportTSV(exportedRows, exportedColumns)
piotr.kupczyk@id.ethz.ch
committed
this.context.setState({
exportState: null
})
} catch (e) {
this.context.setState({
exportState: {
piotr.kupczyk@id.ethz.ch
committed
error: e
piotr.kupczyk@id.ethz.ch
committed
}
})
}
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
async handleExportXLS(exportable) {
piotr.kupczyk@id.ethz.ch
committed
const _this = this
piotr.kupczyk@id.ethz.ch
committed
const state = this.context.getState()
const props = this.context.getProps()
piotr.kupczyk@id.ethz.ch
committed
if (!props.exportXLS) {
piotr.kupczyk@id.ethz.ch
committed
console.error(
piotr.kupczyk@id.ethz.ch
committed
'Missing exportXLS callback function for grid with id: ' + props.id
piotr.kupczyk@id.ethz.ch
committed
)
return
}
piotr.kupczyk@id.ethz.ch
committed
async function _getExportedRows() {
const { exportOptions } = state
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
let exportedRows = []
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (exportOptions.rows === GridExportOptions.ROWS.ALL_PAGES) {
piotr.kupczyk@id.ethz.ch
committed
if (state.local) {
exportedRows = state.sortedRows
} else if (props.loadRows) {
const columns = {}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
state.allColumns.forEach(column => {
columns[column.name] = column
})
const loadedResult = await props.loadRows({
columns: columns,
filterMode: state.filterMode,
filters: state.filters,
globalFilter: state.globalFilter,
page: 0,
pageSize: 1000000,
sortings: state.sortings
})
exportedRows = loadedResult.rows
}
piotr.kupczyk@id.ethz.ch
committed
} else if (exportOptions.rows === GridExportOptions.ROWS.CURRENT_PAGE) {
piotr.kupczyk@id.ethz.ch
committed
exportedRows = state.rows
piotr.kupczyk@id.ethz.ch
committed
} else if (exportOptions.rows === GridExportOptions.ROWS.SELECTED_ROWS) {
piotr.kupczyk@id.ethz.ch
committed
exportedRows = Object.values(state.multiselectedRows).map(
selectedRow => selectedRow.data
)
} else {
piotr.kupczyk@id.ethz.ch
committed
throw Error('Unsupported rows option: ' + exportOptions.columns)
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (exportedRows.some(row => _.isEmpty(row.exportableId))) {
throw Error(
"Some of the rows to be exported do not have 'exportableId' set."
)
}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
return exportedRows
}
async function _getExportedFields(exportedRows) {
piotr.kupczyk@id.ethz.ch
committed
const { exportOptions } = state
let exportedFieldsMap = {}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (exportOptions.columns === GridExportOptions.COLUMNS.ALL) {
exportedFieldsMap = {}
piotr.kupczyk@id.ethz.ch
committed
} else if (exportOptions.columns === GridExportOptions.COLUMNS.VISIBLE) {
const exportableFields = []
piotr.kupczyk@id.ethz.ch
committed
// find visible exportable columns for the exported rows
piotr.kupczyk@id.ethz.ch
committed
const { newAllColumns, newColumnsVisibility, newColumnsSorting } =
piotr.kupczyk@id.ethz.ch
committed
await _this._loadColumns(
piotr.kupczyk@id.ethz.ch
committed
exportedRows,
state.columnsVisibility,
state.columnsSorting
)
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
_this._sortColumns(newAllColumns, newColumnsSorting)
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
newAllColumns.forEach(column => {
if (column.exportableField && newColumnsVisibility[column.name]) {
exportableFields.push(column.exportableField)
piotr.kupczyk@id.ethz.ch
committed
}
})
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
// build exported fields map: { kind: { type: [{ type: "PROPERTY/ATTRIBUTE", id: "propertyCode/attributeCode"}, ...], ... }, ... }
const TYPE_KINDS = {
[GridExportOptions.EXPORTABLE_KIND.SAMPLE_TYPE]: true,
[GridExportOptions.EXPORTABLE_KIND.EXPERIMENT_TYPE]: true,
[GridExportOptions.EXPORTABLE_KIND.DATASET_TYPE]: true,
[GridExportOptions.EXPORTABLE_KIND.VOCABULARY]: true
}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
exportedRows.forEach(exportedRow => {
piotr.kupczyk@id.ethz.ch
committed
let { exportable_kind, type_perm_id } = exportedRow.exportableId
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (!_.isNil(exportable_kind)) {
piotr.kupczyk@id.ethz.ch
committed
if (TYPE_KINDS[exportable_kind]) {
type_perm_id = exportable_kind
exportable_kind = 'TYPE'
}
let exportedFieldsForKind = exportedFieldsMap[exportable_kind]
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (_.isNil(exportedFieldsForKind)) {
exportedFieldsMap[exportable_kind] = exportedFieldsForKind = {}
}
piotr.kupczyk@id.ethz.ch
committed
if (!_.isNil(type_perm_id)) {
exportedFieldsForKind[type_perm_id] = exportableFields
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
}
})
} else {
piotr.kupczyk@id.ethz.ch
committed
throw Error('Unsupported columns option: ' + exportOptions.columns)
piotr.kupczyk@id.ethz.ch
committed
}
return exportedFieldsMap
piotr.kupczyk@id.ethz.ch
committed
}
try {
this.context.setState({
exportState: {
loading: true
}
})
const exportedRows = await _getExportedRows()
const exportedFields = await _getExportedFields(exportedRows)
piotr.kupczyk@id.ethz.ch
committed
const exportedIds = exportedRows.map(row => row.exportableId)
const { sessionToken, exportResult } = await props.exportXLS({
exportedFilePrefix: exportable.filePrefix,
exportedFileContent: exportable.fileContent,
piotr.kupczyk@id.ethz.ch
committed
exportedIds: exportedIds,
exportedFields: exportedFields,
exportedValues: state.exportOptions.values,
piotr.kupczyk@id.ethz.ch
committed
exportedImportCompatible: state.exportOptions.importCompatible,
exportedReferredMasterData:
piotr.kupczyk@id.ethz.ch
committed
exportable.fileContent === GridExportOptions.FILE_CONTENT.TYPES &&
state.exportOptions.includeDependencies
piotr.kupczyk@id.ethz.ch
committed
})
if (exportResult.status === 'OK') {
piotr.kupczyk@id.ethz.ch
committed
const filePath = exportResult.result.file_name
piotr.kupczyk@id.ethz.ch
committed
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1)
const fileUrl =
piotr.kupczyk@id.ethz.ch
committed
'/openbis/openbis/download/?sessionID=' +
piotr.kupczyk@id.ethz.ch
committed
encodeURIComponent(sessionToken) +
'&filePath=' +
encodeURIComponent(filePath)
piotr.kupczyk@id.ethz.ch
committed
if (!_.isEmpty(exportResult.result.warnings)) {
piotr.kupczyk@id.ethz.ch
committed
this.context.setState({
exportState: {
piotr.kupczyk@id.ethz.ch
committed
warnings: exportResult.result.warnings,
piotr.kupczyk@id.ethz.ch
committed
fileName,
fileUrl
}
piotr.kupczyk@id.ethz.ch
committed
})
piotr.kupczyk@id.ethz.ch
committed
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
} else {
this.context.setState({
exportState: null
})
this.handleExportDownload(fileName, fileUrl)
}
} else if (exportResult.status === 'error') {
this.context.setState({
exportState: {
error: exportResult.message
}
})
} else {
this.context.setState({
exportState: {
error: JSON.stringify(exportResult)
}
})
}
} catch (e) {
this.context.setState({
exportState: {
piotr.kupczyk@id.ethz.ch
committed
error: e
piotr.kupczyk@id.ethz.ch
committed
}
})
}
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
handleExportDownload(fileName, fileUrl) {
this.context.setState({
exportState: null
})
const link = document.createElement('a')
link.href = fileUrl
link.download = fileName
link.click()
}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
handleExportCancel() {
this.context.setState({
exportState: null
piotr.kupczyk@id.ethz.ch
committed
})
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
async handleExportOptionsChange(exportOptions) {
await this.context.setState(() => ({
exportOptions
}))
await this._saveSettings()
}
piotr.kupczyk@id.ethz.ch
committed
async handleMeasured(cellRef, column, row) {
piotr.kupczyk@id.ethz.ch
committed
if (!this.measureQueue) {
this.measureQueue = []
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
this.measureQueue.push({
cellRef,
column,
row
})
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (this.measureTimeoutId) {
clearTimeout(this.measureTimeoutId)
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
this.measureTimeoutId = setTimeout(() => {
piotr.kupczyk@id.ethz.ch
committed
this.context.setState(state => {
piotr.kupczyk@id.ethz.ch
committed
const heights = state.heights
let newHeights = heights
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
this.measureQueue.forEach(measureItem => {
const rowHeights = heights[measureItem.row.id]
let newRowHeights = newHeights[measureItem.row.id] || rowHeights
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (measureItem.cellRef.current) {
const height = rowHeights
? rowHeights[measureItem.column.name]
: null
const newHeight = measureItem.cellRef.current.scrollHeight
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (newHeight !== height) {
if (newHeights === heights) {
newHeights = {
...heights
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
}
if (newRowHeights === rowHeights) {
newRowHeights = {
...rowHeights
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
newHeights[measureItem.row.id] = newRowHeights
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
newRowHeights[measureItem.column.name] = newHeight
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
})
return {
heights: newHeights
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
})
piotr.kupczyk@id.ethz.ch
committed
this.measureQueue = []
piotr.kupczyk@id.ethz.ch
committed
}, 500)
piotr.kupczyk@id.ethz.ch
committed
}
getAllColumns() {
const { allColumns, columnsSorting } = this.context.getState()
let columns = [...allColumns]
this._sortColumns(columns, columnsSorting)
piotr.kupczyk@id.ethz.ch
committed
return this._getCachedValue('allColumns', columns)
}
getVisibleColumns() {
const { allColumns, columnsSorting, columnsVisibility } =
this.context.getState()
let columns = [...allColumns]
columns = columns.filter(column => columnsVisibility[column.name])
this._sortColumns(columns, columnsSorting)
piotr.kupczyk@id.ethz.ch
committed
return this._getCachedValue('visibleColumns', columns)
}
piotr.kupczyk@id.ethz.ch
committed
getPage() {
const { page } = this.context.getState()
return page
}
getPageSize() {
const { pageSize } = this.context.getState()
return pageSize
}
piotr.kupczyk@id.ethz.ch
committed
getSortings() {
const { sortings } = this.context.getState()
return sortings
piotr.kupczyk@id.ethz.ch
committed
}
getFilters() {
const { filters } = this.context.getState()
return filters
}
piotr.kupczyk@id.ethz.ch
committed
getGlobalFilter() {
const { globalFilter } = this.context.getState()
return globalFilter
}
getRows() {
const { rows } = this.context.getState()
return rows
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
getSelectedRow() {
const { selectedRow } = this.context.getState()
return selectedRow
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
getMultiselectedRows() {
const { multiselectedRows } = this.context.getState()
return multiselectedRows
}
piotr.kupczyk@id.ethz.ch
committed
getTotalCount() {
const { totalCount } = this.context.getState()
return totalCount
}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
getExportable() {
const { exportable } = this.context.getProps()
piotr.kupczyk@id.ethz.ch
committed
if (exportable !== undefined) {
return exportable
} else {
return null
}
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
_getCachedValue(key, newValue) {
if (_.isEqual(this.cache[key], newValue)) {
return this.cache[key]
} else {
this.cache[key] = newValue
return newValue
}
}
piotr.kupczyk@id.ethz.ch
committed
_getObjectValue(value) {
return _.isObject(value) ? value : undefined
}
_getArrayValue(value) {
return _.isArray(value) ? value : undefined
}
_getStringValue(value) {
return _.isString(value) ? value : undefined
}
_getEnumValue(value, allowedValues) {
return _.includes(allowedValues, value) ? value : undefined
}
piotr.kupczyk@id.ethz.ch
committed
_getBooleanValue(value) {
return _.isBoolean(value) ? value : undefined
}
piotr.kupczyk@id.ethz.ch
committed
_isEmpty(value) {
return (
value === null ||
value === undefined ||
(_.isString(value) && value.trim().length === 0)
)
piotr.kupczyk@id.ethz.ch
committed
}
_split(str) {
return str.split(' ').filter(token => !this._isEmpty(token))
}
_onError(error) {
const { onError } = this.context.getProps()
if (onError) {
onError(error)
}
throw error
}