UNPKG

ucsc-xena-client

Version:

UCSC Xena Client. Functional genomics visualizations.

452 lines (393 loc) 16.7 kB
'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _PureComponent2 = require('./PureComponent'); var _PureComponent3 = _interopRequireDefault(_PureComponent2); var _app_bar = require('react-toolbox/lib/app_bar'); var _app_bar2 = _interopRequireDefault(_app_bar); var _fieldSpec = require('./models/fieldSpec'); var _datasetJoins = require('./models/datasetJoins'); var _SampleSearch = require('./views/SampleSearch'); var _uuid = require('./uuid'); var _uuid2 = _interopRequireDefault(_uuid); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } var React = require('react'); var pdf = require('./pdfSpreadsheet'); var _ = require('./underscore_ext'); var konami = require('./konami'); var widgets = require('./columnWidgets'); var classNames = require('classnames'); var gaEvents = require('./gaEvents'); // Styles var compStyles = require('./AppControls.module.css'); var modeIcon = { chart: 'view_column', heatmap: 'insert_chart' }; var modeEvent = { chart: 'heatmap', heatmap: 'chart' }; var modeHelp = { chart: 'View as columns', heatmap: 'View as chart' }; function download(_ref) { var _ref2 = _slicedToArray(_ref, 2), fields = _ref2[0], rows = _ref2[1]; var txt = _.map([fields].concat(rows), function (row) { return row.join('\t'); }).join('\n'); // use blob for bug in chrome: https://code.google.com/p/chromium/issues/detail?id=373182 var url = URL.createObjectURL(new Blob([txt], { type: 'text/tsv' })); var a = document.createElement('a'); var filename = 'denseDataOnlyDownload.tsv'; _.extend(a, { id: filename, download: filename, href: url }); document.body.appendChild(a); a.click(); document.body.removeChild(a); } var asciiB = 66; var Actions = function Actions(_ref3) { var onPdf = _ref3.onPdf, onDownload = _ref3.onDownload, onShowWelcome = _ref3.onShowWelcome, showWelcome = _ref3.showWelcome, onMode = _ref3.onMode, mode = _ref3.mode, hasColumn = _ref3.hasColumn; return React.createElement( 'div', { className: compStyles.actions }, hasColumn ? React.createElement( 'i', { className: 'material-icons', onClick: onMode, title: modeHelp[mode] }, modeIcon[mode] ) : null, hasColumn && mode === 'heatmap' ? React.createElement( 'i', { className: 'material-icons', onClick: onPdf, title: 'Download as PDF' }, 'picture_as_pdf' ) : null, hasColumn ? React.createElement( 'i', { className: 'material-icons', onClick: onDownload, title: 'Download as tsv' }, 'cloud_download' ) : null, showWelcome ? null : React.createElement( 'i', { className: 'material-icons', onClick: onShowWelcome }, 'help' ) ); }; var BasicSearch = function BasicSearch(_ref4) { var help = _ref4.help, onTies = _ref4.onTies, tiesEnabled = _ref4.tiesEnabled, searchProps = _objectWithoutProperties(_ref4, ['help', 'onTies', 'tiesEnabled']); return React.createElement( 'div', { className: compStyles.filter }, React.createElement(_SampleSearch.SampleSearch, searchProps), help ? React.createElement( 'a', { href: help, target: '_blank', className: compStyles.filterHelp }, React.createElement( 'i', { className: 'material-icons' }, 'help_outline' ) ) : null, tiesEnabled ? React.createElement( 'a', { onClick: onTies, className: compStyles.ties }, React.createElement( 'i', { className: 'material-icons' }, 'toys' ) ) : null ); }; var TiesSearch = function TiesSearch() { return React.createElement( 'div', { className: compStyles.filter }, React.createElement( 'span', null, 'Pathology Report Search and Filter by TIES' ) ); }; var TiesActions = function TiesActions(_ref5) { var onTies = _ref5.onTies, onTiesColumn = _ref5.onTiesColumn; return React.createElement( 'div', { className: compStyles.actions }, React.createElement( 'button', { onClick: onTiesColumn }, 'Create filtered column' ), React.createElement( 'a', { onClick: onTies, className: compStyles.filterHelp }, React.createElement( 'i', { className: 'material-icons' }, 'close' ) ) ); }; function getFilterColumn(title, samples) { var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var field = (0, _fieldSpec.signatureField)(title, _extends({ columnLabel: 'filter', valueType: 'coded', signature: ['in', samples] }, opts)), colSpec = (0, _datasetJoins.getColSpec)([field], []), settings = _.assoc(colSpec, 'width', 136, 'user', _.pick(colSpec, ['columnLabel', 'fieldLabel'])); return { id: (0, _uuid2.default)(), settings: settings }; } // XXX drop this.props.style? Not sure it's used. var AppControls = function (_PureComponent) { _inherits(AppControls, _PureComponent); function AppControls() { var _ref6; var _temp, _this, _ret; _classCallCheck(this, AppControls); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref6 = AppControls.__proto__ || Object.getPrototypeOf(AppControls)).call.apply(_ref6, [this].concat(args))), _this), _this.onFilter = function () { var _this$props = _this.props, callback = _this$props.callback, _this$props$appState = _this$props.appState, samplesMatched = _this$props$appState.samplesMatched, cohortSamples = _this$props$appState.cohortSamples, matching = _.map(samplesMatched, function (i) { return cohortSamples[i]; }); gaEvents('spreadsheet', 'samplesearch', 'filter'); callback(['sampleFilter', matching]); }, _this.onFilterZoom = function () { var _this$props2 = _this.props, _this$props2$appState = _this$props2.appState, samples = _this$props2$appState.samples, samplesMatched = _this$props2$appState.samplesMatched, height = _this$props2$appState.zoom.height, callback = _this$props2.callback, toOrder = _.object(samples, _.range(samples.length)), index = toOrder[_.min(samplesMatched, function (s) { return toOrder[s]; })], last = toOrder[_.max(samplesMatched, function (s) { return toOrder[s]; })]; gaEvents('spreadsheet', 'samplesearch', 'zoom'); callback(['zoom', { index: index, height: height, count: last - index + 1 }]); }, _this.onFilterColumn = function () { var _this$props3 = _this.props, _this$props3$appState = _this$props3.appState, cohortSamples = _this$props3$appState.cohortSamples, sampleSearch = _this$props3$appState.sampleSearch, samplesMatched = _this$props3$appState.samplesMatched, callback = _this$props3.callback, matching = _.map(samplesMatched, function (i) { return cohortSamples[i]; }); gaEvents('spreadsheet', 'samplesearch', 'new column'); callback(['add-column', 0, getFilterColumn(sampleSearch, matching, { filter: sampleSearch })]); }, _this.onTiesColumn = function () { var _this$props4 = _this.props, _this$props4$appState = _this$props4.appState, _this$props4$appState2 = _this$props4$appState.ties, filter = _this$props4$appState2.filter, docs = _this$props4$appState2.docs, cohortSamples = _this$props4$appState.cohortSamples, patient = _this$props4$appState.survival.patient, callback = _this$props4.callback, pindex = patient.data.req.values[0], pcodes = patient.data.codes, keep = new Set(Object.keys(filter).filter(function (k) { return filter[k]; }).map(function (i) { return docs[i].patient; })), matching = cohortSamples.filter(function (s, i) { return keep.has(pcodes[pindex[i]]); }); callback(['add-column', 0, getFilterColumn('TIES selection', matching)]); callback(['ties-dismiss']); }, _this.onMode = function () { var _this$props5 = _this.props, callback = _this$props5.callback, mode = _this$props5.appState.mode; gaEvents('spreadsheet', 'mode', modeEvent[mode]); callback([modeEvent[mode]]); }, _this.onRefresh = function () { var callback = _this.props.callback; callback(['refresh-cohorts']); }, _this.onPdf = function () { gaEvents('spreadsheet', 'pdf', 'spreadsheet'); pdf(_this.props.appState); }, _this.onCohortSelect = function (value) { _this.props.callback(['cohort', value]); }, _this.onTies = function () { var ties = _this.props.appState.ties; _this.props.callback([_.get(ties, 'open') ? 'ties-dismiss' : 'ties-open']); }, _this.onDownload = function () { var sampleFormat = _this.props.sampleFormat, _this$props$appState2 = _this.props.appState, samples = _this$props$appState2.samples, columns = _this$props$appState2.columns, columnOrder = _this$props$appState2.columnOrder, index = _this$props$appState2.index, data = _this$props$appState2.data, rectData = columnOrder.filter(function (id) { return _.contains(['float', 'coded', 'segmented'], columns[id].valueType) && _.getIn(data, [id, 'status']) === 'loaded'; }), datasets = rectData.map(function (id) { return widgets.download({ samples: samples, column: columns[id], index: index[id], data: data[id], sampleFormat: sampleFormat }); }), combinedRows = _.mmap.apply(_, _toConsumableArray(_.pluck(datasets, 1)).concat([function () { for (var _len2 = arguments.length, rows = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { rows[_key2] = arguments[_key2]; } rows.pop(); // mmap passes index return [].concat(_toConsumableArray(rows[0]), _toConsumableArray(_.flatten(rows.slice(1).map(function (cols) { return cols.slice(1); })))); }])), combinedHeaders = _.flatmap(datasets, function (_ref7, i) { var _ref8 = _slicedToArray(_ref7, 1), headers = _ref8[0]; return i === 0 ? headers : headers.slice(1); }); gaEvents('spreadsheet', 'download', 'spreadsheet'); download([combinedHeaders, combinedRows]); }, _this.onShowWelcome = function () { _this.props.onShowWelcome(); }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(AppControls, [{ key: 'componentWillMount', value: function componentWillMount() { var _this2 = this; this.nsub = konami(asciiB).subscribe(function () { _this2.props.callback(['notifications-enable']); }); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this.nsub.unsubscribe(); } }, { key: 'render', value: function render() { var _props = this.props, _props$appState = _props.appState, cohort = _props$appState.cohort, mode = _props$appState.mode, columnOrder = _props$appState.columnOrder, showWelcome = _props$appState.showWelcome, samples = _props$appState.samples, sampleSearch = _props$appState.sampleSearch, samplesMatched = _props$appState.samplesMatched, ties = _props$appState.ties, onReset = _props.onReset, help = _props.help, onResetSampleFilter = _props.onResetSampleFilter, onHighlightChange = _props.onHighlightChange, callback = _props.callback, matches = _.get(samplesMatched, 'length', samples.length), onPdf = this.onPdf, onDownload = this.onDownload, onShowWelcome = this.onShowWelcome, onMode = this.onMode, tiesOpen = _.get(ties, 'open'), cohortName = _.get(cohort, 'name'), hasColumn = !!columnOrder.length, index = _.getIn(this.props, ['zoom', 'index']) || 0, count = _.getIn(this.props, ['zoom', 'count']) || 0, sampleFilter = _.get(cohort, 'sampleFilter'), filter = sampleFilter ? React.createElement( 'span', { onClick: onResetSampleFilter, className: compStyles.appliedFilter }, 'Filtered to ' ) : null, fraction = count === samples.length ? '' : '- Zoomed to ' + (index + 1) + ' - ' + (index + count); return React.createElement( _app_bar2.default, null, React.createElement( 'div', { className: classNames(compStyles.appBarContainer, compStyles.cohort) }, React.createElement( 'div', { className: compStyles.titleContainer }, React.createElement( 'span', { className: compStyles.title }, cohortName ), React.createElement( 'span', { className: compStyles.subtitle }, filter, ' ', samples.length, ' Samples ', fraction ? fraction : null ) ), React.createElement( 'i', { className: 'material-icons', onClick: this.onRefresh, title: 'Reload cohort data' }, 'refresh' ), React.createElement( 'i', { className: 'material-icons', onClick: onReset, title: 'Pick new cohort' }, 'close' ) ), React.createElement( 'div', { className: classNames(compStyles.appBarContainer, compStyles.tools) }, tiesOpen ? React.createElement(TiesSearch, { onTies: this.onTies }) : React.createElement(BasicSearch, { value: sampleSearch, matches: matches, sampleCount: samples.length, onFilter: this.onFilter, onZoom: this.onFilterZoom, onCreateColumn: this.onFilterColumn, onChange: onHighlightChange, mode: mode, onResetSampleFilter: onResetSampleFilter, cohort: cohort, callback: callback, help: help, onTies: this.onTies, tiesEnabled: false }), tiesOpen ? React.createElement(TiesActions, { onTies: this.onTies, onTiesColumn: this.onTiesColumn }) : React.createElement(Actions, { onPdf: onPdf, onDownload: onDownload, onShowWelcome: onShowWelcome, showWelcome: showWelcome, onMode: onMode, mode: mode, hasColumn: hasColumn }) ) ); } }]); return AppControls; }(_PureComponent3.default); module.exports = { AppControls: AppControls };