@papaemmelab/isabl-web 0.3.9 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/isabl-web.common.js +42 -42
- package/dist/isabl-web.umd.js +42 -42
- package/dist/isabl-web.umd.min.js +3 -3
- package/package.json +1 -1
package/dist/isabl-web.common.js
CHANGED
|
@@ -1943,7 +1943,7 @@ exports = module.exports = __webpack_require__("2350")(false);
|
|
|
1943
1943
|
|
|
1944
1944
|
|
|
1945
1945
|
// module
|
|
1946
|
-
exports.push([module.i, ".node-tooltip{background:rgba(0,0,0,.8)}.individual-tree-div{overflow-x:scroll;margin:auto}.individual-tree-div .node{stroke-width:3px}.individual-tree-div .node text{font-size:14px;font-weight:300;fill:#000!important;cursor:pointer}.individual-tree-div .node text.collapse-text{font-size:20px;font-weight:200;cursor:default}.individual-tree-div .node.experiment text{cursor:default}.individual-tree-div .link{fill:none;stroke-width:1.5px;stroke:#aaa}", ""]);
|
|
1946
|
+
exports.push([module.i, ".tree-tooltip.v-tooltip__content{color:#fff;padding:20px;opacity:1;font-size:12px;overflow:hidden}.node-tooltip{background:rgba(0,0,0,.8)}.individual-tree-div{overflow-x:scroll;margin:auto}.individual-tree-div .node{stroke-width:3px}.individual-tree-div .node text{font-size:14px;font-weight:300;fill:#000!important;cursor:pointer}.individual-tree-div .node text.collapse-text{font-size:20px;font-weight:200;cursor:default}.individual-tree-div .node.experiment text{cursor:default}.individual-tree-div .link{fill:none;stroke-width:1.5px;stroke:#aaa}", ""]);
|
|
1947
1947
|
|
|
1948
1948
|
// exports
|
|
1949
1949
|
|
|
@@ -91168,7 +91168,7 @@ module.exports = overArg;
|
|
|
91168
91168
|
/***/ "9224":
|
|
91169
91169
|
/***/ (function(module) {
|
|
91170
91170
|
|
|
91171
|
-
module.exports = JSON.parse("{\"name\":\"@papaemmelab/isabl-web\",\"version\":\"0.3.
|
|
91171
|
+
module.exports = JSON.parse("{\"name\":\"@papaemmelab/isabl-web\",\"version\":\"0.3.10\",\"scripts\":{\"serve\":\"vue-cli-service serve\",\"lint\":\"vue-cli-service lint\",\"build-lib\":\"vue-cli-service build --target lib --name isabl-web ./src/main.js\",\"build-wc\":\"vue-cli-service build --target wc --name isabl-web ./src/components/*.vue\",\"build-wc-async\":\"vue-cli-service build --target wc-async --name isabl-web ./src/components/*.vue\",\"publish-app\":\"yarn version --patch && yarn build-lib && yarn publish --access public\",\"dev\":\"yarn build-lib --watch\",\"test:unit\":\"vue-cli-service test:unit\",\"test:e2e\":\"vue-cli-service test:e2e\",\"test:travis\":\"yarn test:e2e --headless\",\"test:submissions\":\"node tests/utils/create_test_submission.js\",\"test:report-coverage\":\"nyc report --reporter=text-lcov > coverage.lcov && codecov -t $CODECOV_TOKEN\",\"demo\":\"nodemon demo/demo-app.js\"},\"dependencies\":{\"@mdi/font\":\"^7.0.96\",\"ansi_up\":\"^5\",\"axios\":\"^0.21.1\",\"crossfilter\":\"^1.3.12\",\"crossfilter2\":\"^1.4.7\",\"d3-tip\":\"^0.9.1\",\"dc\":\"3.1.2\",\"detect-csv\":\"^1.1.0\",\"js-md5\":\"^0.7.3\",\"minify-css-string\":\"^1.0.0\",\"moment\":\"^2.22.2\",\"register-service-worker\":\"^1.5.2\",\"v-hotkey\":\"^0.6.0\",\"vue\":\"^2.5.16\",\"vue-clipboard2\":\"^0.2.1\",\"vue-gallery\":\"^1.4.0\",\"vue-highlightjs\":\"^1.3.3\",\"vue-json-excel\":\"^0.2.5\",\"vue-observe-visibility\":\"^0.4.6\",\"vue-router\":\"^3.0.1\",\"vue-upload-component\":\"^2.8.11\",\"vuetify\":\"2.6.10\",\"vuex\":\"^3.0.1\",\"vuex-router-sync\":\"^5.0.0\"},\"devDependencies\":{\"@cypress/code-coverage\":\"^1.10.1\",\"@vue/cli-plugin-babel\":\"^3.3.0\",\"@vue/cli-plugin-e2e-cypress\":\"^3.3.0\",\"@vue/cli-plugin-eslint\":\"^3.3.0\",\"@vue/cli-plugin-pwa\":\"^3.3.0\",\"@vue/cli-plugin-unit-jest\":\"^3.3.0\",\"@vue/cli-service\":\"^3.3.0\",\"@vue/eslint-config-prettier\":\"^3.0.5\",\"@vue/test-utils\":\"^1.0.0-beta.20\",\"axios-mock-adapter\":\"^1.15.0\",\"babel-core\":\"7.0.0-bridge.0\",\"babel-jest\":\"^23.0.1\",\"babel-plugin-istanbul\":\"^5.2.0\",\"codecov\":\"^3.6.1\",\"eslint-plugin-vuetify\":\"^1.1.0\",\"express\":\"^4.16.3\",\"html-webpack-plugin\":\"^3.2.0\",\"istanbul-lib-coverage\":\"^2.0.5\",\"mini-css-extract-plugin\":\"^0.4.2\",\"nyc\":\"^14.1.1\",\"sass\":\"^1.55.0\",\"sass-loader\":\"^7.0.1\",\"vue-template-compiler\":\"^2.5.16\",\"xlsx-populate\":\"^1.19.1\"},\"browserslist\":[\"> 1%\",\"last 2 versions\",\"not ie <= 8\"],\"main\":\"./dist/isabl-web.umd.min.js\",\"license\":\"MIT\",\"files\":[\"dist/isabl-web*.js\"],\"author\":\"Juan S. Medina - Juan E. Arango\",\"description\":\"Isabl Frontend of the MSK Academic License.\",\"bugs\":{\"url\":\"https://github.com/papaemmelab/isabl_web/issues\"},\"homepage\":\"https://github.com/papaemmelab/isabl_web#readme\"}");
|
|
91172
91172
|
|
|
91173
91173
|
/***/ }),
|
|
91174
91174
|
|
|
@@ -253214,8 +253214,8 @@ var RerunButton_component = normalizeComponent(
|
|
|
253214
253214
|
)
|
|
253215
253215
|
|
|
253216
253216
|
/* harmony default export */ var RerunButton = (RerunButton_component.exports);
|
|
253217
|
-
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d220a428-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/analyses/ResultsGallery.vue?vue&type=template&id=
|
|
253218
|
-
var
|
|
253217
|
+
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d220a428-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/analyses/ResultsGallery.vue?vue&type=template&id=185780e8&
|
|
253218
|
+
var ResultsGalleryvue_type_template_id_185780e8_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (_vm.showDialog)?_c('v-dialog',{directives:[{name:"hotkey",rawName:"v-hotkey",value:(_vm.keymap),expression:"keymap"}],staticClass:"gallery-dialog",attrs:{"fullscreen":_vm.isResultModalFullScreen,"scrollable":""},model:{value:(_vm.showDialog),callback:function ($$v) {_vm.showDialog=$$v},expression:"showDialog"}},[_c('v-card',{staticClass:"gallery-card",attrs:{"flat":""}},[_c('v-card-title',{staticClass:"pa-2"},[_c('v-row',[_c('v-col',{attrs:{"cols":"6"}},[_c('h3',{staticClass:"font-weight-thin primary--text"},[_vm._v("\n "+_vm._s(_vm.result.verboseName)+"\n ")])]),_c('v-col',{staticClass:"d-flex justify-end align-center panel-slot-actions",attrs:{"cols":"6"}},[(_vm.result.frontendType === 'tsv-file' && _vm.tsvHeaders.length)?_c('v-tooltip',{attrs:{"top":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
|
|
253219
253219
|
var on = ref.on;
|
|
253220
253220
|
return [_c('v-icon',_vm._g({staticClass:"primary--text ml-4",attrs:{"small":""},on:{"click":function($event){_vm.displayRawText = !_vm.displayRawText}}},on),[_vm._v("\n "+_vm._s(_vm.displayRawText ? 'table_chart' : 'text_fields')+"\n ")])]}}],null,false,578865119)},[_vm._v("\n "+_vm._s(_vm.displayRawText ? 'Display Tabulated Content' : 'Display Raw Content')+"\n ")]):_vm._e(),(_vm.result.download)?_c('v-tooltip',{attrs:{"top":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
|
|
253221
253221
|
var on = ref.on;
|
|
@@ -253232,10 +253232,10 @@ var on = ref.on;
|
|
|
253232
253232
|
return [_c('v-icon',_vm._g({staticClass:"primary--text ml-4",attrs:{"small":""},on:{"click":_vm.hideDialog}},on),[_vm._v("\n close\n ")])]}}],null,false,804201733)},[_vm._v("\n Close file\n ")])],1)],1)],1),_c('v-row',{staticClass:"pa-0 ma-0 gallery-content",staticStyle:{"height":"85vh"}},[(_vm.loading)?_c('v-progress-linear',{staticClass:"panel-loader",attrs:{"indeterminate":"","height":"2","color":"primary"}}):_vm._e(),(_vm.resultType === 'raw' && _vm.resultKey === 'command_script')?_c('pre',{directives:[{name:"highlightjs",rawName:"v-highlightjs",value:(_vm.content),expression:"content"}],ref:"raw",staticClass:"v-markup pre-wrap"},[_vm._v(" "),_c('code',{staticClass:"bash"}),_vm._v("\n ")]):(_vm.isAnsi)?_c('code',{ref:"raw",staticClass:"v-markup"},[_c('pre',{domProps:{"innerHTML":_vm._s(_vm.content)}})]):(_vm.resultType === 'raw')?_c('code',{ref:"raw",staticClass:"v-markup"},[_c('pre',[_vm._v(" "+_vm._s(_vm.content)+"\n "),(_vm.content && !_vm.streamOptions.end)?_c('span',{staticClass:"stream-message grey--text lighten-2"},[_vm._v("\n ... Loading more rows\n ")]):_vm._e(),_vm._v("\n "),(!_vm.loading && _vm.streamOptions.end)?_c('span',{staticClass:"stream-message grey--text"},[_vm._v("\n *** End of file. ***\n ")]):_vm._e(),_vm._v("\n ")])]):(_vm.resultType === 'table')?_c('div',{ref:"table",staticClass:"tsv-table"},[_c('v-data-table',{attrs:{"headers":_vm.tsvHeaders,"items":_vm.tsvItems,"items-per-page":_vm.tsvItems.length,"hide-default-footer":"","multi-sort":"","fixed-header":"","dense":""},scopedSlots:_vm._u([{key:"body",fn:function(ref){
|
|
253233
253233
|
var items = ref.items;
|
|
253234
253234
|
return [_c('tbody',_vm._l((items),function(item){return _c('tr',{key:item.name},_vm._l((_vm.tsvHeaders),function(header,index){return _c('td',{key:index + header.value,class:[header.value === 'index' ? 'line-column text' : ''],domProps:{"innerHTML":_vm._s(_vm.parseTsvCell(_vm.$get(item, header.value)))}})}),0)}),0)]}}],null,false,3434796515)}),_c('div',{staticClass:"text-center stream-message"},[(_vm.content && !_vm.streamOptions.end)?_c('span',[_vm._v("... Loading more rows")]):_vm._e(),(!_vm.loading && _vm.streamOptions.end)?_c('span',[_vm._v("End of file.")]):_vm._e()])],1):(_vm.resultType === 'image')?_c('img',{staticClass:"results-image",attrs:{"src":_vm.$store.getters.getBlobUrl(_vm.result.downloadUrl),"alt":_vm.result.verboseName}}):(['html', 'pdf'].includes(_vm.resultType))?_c('iframe',{staticClass:"results-iframe",staticStyle:{"width":"100%","height":"100%","min-height":"80vh"},attrs:{"src":_vm.$store.getters.getBlobUrl(_vm.result.downloadUrl, ''),"frameborder":"0"}}):(_vm.resultType === 'igv_bam')?_c('iframe',{staticClass:"results-iframe",staticStyle:{"width":"100%","height":"100%","min-height":"80vh"},attrs:{"src":_vm.result.downloadUrl,"frameborder":"0"}}):(_vm.resultType === 'number')?_c('code',{staticClass:"v-markup"},[_c('span',{attrs:{"size":"100px"}},[_vm._v(_vm._s(_vm._f("round")(_vm.result.value,3)))])]):(['string', 'url-link'].includes(_vm.resultType))?_c('code',{staticClass:"v-markup"},[_c('span',{attrs:{"size":"100px"}},[_vm._v(_vm._s(_vm.result.value))])]):_vm._e()],1)],1)],1):_vm._e()}
|
|
253235
|
-
var
|
|
253235
|
+
var ResultsGalleryvue_type_template_id_185780e8_staticRenderFns = []
|
|
253236
253236
|
|
|
253237
253237
|
|
|
253238
|
-
// CONCATENATED MODULE: ./src/components/analyses/ResultsGallery.vue?vue&type=template&id=
|
|
253238
|
+
// CONCATENATED MODULE: ./src/components/analyses/ResultsGallery.vue?vue&type=template&id=185780e8&
|
|
253239
253239
|
|
|
253240
253240
|
// EXTERNAL MODULE: ./node_modules/detect-csv/index.js
|
|
253241
253241
|
var detect_csv = __webpack_require__("0f34");
|
|
@@ -253244,7 +253244,7 @@ var detect_csv_default = /*#__PURE__*/__webpack_require__.n(detect_csv);
|
|
|
253244
253244
|
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/@vue/cli-plugin-babel/node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/analyses/ResultsGallery.vue?vue&type=script&lang=js&
|
|
253245
253245
|
var cov_d7x60homs = function () {
|
|
253246
253246
|
var path = "/Users/juanes/papaemmelab/isabl_web/src/components/analyses/ResultsGallery.vue";
|
|
253247
|
-
var hash = "
|
|
253247
|
+
var hash = "fe09864f43de2d4dae5821f382f528b5c4317436";
|
|
253248
253248
|
var global = new Function("return this")();
|
|
253249
253249
|
var gcv = "__coverage__";
|
|
253250
253250
|
var coverageData = {
|
|
@@ -254027,7 +254027,7 @@ var cov_d7x60homs = function () {
|
|
|
254027
254027
|
},
|
|
254028
254028
|
end: {
|
|
254029
254029
|
line: 491,
|
|
254030
|
-
column:
|
|
254030
|
+
column: 41
|
|
254031
254031
|
}
|
|
254032
254032
|
},
|
|
254033
254033
|
"78": {
|
|
@@ -254037,7 +254037,7 @@ var cov_d7x60homs = function () {
|
|
|
254037
254037
|
},
|
|
254038
254038
|
end: {
|
|
254039
254039
|
line: 492,
|
|
254040
|
-
column:
|
|
254040
|
+
column: 77
|
|
254041
254041
|
}
|
|
254042
254042
|
},
|
|
254043
254043
|
"79": {
|
|
@@ -254959,7 +254959,7 @@ var cov_d7x60homs = function () {
|
|
|
254959
254959
|
},
|
|
254960
254960
|
end: {
|
|
254961
254961
|
line: 491,
|
|
254962
|
-
column:
|
|
254962
|
+
column: 41
|
|
254963
254963
|
}
|
|
254964
254964
|
},
|
|
254965
254965
|
line: 491
|
|
@@ -254983,7 +254983,7 @@ var cov_d7x60homs = function () {
|
|
|
254983
254983
|
},
|
|
254984
254984
|
end: {
|
|
254985
254985
|
line: 492,
|
|
254986
|
-
column:
|
|
254986
|
+
column: 77
|
|
254987
254987
|
}
|
|
254988
254988
|
},
|
|
254989
254989
|
line: 492
|
|
@@ -256233,7 +256233,7 @@ var cov_d7x60homs = function () {
|
|
|
256233
256233
|
},
|
|
256234
256234
|
end: {
|
|
256235
256235
|
line: 492,
|
|
256236
|
-
column:
|
|
256236
|
+
column: 78
|
|
256237
256237
|
}
|
|
256238
256238
|
}, {
|
|
256239
256239
|
start: {
|
|
@@ -256288,7 +256288,7 @@ var cov_d7x60homs = function () {
|
|
|
256288
256288
|
},
|
|
256289
256289
|
end: {
|
|
256290
256290
|
line: 492,
|
|
256291
|
-
column:
|
|
256291
|
+
column: 77
|
|
256292
256292
|
}
|
|
256293
256293
|
},
|
|
256294
256294
|
type: "binary-expr",
|
|
@@ -256299,16 +256299,16 @@ var cov_d7x60homs = function () {
|
|
|
256299
256299
|
},
|
|
256300
256300
|
end: {
|
|
256301
256301
|
line: 492,
|
|
256302
|
-
column:
|
|
256302
|
+
column: 48
|
|
256303
256303
|
}
|
|
256304
256304
|
}, {
|
|
256305
256305
|
start: {
|
|
256306
256306
|
line: 492,
|
|
256307
|
-
column:
|
|
256307
|
+
column: 52
|
|
256308
256308
|
},
|
|
256309
256309
|
end: {
|
|
256310
256310
|
line: 492,
|
|
256311
|
-
column:
|
|
256311
|
+
column: 77
|
|
256312
256312
|
}
|
|
256313
256313
|
}],
|
|
256314
256314
|
line: 492
|
|
@@ -256849,10 +256849,10 @@ var cov_d7x60homs = function () {
|
|
|
256849
256849
|
mappings: ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiRA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
|
|
256850
256850
|
file: "ResultsGallery.vue",
|
|
256851
256851
|
sourceRoot: "src/components/analyses",
|
|
256852
|
-
sourcesContent: ["<template>\n <v-dialog\n v-hotkey=\"keymap\"\n v-if=\"showDialog\"\n v-model=\"showDialog\"\n :fullscreen=\"isResultModalFullScreen\"\n scrollable\n class=\"gallery-dialog\"\n >\n <!-- style=\"transition: 0.3s\" -->\n <v-card flat class=\"gallery-card\">\n <v-card-title class=\"pa-2\">\n <v-row>\n <v-col cols=\"6\">\n <h3 class=\"font-weight-thin primary--text\">\n {{ result.verboseName }}\n </h3>\n </v-col>\n\n <v-col cols=\"6\" class=\"d-flex justify-end align-center panel-slot-actions\">\n\n <!-- toggle raw text -->\n <v-tooltip\n v-if=\"result.frontendType === 'tsv-file' && tsvHeaders.length\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"displayRawText = !displayRawText\"\n v-on=\"on\"\n >\n {{ displayRawText ? 'table_chart' : 'text_fields' }}\n </v-icon>\n </template>\n {{ displayRawText ? 'Display Tabulated Content' : 'Display Raw Content' }}\n </v-tooltip>\n\n <!-- download result -->\n <v-tooltip\n v-if=\"result.download\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"result.download\"\n v-on=\"on\"\n >\n {{ result.downloadIcon }}\n </v-icon>\n </template>\n {{ result.downloadIcon === 'open_in_new' ? 'Open in new tab' : 'Download Result' }}\n </v-tooltip>\n\n <!-- copy to clipboard -->\n <v-tooltip\n v-if=\"result.copyToClipBoard\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"result.copyToClipBoard\"\n v-on=\"on\"\n >\n file_copy\n </v-icon>\n </template>\n Copy to clipboard!\n </v-tooltip>\n\n <!-- external link -->\n <v-tooltip\n v-if=\"result.openExternalLink\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"result.openExternalLink\"\n v-on=\"on\"\n >\n info\n </v-icon>\n </template>\n Learn more!\n </v-tooltip>\n\n <!-- show from bottom -->\n <v-tooltip\n v-if=\"['raw'].includes(resultType)\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"reverseContent\"\n v-on=\"on\"\n >\n {{ streamOptions.reverse ? 'vertical_align_bottom' : 'vertical_align_top'}}\n </v-icon>\n </template>\n <span>\n Show content from {{ streamOptions.reverse ? 'top' : 'bottom' }}\n </span>\n </v-tooltip>\n\n <!-- show fullscreen -->\n <v-tooltip\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"toggleFullScreen\"\n v-on=\"on\"\n >\n <!-- @click=\"(isFullScreen = !isFullScreen)\" -->\n {{ isResultModalFullScreen ? 'fullscreen_exit' : 'fullscreen'}}\n </v-icon>\n </template>\n <span>\n Toggle Full Screen\n </span>\n </v-tooltip>\n\n <!-- close dialog -->\n <v-tooltip top>\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"hideDialog\"\n v-on=\"on\"\n >\n close\n </v-icon>\n </template>\n Close file\n </v-tooltip>\n </v-col>\n </v-row>\n </v-card-title>\n\n <v-row class=\"pa-0 ma-0 gallery-content\" style=\"height: 85vh\">\n <v-progress-linear\n v-if=\"loading\"\n class=\"panel-loader\"\n indeterminate\n height=\"2\"\n color=\"primary\"\n />\n\n <pre\n v-highlightjs=\"content\"\n v-if=\"resultType === 'raw' && resultKey === 'command_script'\"\n ref=\"raw\"\n class=\"v-markup pre-wrap\"\n >\n <code class=\"bash\" />\n </pre>\n\n <code\n v-else-if=\"isAnsi\"\n ref=\"raw\"\n class=\"v-markup\"\n >\n <pre v-html=\"content\" />\n </code>\n\n <code\n v-else-if=\"resultType === 'raw'\"\n ref=\"raw\"\n class=\"v-markup\"\n >\n <pre>\n {{ content }}\n <span v-if=\"content && !streamOptions.end\" class=\"stream-message grey--text lighten-2\">\n ... Loading more rows\n </span>\n <span v-if=\"!loading && streamOptions.end\" class=\"stream-message grey--text\">\n *** End of file. ***\n </span>\n </pre>\n </code>\n\n <div\n v-else-if=\"resultType === 'table'\"\n ref=\"table\"\n class=\"tsv-table\"\n >\n <v-data-table\n :headers=\"tsvHeaders\"\n :items=\"tsvItems\"\n :items-per-page=\"tsvItems.length\"\n hide-default-footer\n multi-sort\n fixed-header\n dense\n >\n <template v-slot:body=\"{ items }\">\n <tbody>\n <tr\n v-for=\"item in items\"\n :key=\"item.name\"\n >\n <td\n v-for=\"(header, index) in tsvHeaders\"\n :key=\"index + header.value\"\n :class=\"[header.value === 'index' ? 'line-column text' : '']\"\n v-html=\"parseTsvCell($get(item, header.value))\"\n />\n </tr>\n </tbody>\n </template>\n </v-data-table>\n\n <div class=\"text-center stream-message\">\n <span v-if=\"content && !streamOptions.end\">... Loading more rows</span>\n <span v-if=\"!loading && streamOptions.end\">End of file.</span>\n </div>\n </div>\n\n <img\n v-else-if=\"resultType === 'image'\"\n :src=\"$store.getters.getBlobUrl(result.downloadUrl)\"\n :alt=\"result.verboseName\"\n class=\"results-image\"\n >\n\n <iframe\n v-else-if=\"['html', 'pdf'].includes(resultType)\"\n :src=\"$store.getters.getBlobUrl(result.downloadUrl, '')\"\n frameborder=\"0\"\n class=\"results-iframe\"\n style=\"width: 100%; height: 100%; min-height: 80vh;\"\n />\n\n <iframe\n v-else-if=\"resultType === 'igv_bam'\"\n :src=\"result.downloadUrl\"\n frameborder=\"0\"\n class=\"results-iframe\"\n style=\"width: 100%; height: 100%; min-height: 80vh;\"\n />\n\n <code\n v-else-if=\"resultType === 'number'\"\n class=\"v-markup\"\n >\n <span size=\"100px\">{{ result.value | round(3) }}</span>\n </code>\n\n <code\n v-else-if=\"['string', 'url-link'].includes(resultType)\"\n class=\"v-markup\"\n >\n <span size=\"100px\">{{ result.value }}</span>\n </code>\n </v-row>\n\n </v-card>\n </v-dialog>\n</template>\n\n<script>\nimport { loadResult } from '@/utils/api'\nimport { HIDE_PANEL, SHOW_PANEL } from '@/store/actions/panels'\nimport { TOGGLE_RESULT_FULLSCREEN } from '@/store/actions/user'\nimport { GET_FILE } from '@/store/actions/files'\nimport { mapGetters } from 'vuex'\nimport detect from 'detect-csv'\n\nexport default {\n name: 'ResultsGallery',\n props: {\n resultIndex: {\n type: Number,\n },\n results: {\n type: Array,\n },\n },\n data() {\n return {\n content: '',\n displayRawText: false,\n isBottomScrolled: false,\n loading: false,\n showDialog: false,\n tsvItems: [],\n tsvHeaders: [],\n streamOptions: {\n lines: 200,\n offset: 0,\n reverse: false,\n previous: '',\n end: false,\n },\n }\n },\n computed: {\n ...mapGetters(['resultKey', 'isResultModalFullScreen']),\n keymap() {\n return {\n right: this.increaseIndex,\n left: this.decreaseIndex,\n esc: this.hideDialog,\n }\n },\n result() {\n return this.results[this.resultIndex] || {}\n },\n isAnsi() {\n return this.result && this.result.frontendType === 'ansi'\n },\n resultType() {\n if (this.result.frontendType === 'ansi') {\n return 'raw'\n } else if (this.result.frontendType === 'text-file') {\n return 'raw'\n } else if (this.result.frontendType === 'tsv-file') {\n if (\n !this.displayRawText &&\n this.tsvItems.length &&\n this.tsvHeaders.length\n ) {\n return 'table'\n } else {\n return 'raw'\n }\n } else {\n return this.result.frontendType\n }\n },\n },\n watch: {\n showDialog(value) {\n if (!value) {\n this.$store.dispatch(HIDE_PANEL, 'result')\n this.$emit('display-result', null)\n }\n },\n resultIndex(value) {\n this.showDialog = Number.isInteger(value) && value < this.results.length\n if (this.showDialog && ['raw', 'table'].includes(this.resultType)) {\n this.resetStreamEvents()\n this.loadFileContents()\n }\n },\n resultKey: {\n handler() {\n this.updateResultIndex()\n },\n immediate: true,\n },\n result(value) {\n if (value && value.resultKey) {\n this.$store.dispatch(SHOW_PANEL, {\n result: value.resultKey,\n })\n if (['html', 'pdf'].includes(value.frontendType)) {\n this.$store.dispatch(GET_FILE, value.downloadUrl)\n }\n // Track result viewed\n window.analytics.track('Result Previewed', value.analytics)\n }\n this.updateResultIndex()\n },\n isBottomScrolled(value) {\n if (value) {\n this.loadFileContents()\n }\n },\n displayRawText() {\n this.addScrollListener()\n },\n },\n methods: {\n resetStreamEvents() {\n // Reset content\n this.content = ''\n this.streamOptions = {\n lines: 200,\n offset: 0,\n reverse: false,\n previous: '',\n end: false,\n }\n // Remove listeners\n this.$nextTick(() => {\n if (this.$refs.raw) {\n this.$refs.raw.removeEventListener('scroll', this.isBottomVisible)\n }\n if (this.$refs.table) {\n this.$refs.table.removeEventListener('scroll', this.isBottomVisible)\n }\n })\n },\n addScrollListener() {\n this.$nextTick(() => {\n this.isBottomVisible()\n if (!this.isBottomScrolled) {\n if (this.$refs.raw) {\n this.$refs.raw.addEventListener('scroll', this.isBottomVisible)\n }\n if (this.$refs.table) {\n this.$refs.table.addEventListener('scroll', this.isBottomVisible)\n }\n }\n })\n },\n updateResultIndex() {\n if (this.resultKey !== this.result.resultKey) {\n this.results.forEach((result, index) => {\n if (result.resultKey === this.resultKey) {\n this.showDialog = true\n this.$emit('display-result', index)\n }\n })\n }\n },\n hideDialog() {\n if (this.showDialog) {\n this.showDialog = false\n }\n },\n increaseIndex() {\n if (this.showDialog) {\n if (this.resultIndex < this.results.length - 1) {\n this.$emit('display-result', this.resultIndex + 1)\n this.content = ''\n } else {\n this.$emit('display-result', 0)\n this.content = ''\n }\n }\n },\n decreaseIndex() {\n if (this.showDialog) {\n if (this.resultIndex > 0) {\n this.$emit('display-result', this.resultIndex - 1)\n } else {\n this.$emit('display-result', this.results.length - 1)\n }\n }\n },\n async loadFileContents() {\n const { lines, offset, reverse, end, previous } = this.streamOptions\n if (!end) {\n this.loading = true\n let content = await loadResult(\n this.result.analysis.pk,\n this.result.resultKey,\n lines,\n offset,\n reverse\n )\n this.loading = false\n\n if (content && previous !== content) {\n this.streamOptions.previous = content\n this.streamOptions.offset += lines\n this.content += content\n this.setTsvItems(this.content)\n this.addScrollListener()\n } else {\n this.streamOptions.end = true\n this.setTsvItems(this.content)\n }\n\n }\n },\n setTsvItems(content) {\n const isTsv = this.result.frontendType === 'tsv-file'\n const detectHandler = (\n detect(content.slice(0, 1000)) || { newline: '\\n', delimiter: '\\t'}\n )\n\n // csv to list of lists\n const dataRows =\n content && isTsv\n ? this.csvToArray(content.trim(), detectHandler.delimiter)\n .filter((row) => row)\n .filter((row) => row[0] !== '#' || row.includes('#CHROM'))\n : []\n\n // Headers\n this.tsvHeaders = dataRows.length\n ? dataRows[0].map((header, index) => {\n return {\n text: header,\n value: `index${index}`,\n sortable: this.streamOptions.end,\n }\n })\n : []\n\n this.tsvHeaders.unshift({\n text: 1,\n value: 'index',\n sortable: false,\n align: 'end',\n class: 'line-column text'\n })\n\n // Content rows\n this.tsvItems = dataRows.length\n ? dataRows.slice(1)\n .map((row, index) => {\n let dictRow = { index: index + 2 }\n row.forEach((value, index) => {\n dictRow[`index${index}`] = value\n })\n return dictRow\n })\n : []\n\n if (!isTsv || (isTsv && !this.tsvHeaders.length)) {\n this.displayRawText = true\n }\n },\n reverseContent() {\n const reverse = this.streamOptions.reverse\n this.resetStreamEvents()\n this.streamOptions.reverse = !reverse\n this.loadFileContents()\n },\n isBottomVisible() {\n const divElement = this.$refs[this.resultType]\n const scrollTop = divElement.scrollTop\n const visible = divElement.clientHeight\n const pageHeight = divElement.scrollHeight\n const bottomOfPage = visible + scrollTop >= pageHeight\n this.isBottomScrolled = bottomOfPage || pageHeight < visible\n },\n toggleFullScreen() {\n this.$store.dispatch(TOGGLE_RESULT_FULLSCREEN, {\n value: !this.isResultModalFullScreen\n })\n },\n parseTsvCell(value) {\n let pattern = /^((http|https|ftp):\\/\\/)/\n if (pattern.test(value)) {\n return `<a href=\"${value}\" target=\"_blank\">Open link</a>`\n } else {\n return value\n }\n },\n\n csvToArray(strData, strDelimiter=\",\") {\n // See: https://stackoverflow.com/a/1293163/3949081\n const objPattern = new RegExp(\n (\n // Delimiters.\n \"(\\\\\" + strDelimiter + \"|\\\\r?\\\\n|\\\\r|^)\" +\n // Quoted fields.\n \"(?:\\\"([^\\\"]*(?:\\\"\\\"[^\\\"]*)*)\\\"|\" +\n // Standard fields.\n \"([^\\\"\\\\\" + strDelimiter + \"\\\\r\\\\n]*))\"\n ),\n \"gi\"\n )\n const arrData = [[]]\n let arrMatches = null\n\n while (arrMatches = objPattern.exec(strData)) {\n // If not delimiter, an end of row has been reached\n const strMatchedDelimiter = arrMatches[1]\n if (\n strMatchedDelimiter.length &&\n strMatchedDelimiter !== strDelimiter\n ){\n arrData.push([])\n }\n\n let strMatchedValue\n if (arrMatches[2]){\n // Quoted value, Unescape any double quotes.\n strMatchedValue = arrMatches[2].replace(\n new RegExp( \"\\\"\\\"\", \"g\" ),\n \"\\\"\"\n )\n } else {\n // Non-quoted value.\n strMatchedValue = arrMatches[3]\n }\n arrData[arrData.length - 1].push(strMatchedValue)\n }\n return arrData\n }\n },\n}\n</script>\n\n<style lang=\"scss\">\n.tsv-table {\n max-width: 100%;\n max-height: 100%;\n margin: 0px auto;\n overflow: auto;\n}\n.v-dialog {\n overflow-y: visible !important; // truly important for iframe performance, dont remove!\n &:not(.v-dialog--fullscreen) {\n max-height: 100% !important;\n max-width: calc(100% - 48px);\n }\n iframe.results-iframe {\n height: 100% !important;\n }\n &.gallery-dialog {\n height: calc(100vh - 60px);\n }\n}\n.results-image {\n max-width: 100%;\n max-height: 85vh;\n margin: auto;\n max-height: 100%;\n width: auto;\n}\n.gallery-card {\n ::-webkit-scrollbar {\n width: 0px;\n height: 0px;\n }\n}\n.v-application .gallery-card {\n .gallery-content {\n background: var(--v-background-base);\n }\n\n pre {\n white-space: pre-line;\n &.pre-wrap {\n white-space: pre-wrap;\n }\n code {\n font-size: 12px;\n font-weight: 600;\n }\n }\n\n &.theme--dark code {\n background-color: rgba(0,0,0,.05);\n }\n\n code.v-markup,\n pre.v-markup {\n padding: 10px;\n width: 100%;\n height: 100%;\n text-align: start;\n box-shadow: none;\n text-shadow: none;\n display: flex;\n position: relative;\n overflow-x: auto;\n overflow-y: auto;\n margin: 0px;\n top: 0px;\n color: rgb(255, 255, 255);\n border-radius: 0px;\n background: rgb(0, 0, 0);\n font-size: 12px;\n font-weight: 600;\n\n code.hljs {\n font-size: 12px;\n padding: 0px;\n\n .hljs-string,\n .hljs-bullet,\n .hljs-subst,\n .hljs-title,\n .hljs-section,\n .hljs-emphasis,\n .hljs-type,\n .hljs-built_in,\n .hljs-builtin-name,\n .hljs-selector-attr,\n .hljs-selector-pseudo,\n .hljs-addition,\n .hljs-variable,\n .hljs-template-tag,\n .hljs-template-variable {\n color: var(--v-warning-base);\n }\n }\n }\n\n .tsv-table {\n border: thin solid rgba(0,0,0,.12);\n margin-left: 0;\n\n .theme--dark {\n thead tr th {\n background: var(--v-surface-darken1);\n span {\n color: #9e9e9e;\n }\n }\n tbody tr td {\n background: var(--v-background-base);\n span {\n color: #9e9e9e;\n }\n }\n }\n\n thead tr {\n th {\n background: var(--v-background-base);\n max-width: 250px;\n white-space: nowrap;\n span {\n font-size: 12px;\n font-family: Roboto;\n color: #333333;\n }\n }\n }\n tbody tr {\n td {\n font-size: 12px;\n font-family: Roboto;\n overflow-x: auto;\n white-space: nowrap;\n max-width: 250px;\n }\n }\n\n thead tr th, tbody tr td {\n &.line-column {\n background: var(--v-surface-darken1);\n width: 50px;\n text-align: right;\n font-weight: normal;\n // Make line-column sticky\n position: sticky !important;\n left: 0;\n z-index: 9998;\n }\n }\n\n thead tr th .line-column {\n z-index: 9999;\n }\n }\n\n\n .stream-message {\n font-size: 12px;\n font-style: italic;\n margin: 20px 0px;\n }\n}\n</style>\n"]
|
|
256852
|
+
sourcesContent: ["<template>\n <v-dialog\n v-hotkey=\"keymap\"\n v-if=\"showDialog\"\n v-model=\"showDialog\"\n :fullscreen=\"isResultModalFullScreen\"\n scrollable\n class=\"gallery-dialog\"\n >\n <!-- style=\"transition: 0.3s\" -->\n <v-card flat class=\"gallery-card\">\n <v-card-title class=\"pa-2\">\n <v-row>\n <v-col cols=\"6\">\n <h3 class=\"font-weight-thin primary--text\">\n {{ result.verboseName }}\n </h3>\n </v-col>\n\n <v-col cols=\"6\" class=\"d-flex justify-end align-center panel-slot-actions\">\n\n <!-- toggle raw text -->\n <v-tooltip\n v-if=\"result.frontendType === 'tsv-file' && tsvHeaders.length\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"displayRawText = !displayRawText\"\n v-on=\"on\"\n >\n {{ displayRawText ? 'table_chart' : 'text_fields' }}\n </v-icon>\n </template>\n {{ displayRawText ? 'Display Tabulated Content' : 'Display Raw Content' }}\n </v-tooltip>\n\n <!-- download result -->\n <v-tooltip\n v-if=\"result.download\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"result.download\"\n v-on=\"on\"\n >\n {{ result.downloadIcon }}\n </v-icon>\n </template>\n {{ result.downloadIcon === 'open_in_new' ? 'Open in new tab' : 'Download Result' }}\n </v-tooltip>\n\n <!-- copy to clipboard -->\n <v-tooltip\n v-if=\"result.copyToClipBoard\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"result.copyToClipBoard\"\n v-on=\"on\"\n >\n file_copy\n </v-icon>\n </template>\n Copy to clipboard!\n </v-tooltip>\n\n <!-- external link -->\n <v-tooltip\n v-if=\"result.openExternalLink\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"result.openExternalLink\"\n v-on=\"on\"\n >\n info\n </v-icon>\n </template>\n Learn more!\n </v-tooltip>\n\n <!-- show from bottom -->\n <v-tooltip\n v-if=\"['raw'].includes(resultType)\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"reverseContent\"\n v-on=\"on\"\n >\n {{ streamOptions.reverse ? 'vertical_align_bottom' : 'vertical_align_top'}}\n </v-icon>\n </template>\n <span>\n Show content from {{ streamOptions.reverse ? 'top' : 'bottom' }}\n </span>\n </v-tooltip>\n\n <!-- show fullscreen -->\n <v-tooltip\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"toggleFullScreen\"\n v-on=\"on\"\n >\n <!-- @click=\"(isFullScreen = !isFullScreen)\" -->\n {{ isResultModalFullScreen ? 'fullscreen_exit' : 'fullscreen'}}\n </v-icon>\n </template>\n <span>\n Toggle Full Screen\n </span>\n </v-tooltip>\n\n <!-- close dialog -->\n <v-tooltip top>\n <template v-slot:activator=\"{ on }\">\n <v-icon\n class=\"primary--text ml-4\"\n small\n @click=\"hideDialog\"\n v-on=\"on\"\n >\n close\n </v-icon>\n </template>\n Close file\n </v-tooltip>\n </v-col>\n </v-row>\n </v-card-title>\n\n <v-row class=\"pa-0 ma-0 gallery-content\" style=\"height: 85vh\">\n <v-progress-linear\n v-if=\"loading\"\n class=\"panel-loader\"\n indeterminate\n height=\"2\"\n color=\"primary\"\n />\n\n <pre\n v-highlightjs=\"content\"\n v-if=\"resultType === 'raw' && resultKey === 'command_script'\"\n ref=\"raw\"\n class=\"v-markup pre-wrap\"\n >\n <code class=\"bash\" />\n </pre>\n\n <code\n v-else-if=\"isAnsi\"\n ref=\"raw\"\n class=\"v-markup\"\n >\n <pre v-html=\"content\" />\n </code>\n\n <code\n v-else-if=\"resultType === 'raw'\"\n ref=\"raw\"\n class=\"v-markup\"\n >\n <pre>\n {{ content }}\n <span v-if=\"content && !streamOptions.end\" class=\"stream-message grey--text lighten-2\">\n ... Loading more rows\n </span>\n <span v-if=\"!loading && streamOptions.end\" class=\"stream-message grey--text\">\n *** End of file. ***\n </span>\n </pre>\n </code>\n\n <div\n v-else-if=\"resultType === 'table'\"\n ref=\"table\"\n class=\"tsv-table\"\n >\n <v-data-table\n :headers=\"tsvHeaders\"\n :items=\"tsvItems\"\n :items-per-page=\"tsvItems.length\"\n hide-default-footer\n multi-sort\n fixed-header\n dense\n >\n <template v-slot:body=\"{ items }\">\n <tbody>\n <tr\n v-for=\"item in items\"\n :key=\"item.name\"\n >\n <td\n v-for=\"(header, index) in tsvHeaders\"\n :key=\"index + header.value\"\n :class=\"[header.value === 'index' ? 'line-column text' : '']\"\n v-html=\"parseTsvCell($get(item, header.value))\"\n />\n </tr>\n </tbody>\n </template>\n </v-data-table>\n\n <div class=\"text-center stream-message\">\n <span v-if=\"content && !streamOptions.end\">... Loading more rows</span>\n <span v-if=\"!loading && streamOptions.end\">End of file.</span>\n </div>\n </div>\n\n <img\n v-else-if=\"resultType === 'image'\"\n :src=\"$store.getters.getBlobUrl(result.downloadUrl)\"\n :alt=\"result.verboseName\"\n class=\"results-image\"\n >\n\n <iframe\n v-else-if=\"['html', 'pdf'].includes(resultType)\"\n :src=\"$store.getters.getBlobUrl(result.downloadUrl, '')\"\n frameborder=\"0\"\n class=\"results-iframe\"\n style=\"width: 100%; height: 100%; min-height: 80vh;\"\n />\n\n <iframe\n v-else-if=\"resultType === 'igv_bam'\"\n :src=\"result.downloadUrl\"\n frameborder=\"0\"\n class=\"results-iframe\"\n style=\"width: 100%; height: 100%; min-height: 80vh;\"\n />\n\n <code\n v-else-if=\"resultType === 'number'\"\n class=\"v-markup\"\n >\n <span size=\"100px\">{{ result.value | round(3) }}</span>\n </code>\n\n <code\n v-else-if=\"['string', 'url-link'].includes(resultType)\"\n class=\"v-markup\"\n >\n <span size=\"100px\">{{ result.value }}</span>\n </code>\n </v-row>\n\n </v-card>\n </v-dialog>\n</template>\n\n<script>\nimport { loadResult } from '@/utils/api'\nimport { HIDE_PANEL, SHOW_PANEL } from '@/store/actions/panels'\nimport { TOGGLE_RESULT_FULLSCREEN } from '@/store/actions/user'\nimport { GET_FILE } from '@/store/actions/files'\nimport { mapGetters } from 'vuex'\nimport detect from 'detect-csv'\n\nexport default {\n name: 'ResultsGallery',\n props: {\n resultIndex: {\n type: Number,\n },\n results: {\n type: Array,\n },\n },\n data() {\n return {\n content: '',\n displayRawText: false,\n isBottomScrolled: false,\n loading: false,\n showDialog: false,\n tsvItems: [],\n tsvHeaders: [],\n streamOptions: {\n lines: 200,\n offset: 0,\n reverse: false,\n previous: '',\n end: false,\n },\n }\n },\n computed: {\n ...mapGetters(['resultKey', 'isResultModalFullScreen']),\n keymap() {\n return {\n right: this.increaseIndex,\n left: this.decreaseIndex,\n esc: this.hideDialog,\n }\n },\n result() {\n return this.results[this.resultIndex] || {}\n },\n isAnsi() {\n return this.result && this.result.frontendType === 'ansi'\n },\n resultType() {\n if (this.result.frontendType === 'ansi') {\n return 'raw'\n } else if (this.result.frontendType === 'text-file') {\n return 'raw'\n } else if (this.result.frontendType === 'tsv-file') {\n if (\n !this.displayRawText &&\n this.tsvItems.length &&\n this.tsvHeaders.length\n ) {\n return 'table'\n } else {\n return 'raw'\n }\n } else {\n return this.result.frontendType\n }\n },\n },\n watch: {\n showDialog(value) {\n if (!value) {\n this.$store.dispatch(HIDE_PANEL, 'result')\n this.$emit('display-result', null)\n }\n },\n resultIndex(value) {\n this.showDialog = Number.isInteger(value) && value < this.results.length\n if (this.showDialog && ['raw', 'table'].includes(this.resultType)) {\n this.resetStreamEvents()\n this.loadFileContents()\n }\n },\n resultKey: {\n handler() {\n this.updateResultIndex()\n },\n immediate: true,\n },\n result(value) {\n if (value && value.resultKey) {\n this.$store.dispatch(SHOW_PANEL, {\n result: value.resultKey,\n })\n if (['html', 'pdf'].includes(value.frontendType)) {\n this.$store.dispatch(GET_FILE, value.downloadUrl)\n }\n // Track result viewed\n window.analytics.track('Result Previewed', value.analytics)\n }\n this.updateResultIndex()\n },\n isBottomScrolled(value) {\n if (value) {\n this.loadFileContents()\n }\n },\n displayRawText() {\n this.addScrollListener()\n },\n },\n methods: {\n resetStreamEvents() {\n // Reset content\n this.content = ''\n this.streamOptions = {\n lines: 200,\n offset: 0,\n reverse: false,\n previous: '',\n end: false,\n }\n // Remove listeners\n this.$nextTick(() => {\n if (this.$refs.raw) {\n this.$refs.raw.removeEventListener('scroll', this.isBottomVisible)\n }\n if (this.$refs.table) {\n this.$refs.table.removeEventListener('scroll', this.isBottomVisible)\n }\n })\n },\n addScrollListener() {\n this.$nextTick(() => {\n this.isBottomVisible()\n if (!this.isBottomScrolled) {\n if (this.$refs.raw) {\n this.$refs.raw.addEventListener('scroll', this.isBottomVisible)\n }\n if (this.$refs.table) {\n this.$refs.table.addEventListener('scroll', this.isBottomVisible)\n }\n }\n })\n },\n updateResultIndex() {\n if (this.resultKey !== this.result.resultKey) {\n this.results.forEach((result, index) => {\n if (result.resultKey === this.resultKey) {\n this.showDialog = true\n this.$emit('display-result', index)\n }\n })\n }\n },\n hideDialog() {\n if (this.showDialog) {\n this.showDialog = false\n }\n },\n increaseIndex() {\n if (this.showDialog) {\n if (this.resultIndex < this.results.length - 1) {\n this.$emit('display-result', this.resultIndex + 1)\n this.content = ''\n } else {\n this.$emit('display-result', 0)\n this.content = ''\n }\n }\n },\n decreaseIndex() {\n if (this.showDialog) {\n if (this.resultIndex > 0) {\n this.$emit('display-result', this.resultIndex - 1)\n } else {\n this.$emit('display-result', this.results.length - 1)\n }\n }\n },\n async loadFileContents() {\n const { lines, offset, reverse, end, previous } = this.streamOptions\n if (!end) {\n this.loading = true\n let content = await loadResult(\n this.result.analysis.pk,\n this.result.resultKey,\n lines,\n offset,\n reverse\n )\n this.loading = false\n\n if (content && previous !== content) {\n this.streamOptions.previous = content\n this.streamOptions.offset += lines\n this.content += content\n this.setTsvItems(this.content)\n this.addScrollListener()\n } else {\n this.streamOptions.end = true\n this.setTsvItems(this.content)\n }\n\n }\n },\n setTsvItems(content) {\n const isTsv = this.result.frontendType === 'tsv-file'\n const detectHandler = (\n detect(content.slice(0, 1000)) || { newline: '\\n', delimiter: '\\t'}\n )\n\n // csv to list of lists\n const dataRows =\n content && isTsv\n ? this.csvToArray(content.trim(), detectHandler.delimiter)\n .filter((row) => row.length)\n .filter((row) => row[0][0] !== '#' || row[0].includes('#CHROM'))\n : []\n\n // Headers\n this.tsvHeaders = dataRows.length\n ? dataRows[0].map((header, index) => {\n return {\n text: header,\n value: `index${index}`,\n sortable: this.streamOptions.end,\n }\n })\n : []\n\n this.tsvHeaders.unshift({\n text: 1,\n value: 'index',\n sortable: false,\n align: 'end',\n class: 'line-column text'\n })\n\n // Content rows\n this.tsvItems = dataRows.length\n ? dataRows.slice(1)\n .map((row, index) => {\n let dictRow = { index: index + 2 }\n row.forEach((value, index) => {\n dictRow[`index${index}`] = value\n })\n return dictRow\n })\n : []\n\n if (!isTsv || (isTsv && !this.tsvHeaders.length)) {\n this.displayRawText = true\n }\n },\n reverseContent() {\n const reverse = this.streamOptions.reverse\n this.resetStreamEvents()\n this.streamOptions.reverse = !reverse\n this.loadFileContents()\n },\n isBottomVisible() {\n const divElement = this.$refs[this.resultType]\n const scrollTop = divElement.scrollTop\n const visible = divElement.clientHeight\n const pageHeight = divElement.scrollHeight\n const bottomOfPage = visible + scrollTop >= pageHeight\n this.isBottomScrolled = bottomOfPage || pageHeight < visible\n },\n toggleFullScreen() {\n this.$store.dispatch(TOGGLE_RESULT_FULLSCREEN, {\n value: !this.isResultModalFullScreen\n })\n },\n parseTsvCell(value) {\n let pattern = /^((http|https|ftp):\\/\\/)/\n if (pattern.test(value)) {\n return `<a href=\"${value}\" target=\"_blank\">Open link</a>`\n } else {\n return value\n }\n },\n\n csvToArray(strData, strDelimiter=\",\") {\n // See: https://stackoverflow.com/a/1293163/3949081\n const objPattern = new RegExp(\n (\n // Delimiters.\n \"(\\\\\" + strDelimiter + \"|\\\\r?\\\\n|\\\\r|^)\" +\n // Quoted fields.\n \"(?:\\\"([^\\\"]*(?:\\\"\\\"[^\\\"]*)*)\\\"|\" +\n // Standard fields.\n \"([^\\\"\\\\\" + strDelimiter + \"\\\\r\\\\n]*))\"\n ),\n \"gi\"\n )\n const arrData = [[]]\n let arrMatches = null\n\n while (arrMatches = objPattern.exec(strData)) {\n // If not delimiter, an end of row has been reached\n const strMatchedDelimiter = arrMatches[1]\n if (\n strMatchedDelimiter.length &&\n strMatchedDelimiter !== strDelimiter\n ){\n arrData.push([])\n }\n\n let strMatchedValue\n if (arrMatches[2]){\n // Quoted value, Unescape any double quotes.\n strMatchedValue = arrMatches[2].replace(\n new RegExp( \"\\\"\\\"\", \"g\" ),\n \"\\\"\"\n )\n } else {\n // Non-quoted value.\n strMatchedValue = arrMatches[3]\n }\n arrData[arrData.length - 1].push(strMatchedValue)\n }\n return arrData\n }\n },\n}\n</script>\n\n<style lang=\"scss\">\n.tsv-table {\n max-width: 100%;\n max-height: 100%;\n margin: 0px auto;\n overflow: auto;\n}\n.v-dialog {\n overflow-y: visible !important; // truly important for iframe performance, dont remove!\n &:not(.v-dialog--fullscreen) {\n max-height: 100% !important;\n max-width: calc(100% - 48px);\n }\n iframe.results-iframe {\n height: 100% !important;\n }\n &.gallery-dialog {\n height: calc(100vh - 60px);\n }\n}\n.results-image {\n max-width: 100%;\n max-height: 85vh;\n margin: auto;\n max-height: 100%;\n width: auto;\n}\n.gallery-card {\n ::-webkit-scrollbar {\n width: 0px;\n height: 0px;\n }\n}\n.v-application .gallery-card {\n .gallery-content {\n background: var(--v-background-base);\n }\n\n pre {\n white-space: pre-line;\n &.pre-wrap {\n white-space: pre-wrap;\n }\n code {\n font-size: 12px;\n font-weight: 600;\n }\n }\n\n &.theme--dark code {\n background-color: rgba(0,0,0,.05);\n }\n\n code.v-markup,\n pre.v-markup {\n padding: 10px;\n width: 100%;\n height: 100%;\n text-align: start;\n box-shadow: none;\n text-shadow: none;\n display: flex;\n position: relative;\n overflow-x: auto;\n overflow-y: auto;\n margin: 0px;\n top: 0px;\n color: rgb(255, 255, 255);\n border-radius: 0px;\n background: rgb(0, 0, 0);\n font-size: 12px;\n font-weight: 600;\n\n code.hljs {\n font-size: 12px;\n padding: 0px;\n\n .hljs-string,\n .hljs-bullet,\n .hljs-subst,\n .hljs-title,\n .hljs-section,\n .hljs-emphasis,\n .hljs-type,\n .hljs-built_in,\n .hljs-builtin-name,\n .hljs-selector-attr,\n .hljs-selector-pseudo,\n .hljs-addition,\n .hljs-variable,\n .hljs-template-tag,\n .hljs-template-variable {\n color: var(--v-warning-base);\n }\n }\n }\n\n .tsv-table {\n border: thin solid rgba(0,0,0,.12);\n margin-left: 0;\n\n .theme--dark {\n thead tr th {\n background: var(--v-surface-darken1);\n span {\n color: #9e9e9e;\n }\n }\n tbody tr td {\n background: var(--v-background-base);\n span {\n color: #9e9e9e;\n }\n }\n }\n\n thead tr {\n th {\n background: var(--v-background-base);\n max-width: 250px;\n white-space: nowrap;\n span {\n font-size: 12px;\n font-family: Roboto;\n color: #333333;\n }\n }\n }\n tbody tr {\n td {\n font-size: 12px;\n font-family: Roboto;\n overflow-x: auto;\n white-space: nowrap;\n max-width: 250px;\n }\n }\n\n thead tr th, tbody tr td {\n &.line-column {\n background: var(--v-surface-darken1);\n width: 50px;\n text-align: right;\n font-weight: normal;\n // Make line-column sticky\n position: sticky !important;\n left: 0;\n z-index: 9998;\n }\n }\n\n thead tr th .line-column {\n z-index: 9999;\n }\n }\n\n\n .stream-message {\n font-size: 12px;\n font-style: italic;\n margin: 20px 0px;\n }\n}\n</style>\n"]
|
|
256853
256853
|
},
|
|
256854
256854
|
_coverageSchema: "43e27e138ebf9cfc5966b082cf9a028302ed4184",
|
|
256855
|
-
hash: "
|
|
256855
|
+
hash: "fe09864f43de2d4dae5821f382f528b5c4317436"
|
|
256856
256856
|
};
|
|
256857
256857
|
var coverage = global[gcv] || (global[gcv] = {});
|
|
256858
256858
|
|
|
@@ -257585,11 +257585,11 @@ function ResultsGalleryvue_type_script_lang_js_defineProperty(obj, key, value) {
|
|
|
257585
257585
|
var dataRows = (cov_d7x60homs.s[76]++, (cov_d7x60homs.b[32][0]++, content) && (cov_d7x60homs.b[32][1]++, isTsv) ? (cov_d7x60homs.b[31][0]++, this.csvToArray(content.trim(), detectHandler.delimiter).filter(function (row) {
|
|
257586
257586
|
cov_d7x60homs.f[22]++;
|
|
257587
257587
|
cov_d7x60homs.s[77]++;
|
|
257588
|
-
return row;
|
|
257588
|
+
return row.length;
|
|
257589
257589
|
}).filter(function (row) {
|
|
257590
257590
|
cov_d7x60homs.f[23]++;
|
|
257591
257591
|
cov_d7x60homs.s[78]++;
|
|
257592
|
-
return (cov_d7x60homs.b[33][0]++, row[0] !== '#') || (cov_d7x60homs.b[33][1]++, row.includes('#CHROM'));
|
|
257592
|
+
return (cov_d7x60homs.b[33][0]++, row[0][0] !== '#') || (cov_d7x60homs.b[33][1]++, row[0].includes('#CHROM'));
|
|
257593
257593
|
})) : (cov_d7x60homs.b[31][1]++, [])); // Headers
|
|
257594
257594
|
|
|
257595
257595
|
cov_d7x60homs.s[79]++;
|
|
@@ -257743,8 +257743,8 @@ var ResultsGalleryvue_type_style_index_0_lang_scss_ = __webpack_require__("3942"
|
|
|
257743
257743
|
|
|
257744
257744
|
var ResultsGallery_component = normalizeComponent(
|
|
257745
257745
|
analyses_ResultsGalleryvue_type_script_lang_js_,
|
|
257746
|
-
|
|
257747
|
-
|
|
257746
|
+
ResultsGalleryvue_type_template_id_185780e8_render,
|
|
257747
|
+
ResultsGalleryvue_type_template_id_185780e8_staticRenderFns,
|
|
257748
257748
|
false,
|
|
257749
257749
|
null,
|
|
257750
257750
|
null,
|
|
@@ -264731,12 +264731,12 @@ var ProjectPanelvue_type_template_id_7c1bc440_staticRenderFns = []
|
|
|
264731
264731
|
|
|
264732
264732
|
// CONCATENATED MODULE: ./src/components/projects/ProjectPanel.vue?vue&type=template&id=7c1bc440&
|
|
264733
264733
|
|
|
264734
|
-
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d220a428-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/dashboard/BaseDashboard.vue?vue&type=template&id=
|
|
264735
|
-
var
|
|
264736
|
-
var
|
|
264734
|
+
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d220a428-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/dashboard/BaseDashboard.vue?vue&type=template&id=2fd2fca6&
|
|
264735
|
+
var BaseDashboardvue_type_template_id_2fd2fca6_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{ref:"dashboard"},[_c('v-card',{staticClass:"isabl-base-card",attrs:{"flat":""}},[_c('dc-graph',{attrs:{"model":_vm.model,"params":_vm.params,"items":_vm.items,"figures":_vm.figures,"loading":_vm.loading,"max-records":_vm.maxRecords,"total-items":_vm.totalItems,"is-embedded":_vm.isEmbedded},on:{"set-max-records":_vm.setMaxRecords,"set-options":_vm.setOptions}})],1)],1)}
|
|
264736
|
+
var BaseDashboardvue_type_template_id_2fd2fca6_staticRenderFns = []
|
|
264737
264737
|
|
|
264738
264738
|
|
|
264739
|
-
// CONCATENATED MODULE: ./src/components/dashboard/BaseDashboard.vue?vue&type=template&id=
|
|
264739
|
+
// CONCATENATED MODULE: ./src/components/dashboard/BaseDashboard.vue?vue&type=template&id=2fd2fca6&
|
|
264740
264740
|
|
|
264741
264741
|
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d220a428-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/dashboard/DcGraph.vue?vue&type=template&id=7d68029b&
|
|
264742
264742
|
var DcGraphvue_type_template_id_7d68029b_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{ref:"main",class:['main-dc', !_vm.isEmbedded ? 'px-2' : '']},[_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.loading),expression:"loading"}],staticClass:"overlay"},[_c('v-progress-circular',{staticClass:"loading",attrs:{"width":4,"size":40,"indeterminate":"","color":"primary"}}),_c('div',{staticClass:"mt-6"},[_vm._v("loading records...")])],1),_c('transition',{attrs:{"name":"slide-fade"}},[_c('data-table',{directives:[{name:"show",rawName:"v-show",value:(_vm.showPrefilterTable),expression:"showPrefilterTable"}],attrs:{"model":_vm.model,"params":_vm.params,"open-records-in-new-tab":!_vm.isEmbedded,"title":"Import Into dashboard","info-text":"Search and filter the records you may want to import into the interactive dashboard.","card-classes":"elevation-0 pa-0 mb-12"},on:{"fetch-data":_vm.setOptions}})],1),_c('div',{directives:[{name:"observe-visibility",rawName:"v-observe-visibility",value:(_vm.onVisible),expression:"onVisible"}],staticClass:"dashboard-graphs dc-data-count",attrs:{"id":("dc-data-count-" + _vm.uuid)}},[_c('v-container',{attrs:{"fluid":""}},[_c('v-row',{staticClass:"pb-6 justify-space-between"},[_c('v-col',{staticClass:"pa-0",attrs:{"cols":"4"}},[_c('h2',{staticClass:"isabl-section-title text-left"},[_vm._v(_vm._s(_vm._f("capitalize")(_vm.title || 'Interactive Dashboard')))])]),_c('v-col',{staticClass:"text-center pa-0",attrs:{"cols":"4"}},[_c('span',{staticClass:"filter-count primary--text"}),_vm._v(" selected out of\n "),_c('span',{staticClass:"total-count primary--text"}),(_vm.totalItems && _vm.totalItems > _vm.maxRecords)?_c('span',{staticClass:"total-items"},[_vm._v("\n /\n "),_c('span',{staticClass:"primary--text"},[_c('b',[_vm._v(_vm._s(_vm._f("formatNumber")(_vm.totalItems)))])])]):_vm._e(),_vm._v("\n records\n\n "),(_vm.totalItems && _vm.totalItems > _vm.maxRecords)?_c('v-tooltip',{attrs:{"top":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
|
|
@@ -291366,7 +291366,7 @@ var DcGraph_component = normalizeComponent(
|
|
|
291366
291366
|
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/@vue/cli-plugin-babel/node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/dashboard/BaseDashboard.vue?vue&type=script&lang=js&
|
|
291367
291367
|
var cov_21s3whnekh = function () {
|
|
291368
291368
|
var path = "/Users/juanes/papaemmelab/isabl_web/src/components/dashboard/BaseDashboard.vue";
|
|
291369
|
-
var hash = "
|
|
291369
|
+
var hash = "80378eaf505b52746695623a345007e2d0c5f9ea";
|
|
291370
291370
|
var global = new Function("return this")();
|
|
291371
291371
|
var gcv = "__coverage__";
|
|
291372
291372
|
var coverageData = {
|
|
@@ -292258,10 +292258,10 @@ var cov_21s3whnekh = function () {
|
|
|
292258
292258
|
mappings: ";;;;;;;;;;;;;;;;;;;;AAoBA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
|
|
292259
292259
|
file: "BaseDashboard.vue",
|
|
292260
292260
|
sourceRoot: "src/components/dashboard",
|
|
292261
|
-
sourcesContent: ["<template>\n <div ref=\"dashboard\">\n <v-card flat class=\"isabl-base-card\">\n <dc-graph\n :model=\"model\"\n :params=\"params\"\n :items=\"items\"\n :figures=\"figures\"\n :loading=\"loading\"\n :max-records=\"maxRecords\"\n :total-items=\"totalItems\"\n :is-embedded=\"isEmbedded\"\n @set-max-records=\"setMaxRecords\"\n @set-options=\"setOptions\"\n />\n </v-card>\n </div>\n</template>\n\n<script>\
|
|
292261
|
+
sourcesContent: ["<template>\n <div ref=\"dashboard\">\n <v-card flat class=\"isabl-base-card\">\n <dc-graph\n :model=\"model\"\n :params=\"params\"\n :items=\"items\"\n :figures=\"figures\"\n :loading=\"loading\"\n :max-records=\"maxRecords\"\n :total-items=\"totalItems\"\n :is-embedded=\"isEmbedded\"\n @set-max-records=\"setMaxRecords\"\n @set-options=\"setOptions\"\n />\n </v-card>\n </div>\n</template>\n\n<script>\n import BasePanel from '@/components/base/BasePanel.vue'\n import BaseSectionTitle from '@/components/base/BaseSectionTitle.vue'\n import DataTable from '@/components/table/DataTable.vue'\n import DcGraph from '@/components/dashboard/DcGraph.vue'\n import { fetchListRecords } from '@/utils/api'\n import { SHOW_ALERT } from '@/store/actions/alert'\n\n export default {\n name: 'BaseDashboard',\n components: {\n BasePanel,\n BaseSectionTitle,\n DataTable,\n DcGraph\n },\n props: {\n params: {\n type: Object,\n default: () => ({})\n },\n isEmbedded: {\n type: Boolean,\n default: true\n },\n model: {\n type: String,\n required: true\n },\n figures: {\n type: Array,\n required: true\n },\n requiredFields: {\n type: Array,\n default: () => []\n }\n },\n data() {\n return {\n items: [],\n loading: false,\n maxRecords: 500,\n options: {},\n totalItems: null\n }\n },\n computed: {\n queryFields() {\n const fields = this.figures.map(figure => figure.queryFields)\n // flat and remove duplicates\n return [...new Set(fields.flat())]\n },\n fields() {\n return [\n ...new Set([\n 'pk',\n 'created',\n 'modified',\n 'analytics',\n ...this.requiredFields,\n ...this.queryFields\n ])\n ]\n .filter(i => !!i)\n .map(i => i.replace(/\\./g, '__'))\n }\n },\n created() {\n this.loading = true\n },\n methods: {\n setOptions(options) {\n delete options.offset\n this.options = options\n this.fetchData()\n },\n setMaxRecords(value) {\n if (value !== this.maxRecords) {\n this.maxRecords = value\n this.fetchData()\n }\n },\n fetchData() {\n this.loading = true\n\n const fields = this.fields.map(i => i.replace(/\\./g, '__'))\n fetchListRecords(this.model, {\n ...this.options,\n ...this.params,\n limit: this.maxRecords,\n distinct: true,\n fields,\n 'fields!': ''\n })\n .then(response => {\n this.items = response.results.map(r => {\n const result = {\n ...r,\n ...r.analytics\n }\n delete result.analytics\n return result\n })\n this.totalItems = response.count\n })\n .catch(error => {\n let errorMessage = `Search failed: `\n if (error.response) {\n const errorMessages = Object.values(error.response.data).flat()\n errorMessage += errorMessages.length ? errorMessages[0] : '...'\n }\n this.$store.dispatch(SHOW_ALERT, {\n error: errorMessage\n })\n })\n .finally(() => (this.loading = false))\n }\n }\n }\n</script>\n<style lang=\"scss\">\n.dashboard .panels {\n max-width: 95%;\n max-width: 1800px;\n padding-bottom: 100px;\n}\n</style>\n"]
|
|
292262
292262
|
},
|
|
292263
292263
|
_coverageSchema: "43e27e138ebf9cfc5966b082cf9a028302ed4184",
|
|
292264
|
-
hash: "
|
|
292264
|
+
hash: "80378eaf505b52746695623a345007e2d0c5f9ea"
|
|
292265
292265
|
};
|
|
292266
292266
|
var coverage = global[gcv] || (global[gcv] = {});
|
|
292267
292267
|
|
|
@@ -292492,8 +292492,8 @@ var BaseDashboardvue_type_style_index_0_lang_scss_ = __webpack_require__("f624")
|
|
|
292492
292492
|
|
|
292493
292493
|
var BaseDashboard_component = normalizeComponent(
|
|
292494
292494
|
dashboard_BaseDashboardvue_type_script_lang_js_,
|
|
292495
|
-
|
|
292496
|
-
|
|
292495
|
+
BaseDashboardvue_type_template_id_2fd2fca6_render,
|
|
292496
|
+
BaseDashboardvue_type_template_id_2fd2fca6_staticRenderFns,
|
|
292497
292497
|
false,
|
|
292498
292498
|
null,
|
|
292499
292499
|
null,
|
|
@@ -298468,18 +298468,18 @@ var BioModelPanelvue_type_template_id_b52cff22_staticRenderFns = []
|
|
|
298468
298468
|
|
|
298469
298469
|
// CONCATENATED MODULE: ./src/components/bioModels/BioModelPanel.vue?vue&type=template&id=b52cff22&
|
|
298470
298470
|
|
|
298471
|
-
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d220a428-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/bioModels/BioModelTree.vue?vue&type=template&id=
|
|
298472
|
-
var
|
|
298471
|
+
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d220a428-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/bioModels/BioModelTree.vue?vue&type=template&id=2b110930&
|
|
298472
|
+
var BioModelTreevue_type_template_id_2b110930_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-card',{staticClass:"isabl-base-card",attrs:{"flat":"","data-test":"biomodel-tree"}},[_c('base-section-title',{attrs:{"show-more":_vm.showTree},on:{"toggle-show-more":function($event){_vm.showTree = !_vm.showTree}},scopedSlots:_vm._u([{key:"title",fn:function(){return [_vm._v("Samples Tree")]},proxy:true},{key:"actions",fn:function(){return [_c('div',[(_vm.isBigTree)?_c('v-btn',{staticClass:"table-action-btn pull-right ma-0",attrs:{"fab":"","outlined":"","color":"primary"},on:{"click":function($event){_vm.showFullHeight = !_vm.showFullHeight
|
|
298473
298473
|
_vm.scrollToCurrentNode()}}},[_c('v-icon',{attrs:{"color":"primary"}},[_vm._v(_vm._s(_vm.showFullHeight ? 'expand_less' : 'expand_more'))])],1):_vm._e()],1)]},proxy:true}])}),_c('v-row',{directives:[{name:"show",rawName:"v-show",value:(_vm.showTree),expression:"showTree"}],staticClass:"individual-tree-div ma-0",style:(_vm.showFullHeight ? '' : 'max-height: 300px;'),attrs:{"id":"tree-div"}},[_c('v-col',{staticClass:"individual-tree text-center pa-0 ma-0"})],1)],1)}
|
|
298474
|
-
var
|
|
298474
|
+
var BioModelTreevue_type_template_id_2b110930_staticRenderFns = []
|
|
298475
298475
|
|
|
298476
298476
|
|
|
298477
|
-
// CONCATENATED MODULE: ./src/components/bioModels/BioModelTree.vue?vue&type=template&id=
|
|
298477
|
+
// CONCATENATED MODULE: ./src/components/bioModels/BioModelTree.vue?vue&type=template&id=2b110930&
|
|
298478
298478
|
|
|
298479
298479
|
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/@vue/cli-plugin-babel/node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/bioModels/BioModelTree.vue?vue&type=script&lang=js&
|
|
298480
298480
|
var cov_2hmzqbstvs = function () {
|
|
298481
298481
|
var path = "/Users/juanes/papaemmelab/isabl_web/src/components/bioModels/BioModelTree.vue";
|
|
298482
|
-
var hash = "
|
|
298482
|
+
var hash = "1e089864fe6792f2d8555180af07f2e5d7f516a5";
|
|
298483
298483
|
var global = new Function("return this")();
|
|
298484
298484
|
var gcv = "__coverage__";
|
|
298485
298485
|
var coverageData = {
|
|
@@ -303764,10 +303764,10 @@ var cov_2hmzqbstvs = function () {
|
|
|
303764
303764
|
mappings: ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
|
|
303765
303765
|
file: "BioModelTree.vue",
|
|
303766
303766
|
sourceRoot: "src/components/bioModels",
|
|
303767
|
-
sourcesContent: ["<template>\n <v-card\n flat\n class=\"isabl-base-card\"\n data-test=\"biomodel-tree\"\n >\n <base-section-title\n :show-more=\"showTree\"\n @toggle-show-more=\"showTree = !showTree\"\n >\n <template v-slot:title>Samples Tree</template>\n <template v-slot:actions>\n <div>\n <v-btn\n v-if=\"isBigTree\"\n class=\"table-action-btn pull-right ma-0\"\n fab\n outlined\n color=\"primary\"\n @click=\"\n showFullHeight = !showFullHeight\n scrollToCurrentNode()\n \"\n >\n <v-icon color=\"primary\">{{ showFullHeight ? 'expand_less' : 'expand_more' }}</v-icon>\n </v-btn>\n </div>\n </template>\n </base-section-title>\n\n <!-- Graph -->\n <v-row\n v-show=\"showTree\"\n id=\"tree-div\"\n :style=\"showFullHeight ? '' : 'max-height: 300px;'\"\n class=\"individual-tree-div ma-0\"\n >\n <v-col class=\"individual-tree text-center pa-0 ma-0\" />\n </v-row>\n\n </v-card>\n</template>\n\n<script>\n/*\n Vue implementation of D3 Tree from:\n https://beta.observablehq.com/@asktree/interactive-tree-diagram-d3v4-v5\n*/\n\nimport { fetchIndividualTree } from '@/utils/api'\nimport { mapGetters } from 'vuex'\nimport { SHOW_ALERT } from '@/store/actions/alert'\nimport { SHOW_PANEL } from '@/store/actions/panels'\nimport BasePanel from '@/components/base/BasePanel.vue'\nimport BaseSectionTitle from '@/components/base/BaseSectionTitle'\nimport {\n tree as d3Tree,\n event as d3Event,\n select as d3Select,\n hierarchy as d3Hierarchy,\n linkHorizontal as d3linkHorizontal\n} from 'd3'\n\nexport default {\n name: 'BioModelTree',\n components: {\n BasePanel,\n BaseSectionTitle\n },\n data() {\n const { treeIcons } = this.$settings\n return {\n loading: false,\n duration: 0,\n data: null,\n root: null,\n tree: null,\n graph: null,\n species: null,\n dataNodes: null,\n showTree: true,\n isBigTree: false,\n showFullHeight: true,\n skipToScrollNode: false,\n currentNode: null,\n nodeSize: Object.keys(treeIcons).length ? 15 : 5,\n margin: { top: 20, bottom: 20, right: 0, left: 105 },\n diagonal: d3linkHorizontal()\n .x(d => d.y)\n .y(d => d.x),\n treeIcons\n }\n },\n computed: {\n ...mapGetters({\n currentModel: 'bioModelId',\n individual: 'individualId'\n })\n },\n watch: {\n individual(value, oldValue) {\n if (value !== oldValue) {\n this.fetchData()\n }\n },\n currentModel() {\n this.data && this.update(this.data)\n }\n },\n mounted() {\n this.fetchData()\n },\n methods: {\n buildTree() {\n let dx = Object.keys(this.treeIcons).length ? this.nodeSize + 4 : 18\n let dy = 0\n let iconSize = this.nodeSize\n\n // set width\n this.width = 540 - this.margin.right - this.margin.left\n this.tree = d3Tree()\n .nodeSize([dx, dy])\n .separation((a, b) => (a.parent == b.parent ? 1.75 : 2.5))\n\n // clear div\n let div = d3Select(this.$el).select('.individual-tree')\n div.selectAll('svg').remove()\n\n // create svg\n this.svg = div\n .append('svg')\n .attr('width', this.width)\n .attr('height', dx)\n .attr('viewBox', [-this.margin.left, -this.margin.top, this.width, dx])\n .style('font', '10px sans-serif')\n .style('user-select', 'none')\n\n // create filters\n this.svg\n .append('svg:filter')\n .attr('id', 'invertColor')\n .append('feColorMatrix')\n .attr('in', 'SourceGraphic')\n .attr('type', 'matrix')\n .attr('values', '-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0')\n\n // create image definitions\n const defs = this.svg.append('svg:defs')\n Object.keys(this.treeIcons).forEach(model => {\n const pattern = defs\n .append('svg:pattern')\n .attr('id', `icon-${model}`)\n .attr('width', iconSize)\n .attr('height', iconSize)\n .attr('patternUnits', 'objectBoundingBox')\n\n pattern\n .append('rect')\n .attr('width', '100%')\n .attr('height', '100%')\n .attr('fill', 'var(--v-primary-base)')\n\n pattern\n .append('svg:image')\n .attr('xlink:href', this.treeIcons[model])\n .attr('width', iconSize)\n .attr('height', iconSize)\n .attr('x', iconSize / 2)\n .attr('y', iconSize / 2)\n .attr('filter', 'url(#invertColor)')\n })\n\n // create links\n this.gLink = this.svg\n .append('g')\n .attr('fill', 'none')\n .attr('stroke', '#555')\n .attr('stroke-opacity', 0.4)\n .attr('stroke-width', 1.5)\n\n // create tooltip\n this.tooltip = d3Select('body')\n .append('div')\n .style('position', 'absolute')\n .style('z-index', '9999')\n .style('visibility', 'hidden')\n\n // create nodes\n this.gNode = this.svg.append('g')\n\n // build root\n this.root = d3Hierarchy(this.data, d => d.children)\n this.root.x0 = dy\n this.root.y0 = 0\n this.root.descendants().forEach((d, i) => {\n d.id = i\n d.collapsed = false\n d._children = d.children\n\n // collapse samples with too many experiments\n if (d.depth !== 0 && d.children ? d.children.length > 10 : false) {\n d.children = null\n d.collapsed = true\n }\n\n // by default hide tree if too many samples\n if (d.depth === 0 && d.children && d.children.length > 10) {\n this.showFullHeight = false\n this.isBigTree = true\n }\n })\n\n this.update(this.root)\n },\n async fetchData() {\n if (this.individual) {\n this.loading = true\n let individual = await fetchIndividualTree(this.individual)\n this.species = individual.species\n\n // Format Individual Tree\n let individualNode = {}\n individualNode.id = individual.system_id\n individualNode.uuid = individual.uuid\n individualNode.name = individual.system_id\n individualNode.parent = null\n individualNode.individual = individual\n individualNode.class = 'individual'\n if (individual.species === 'MOUSE') {\n individualNode.img = 'mouse'\n } else if (individual.species === 'HUMAN') {\n if (individual.gender === 'FEMALE') {\n individualNode.img = 'female'\n } else {\n individualNode.img = 'male'\n }\n } else {\n individualNode.img = 'alien'\n }\n individualNode.children = individual.sample_set.map(sample => {\n // Samples Children\n let sampleNode = {}\n sampleNode.id = sample.system_id\n sampleNode.uuid = sample.uuid\n sampleNode.name = sample.system_id.split('_')\n sampleNode.name = sampleNode.name[sampleNode.name.length - 1]\n sampleNode.parent = individual.system_id\n sampleNode.sample = sample\n sampleNode.individual = individual\n sampleNode.class = 'sample'\n\n if (sample.category === 'TUMOR') {\n sampleNode.img = 'tumor'\n } else {\n sampleNode.img = 'normal'\n }\n\n let aliquots_ids = [\n ...new Set(sample.experiment_set.map(e => e.aliquot_id))\n ]\n\n sampleNode.children = aliquots_ids\n .map(aliquot_id => {\n // Aliquot children\n let aliquotNode = {}\n aliquotNode.aliquot_id = aliquot_id\n aliquotNode.name = ''\n aliquotNode.parent = sample.system_id\n aliquotNode.sample = sample\n aliquotNode.sampleNode = sampleNode\n aliquotNode.individual = individual\n aliquotNode.class = 'aliquot'\n aliquotNode.img = 'aliquot'\n aliquotNode.children = []\n\n sample.experiment_set.map(experiment => {\n // Experiment Children\n if (experiment.aliquot_id === aliquot_id) {\n let experimentNode = {}\n experimentNode.parent = sample.system_id\n experimentNode.sample = sample\n experimentNode.individual = individual\n experimentNode.aliquot_id = experiment.aliquot_id\n experimentNode.id = experiment.system_id\n experimentNode.uuid = experiment.uuid\n experimentNode.class = 'experiment'\n experimentNode.experiment = experiment\n\n let name = experiment.system_id.split('_')\n experimentNode.name = name[name.length - 1]\n\n if (experiment.custom_fields.is_pdx) {\n experimentNode.img = 'mouse'\n } else {\n if (experiment.technique.category === 'IMG') {\n experimentNode.img = 'image'\n } else if (experiment.technique.category === 'RNA') {\n experimentNode.img = 'rna'\n } else if (experiment.technique.category === 'DNA') {\n experimentNode.img = 'dna'\n } else {\n experimentNode.img = 'dna'\n }\n }\n\n // legacy leukgen ID\n if (experiment.system_id.split('-').length === 7) {\n aliquotNode.name = experiment.system_id.split('-')[4]\n experimentNode.name = experiment.system_id\n .split('-')\n .slice(5, 7)\n .join('-')\n } else {\n aliquotNode.name = experiment.system_id.split('_')\n aliquotNode.name = parseInt(\n aliquotNode.name[aliquotNode.name.length - 2]\n )\n }\n aliquotNode.children.push(experimentNode)\n }\n })\n return aliquotNode\n })\n .sort((a, b) => a.name - b.name)\n return sampleNode\n })\n\n this.data = individualNode\n this.dataNodes = individualNode.children.reduce(\n (totalNodes, nodeInChildren) => {\n return totalNodes + nodeInChildren.children.length\n },\n 0\n )\n\n this.buildTree()\n this.loading = false\n }\n },\n update(source) {\n const duration = d3Event && d3Event.altKey ? 2500 : 250\n const nodes = this.root.descendants().reverse()\n const links = this.root.links()\n\n // Compute the new tree layout.\n this.tree(this.root)\n\n let left = this.root\n let right = this.root\n this.root.eachBefore(node => {\n if (node.x < left.x) left = node\n if (node.x > right.x) right = node\n })\n\n const height = right.x - left.x + this.margin.top + this.margin.bottom\n\n this.svg\n .transition()\n .duration(duration)\n .attr('height', height)\n .attr('viewBox', [\n -this.margin.left,\n left.x - this.margin.top,\n this.width,\n height\n ])\n .tween(\n 'resize',\n window.ResizeObserver ? null : () => () => this.svg.dispatch('toggle')\n )\n\n // Normalize for fixed-depth.\n nodes.forEach(d => {\n d.y = {\n individual: 0,\n sample: 150,\n aliquot: 225,\n experiment: 300\n }[d.data.class]\n })\n\n // ****************** Nodes section ***************************\n\n // Update the nodes...\n let node = this.gNode.selectAll('g').data(nodes, d => d.id)\n\n // Enter any new modes at the parent's previous position.\n let nodeEnter = node\n .enter()\n .append('g')\n .attr('class', d => `node ${d.data.class}`)\n .attr('transform', () => `translate(${source.y0},${source.x0})`)\n\n const circles = nodeEnter\n .append('circle')\n .attr('cursor', d => (d.data.class !== 'aliquot' ? 'pointer' : null))\n .attr('class', 'node shades--text')\n\n circles.style('fill', d =>\n this.treeIcons[d.data.img] ? `url(#icon-${d.data.img})` : ''\n )\n\n nodeEnter\n .on('click', this.changeModel)\n // tooltip, see https://stackoverflow.com/questions/10805184\n .on('mouseover', d => {\n if (d.data.class === 'aliquot' && d.parent.children.length < 2) return\n\n let leftPaddings = { experiment: 300, individual: 120, sample: 200 }\n this.tooltip\n .html(this.getTooltip(d))\n .style('visibility', 'visible')\n .attr('transform', `translate(${d.y},${d.x})`)\n .style('top', `${d3Event.pageY + 20}px`)\n .style('left', `${d3Event.pageX - leftPaddings[d.data.class]}px`)\n })\n .on('mouseout', () => this.tooltip.style('visibility', 'hidden'))\n\n // Add labels for the nodes\n nodeEnter\n .append('text')\n .on('click', this.onTextClick)\n .attr('dy', '.35em')\n .attr('x', -13)\n .attr('text-anchor', d => (d.children || d._children ? 'end' : 'end'))\n .text(d =>\n d.data.class === 'aliquot' && d.parent.children.length < 2\n ? ''\n : d.data.name\n )\n\n // Add collapse text to indicate node can be opened\n nodeEnter\n .append('text')\n .attr('dy', 0)\n .attr('x', 26)\n .text('...')\n .attr('class', 'collapse-text')\n\n // UPDATE\n let nodeUpdate = nodeEnter.merge(node)\n\n // Transition to the proper position for the node\n nodeUpdate\n .transition()\n .duration(this.duration)\n .attr('transform', d => `translate(${d.y},${d.x})`)\n\n // Update the node attributes and style\n nodeUpdate\n .select('.node')\n .attr('r', d => (d.data.class !== 'aliquot' ? this.nodeSize : 5))\n .attr('cx', this.nodeSize / 2)\n .attr('cy', 0)\n .attr('data-intercom-target', d => `tree-node-circle-${d.data.id}`)\n .attr('fill', d =>\n d._children && !d.children ? 'gray' : 'var(--v-primary-base)'\n )\n .attr('opacity', d =>\n d.data.class === 'aliquot' && d.parent.children.length < 2 ? 0 : 1\n )\n .style('stroke', d => {\n if (\n d.data.id === this.currentModel ||\n d.data.uuid === this.currentModel\n ) {\n this.currentNode = d\n if (!this.skipToScrollNode) {\n this.scrollToCurrentNode()\n }\n this.skipToScrollNode = false\n return 'var(--v-secondary-base)'\n }\n return 'transparent'\n })\n\n // Only show dots for collapsed and collapsible nodes\n nodeUpdate\n .select('text.collapse-text')\n .attr('visibility', d =>\n d.collapsed && d._children ? 'visible' : 'hidden'\n )\n\n // Remove any exiting nodes\n let nodeExit = node\n .exit()\n .transition()\n .duration(this.duration)\n .attr('transform', `translate(${source.y},${source.x})`)\n .remove()\n\n // On exit reduce the node circles size to 0\n nodeExit.select('.node').attr('r', 1e-6)\n\n // On exit reduce the opacity of text labels\n nodeExit.select('text').style('fill-opacity', 1e-6)\n\n // ================ links section ================\n\n // Update the links\n let link = this.gLink.selectAll('path.link').data(links, d => d.id)\n\n // Enter any new links at the parent's previous position.\n let linkEnter = link\n .enter()\n .insert('path', 'g')\n .attr('class', 'link')\n\n // UPDATE\n let linkUpdate = linkEnter.merge(link)\n\n // Transition back to the parent element position\n linkUpdate\n .transition()\n .duration(this.duration)\n .attr('d', this.diagonal)\n\n // Remove any exiting links\n link\n .exit()\n .transition()\n .duration(this.duration)\n .remove()\n\n // Store the old positions for transition.\n nodes.forEach(d => {\n d.x0 = d.x\n d.y0 = d.y\n })\n\n this.$emit('update-size')\n },\n onTextClick(d) {\n this.collapseBranch(d)\n if (!d._children && d.data.id) {\n this.$copyText(d.data.id).then(\n () => {\n this.$store.dispatch(SHOW_ALERT, {\n message: 'Copied System ID to clipboard!'\n })\n },\n () => {\n this.$store.dispatch(SHOW_ALERT, {\n error: 'System ID could not be copied to clipboard'\n })\n }\n )\n }\n },\n collapseBranch(d) {\n d.children = d.children ? null : d._children\n d.collapsed = !d.collapsed\n this.update(d)\n },\n changeModel(d) {\n if (d.data.id) {\n this.skipToScrollNode = true // don't scroll to node when click\n\n // Track individual tree usage\n window.analytics.track('Browsed Individual Tree', {\n model: d.data.class,\n record: d.data.id\n })\n\n this.$store.dispatch(SHOW_PANEL, {\n bioModel: d.data.id\n })\n }\n },\n scrollToCurrentNode() {\n this.$nextTick(() => {\n if (!this.showFullHeight)\n setTimeout(() => {\n document.getElementById('tree-div').scrollTop =\n this.currentNode.x0 + 395 // 395 is a function of the max height\n }, 100) // this delay was determined kind of experimentally\n })\n },\n getTooltip(d) {\n const keyValue = (key, verboseName) => {\n let value = this.$get(d.data, key, null)\n return value === null\n ? ''\n : `\n <div class=\"layout row mb-1\" style=\"max-width: 100%\"\">\n <div class=\"flex xs5\" style=\"width: 100%\">${verboseName}</div>\n <div class=\"flex xs7\" style=\"width: 100%\"><b>${value}</b></div>\n </div>\n `\n }\n return `\n <div class=\"v-tooltip__content\" style=\"width: 350px;\">\n ${keyValue('experiment.system_id', 'System ID')}\n ${keyValue('experiment.identifier', 'Experiment ID')}\n ${keyValue('aliquot_id', 'Aliquot ID')}\n ${keyValue('sample.identifier', 'Sample ID')}\n ${keyValue('individual.identifier', 'Individual ID')}\n ${keyValue('experiment.technique.method', 'Method')}\n ${keyValue('experiment.technique.name', 'Technique Name')}\n ${keyValue('sample.disease.acronym', 'Disease')}\n ${keyValue('individual.species', 'Species')}\n ${keyValue('individual.center.acronym', 'Center')}\n </div>\n `\n }\n }\n}\n</script>\n\n<style lang=\"scss\">\n.node-tooltip {\n background: rgba($color: #000000, $alpha: 0.8);\n}\n.individual-tree-div {\n overflow-x: scroll;\n margin: auto;\n .node {\n stroke-width: 3px;\n text {\n font-size: 14px;\n font-weight: 300;\n fill: black !important;\n cursor: pointer;\n &.collapse-text {\n font-size: 20px;\n font-weight: 200;\n cursor: default;\n }\n }\n &.experiment text {\n cursor: default;\n }\n }\n .link {\n fill: none;\n stroke-width: 1.5px;\n stroke: #aaa;\n }\n}\n</style>\n"]
|
|
303767
|
+
sourcesContent: ["<template>\n <v-card\n flat\n class=\"isabl-base-card\"\n data-test=\"biomodel-tree\"\n >\n <base-section-title\n :show-more=\"showTree\"\n @toggle-show-more=\"showTree = !showTree\"\n >\n <template v-slot:title>Samples Tree</template>\n <template v-slot:actions>\n <div>\n <v-btn\n v-if=\"isBigTree\"\n class=\"table-action-btn pull-right ma-0\"\n fab\n outlined\n color=\"primary\"\n @click=\"\n showFullHeight = !showFullHeight\n scrollToCurrentNode()\n \"\n >\n <v-icon color=\"primary\">{{ showFullHeight ? 'expand_less' : 'expand_more' }}</v-icon>\n </v-btn>\n </div>\n </template>\n </base-section-title>\n\n <!-- Graph -->\n <v-row\n v-show=\"showTree\"\n id=\"tree-div\"\n :style=\"showFullHeight ? '' : 'max-height: 300px;'\"\n class=\"individual-tree-div ma-0\"\n >\n <v-col class=\"individual-tree text-center pa-0 ma-0\" />\n </v-row>\n\n </v-card>\n</template>\n\n<script>\n/*\n Vue implementation of D3 Tree from:\n https://beta.observablehq.com/@asktree/interactive-tree-diagram-d3v4-v5\n*/\n\nimport { fetchIndividualTree } from '@/utils/api'\nimport { mapGetters } from 'vuex'\nimport { SHOW_ALERT } from '@/store/actions/alert'\nimport { SHOW_PANEL } from '@/store/actions/panels'\nimport BasePanel from '@/components/base/BasePanel.vue'\nimport BaseSectionTitle from '@/components/base/BaseSectionTitle'\nimport {\n tree as d3Tree,\n event as d3Event,\n select as d3Select,\n hierarchy as d3Hierarchy,\n linkHorizontal as d3linkHorizontal\n} from 'd3'\n\nexport default {\n name: 'BioModelTree',\n components: {\n BasePanel,\n BaseSectionTitle\n },\n data() {\n const { treeIcons } = this.$settings\n return {\n loading: false,\n duration: 0,\n data: null,\n root: null,\n tree: null,\n graph: null,\n species: null,\n dataNodes: null,\n showTree: true,\n isBigTree: false,\n showFullHeight: true,\n skipToScrollNode: false,\n currentNode: null,\n nodeSize: Object.keys(treeIcons).length ? 15 : 5,\n margin: { top: 20, bottom: 20, right: 0, left: 105 },\n diagonal: d3linkHorizontal()\n .x(d => d.y)\n .y(d => d.x),\n treeIcons\n }\n },\n computed: {\n ...mapGetters({\n currentModel: 'bioModelId',\n individual: 'individualId'\n })\n },\n watch: {\n individual(value, oldValue) {\n if (value !== oldValue) {\n this.fetchData()\n }\n },\n currentModel() {\n this.data && this.update(this.data)\n }\n },\n mounted() {\n this.fetchData()\n },\n methods: {\n buildTree() {\n let dx = Object.keys(this.treeIcons).length ? this.nodeSize + 4 : 18\n let dy = 0\n let iconSize = this.nodeSize\n\n // set width\n this.width = 540 - this.margin.right - this.margin.left\n this.tree = d3Tree()\n .nodeSize([dx, dy])\n .separation((a, b) => (a.parent == b.parent ? 1.75 : 2.5))\n\n // clear div\n let div = d3Select(this.$el).select('.individual-tree')\n div.selectAll('svg').remove()\n\n // create svg\n this.svg = div\n .append('svg')\n .attr('width', this.width)\n .attr('height', dx)\n .attr('viewBox', [-this.margin.left, -this.margin.top, this.width, dx])\n .style('font', '10px sans-serif')\n .style('user-select', 'none')\n\n // create filters\n this.svg\n .append('svg:filter')\n .attr('id', 'invertColor')\n .append('feColorMatrix')\n .attr('in', 'SourceGraphic')\n .attr('type', 'matrix')\n .attr('values', '-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0')\n\n // create image definitions\n const defs = this.svg.append('svg:defs')\n Object.keys(this.treeIcons).forEach(model => {\n const pattern = defs\n .append('svg:pattern')\n .attr('id', `icon-${model}`)\n .attr('width', iconSize)\n .attr('height', iconSize)\n .attr('patternUnits', 'objectBoundingBox')\n\n pattern\n .append('rect')\n .attr('width', '100%')\n .attr('height', '100%')\n .attr('fill', 'var(--v-primary-base)')\n\n pattern\n .append('svg:image')\n .attr('xlink:href', this.treeIcons[model])\n .attr('width', iconSize)\n .attr('height', iconSize)\n .attr('x', iconSize / 2)\n .attr('y', iconSize / 2)\n .attr('filter', 'url(#invertColor)')\n })\n\n // create links\n this.gLink = this.svg\n .append('g')\n .attr('fill', 'none')\n .attr('stroke', '#555')\n .attr('stroke-opacity', 0.4)\n .attr('stroke-width', 1.5)\n\n // create tooltip\n this.tooltip = d3Select('body')\n .append('div')\n .style('position', 'absolute')\n .style('z-index', '9999')\n .style('visibility', 'hidden')\n\n // create nodes\n this.gNode = this.svg.append('g')\n\n // build root\n this.root = d3Hierarchy(this.data, d => d.children)\n this.root.x0 = dy\n this.root.y0 = 0\n this.root.descendants().forEach((d, i) => {\n d.id = i\n d.collapsed = false\n d._children = d.children\n\n // collapse samples with too many experiments\n if (d.depth !== 0 && d.children ? d.children.length > 10 : false) {\n d.children = null\n d.collapsed = true\n }\n\n // by default hide tree if too many samples\n if (d.depth === 0 && d.children && d.children.length > 10) {\n this.showFullHeight = false\n this.isBigTree = true\n }\n })\n\n this.update(this.root)\n },\n async fetchData() {\n if (this.individual) {\n this.loading = true\n let individual = await fetchIndividualTree(this.individual)\n this.species = individual.species\n\n // Format Individual Tree\n let individualNode = {}\n individualNode.id = individual.system_id\n individualNode.uuid = individual.uuid\n individualNode.name = individual.system_id\n individualNode.parent = null\n individualNode.individual = individual\n individualNode.class = 'individual'\n if (individual.species === 'MOUSE') {\n individualNode.img = 'mouse'\n } else if (individual.species === 'HUMAN') {\n if (individual.gender === 'FEMALE') {\n individualNode.img = 'female'\n } else {\n individualNode.img = 'male'\n }\n } else {\n individualNode.img = 'alien'\n }\n individualNode.children = individual.sample_set.map(sample => {\n // Samples Children\n let sampleNode = {}\n sampleNode.id = sample.system_id\n sampleNode.uuid = sample.uuid\n sampleNode.name = sample.system_id.split('_')\n sampleNode.name = sampleNode.name[sampleNode.name.length - 1]\n sampleNode.parent = individual.system_id\n sampleNode.sample = sample\n sampleNode.individual = individual\n sampleNode.class = 'sample'\n\n if (sample.category === 'TUMOR') {\n sampleNode.img = 'tumor'\n } else {\n sampleNode.img = 'normal'\n }\n\n let aliquots_ids = [\n ...new Set(sample.experiment_set.map(e => e.aliquot_id))\n ]\n\n sampleNode.children = aliquots_ids\n .map(aliquot_id => {\n // Aliquot children\n let aliquotNode = {}\n aliquotNode.aliquot_id = aliquot_id\n aliquotNode.name = ''\n aliquotNode.parent = sample.system_id\n aliquotNode.sample = sample\n aliquotNode.sampleNode = sampleNode\n aliquotNode.individual = individual\n aliquotNode.class = 'aliquot'\n aliquotNode.img = 'aliquot'\n aliquotNode.children = []\n\n sample.experiment_set.map(experiment => {\n // Experiment Children\n if (experiment.aliquot_id === aliquot_id) {\n let experimentNode = {}\n experimentNode.parent = sample.system_id\n experimentNode.sample = sample\n experimentNode.individual = individual\n experimentNode.aliquot_id = experiment.aliquot_id\n experimentNode.id = experiment.system_id\n experimentNode.uuid = experiment.uuid\n experimentNode.class = 'experiment'\n experimentNode.experiment = experiment\n\n let name = experiment.system_id.split('_')\n experimentNode.name = name[name.length - 1]\n\n if (experiment.custom_fields.is_pdx) {\n experimentNode.img = 'mouse'\n } else {\n if (experiment.technique.category === 'IMG') {\n experimentNode.img = 'image'\n } else if (experiment.technique.category === 'RNA') {\n experimentNode.img = 'rna'\n } else if (experiment.technique.category === 'DNA') {\n experimentNode.img = 'dna'\n } else {\n experimentNode.img = 'dna'\n }\n }\n\n // legacy leukgen ID\n if (experiment.system_id.split('-').length === 7) {\n aliquotNode.name = experiment.system_id.split('-')[4]\n experimentNode.name = experiment.system_id\n .split('-')\n .slice(5, 7)\n .join('-')\n } else {\n aliquotNode.name = experiment.system_id.split('_')\n aliquotNode.name = parseInt(\n aliquotNode.name[aliquotNode.name.length - 2]\n )\n }\n aliquotNode.children.push(experimentNode)\n }\n })\n return aliquotNode\n })\n .sort((a, b) => a.name - b.name)\n return sampleNode\n })\n\n this.data = individualNode\n this.dataNodes = individualNode.children.reduce(\n (totalNodes, nodeInChildren) => {\n return totalNodes + nodeInChildren.children.length\n },\n 0\n )\n\n this.buildTree()\n this.loading = false\n }\n },\n update(source) {\n const duration = d3Event && d3Event.altKey ? 2500 : 250\n const nodes = this.root.descendants().reverse()\n const links = this.root.links()\n\n // Compute the new tree layout.\n this.tree(this.root)\n\n let left = this.root\n let right = this.root\n this.root.eachBefore(node => {\n if (node.x < left.x) left = node\n if (node.x > right.x) right = node\n })\n\n const height = right.x - left.x + this.margin.top + this.margin.bottom\n\n this.svg\n .transition()\n .duration(duration)\n .attr('height', height)\n .attr('viewBox', [\n -this.margin.left,\n left.x - this.margin.top,\n this.width,\n height\n ])\n .tween(\n 'resize',\n window.ResizeObserver ? null : () => () => this.svg.dispatch('toggle')\n )\n\n // Normalize for fixed-depth.\n nodes.forEach(d => {\n d.y = {\n individual: 0,\n sample: 150,\n aliquot: 225,\n experiment: 300\n }[d.data.class]\n })\n\n // ****************** Nodes section ***************************\n\n // Update the nodes...\n let node = this.gNode.selectAll('g').data(nodes, d => d.id)\n\n // Enter any new modes at the parent's previous position.\n let nodeEnter = node\n .enter()\n .append('g')\n .attr('class', d => `node ${d.data.class}`)\n .attr('transform', () => `translate(${source.y0},${source.x0})`)\n\n const circles = nodeEnter\n .append('circle')\n .attr('cursor', d => (d.data.class !== 'aliquot' ? 'pointer' : null))\n .attr('class', 'node shades--text')\n\n circles.style('fill', d =>\n this.treeIcons[d.data.img] ? `url(#icon-${d.data.img})` : ''\n )\n\n nodeEnter\n .on('click', this.changeModel)\n // tooltip, see https://stackoverflow.com/questions/10805184\n .on('mouseover', d => {\n if (d.data.class === 'aliquot' && d.parent.children.length < 2) return\n\n let leftPaddings = { experiment: 300, individual: 120, sample: 200 }\n this.tooltip\n .html(this.getTooltip(d))\n .style('visibility', 'visible')\n .attr('transform', `translate(${d.y},${d.x})`)\n .style('top', `${d3Event.pageY + 20}px`)\n .style('left', `${d3Event.pageX - leftPaddings[d.data.class]}px`)\n })\n .on('mouseout', () => this.tooltip.style('visibility', 'hidden'))\n\n // Add labels for the nodes\n nodeEnter\n .append('text')\n .on('click', this.onTextClick)\n .attr('dy', '.35em')\n .attr('x', -13)\n .attr('text-anchor', d => (d.children || d._children ? 'end' : 'end'))\n .text(d =>\n d.data.class === 'aliquot' && d.parent.children.length < 2\n ? ''\n : d.data.name\n )\n\n // Add collapse text to indicate node can be opened\n nodeEnter\n .append('text')\n .attr('dy', 0)\n .attr('x', 26)\n .text('...')\n .attr('class', 'collapse-text')\n\n // UPDATE\n let nodeUpdate = nodeEnter.merge(node)\n\n // Transition to the proper position for the node\n nodeUpdate\n .transition()\n .duration(this.duration)\n .attr('transform', d => `translate(${d.y},${d.x})`)\n\n // Update the node attributes and style\n nodeUpdate\n .select('.node')\n .attr('r', d => (d.data.class !== 'aliquot' ? this.nodeSize : 5))\n .attr('cx', this.nodeSize / 2)\n .attr('cy', 0)\n .attr('data-intercom-target', d => `tree-node-circle-${d.data.id}`)\n .attr('fill', d =>\n d._children && !d.children ? 'gray' : 'var(--v-primary-base)'\n )\n .attr('opacity', d =>\n d.data.class === 'aliquot' && d.parent.children.length < 2 ? 0 : 1\n )\n .style('stroke', d => {\n if (\n d.data.id === this.currentModel ||\n d.data.uuid === this.currentModel\n ) {\n this.currentNode = d\n if (!this.skipToScrollNode) {\n this.scrollToCurrentNode()\n }\n this.skipToScrollNode = false\n return 'var(--v-secondary-base)'\n }\n return 'transparent'\n })\n\n // Only show dots for collapsed and collapsible nodes\n nodeUpdate\n .select('text.collapse-text')\n .attr('visibility', d =>\n d.collapsed && d._children ? 'visible' : 'hidden'\n )\n\n // Remove any exiting nodes\n let nodeExit = node\n .exit()\n .transition()\n .duration(this.duration)\n .attr('transform', `translate(${source.y},${source.x})`)\n .remove()\n\n // On exit reduce the node circles size to 0\n nodeExit.select('.node').attr('r', 1e-6)\n\n // On exit reduce the opacity of text labels\n nodeExit.select('text').style('fill-opacity', 1e-6)\n\n // ================ links section ================\n\n // Update the links\n let link = this.gLink.selectAll('path.link').data(links, d => d.id)\n\n // Enter any new links at the parent's previous position.\n let linkEnter = link\n .enter()\n .insert('path', 'g')\n .attr('class', 'link')\n\n // UPDATE\n let linkUpdate = linkEnter.merge(link)\n\n // Transition back to the parent element position\n linkUpdate\n .transition()\n .duration(this.duration)\n .attr('d', this.diagonal)\n\n // Remove any exiting links\n link\n .exit()\n .transition()\n .duration(this.duration)\n .remove()\n\n // Store the old positions for transition.\n nodes.forEach(d => {\n d.x0 = d.x\n d.y0 = d.y\n })\n\n this.$emit('update-size')\n },\n onTextClick(d) {\n this.collapseBranch(d)\n if (!d._children && d.data.id) {\n this.$copyText(d.data.id).then(\n () => {\n this.$store.dispatch(SHOW_ALERT, {\n message: 'Copied System ID to clipboard!'\n })\n },\n () => {\n this.$store.dispatch(SHOW_ALERT, {\n error: 'System ID could not be copied to clipboard'\n })\n }\n )\n }\n },\n collapseBranch(d) {\n d.children = d.children ? null : d._children\n d.collapsed = !d.collapsed\n this.update(d)\n },\n changeModel(d) {\n if (d.data.id) {\n this.skipToScrollNode = true // don't scroll to node when click\n\n // Track individual tree usage\n window.analytics.track('Browsed Individual Tree', {\n model: d.data.class,\n record: d.data.id\n })\n\n this.$store.dispatch(SHOW_PANEL, {\n bioModel: d.data.id\n })\n }\n },\n scrollToCurrentNode() {\n this.$nextTick(() => {\n if (!this.showFullHeight)\n setTimeout(() => {\n document.getElementById('tree-div').scrollTop =\n this.currentNode.x0 + 395 // 395 is a function of the max height\n }, 100) // this delay was determined kind of experimentally\n })\n },\n getTooltip(d) {\n const keyValue = (key, verboseName) => {\n let value = this.$get(d.data, key, null)\n return value === null\n ? ''\n : `\n <div class=\"layout row ma-3\" style=\"max-width: 100%\"\">\n <div class=\"flex xs5\" style=\"width: 100%\">${verboseName}</div>\n <div class=\"flex xs7\" style=\"width: 100%\"><b>${value}</b></div>\n </div>\n `\n }\n return `\n <div class=\"v-tooltip__content tree-tooltip\" style=\"min-width: 350px;\">\n ${keyValue('experiment.system_id', 'System ID')}\n ${keyValue('experiment.identifier', 'Experiment ID')}\n ${keyValue('aliquot_id', 'Aliquot ID')}\n ${keyValue('sample.identifier', 'Sample ID')}\n ${keyValue('individual.identifier', 'Individual ID')}\n ${keyValue('experiment.technique.method', 'Method')}\n ${keyValue('experiment.technique.name', 'Technique Name')}\n ${keyValue('sample.disease.acronym', 'Disease')}\n ${keyValue('individual.species', 'Species')}\n ${keyValue('individual.center.acronym', 'Center')}\n </div>\n `\n }\n }\n}\n</script>\n\n<style lang=\"scss\">\n.tree-tooltip.v-tooltip__content {\n color: white;\n padding: 20px;\n opacity: 1;\n font-size: 12px;\n overflow: hidden;\n}\n.node-tooltip {\n background: rgba($color: #000000, $alpha: 0.8);\n}\n.individual-tree-div {\n overflow-x: scroll;\n margin: auto;\n .node {\n stroke-width: 3px;\n text {\n font-size: 14px;\n font-weight: 300;\n fill: black !important;\n cursor: pointer;\n &.collapse-text {\n font-size: 20px;\n font-weight: 200;\n cursor: default;\n }\n }\n &.experiment text {\n cursor: default;\n }\n }\n .link {\n fill: none;\n stroke-width: 1.5px;\n stroke: #aaa;\n }\n}\n</style>\n"]
|
|
303768
303768
|
},
|
|
303769
303769
|
_coverageSchema: "43e27e138ebf9cfc5966b082cf9a028302ed4184",
|
|
303770
|
-
hash: "
|
|
303770
|
+
hash: "1e089864fe6792f2d8555180af07f2e5d7f516a5"
|
|
303771
303771
|
};
|
|
303772
303772
|
var coverage = global[gcv] || (global[gcv] = {});
|
|
303773
303773
|
|
|
@@ -304613,11 +304613,11 @@ function BioModelTreevue_type_script_lang_js_defineProperty(obj, key, value) { i
|
|
|
304613
304613
|
cov_2hmzqbstvs.f[50]++;
|
|
304614
304614
|
var value = (cov_2hmzqbstvs.s[204]++, _this5.$get(d.data, key, null));
|
|
304615
304615
|
cov_2hmzqbstvs.s[205]++;
|
|
304616
|
-
return value === null ? (cov_2hmzqbstvs.b[49][0]++, '') : (cov_2hmzqbstvs.b[49][1]++, "\n <div class=\"layout row
|
|
304616
|
+
return value === null ? (cov_2hmzqbstvs.b[49][0]++, '') : (cov_2hmzqbstvs.b[49][1]++, "\n <div class=\"layout row ma-3\" style=\"max-width: 100%\"\">\n <div class=\"flex xs5\" style=\"width: 100%\">".concat(verboseName, "</div>\n <div class=\"flex xs7\" style=\"width: 100%\"><b>").concat(value, "</b></div>\n </div>\n "));
|
|
304617
304617
|
};
|
|
304618
304618
|
|
|
304619
304619
|
cov_2hmzqbstvs.s[206]++;
|
|
304620
|
-
return "\n <div class=\"v-tooltip__content\" style=\"width: 350px;\">\n ".concat(keyValue('experiment.system_id', 'System ID'), "\n ").concat(keyValue('experiment.identifier', 'Experiment ID'), "\n ").concat(keyValue('aliquot_id', 'Aliquot ID'), "\n ").concat(keyValue('sample.identifier', 'Sample ID'), "\n ").concat(keyValue('individual.identifier', 'Individual ID'), "\n ").concat(keyValue('experiment.technique.method', 'Method'), "\n ").concat(keyValue('experiment.technique.name', 'Technique Name'), "\n ").concat(keyValue('sample.disease.acronym', 'Disease'), "\n ").concat(keyValue('individual.species', 'Species'), "\n ").concat(keyValue('individual.center.acronym', 'Center'), "\n </div>\n ");
|
|
304620
|
+
return "\n <div class=\"v-tooltip__content tree-tooltip\" style=\"min-width: 350px;\">\n ".concat(keyValue('experiment.system_id', 'System ID'), "\n ").concat(keyValue('experiment.identifier', 'Experiment ID'), "\n ").concat(keyValue('aliquot_id', 'Aliquot ID'), "\n ").concat(keyValue('sample.identifier', 'Sample ID'), "\n ").concat(keyValue('individual.identifier', 'Individual ID'), "\n ").concat(keyValue('experiment.technique.method', 'Method'), "\n ").concat(keyValue('experiment.technique.name', 'Technique Name'), "\n ").concat(keyValue('sample.disease.acronym', 'Disease'), "\n ").concat(keyValue('individual.species', 'Species'), "\n ").concat(keyValue('individual.center.acronym', 'Center'), "\n </div>\n ");
|
|
304621
304621
|
}
|
|
304622
304622
|
}
|
|
304623
304623
|
});
|
|
@@ -304637,8 +304637,8 @@ var BioModelTreevue_type_style_index_0_lang_scss_ = __webpack_require__("34ec");
|
|
|
304637
304637
|
|
|
304638
304638
|
var BioModelTree_component = normalizeComponent(
|
|
304639
304639
|
bioModels_BioModelTreevue_type_script_lang_js_,
|
|
304640
|
-
|
|
304641
|
-
|
|
304640
|
+
BioModelTreevue_type_template_id_2b110930_render,
|
|
304641
|
+
BioModelTreevue_type_template_id_2b110930_staticRenderFns,
|
|
304642
304642
|
false,
|
|
304643
304643
|
null,
|
|
304644
304644
|
null,
|