Skip to content

Commit

Permalink
Export to different data formats (#54)
Browse files Browse the repository at this point in the history
* Empty commit

* Stub export modal

* Stub IRIDA/GSAID opts and CSS fixes

* Properly use bootstrap justification

* Remove unused param

* wip

* Missing semicolon

* Implemented IRIDA export

* Move irida export logic to fn

* wip

* wip

* Finish implementing gisaid export

* clean-up

* Fill out type for gisaid

* Use trimmed data on export
  • Loading branch information
ivansg44 authored Jun 11, 2020
1 parent 5b277ce commit 4087524
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 15 deletions.
66 changes: 54 additions & 12 deletions main.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<label for="open-file-input" class="dropdown-item mb-0" id="open-dropdown-item">Open</label>
<input type="file" accept=".xlsx,.xls,.tsv,.csv" class="form-control-file" id="open-file-input">
<span class="dropdown-item" data-toggle="modal" data-target="#save-as-modal">Save As...</span>
<span class="dropdown-item" data-toggle="modal" data-target="#export-to-modal">Export To...</span>
</div>
</div>
<div class="btn-group" id="settings-dropdown-btn-group" role="group">
Expand Down Expand Up @@ -69,11 +70,12 @@
<span class="text-danger">Clear existing data?</span>
</div>
</div>
<div class="row justify-content-end">
<div class="col-3 col-sm-2 mr-3">
<div class="row mt-3">
<div class="col-2 col-sm-6"></div>
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
<div class="col-3 col-sm-2">
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-danger" id="clear-data-confirm-btn" data-dismiss="modal">Clear</button>
</div>
</div>
Expand Down Expand Up @@ -105,11 +107,12 @@
</div>
</div>
</div>
<div class="row justify-content-end mt-3">
<div class="col-3 col-sm-2 mr-3">
<div class="row mt-3">
<div class="col-2 col-sm-6"></div>
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
<div class="col-3 col-sm-2">
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-primary" id="save-as-confirm-btn">Save</button>
</div>
</div>
Expand All @@ -118,6 +121,45 @@
</div>
</div>
</div>
<div class="modal" id="export-to-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col text-danger" id="export-to-err-msg"></div>
</div>
<div class="row">
<div class="col-12 col-sm-8">
<div class="input-group">
<input type="text" class="form-control" id="base-name-export-to-input" placeholder="file name">
<div class="input-group-append">
<div class="input-group-text">.xls</div>
</div>
</div>
</div>
<div class="col mt-2 mt-sm-0">
<select class="form-control" id="export-to-format-select">
<option value="" disabled selected>Format</option>
<option value="gisaid">GISAID</option>
<option value="irida">IRIDA</option>
</select>
</div>
</div>
<div class="row mt-3">
<div class="col-2 col-sm-6"></div>
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-primary" id="export-to-confirm-btn">Export</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="specify-headers-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
Expand Down Expand Up @@ -162,8 +204,8 @@
<div class="row">
<div class="col text-danger" id="specify-headers-err-msg">Invalid row</div>
</div>
<div class="row justify-content-end mt-3">
<div class="col-3 col-sm-2">
<div class="row mt-3">
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-primary" id="specify-headers-confirm-btn">Ok</button>
</div>
</div>
Expand All @@ -180,8 +222,8 @@
<div class="row">
<div class="col text-danger" id="open-err-msg"></div>
</div>
<div class="row justify-content-end mt-3">
<div class="col-3 col-sm-2">
<div class="row mt-3">
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Ok</button>
</div>
</div>
Expand All @@ -198,8 +240,8 @@
<div class="row">
<div class="col" id="field-description-text"></div>
</div>
<div class="row justify-content-end mt-3">
<div class="col-3 col-sm-2">
<div class="row mt-3">
<div class="col d-flex justify-content-end">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Ok</button>
</div>
</div>
Expand Down
115 changes: 112 additions & 3 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,8 @@ const getTrimmedData = (hot) => {
};

/**
* Download grid headers and data to file.
* @param {Array<Array<String>>} matrix Grid data.
* Download matrix to file.
* @param {Array<Array<String>>} matrix Matrix to download.
* @param {String} baseName Basename of downloaded file.
* @param {String} ext Extension of downloaded file.
* @param {Object} xlsx SheetJS variable.
Expand All @@ -330,6 +330,94 @@ const exportFile = (matrix, baseName, ext, xlsx) => {
}
};

/**
* Download secondary headers and grid data.
* @param {String} baseName Basename of downloaded file.
* @param {Object} hot Handonstable grid instance.
* @param {Object} data See `data.js`.
* @param {Object} xlsx SheetJS variable.
*/
const exportIRIDA = (baseName, hot, data, xlsx) => {
const matrix = [getFlatHeaders(data)[1], ...getTrimmedData(hot)];
exportFile(matrix, baseName, 'xls', xlsx);
};

/**
* Download grid mapped to GISAID format.
* @param {String} baseName Basename of downloaded file.
* @param {Object} hot Handonstable grid instance.
* @param {Object} data See `data.js`.
* @param {Object} xlsx SheetJS variable.
*/
const exportGISAID = (baseName, hot, data, xlsx) => {
// TODO: As we add more formats, we should add such headers to `data.js`
const GISAIDHeaders = [
'Submitter', 'FASTA filename', 'Virus name', 'Type',
'Passage details/history', 'Collection date', 'Location',
'Additional location information', 'Host', 'Additional host information',
'Gender', 'Patient age', 'Patient status', 'Specimen source', 'Outbreak',
'Last vaccinated', 'Treatment', 'Sequencing technology', 'Assembly method',
'Coverage', 'Originating lab', 'Address',
'Sample ID given by the sample provider', 'Submitting lab', 'Address',
'Sample ID given by the submitting laboratory', 'Authors',
];

// Create a map of GISAID headers to our fields. It is a one-to-many
// relationship, with indices representing the maps.
const headerMap = {};
for (const [GISAIDIndex, _] of GISAIDHeaders.entries()) {
headerMap[GISAIDIndex] = [];
}
const fields = getFields(data);
for (const [fieldIndex, field] of fields.entries()) {
if (field.GISAID) {
let GISAIDIndex = GISAIDHeaders.indexOf(field.GISAID);
// GISAID has two fields called 'Address'
const secondAddress = 'sequence submitter contact address';
if (field.GISAID === 'Address' && field.fieldName === secondAddress) {
GISAIDIndex = GISAIDHeaders.indexOf(field.GISAID, GISAIDIndex+1);
}
headerMap[GISAIDIndex].push(fieldIndex);
}
}

// Construct GISAID's matrix
const mappedMatrix = [GISAIDHeaders];
const unmappedMatrix = getTrimmedData(hot);
for (const unmappedRow of unmappedMatrix) {
const mappedRow = [];
for (const [GISAIDIndex, GISAIDHeader] of GISAIDHeaders.entries()) {
if (GISAIDHeader === 'Type') {
mappedRow.push('coronavirus');
continue;
}

const mappedCell = [];
for (const mappedFieldIndex of headerMap[GISAIDIndex]) {
let mappedCellVal = unmappedRow[mappedFieldIndex];
if (!mappedCellVal) continue;

let unknown = mappedCellVal.toLowerCase() === 'missing';
unknown |= mappedCellVal.toLowerCase() === 'not applicable';
if (unknown) {
mappedCellVal = 'Unknown';
}

const fieldName = fields[mappedFieldIndex].fieldName;
if (fieldName === 'passage number') {
mappedCellVal = 'passage number ' + mappedCellVal;
}

mappedCell.push(mappedCellVal);
}
mappedRow.push(mappedCell.join(';'));
}
mappedMatrix.push(mappedRow);
}

exportFile(mappedMatrix, baseName, 'xls', xlsx);
};

/**
* Read local file opened by user.
* Only reads `xlsx`, `xlsx`, `csv` and `tsv` files.
Expand Down Expand Up @@ -692,7 +780,7 @@ $(document).ready(() => {
});

// File -> Save
$('#save-as-confirm-btn').click((e) => {
$('#save-as-confirm-btn').click(() => {
try {
const baseName = $('#base-name-save-as-input').val();
const ext = $('#file-ext-save-as-select').val();
Expand All @@ -709,6 +797,27 @@ $(document).ready(() => {
$('#base-name-save-as-input').val('');
});

// File -> Export to...
$('#export-to-confirm-btn').click(() => {
const baseName = $('#base-name-export-to-input').val();
const exportFormat = $('#export-to-format-select').val();
if (!exportFormat) {
$('#export-to-err-msg').text('Select a format');
return;
}
if (exportFormat === 'gisaid') {
exportGISAID(baseName, HOT, DATA, XLSX);
} else if (exportFormat === 'irida') {
exportIRIDA(baseName, HOT, DATA, XLSX);
}
$('#export-to-modal').modal('hide');
});
// Reset export modal values when the modal is closed
$('#export-to-modal').on('hidden.bs.modal', () => {
$('#export-to-err-msg').text('');
$('#base-name-export-to-input').val('');
});

// Settings -> Show ... columns
const showColsSelectors =
['#show-all-cols-dropdown-item', '#show-required-cols-dropdown-item'];
Expand Down

0 comments on commit 4087524

Please sign in to comment.