@papaemmelab/isabl-web 0.3.16 → 0.3.18

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/README.md CHANGED
@@ -41,5 +41,3 @@ Isabl was created at [Elli Papaemmanuil's lab].
41
41
  [prettier_badge]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
42
42
  [prettier_base]: https://github.com/prettier/prettier
43
43
  [Elli Papaemmanuil's lab]: https://www.mskcc.org/research-areas/labs/elli-papaemmanuilil
44
-
45
-
@@ -89268,7 +89268,7 @@ exports = module.exports = __webpack_require__("2350")(false);
89268
89268
 
89269
89269
 
89270
89270
  // module
89271
- exports.push([module.i, ".isabl-base-card .v-data-table th.column.sortable.active.desc button.sort-icon{-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.isabl-base-card .v-data-table th.column.sortable.active button.sort-icon{color:var(--v-primary-base)}.isabl-base-card .v-data-table th.column.sortable button{font-size:13px!important;margin-left:4px}.isabl-base-card .v-data-table .v-data-table__wrapper{max-height:300px;overflow-y:auto}.isabl-base-card .v-data-table .table-cell{height:25px!important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:300px;padding-left:5px!important}.isabl-base-card .v-data-table .table-cell .v-chip.v-size--small{height:20px}.isabl-base-card .v-data-table tr.table-headers.table-cell{position:sticky;top:0;background:#fff;cursor:pointer;height:32px}.isabl-base-card .v-data-table tr.table-headers.table-cell th{background:rgba(0,0,0,.04)}.isabl-base-card .v-data-table.theme--dark,.isabl-base-card .v-data-table.theme--dark tr.column-filters th,.isabl-base-card .v-data-table.theme--dark tr.table-headers.table-cell th{background:var(--v-surface-base)}.isabl-base-card .v-data-table th.column.sortable{padding:0 5px}.isabl-base-card .v-data-table tr.column-filters th{height:32px}.isabl-base-card .v-data-table .v-data-table__empty-wrapper>td{padding:0}.table-filter-input{min-width:150px}.table-filter-input .v-input__icon--append .v-icon{font-size:14px}.table-filter-input input{font-size:14px;font-weight:400;padding-left:6px!important}.table-filter-input label{font-size:13px;padding-left:6px}.column-filters{position:sticky;top:25px;background:#fff;z-index:10}.column-filters .v-select{margin:0}.column-filters .v-select .v-input__slot,.column-filters .v-select input{height:25px}.column-filters .v-select .v-icon{font-size:16px}.column-filters .v-select__selections{display:contents;max-width:120px;font-size:14px;font-weight:400}.column-filters .v-select__selections span,.column-filters .v-text-field .v-input__append-inner{padding:0}.v-list .v-list-item{min-height:25px}.v-list .v-list-item .v-list-item__title{font-size:14px;font-weight:400}.v-list .v-list-item .v-list-item__content{padding:0 10px}div.v-list--dense .v-list-item{min-height:25px;padding:0}div.v-list--dense .v-list-item .v-list-item__action{margin:0;padding:0 4px}div.v-list--dense .v-list-item .v-list-item__title{font-size:14px;font-weight:400}div.v-list--dense .v-list-item .v-list-item__content{padding:0}.v-select-list{overflow:hidden}.v-menu__content:not(.v-autocomplete__content) .v-list__tile{height:23px}table.v-table tbody tr{border:0!important}table.v-table thead tr{height:30px!important}table.v-table thead tr.v-datatable__progress{height:0!important;border-top:1px solid rgba(0,0,0,.05)}table.v-table thead th{padding-left:5px!important;padding-right:5px!important}div.v-data-table__actions{-ms-flex-wrap:nowrap;flex-wrap:nowrap}div.v-data-table__actions__pagination{width:100%;min-width:170px;margin:0 10px 0 10px}div.v-data-table__actions__select{white-space:normal;overflow:hidden;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;margin-right:5px;max-width:100px}div.v-data-table__actions__select .v-select{margin-left:25px;margin-right:0;margin-top:0;margin-bottom:0}div.v-data-table__actions__range-controls{width:100%}div.v-data-table__actions button{margin:0;margin-right:5px}.section-toggle{cursor:pointer}.isabl-base-card .v-data-footer{font-size:12px;padding:0}.isabl-base-card .v-data-footer div.v-select__selection{font-size:12px}.isabl-base-card .v-data-footer div.v-select{margin:4px 0 4px 16px}.v-data-footer__select .v-menu__content .v-list-item{min-height:25px;font-size:14px}.v-data-footer__select .v-menu__content .v-list-item .v-list-item__content{padding:0}code.markdown-style{padding:.2em .4em;margin:0;font-size:85%;background-color:rgba(175,184,193,.2);border-radius:6px;color:#24292f}.v-data-table .v-data-footer .v-data-footer__select{margin-left:0;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__pagination{margin-left:auto;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__icons-before{margin-left:auto;margin-right:0}.v-data-table .v-data-footer .v-data-footer__icons-after{margin-left:0;margin-right:0}", ""]);
89271
+ exports.push([module.i, ".isabl-base-card .v-data-table th.column.sortable.active.desc button.sort-icon{-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.isabl-base-card .v-data-table th.column.sortable.active button.sort-icon{color:var(--v-primary-base)}.isabl-base-card .v-data-table th.column.sortable button{font-size:13px!important;margin-left:4px}.isabl-base-card .v-data-table .v-data-table__wrapper{max-height:300px;overflow-y:auto}.isabl-base-card .v-data-table .table-cell{height:25px!important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:300px;padding-left:5px!important}.isabl-base-card .v-data-table .table-cell .v-chip.v-size--small{height:20px}.isabl-base-card .v-data-table tr.table-headers.table-cell{position:sticky;top:0;background:#fff;cursor:pointer;height:32px;z-index:1}.isabl-base-card .v-data-table tr.table-headers.table-cell th{background:rgba(0,0,0,.04)}.isabl-base-card .v-data-table.theme--dark,.isabl-base-card .v-data-table.theme--dark tr.column-filters th,.isabl-base-card .v-data-table.theme--dark tr.table-headers.table-cell th{background:var(--v-surface-base)}.isabl-base-card .v-data-table th.column.sortable{padding:0 5px}.isabl-base-card .v-data-table tr.column-filters th{height:32px}.isabl-base-card .v-data-table .v-data-table__empty-wrapper>td{padding:0}.table-filter-input{min-width:150px}.table-filter-input .v-input__icon--append .v-icon{font-size:14px}.table-filter-input input{font-size:14px;font-weight:400;padding-left:6px!important}.table-filter-input label{font-size:13px;padding-left:6px}.column-filters{position:sticky;top:25px;background:#fff;z-index:1}.column-filters .v-select{margin:0}.column-filters .v-select .v-input__slot,.column-filters .v-select input{height:25px}.column-filters .v-select .v-icon{font-size:16px}.column-filters .v-select__selections{display:contents;max-width:120px;font-size:14px;font-weight:400}.column-filters .v-select__selections span,.column-filters .v-text-field .v-input__append-inner{padding:0}.v-list .v-list-item{min-height:25px}.v-list .v-list-item .v-list-item__title{font-size:14px;font-weight:400}.v-list .v-list-item .v-list-item__content{padding:0 10px}div.v-list--dense .v-list-item{min-height:25px;padding:0}div.v-list--dense .v-list-item .v-list-item__action{margin:0;padding:0 4px}div.v-list--dense .v-list-item .v-list-item__title{font-size:14px;font-weight:400}div.v-list--dense .v-list-item .v-list-item__content{padding:0}.v-select-list{overflow:hidden}.v-menu__content:not(.v-autocomplete__content) .v-list__tile{height:23px}table.v-table tbody tr{border:0!important}table.v-table thead tr{height:30px!important}table.v-table thead tr.v-datatable__progress{height:0!important;border-top:1px solid rgba(0,0,0,.05)}table.v-table thead th{padding-left:5px!important;padding-right:5px!important}div.v-data-table__actions{-ms-flex-wrap:nowrap;flex-wrap:nowrap}div.v-data-table__actions__pagination{width:100%;min-width:170px;margin:0 10px 0 10px}div.v-data-table__actions__select{white-space:normal;overflow:hidden;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;margin-right:5px;max-width:100px}div.v-data-table__actions__select .v-select{margin-left:25px;margin-right:0;margin-top:0;margin-bottom:0}div.v-data-table__actions__range-controls{width:100%}div.v-data-table__actions button{margin:0;margin-right:5px}.section-toggle{cursor:pointer}.isabl-base-card .v-data-footer{font-size:12px;padding:0}.isabl-base-card .v-data-footer div.v-select__selection{font-size:12px}.isabl-base-card .v-data-footer div.v-select{margin:4px 0 4px 16px}.v-data-footer__select .v-menu__content .v-list-item{min-height:25px;font-size:14px}.v-data-footer__select .v-menu__content .v-list-item .v-list-item__content{padding:0}code.markdown-style{padding:.2em .4em;margin:0;font-size:85%;background-color:rgba(175,184,193,.2);border-radius:6px;color:#24292f}.v-data-table .v-data-footer .v-data-footer__select{margin-left:0;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__pagination{margin-left:auto;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__icons-before{margin-left:auto;margin-right:0}.v-data-table .v-data-footer .v-data-footer__icons-after{margin-left:0;margin-right:0}", ""]);
89272
89272
 
89273
89273
  // exports
89274
89274
 
@@ -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.16\",\"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\"}");
91171
+ module.exports = JSON.parse("{\"name\":\"@papaemmelab/isabl-web\",\"version\":\"0.3.18\",\"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
 
@@ -243670,8 +243670,8 @@ var BaseTabs_component = normalizeComponent(
243670
243670
  )
243671
243671
 
243672
243672
  /* harmony default export */ var BaseTabs = (BaseTabs_component.exports);
243673
- // 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/table/DataTable.vue?vue&type=template&id=31c65eb2&
243674
- var DataTablevue_type_template_id_31c65eb2_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-card',{class:['isabl-base-card no-shadow', _vm.cardClasses]},[_c('base-section-title',{attrs:{"show-more":_vm.showTable},on:{"toggle-show-more":function($event){_vm.showTable = !_vm.showTable}},scopedSlots:_vm._u([{key:"title",fn:function(){return [_vm._v("\n "+_vm._s(_vm._f("capitalize")(_vm.title || _vm.model))+"\n "),(_vm.infoText)?_c('v-tooltip',{attrs:{"top":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
243673
+ // 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/table/DataTable.vue?vue&type=template&id=57e40a80&
243674
+ var DataTablevue_type_template_id_57e40a80_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-card',{class:['isabl-base-card no-shadow', _vm.cardClasses]},[_c('base-section-title',{attrs:{"show-more":_vm.showTable},on:{"toggle-show-more":function($event){_vm.showTable = !_vm.showTable}},scopedSlots:_vm._u([{key:"title",fn:function(){return [_vm._v("\n "+_vm._s(_vm._f("capitalize")(_vm.title || _vm.model))+"\n "),(_vm.infoText)?_c('v-tooltip',{attrs:{"top":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
243675
243675
  var on = ref.on;
243676
243676
  return [_c('v-icon',_vm._g({staticClass:"pl-1",staticStyle:{"cursor":"help"},attrs:{"small":"","color":"grey lighten-2"}},on),[_vm._v("\n info\n ")])]}}],null,false,2192405103)},[_c('span',{attrs:{"text-center":""}},[_vm._v(_vm._s(_vm.infoText))])]):_vm._e()]},proxy:true},{key:"actions",fn:function(){return [(_vm.items)?_c('data-table-actions',{attrs:{"model":_vm.model,"items":_vm.items,"headers":_vm.headers,"global-search":_vm.globalSearch,"query-params":_vm.queryParams},on:{"fetch-data":_vm.updateSearchText}}):_vm._e()]},proxy:true}])}),_c('v-data-table',{directives:[{name:"show",rawName:"v-show",value:(_vm.showTable),expression:"showTable"}],attrs:{"headers":_vm.headers,"items":_vm.items,"server-items-length":_vm.totalItems,"loading":_vm.loading,"items-per-page":_vm.itemsPerPage,"page":_vm.page,"footer-props":{ itemsPerPageOptions: _vm.itemsPerPageItems, itemsPerPageText: '' },"loader-height":"2","calculate-widths":"","hide-default-header":"","dense":""},on:{"update:itemsPerPage":function($event){_vm.itemsPerPage=$event},"update:items-per-page":function($event){_vm.itemsPerPage=$event},"update:page":function($event){_vm.page=$event},"page-count":function($event){_vm.pageCount = $event}},scopedSlots:_vm._u([{key:"header",fn:function(ref){
243677
243677
  var props = ref.props;
@@ -243696,10 +243696,10 @@ return [_c('span',{class:[
243696
243696
  var pageStart = ref.pageStart;
243697
243697
  var pageStop = ref.pageStop;
243698
243698
  return [_c('span',{staticClass:"text-body-1"},[_vm._v("\n "+_vm._s(pageStart)+" - "+_vm._s(pageStop)+" of\n "),_c('span',{staticClass:"primary--text text-h6 mx-1"},[_vm._v(_vm._s(_vm._f("formatNumber")(_vm.totalItems)))])])]}}])})],1)}
243699
- var DataTablevue_type_template_id_31c65eb2_staticRenderFns = []
243699
+ var DataTablevue_type_template_id_57e40a80_staticRenderFns = []
243700
243700
 
243701
243701
 
243702
- // CONCATENATED MODULE: ./src/components/table/DataTable.vue?vue&type=template&id=31c65eb2&
243702
+ // CONCATENATED MODULE: ./src/components/table/DataTable.vue?vue&type=template&id=57e40a80&
243703
243703
 
243704
243704
  // 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/table/DataTableActions.vue?vue&type=template&id=0e1da098&
243705
243705
  var DataTableActionsvue_type_template_id_0e1da098_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-row',{staticClass:"pa-0 ma-0 float-right"},[(_vm.searchText || _vm.showSearch)?_c('transition',{attrs:{"name":"slide"}},[_c('v-form',{on:{"submit":function($event){$event.preventDefault();}}},[_c('v-text-field',{ref:"input",staticClass:"pa-0 my-0 table-filter-input",attrs:{"autofocus":true,"append-icon":_vm.searchText ? 'close' : null,"label":"Search","data-test":"table-search-input","single-line":"","hide-details":"","dense":""},on:{"click:append":function($event){_vm.searchText ? (_vm.searchText = '') : null},"keyup":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }_vm.searchText = ''},"blur":_vm.onSearchInputBlur},model:{value:(_vm.searchText),callback:function ($$v) {_vm.searchText=$$v},expression:"searchText"}})],1)],1):_vm._e(),_c('v-speed-dial',{staticClass:"float-right",attrs:{"direction":"bottom","color":"primary","transition":"slide-y-transition","open-on-hover":""},scopedSlots:_vm._u([{key:"activator",fn:function(){return [_c('v-btn',{staticClass:"table-action-btn",attrs:{"fab":"","x-small":"","elevation":"0","color":"transparent"},on:{"click":function($event){_vm.showSearch = !_vm.showSearch}}},[(_vm.loading)?_c('v-progress-circular',{attrs:{"width":2,"size":18,"indeterminate":"","color":"primary"}}):(_vm.showActions || _vm.showSearch)?_c('v-icon',{attrs:{"small":""}},[_vm._v("\n search\n ")]):_c('v-icon',[_vm._v("\n more_vert\n ")])],1)]},proxy:true}]),model:{value:(_vm.showActions),callback:function ($$v) {_vm.showActions=$$v},expression:"showActions"}},[_c('JsonExcel',{attrs:{"fields":_vm.jsonHeaders,"fetch":_vm.fetchAllRecords,"worksheet":_vm.model,"name":_vm.exportedFilename,"before-finish":_vm.showFinishedAlert}},[_c('v-btn',{staticClass:"table-action-btn float-right",attrs:{"fab":"","x-small":""}},[_c('v-tooltip',{attrs:{"left":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
@@ -247617,7 +247617,7 @@ var orderBy_default = /*#__PURE__*/__webpack_require__.n(orderBy);
247617
247617
  // 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/table/DataTable.vue?vue&type=script&lang=js&
247618
247618
  var cov_2h6d9k0h00 = function () {
247619
247619
  var path = "/Users/juanes/papaemmelab/isabl_web/src/components/table/DataTable.vue";
247620
- var hash = "235fafbf88a72a48e239d67dc7b99e287750338d";
247620
+ var hash = "d785cc7739c0c8a3532fce89055018d808c250a9";
247621
247621
  var global = new Function("return this")();
247622
247622
  var gcv = "__coverage__";
247623
247623
  var coverageData = {
@@ -251035,10 +251035,10 @@ var cov_2h6d9k0h00 = function () {
251035
251035
  mappings: ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+NA;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;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;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;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;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
251036
251036
  file: "DataTable.vue",
251037
251037
  sourceRoot: "src/components/table",
251038
- sourcesContent: ["<template>\n <v-card :class=\"['isabl-base-card no-shadow', cardClasses]\">\n <base-section-title\n :show-more=\"showTable\"\n @toggle-show-more=\"showTable = !showTable\"\n >\n <template v-slot:title>\n {{ title || model | capitalize }}\n <v-tooltip\n v-if=\"infoText\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n small\n style=\"cursor: help\"\n color=\"grey lighten-2\"\n class=\"pl-1\"\n v-on=\"on\"\n >\n info\n </v-icon>\n </template>\n <span text-center>{{ infoText }}</span>\n </v-tooltip>\n </template>\n <template v-slot:actions>\n <data-table-actions\n v-if=\"items\"\n :model=\"model\"\n :items=\"items\"\n :headers=\"headers\"\n :global-search=\"globalSearch\"\n :query-params=\"queryParams\"\n @fetch-data=\"updateSearchText\"\n />\n </template>\n </base-section-title>\n\n <v-data-table\n v-show=\"showTable\"\n :headers=\"headers\"\n :items=\"items\"\n :server-items-length=\"totalItems\"\n :loading=\"loading\"\n :items-per-page.sync=\"itemsPerPage\"\n :page.sync=\"page\"\n :footer-props=\"{ itemsPerPageOptions: itemsPerPageItems, itemsPerPageText: '' }\"\n loader-height=\"2\"\n calculate-widths\n hide-default-header\n dense\n @page-count=\"pageCount = $event\"\n >\n <template v-slot:header=\"{ props }\">\n <tr class=\"table-headers text-left table-cell py-0 font-normal\">\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n :class=\"[\n 'column sortable',\n sortByColumns.includes(header.value)\n ? 'asc active'\n : '',\n sortByColumns.includes(`-${header.value}`)\n ? 'desc active'\n : ''\n ]\"\n >\n <v-hover v-slot=\"{ hover }\">\n <span\n :class=\"[\n 'font-weight-medium',\n 'grey--text',\n ]\"\n >\n {{ header.text }}\n <v-icon\n :color=\"\n hover || sortByColumns.includes(header.value) || sortByColumns.includes(`-${header.value}`)\n ? 'text--darken-2'\n : 'transparent'\n \"\n class=\"sort-icon\"\n style=\"vertical-align: middle\"\n small\n @click=\"changeSort(header.value)\"\n >arrow_downward</v-icon>\n <v-icon\n :color=\"hover ? 'text--darken-2' : 'transparent'\"\n class=\"\"\n style=\"vertical-align: middle\"\n small\n @click=\"toggleColumnFilters\"\n >filter_list</v-icon>\n </span>\n </v-hover>\n </th>\n </tr>\n <tr\n v-if=\"showFilters\"\n class=\"column-filters\"\n >\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n class=\"pa-0 ma-0\"\n >\n <data-table-date-picker\n v-if=\"header.filterType === 'date'\"\n :header=\"header\"\n @filter-search=\"filterSearch\"\n />\n <data-table-select-filter\n v-else\n :header=\"header\"\n :model=\"title || model\"\n @filter-search=\"filterSearch\"\n />\n </th>\n </tr>\n </template>\n <template v-slot:item=\"attrs\">\n <tr>\n <td\n v-for=\"(header, index) in attrs.headers\"\n :key=\"index + header.verboseName\"\n class=\"text-left table-cell py-0 text-body-1\"\n >\n <!-- if value is a model(s) link -->\n <span v-if=\"header.model\">\n <span v-if=\"Array.isArray(getValue(attrs.item, header))\">\n <span\n v-for=\"(value, index) in getValue(attrs.item, header)\"\n :key=\"index\"\n class=\"active-link\"\n @click=\"onClickRecord(value, header.model)\"\n v-html=\"\n highlightText(value, header) +\n `${index + 1 < getValue(attrs.item, header).length ? ', ' : ''}`\n \"\n />\n </span>\n\n <span v-else>\n <span\n class=\"active-link\"\n @click=\"onClickRecord(getValue(attrs.item, header), header.model)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n </span>\n </span>\n\n <!-- if value is analysis' result -->\n <span\n v-else-if=\"header.field === 'status'\"\n :class=\"classValue(attrs.item, header.field)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n\n <div\n v-else-if=\"header.field === 'resultName'\"\n class=\"mr-2\"\n >\n <result-chip\n :result=\"attrs.item\"\n :result-index=\"itemsPerPage * (page - 1) + attrs.index\"\n show-all\n @display-result=\"$emit('display-result', $event)\"\n />\n </div>\n\n <span\n v-else-if=\"header.field === 'resultKey'\"\n class=\"mr-2\"\n >\n <code class=\"markdown-style\" v-html=\"tableValue(attrs.item, header)\"/>\n </span>\n\n <!-- any other case -->\n <span\n v-else\n v-html=\"tableValue(attrs.item, header)\"\n />\n </td>\n </tr>\n </template>\n\n <template v-slot:no-data>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : errorMessage || 'No records found.' }}</td>\n </template>\n\n <template v-slot:loading>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >Querying records...</td>\n </template>\n\n <template v-slot:no-results>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : 'No records found.' }}</td>\n </template>\n\n <template v-slot:footer.page-text=\"{ pageStart, pageStop }\">\n <span class=\"text-body-1\">\n {{ pageStart }} - {{ pageStop }} of\n <span\n class=\"primary--text text-h6 mx-1\"\n >{{ totalItems | formatNumber }}</span>\n </span>\n </template>\n\n </v-data-table>\n </v-card>\n</template>\n\n<script>\nimport { fetchListRecords } from '@/utils/api'\nimport { SHOW_ALERT } from '@/store/actions/alert'\nimport { SHOW_PANEL } from '@/store/actions/panels'\nimport { tableColumns } from '@/utils/tableColumns'\nimport BaseSectionTitle from '@/components/base/BaseSectionTitle.vue'\nimport DataTableActions from '@/components/table/DataTableActions.vue'\nimport DataTableSelectFilter from '@/components/table/DataTableSelectFilter.vue'\nimport DataTableDatePicker from '@/components/table/DataTableDatePicker.vue'\nimport ResultChip from '@/components/analyses/ResultChip'\nimport debounce from 'lodash/debounce'\nimport isEqual from 'lodash/isEqual'\nimport orderBy from 'lodash/orderBy'\n\nexport default {\n name: 'DataTable',\n components: {\n BaseSectionTitle,\n DataTableActions,\n DataTableSelectFilter,\n DataTableDatePicker,\n ResultChip,\n },\n props: {\n model: {\n type: String,\n required: false\n },\n title: {\n type: String,\n default: ''\n },\n globalSearch: {\n type: Boolean,\n default: false\n },\n params: {\n type: Object,\n default: () => ({})\n },\n // skip columns using the verbose name\n skipColumns: {\n type: Array,\n default: () => []\n },\n // columns using the verbose name\n headersKey: {\n type: String,\n default: ''\n },\n cardClasses: {\n type: String,\n default: ''\n },\n collapse: {\n type: Boolean,\n default: false\n },\n infoText: {\n type: String,\n default: ''\n },\n openRecordsInNewTab: {\n type: Boolean,\n default: false\n },\n data: {\n type: Array,\n default: () => []\n },\n filterRemotely: {\n type: Boolean,\n default: true,\n },\n initialSort: {\n type: Array,\n default: () => [\"-pk\"]\n },\n initialItemsPerPage: {\n type: Number,\n default: 5,\n }\n },\n data() {\n return {\n items: this.filterRemotely ? [] : this.data,\n totalItems: 0,\n loading: true,\n showTable: !this.collapse,\n showFilters: false,\n\n // table params\n headers: tableColumns[this.headersKey || this.model]\n .map(col => {\n col.text = col.verboseName\n col.value = col.field\n return col\n })\n .filter(col => !this.skipColumns.includes(col.verboseName)),\n page: 1,\n pageCount: 0,\n itemsPerPage: this.initialItemsPerPage,\n itemsPerPageItems: [3, 5, 10, 25, 50, 200, 500, 5000],\n sortByColumns: this.initialSort,\n\n // query params\n limit: null,\n offset: null,\n ordering: null,\n errorMessage: null,\n searchText: '',\n filterParams: {},\n queryParams: {}\n }\n },\n watch: {\n params(newParams, oldParams) {\n if (!isEqual(newParams, oldParams)) {\n this.fetchData()\n }\n },\n page() {\n this.updateTable()\n },\n sortByColumns() {\n this.updateTable()\n },\n itemsPerPage() {\n this.updateTable()\n },\n data() {\n this.updateTable()\n }\n },\n created() {\n this.fetchData = debounce(this._fetchData, 500)\n this.updateTable()\n },\n methods: {\n changeSort(column) {\n let sort = this.sortByColumns\n\n if (sort.includes(column)) {\n // Make ordering column -> None\n sort = sort.filter(columns => columns !== column)\n } else if (sort.includes(`-${column}`)) {\n // Make ordering -column -> column\n sort = sort.filter(columns => columns !== `-${column}`)\n sort.push(column)\n } else {\n // Make ordering None -> -column\n sort.push(`-${column}`)\n }\n\n // Move pk to last if exist\n sort.push(sort.splice(sort.indexOf('pk'), 1)[0])\n sort.push(sort.splice(sort.indexOf('-pk'), 1)[0])\n\n this.sortByColumns = sort\n },\n filterSearch(value, field, filter = 'icontains') {\n field = field.split('.').join('__')\n value = Array.isArray(value) ? value.join(',') : value\n\n // Ensure only one filter per key\n this.filterParams = Object.keys(this.filterParams)\n .filter(param => {\n const filterWithSameKey = `${field}__`\n return !param.includes(filterWithSameKey)\n })\n .reduce((obj, key) => {\n obj[key] = this.filterParams[key]\n return obj\n }, {})\n\n this.filterParams[`${field}__${filter}`] = value\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Filter from table column', {\n model: this.model,\n query: this.filterParams\n })\n },\n\n columnValueList(val) {\n return this.items.map(d => d[val])\n },\n\n updateSearchText(text) {\n this.searchText = text\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Searched From Table', {\n model: this.model,\n search: this.searchText,\n query: this.queryParams\n })\n },\n\n tableValue(item, header) {\n let value = this.getValue(item, header)\n return this.highlightText(value, header)\n },\n\n formatValue(value) {\n return this.highlightText(value)\n },\n\n getValue(item, header) {\n return this.$get(\n item,\n header.accessor || header.field,\n header.default || '-'\n )\n },\n\n isTableSmall() {\n let tables = document.getElementsByClassName('v-datatable__actions')\n return tables && tables.length > 0 && tables[0].offsetWidth < 400\n },\n\n classValue(item, accessor) {\n let value = this.$get(item, accessor)\n .toString()\n .toLowerCase()\n return `status-${value}`\n },\n\n highlightText(rawText, header) {\n header = header.value.split('.').join('__')\n const filterParams = {\n ...this.filterParams,\n search: this.searchText\n }\n let keywords = Object.entries(filterParams)\n .filter(([key, value]) => {\n return (\n value &&\n typeof value !== 'boolean' &&\n (key === 'search' || key.replace(/(__icontains)/, '') === header)\n )\n })\n .map(([, value]) => value.toString().toLowerCase())\n\n let { text, element } = this.$getInnerHtmlText(rawText)\n let shownText = text ? text.toString().slice(0, 41) : ''\n let highlightText = shownText\n\n // Search for match of full string if not each word\n let wordsToHighlight = []\n keywords.forEach(keyword => {\n keyword = keyword.trim()\n if (keyword && shownText.toLowerCase().includes(keyword)) {\n wordsToHighlight.push(keyword)\n } else {\n keyword.split(' ').forEach(word => {\n if (word && shownText.toLowerCase().includes(word)) {\n wordsToHighlight.push(word)\n }\n })\n }\n })\n\n // Highlight the matches\n if (wordsToHighlight.length) {\n const keywordRegex = new RegExp(`(${wordsToHighlight.join('|')})`, 'gi')\n highlightText = text\n .toString()\n .replace(keywordRegex, '<span class=\"highlight\">$1</span>')\n }\n return this.$setInnerHtmlText(element, highlightText)\n },\n\n updateTable() {\n this.limit = this.itemsPerPage\n this.offset = this.itemsPerPage * (this.page - 1)\n this.ordering = this.sortByColumns.join(',')\n\n if (this.filterRemotely) {\n // Make server-side filtering\n this.fetchData()\n } else {\n // Local Items\n this.loading = true\n let rows = this.data\n\n if (this.searchText) {\n rows = rows.filter((row) =>\n Object.values(row).some((column) =>\n column.toLowerCase().includes(this.searchText.toLowerCase())\n )\n )\n }\n if (this.sortByColumns.length) {\n const columns = []\n const order = []\n this.sortByColumns.forEach(param => {\n const [first, ...rest] = param\n if (first === '-') {\n columns.push(rest.join(''))\n order.push('desc')\n } else {\n columns.push(param)\n order.push('asc')\n }\n })\n rows = orderBy(rows, columns, order)\n }\n rows = rows.slice(this.offset, this.offset + this.limit)\n this.items = rows\n this.totalItems = this.data.length\n this.pages = Math.ceil(this.totalItems / this.items)\n this.loading = false\n }\n },\n\n _fetchData() {\n this.loading = true\n const {\n model,\n limit,\n offset,\n ordering,\n params,\n filterParams,\n searchText\n } = this\n\n this.queryParams = {\n ...params,\n ...filterParams,\n limit,\n offset,\n search: searchText,\n ordering,\n }\n\n this.$emit('fetch-data', this.queryParams)\n\n fetchListRecords(model, this.queryParams)\n .then(response => {\n if (searchText === this.searchText) {\n this.items = response.results\n this.totalItems = response.count\n this.pages = Math.ceil(response.count / limit)\n this.errorMessage = response.error || ''\n }\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 onClickRecord(value, model) {\n if (this.openRecordsInNewTab) {\n const queryParams = {\n individual: 'bioModel',\n sample: 'bioModel',\n experiment: 'bioModel'\n }\n const queryParam = this.$get(queryParams, model, model)\n window.open(`/?${queryParam}=${value}`, '_blank')\n } else {\n this.$store.dispatch(SHOW_PANEL, {\n [model]: value\n })\n }\n },\n\n toggleColumnFilters() {\n this.showFilters = !this.showFilters\n if (!this.showFilters) {\n this.filterParams = {}\n this.fetchData()\n }\n },\n }\n}\n</script>\n\n<style lang=\"scss\">\n\n.isabl-base-card .v-data-table {\n th.column.sortable.active.desc button.sort-icon {\n transform: rotate(-180deg);\n }\n th.column.sortable.active button.sort-icon {\n color: var(--v-primary-base);\n }\n th.column.sortable button {\n font-size: 13px !important;\n margin-left: 4px;\n }\n .v-data-table__wrapper {\n max-height: 300px;\n overflow-y: auto;\n }\n .table-cell {\n height: 25px !important;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 300px;\n padding-left: 5px !important;\n .v-chip.v-size--small {\n height: 20px;\n }\n }\n tr.table-headers.table-cell {\n position: sticky;\n top: 0;\n background: white;\n cursor: pointer;\n height: 32px;\n th {\n // border-bottom: thin solid rgba(0,0,0,.12);\n background: rgba(0,0,0,.04);\n }\n }\n &.theme--dark, &.theme--dark tr.table-headers.table-cell th {\n background: var(--v-surface-base);\n }\n &.theme--dark tr.column-filters th {\n background: var(--v-surface-base);\n }\n th.column.sortable {\n padding: 0px 5px;\n }\n tr.column-filters th {\n height: 32px;\n }\n .v-data-table__empty-wrapper>td {\n padding: 0px;\n }\n}\n\n.table-filter-input {\n min-width: 150px;\n .v-input__icon--append .v-icon {\n font-size: 14px;\n }\n input {\n font-size: 14px;\n font-weight: 400;\n padding-left: 6px !important;\n }\n label {\n font-size: 13px;\n padding-left: 6px;\n }\n}\n.column-filters {\n position: sticky;\n top: 25px;\n background: white;\n z-index: 10;\n .v-select {\n margin: 0px;\n .v-input__slot, input {\n height: 25px;\n }\n .v-icon {\n font-size: 16px;\n }\n }\n .v-select__selections {\n display: contents;\n max-width: 120px;\n font-size: 14px;\n font-weight: 400;\n span {\n padding: 0px;\n }\n }\n .v-text-field .v-input__append-inner {\n padding: 0px;\n }\n}\n\n.v-list .v-list-item {\n min-height: 25px;\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px 10px;\n }\n}\n\ndiv.v-list--dense .v-list-item {\n min-height: 25px;\n padding: 0px;\n .v-list-item__action {\n margin: 0px;\n padding: 0px 4px;\n }\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px;\n }\n}\n\n.v-select-list {\n overflow: hidden;\n}\n\n.v-menu__content:not(.v-autocomplete__content) {\n .v-list__tile {\n height: 23px;\n }\n}\ntable.v-table tbody tr {\n border: 0px !important;\n}\n\ntable.v-table thead {\n tr {\n height: 30px !important;\n }\n tr.v-datatable__progress {\n height: 0px !important;\n border-top: 1px solid rgba(0, 0, 0, 0.05);\n }\n th {\n padding-left: 5px !important;\n padding-right: 5px !important;\n }\n}\n\ndiv.v-data-table__actions {\n flex-wrap: nowrap;\n &__pagination {\n width: 100%;\n min-width: 170px;\n margin: 0 10px 0 10px;\n }\n &__select {\n white-space: normal;\n overflow: hidden;\n justify-content: flex-start;\n margin-right: 5px;\n max-width: 100px;\n .v-select {\n margin-left: 25px;\n margin-right: 0px;\n margin-top: 0px;\n margin-bottom: 0px;\n }\n }\n &__range-controls {\n width: 100%;\n }\n button {\n margin: 0px;\n margin-right: 5px;\n }\n}\n\n.section-toggle {\n cursor: pointer;\n}\n\n.isabl-base-card .v-data-footer {\n font-size: 12px;\n padding: 0px;\n div.v-select__selection {\n font-size: 12px;\n }\n div.v-select {\n margin: 4px 0px 4px 16px;\n }\n}\n.v-data-footer__select\n.v-menu__content .v-list-item {\n min-height: 25px;\n font-size: 14px;\n .v-list-item__content {\n padding: 0px;\n }\n}\n// Style taken from github\ncode.markdown-style {\n padding: 0.2em 0.4em;\n margin: 0;\n font-size: 85%;\n background-color: rgba(175,184,193,0.2);\n border-radius: 6px;\n color: #24292f;\n}\n\n.v-data-table .v-data-footer {\n .v-data-footer__select {\n margin-left: 0;\n margin-right: auto;\n }\n .v-data-footer__pagination {\n margin-left: auto;\n margin-right: auto;\n }\n .v-data-footer__icons-before {\n margin-left: auto;\n margin-right: 0;\n }\n .v-data-footer__icons-after {\n margin-left: 0;\n margin-right: 0;\n }\n}\n\n</style>\n"]
251038
+ sourcesContent: ["<template>\n <v-card :class=\"['isabl-base-card no-shadow', cardClasses]\">\n <base-section-title\n :show-more=\"showTable\"\n @toggle-show-more=\"showTable = !showTable\"\n >\n <template v-slot:title>\n {{ title || model | capitalize }}\n <v-tooltip\n v-if=\"infoText\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n small\n style=\"cursor: help\"\n color=\"grey lighten-2\"\n class=\"pl-1\"\n v-on=\"on\"\n >\n info\n </v-icon>\n </template>\n <span text-center>{{ infoText }}</span>\n </v-tooltip>\n </template>\n <template v-slot:actions>\n <data-table-actions\n v-if=\"items\"\n :model=\"model\"\n :items=\"items\"\n :headers=\"headers\"\n :global-search=\"globalSearch\"\n :query-params=\"queryParams\"\n @fetch-data=\"updateSearchText\"\n />\n </template>\n </base-section-title>\n\n <v-data-table\n v-show=\"showTable\"\n :headers=\"headers\"\n :items=\"items\"\n :server-items-length=\"totalItems\"\n :loading=\"loading\"\n :items-per-page.sync=\"itemsPerPage\"\n :page.sync=\"page\"\n :footer-props=\"{ itemsPerPageOptions: itemsPerPageItems, itemsPerPageText: '' }\"\n loader-height=\"2\"\n calculate-widths\n hide-default-header\n dense\n @page-count=\"pageCount = $event\"\n >\n <template v-slot:header=\"{ props }\">\n <tr class=\"table-headers text-left table-cell py-0 font-normal\">\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n :class=\"[\n 'column sortable',\n sortByColumns.includes(header.value)\n ? 'asc active'\n : '',\n sortByColumns.includes(`-${header.value}`)\n ? 'desc active'\n : ''\n ]\"\n >\n <v-hover v-slot=\"{ hover }\">\n <span\n :class=\"[\n 'font-weight-medium',\n 'grey--text',\n ]\"\n >\n {{ header.text }}\n <v-icon\n :color=\"\n hover || sortByColumns.includes(header.value) || sortByColumns.includes(`-${header.value}`)\n ? 'text--darken-2'\n : 'transparent'\n \"\n class=\"sort-icon\"\n style=\"vertical-align: middle\"\n small\n @click=\"changeSort(header.value)\"\n >arrow_downward</v-icon>\n <v-icon\n :color=\"hover ? 'text--darken-2' : 'transparent'\"\n class=\"\"\n style=\"vertical-align: middle\"\n small\n @click=\"toggleColumnFilters\"\n >filter_list</v-icon>\n </span>\n </v-hover>\n </th>\n </tr>\n <tr\n v-if=\"showFilters\"\n class=\"column-filters\"\n >\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n class=\"pa-0 ma-0\"\n >\n <data-table-date-picker\n v-if=\"header.filterType === 'date'\"\n :header=\"header\"\n @filter-search=\"filterSearch\"\n />\n <data-table-select-filter\n v-else\n :header=\"header\"\n :model=\"title || model\"\n @filter-search=\"filterSearch\"\n />\n </th>\n </tr>\n </template>\n <template v-slot:item=\"attrs\">\n <tr>\n <td\n v-for=\"(header, index) in attrs.headers\"\n :key=\"index + header.verboseName\"\n class=\"text-left table-cell py-0 text-body-1\"\n >\n <!-- if value is a model(s) link -->\n <span v-if=\"header.model\">\n <span v-if=\"Array.isArray(getValue(attrs.item, header))\">\n <span\n v-for=\"(value, index) in getValue(attrs.item, header)\"\n :key=\"index\"\n class=\"active-link\"\n @click=\"onClickRecord(value, header.model)\"\n v-html=\"\n highlightText(value, header) +\n `${index + 1 < getValue(attrs.item, header).length ? ', ' : ''}`\n \"\n />\n </span>\n\n <span v-else>\n <span\n class=\"active-link\"\n @click=\"onClickRecord(getValue(attrs.item, header), header.model)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n </span>\n </span>\n\n <!-- if value is analysis' result -->\n <span\n v-else-if=\"header.field === 'status'\"\n :class=\"classValue(attrs.item, header.field)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n\n <div\n v-else-if=\"header.field === 'resultName'\"\n class=\"mr-2\"\n >\n <result-chip\n :result=\"attrs.item\"\n :result-index=\"itemsPerPage * (page - 1) + attrs.index\"\n show-all\n @display-result=\"$emit('display-result', $event)\"\n />\n </div>\n\n <span\n v-else-if=\"header.field === 'resultKey'\"\n class=\"mr-2\"\n >\n <code class=\"markdown-style\" v-html=\"tableValue(attrs.item, header)\"/>\n </span>\n\n <!-- any other case -->\n <span\n v-else\n v-html=\"tableValue(attrs.item, header)\"\n />\n </td>\n </tr>\n </template>\n\n <template v-slot:no-data>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : errorMessage || 'No records found.' }}</td>\n </template>\n\n <template v-slot:loading>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >Querying records...</td>\n </template>\n\n <template v-slot:no-results>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : 'No records found.' }}</td>\n </template>\n\n <template v-slot:footer.page-text=\"{ pageStart, pageStop }\">\n <span class=\"text-body-1\">\n {{ pageStart }} - {{ pageStop }} of\n <span\n class=\"primary--text text-h6 mx-1\"\n >{{ totalItems | formatNumber }}</span>\n </span>\n </template>\n\n </v-data-table>\n </v-card>\n</template>\n\n<script>\nimport { fetchListRecords } from '@/utils/api'\nimport { SHOW_ALERT } from '@/store/actions/alert'\nimport { SHOW_PANEL } from '@/store/actions/panels'\nimport { tableColumns } from '@/utils/tableColumns'\nimport BaseSectionTitle from '@/components/base/BaseSectionTitle.vue'\nimport DataTableActions from '@/components/table/DataTableActions.vue'\nimport DataTableSelectFilter from '@/components/table/DataTableSelectFilter.vue'\nimport DataTableDatePicker from '@/components/table/DataTableDatePicker.vue'\nimport ResultChip from '@/components/analyses/ResultChip'\nimport debounce from 'lodash/debounce'\nimport isEqual from 'lodash/isEqual'\nimport orderBy from 'lodash/orderBy'\n\nexport default {\n name: 'DataTable',\n components: {\n BaseSectionTitle,\n DataTableActions,\n DataTableSelectFilter,\n DataTableDatePicker,\n ResultChip,\n },\n props: {\n model: {\n type: String,\n required: false\n },\n title: {\n type: String,\n default: ''\n },\n globalSearch: {\n type: Boolean,\n default: false\n },\n params: {\n type: Object,\n default: () => ({})\n },\n // skip columns using the verbose name\n skipColumns: {\n type: Array,\n default: () => []\n },\n // columns using the verbose name\n headersKey: {\n type: String,\n default: ''\n },\n cardClasses: {\n type: String,\n default: ''\n },\n collapse: {\n type: Boolean,\n default: false\n },\n infoText: {\n type: String,\n default: ''\n },\n openRecordsInNewTab: {\n type: Boolean,\n default: false\n },\n data: {\n type: Array,\n default: () => []\n },\n filterRemotely: {\n type: Boolean,\n default: true,\n },\n initialSort: {\n type: Array,\n default: () => [\"-pk\"]\n },\n initialItemsPerPage: {\n type: Number,\n default: 5,\n }\n },\n data() {\n return {\n items: this.filterRemotely ? [] : this.data,\n totalItems: 0,\n loading: true,\n showTable: !this.collapse,\n showFilters: false,\n\n // table params\n headers: tableColumns[this.headersKey || this.model]\n .map(col => {\n col.text = col.verboseName\n col.value = col.field\n return col\n })\n .filter(col => !this.skipColumns.includes(col.verboseName)),\n page: 1,\n pageCount: 0,\n itemsPerPage: this.initialItemsPerPage,\n itemsPerPageItems: [3, 5, 10, 25, 50, 200, 500, 5000],\n sortByColumns: this.initialSort,\n\n // query params\n limit: null,\n offset: null,\n ordering: null,\n errorMessage: null,\n searchText: '',\n filterParams: {},\n queryParams: {}\n }\n },\n watch: {\n params(newParams, oldParams) {\n if (!isEqual(newParams, oldParams)) {\n this.fetchData()\n }\n },\n page() {\n this.updateTable()\n },\n sortByColumns() {\n this.updateTable()\n },\n itemsPerPage() {\n this.updateTable()\n },\n data() {\n this.updateTable()\n }\n },\n created() {\n this.fetchData = debounce(this._fetchData, 500)\n this.updateTable()\n },\n methods: {\n changeSort(column) {\n let sort = this.sortByColumns\n\n if (sort.includes(column)) {\n // Make ordering column -> None\n sort = sort.filter(columns => columns !== column)\n } else if (sort.includes(`-${column}`)) {\n // Make ordering -column -> column\n sort = sort.filter(columns => columns !== `-${column}`)\n sort.push(column)\n } else {\n // Make ordering None -> -column\n sort.push(`-${column}`)\n }\n\n // Move pk to last if exist\n sort.push(sort.splice(sort.indexOf('pk'), 1)[0])\n sort.push(sort.splice(sort.indexOf('-pk'), 1)[0])\n\n this.sortByColumns = sort\n },\n filterSearch(value, field, filter = 'icontains') {\n field = field.split('.').join('__')\n value = Array.isArray(value) ? value.join(',') : value\n\n // Ensure only one filter per key\n this.filterParams = Object.keys(this.filterParams)\n .filter(param => {\n const filterWithSameKey = `${field}__`\n return !param.includes(filterWithSameKey)\n })\n .reduce((obj, key) => {\n obj[key] = this.filterParams[key]\n return obj\n }, {})\n\n this.filterParams[`${field}__${filter}`] = value\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Filter from table column', {\n model: this.model,\n query: this.filterParams\n })\n },\n\n columnValueList(val) {\n return this.items.map(d => d[val])\n },\n\n updateSearchText(text) {\n this.searchText = text\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Searched From Table', {\n model: this.model,\n search: this.searchText,\n query: this.queryParams\n })\n },\n\n tableValue(item, header) {\n let value = this.getValue(item, header)\n return this.highlightText(value, header)\n },\n\n formatValue(value) {\n return this.highlightText(value)\n },\n\n getValue(item, header) {\n return this.$get(\n item,\n header.accessor || header.field,\n header.default || '-'\n )\n },\n\n isTableSmall() {\n let tables = document.getElementsByClassName('v-datatable__actions')\n return tables && tables.length > 0 && tables[0].offsetWidth < 400\n },\n\n classValue(item, accessor) {\n let value = this.$get(item, accessor)\n .toString()\n .toLowerCase()\n return `status-${value}`\n },\n\n highlightText(rawText, header) {\n header = header.value.split('.').join('__')\n const filterParams = {\n ...this.filterParams,\n search: this.searchText\n }\n let keywords = Object.entries(filterParams)\n .filter(([key, value]) => {\n return (\n value &&\n typeof value !== 'boolean' &&\n (key === 'search' || key.replace(/(__icontains)/, '') === header)\n )\n })\n .map(([, value]) => value.toString().toLowerCase())\n\n let { text, element } = this.$getInnerHtmlText(rawText)\n let shownText = text ? text.toString().slice(0, 41) : ''\n let highlightText = shownText\n\n // Search for match of full string if not each word\n let wordsToHighlight = []\n keywords.forEach(keyword => {\n keyword = keyword.trim()\n if (keyword && shownText.toLowerCase().includes(keyword)) {\n wordsToHighlight.push(keyword)\n } else {\n keyword.split(' ').forEach(word => {\n if (word && shownText.toLowerCase().includes(word)) {\n wordsToHighlight.push(word)\n }\n })\n }\n })\n\n // Highlight the matches\n if (wordsToHighlight.length) {\n const keywordRegex = new RegExp(`(${wordsToHighlight.join('|')})`, 'gi')\n highlightText = text\n .toString()\n .replace(keywordRegex, '<span class=\"highlight\">$1</span>')\n }\n return this.$setInnerHtmlText(element, highlightText)\n },\n\n updateTable() {\n this.limit = this.itemsPerPage\n this.offset = this.itemsPerPage * (this.page - 1)\n this.ordering = this.sortByColumns.join(',')\n\n if (this.filterRemotely) {\n // Make server-side filtering\n this.fetchData()\n } else {\n // Local Items\n this.loading = true\n let rows = this.data\n\n if (this.searchText) {\n rows = rows.filter((row) =>\n Object.values(row).some((column) =>\n column.toLowerCase().includes(this.searchText.toLowerCase())\n )\n )\n }\n if (this.sortByColumns.length) {\n const columns = []\n const order = []\n this.sortByColumns.forEach(param => {\n const [first, ...rest] = param\n if (first === '-') {\n columns.push(rest.join(''))\n order.push('desc')\n } else {\n columns.push(param)\n order.push('asc')\n }\n })\n rows = orderBy(rows, columns, order)\n }\n rows = rows.slice(this.offset, this.offset + this.limit)\n this.items = rows\n this.totalItems = this.data.length\n this.pages = Math.ceil(this.totalItems / this.items)\n this.loading = false\n }\n },\n\n _fetchData() {\n this.loading = true\n const {\n model,\n limit,\n offset,\n ordering,\n params,\n filterParams,\n searchText\n } = this\n\n this.queryParams = {\n ...params,\n ...filterParams,\n limit,\n offset,\n search: searchText,\n ordering,\n }\n\n this.$emit('fetch-data', this.queryParams)\n\n fetchListRecords(model, this.queryParams)\n .then(response => {\n if (searchText === this.searchText) {\n this.items = response.results\n this.totalItems = response.count\n this.pages = Math.ceil(response.count / limit)\n this.errorMessage = response.error || ''\n }\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 onClickRecord(value, model) {\n if (this.openRecordsInNewTab) {\n const queryParams = {\n individual: 'bioModel',\n sample: 'bioModel',\n experiment: 'bioModel'\n }\n const queryParam = this.$get(queryParams, model, model)\n window.open(`/?${queryParam}=${value}`, '_blank')\n } else {\n this.$store.dispatch(SHOW_PANEL, {\n [model]: value\n })\n }\n },\n\n toggleColumnFilters() {\n this.showFilters = !this.showFilters\n if (!this.showFilters) {\n this.filterParams = {}\n this.fetchData()\n }\n },\n }\n}\n</script>\n\n<style lang=\"scss\">\n\n.isabl-base-card .v-data-table {\n th.column.sortable.active.desc button.sort-icon {\n transform: rotate(-180deg);\n }\n th.column.sortable.active button.sort-icon {\n color: var(--v-primary-base);\n }\n th.column.sortable button {\n font-size: 13px !important;\n margin-left: 4px;\n }\n .v-data-table__wrapper {\n max-height: 300px;\n overflow-y: auto;\n }\n .table-cell {\n height: 25px !important;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 300px;\n padding-left: 5px !important;\n .v-chip.v-size--small {\n height: 20px;\n }\n }\n tr.table-headers.table-cell {\n position: sticky;\n top: 0;\n background: white;\n cursor: pointer;\n height: 32px;\n z-index: 1;\n th {\n // border-bottom: thin solid rgba(0,0,0,.12);\n background: rgba(0,0,0,.04);\n }\n }\n &.theme--dark, &.theme--dark tr.table-headers.table-cell th {\n background: var(--v-surface-base);\n }\n &.theme--dark tr.column-filters th {\n background: var(--v-surface-base);\n }\n th.column.sortable {\n padding: 0px 5px;\n }\n tr.column-filters th {\n height: 32px;\n }\n .v-data-table__empty-wrapper>td {\n padding: 0px;\n }\n}\n\n.table-filter-input {\n min-width: 150px;\n .v-input__icon--append .v-icon {\n font-size: 14px;\n }\n input {\n font-size: 14px;\n font-weight: 400;\n padding-left: 6px !important;\n }\n label {\n font-size: 13px;\n padding-left: 6px;\n }\n}\n.column-filters {\n position: sticky;\n top: 25px;\n background: white;\n z-index: 1;\n .v-select {\n margin: 0px;\n .v-input__slot, input {\n height: 25px;\n }\n .v-icon {\n font-size: 16px;\n }\n }\n .v-select__selections {\n display: contents;\n max-width: 120px;\n font-size: 14px;\n font-weight: 400;\n span {\n padding: 0px;\n }\n }\n .v-text-field .v-input__append-inner {\n padding: 0px;\n }\n}\n\n.v-list .v-list-item {\n min-height: 25px;\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px 10px;\n }\n}\n\ndiv.v-list--dense .v-list-item {\n min-height: 25px;\n padding: 0px;\n .v-list-item__action {\n margin: 0px;\n padding: 0px 4px;\n }\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px;\n }\n}\n\n.v-select-list {\n overflow: hidden;\n}\n\n.v-menu__content:not(.v-autocomplete__content) {\n .v-list__tile {\n height: 23px;\n }\n}\ntable.v-table tbody tr {\n border: 0px !important;\n}\n\ntable.v-table thead {\n tr {\n height: 30px !important;\n }\n tr.v-datatable__progress {\n height: 0px !important;\n border-top: 1px solid rgba(0, 0, 0, 0.05);\n }\n th {\n padding-left: 5px !important;\n padding-right: 5px !important;\n }\n}\n\ndiv.v-data-table__actions {\n flex-wrap: nowrap;\n &__pagination {\n width: 100%;\n min-width: 170px;\n margin: 0 10px 0 10px;\n }\n &__select {\n white-space: normal;\n overflow: hidden;\n justify-content: flex-start;\n margin-right: 5px;\n max-width: 100px;\n .v-select {\n margin-left: 25px;\n margin-right: 0px;\n margin-top: 0px;\n margin-bottom: 0px;\n }\n }\n &__range-controls {\n width: 100%;\n }\n button {\n margin: 0px;\n margin-right: 5px;\n }\n}\n\n.section-toggle {\n cursor: pointer;\n}\n\n.isabl-base-card .v-data-footer {\n font-size: 12px;\n padding: 0px;\n div.v-select__selection {\n font-size: 12px;\n }\n div.v-select {\n margin: 4px 0px 4px 16px;\n }\n}\n.v-data-footer__select\n.v-menu__content .v-list-item {\n min-height: 25px;\n font-size: 14px;\n .v-list-item__content {\n padding: 0px;\n }\n}\n// Style taken from github\ncode.markdown-style {\n padding: 0.2em 0.4em;\n margin: 0;\n font-size: 85%;\n background-color: rgba(175,184,193,0.2);\n border-radius: 6px;\n color: #24292f;\n}\n\n.v-data-table .v-data-footer {\n .v-data-footer__select {\n margin-left: 0;\n margin-right: auto;\n }\n .v-data-footer__pagination {\n margin-left: auto;\n margin-right: auto;\n }\n .v-data-footer__icons-before {\n margin-left: auto;\n margin-right: 0;\n }\n .v-data-footer__icons-after {\n margin-left: 0;\n margin-right: 0;\n }\n}\n\n</style>\n"]
251039
251039
  },
251040
251040
  _coverageSchema: "43e27e138ebf9cfc5966b082cf9a028302ed4184",
251041
- hash: "235fafbf88a72a48e239d67dc7b99e287750338d"
251041
+ hash: "d785cc7739c0c8a3532fce89055018d808c250a9"
251042
251042
  };
251043
251043
  var coverage = global[gcv] || (global[gcv] = {});
251044
251044
 
@@ -251897,8 +251897,8 @@ var DataTablevue_type_style_index_0_lang_scss_ = __webpack_require__("7bec");
251897
251897
 
251898
251898
  var DataTable_component = normalizeComponent(
251899
251899
  table_DataTablevue_type_script_lang_js_,
251900
- DataTablevue_type_template_id_31c65eb2_render,
251901
- DataTablevue_type_template_id_31c65eb2_staticRenderFns,
251900
+ DataTablevue_type_template_id_57e40a80_render,
251901
+ DataTablevue_type_template_id_57e40a80_staticRenderFns,
251902
251902
  false,
251903
251903
  null,
251904
251904
  null,
@@ -89277,7 +89277,7 @@ exports = module.exports = __webpack_require__("2350")(false);
89277
89277
 
89278
89278
 
89279
89279
  // module
89280
- exports.push([module.i, ".isabl-base-card .v-data-table th.column.sortable.active.desc button.sort-icon{-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.isabl-base-card .v-data-table th.column.sortable.active button.sort-icon{color:var(--v-primary-base)}.isabl-base-card .v-data-table th.column.sortable button{font-size:13px!important;margin-left:4px}.isabl-base-card .v-data-table .v-data-table__wrapper{max-height:300px;overflow-y:auto}.isabl-base-card .v-data-table .table-cell{height:25px!important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:300px;padding-left:5px!important}.isabl-base-card .v-data-table .table-cell .v-chip.v-size--small{height:20px}.isabl-base-card .v-data-table tr.table-headers.table-cell{position:sticky;top:0;background:#fff;cursor:pointer;height:32px}.isabl-base-card .v-data-table tr.table-headers.table-cell th{background:rgba(0,0,0,.04)}.isabl-base-card .v-data-table.theme--dark,.isabl-base-card .v-data-table.theme--dark tr.column-filters th,.isabl-base-card .v-data-table.theme--dark tr.table-headers.table-cell th{background:var(--v-surface-base)}.isabl-base-card .v-data-table th.column.sortable{padding:0 5px}.isabl-base-card .v-data-table tr.column-filters th{height:32px}.isabl-base-card .v-data-table .v-data-table__empty-wrapper>td{padding:0}.table-filter-input{min-width:150px}.table-filter-input .v-input__icon--append .v-icon{font-size:14px}.table-filter-input input{font-size:14px;font-weight:400;padding-left:6px!important}.table-filter-input label{font-size:13px;padding-left:6px}.column-filters{position:sticky;top:25px;background:#fff;z-index:10}.column-filters .v-select{margin:0}.column-filters .v-select .v-input__slot,.column-filters .v-select input{height:25px}.column-filters .v-select .v-icon{font-size:16px}.column-filters .v-select__selections{display:contents;max-width:120px;font-size:14px;font-weight:400}.column-filters .v-select__selections span,.column-filters .v-text-field .v-input__append-inner{padding:0}.v-list .v-list-item{min-height:25px}.v-list .v-list-item .v-list-item__title{font-size:14px;font-weight:400}.v-list .v-list-item .v-list-item__content{padding:0 10px}div.v-list--dense .v-list-item{min-height:25px;padding:0}div.v-list--dense .v-list-item .v-list-item__action{margin:0;padding:0 4px}div.v-list--dense .v-list-item .v-list-item__title{font-size:14px;font-weight:400}div.v-list--dense .v-list-item .v-list-item__content{padding:0}.v-select-list{overflow:hidden}.v-menu__content:not(.v-autocomplete__content) .v-list__tile{height:23px}table.v-table tbody tr{border:0!important}table.v-table thead tr{height:30px!important}table.v-table thead tr.v-datatable__progress{height:0!important;border-top:1px solid rgba(0,0,0,.05)}table.v-table thead th{padding-left:5px!important;padding-right:5px!important}div.v-data-table__actions{-ms-flex-wrap:nowrap;flex-wrap:nowrap}div.v-data-table__actions__pagination{width:100%;min-width:170px;margin:0 10px 0 10px}div.v-data-table__actions__select{white-space:normal;overflow:hidden;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;margin-right:5px;max-width:100px}div.v-data-table__actions__select .v-select{margin-left:25px;margin-right:0;margin-top:0;margin-bottom:0}div.v-data-table__actions__range-controls{width:100%}div.v-data-table__actions button{margin:0;margin-right:5px}.section-toggle{cursor:pointer}.isabl-base-card .v-data-footer{font-size:12px;padding:0}.isabl-base-card .v-data-footer div.v-select__selection{font-size:12px}.isabl-base-card .v-data-footer div.v-select{margin:4px 0 4px 16px}.v-data-footer__select .v-menu__content .v-list-item{min-height:25px;font-size:14px}.v-data-footer__select .v-menu__content .v-list-item .v-list-item__content{padding:0}code.markdown-style{padding:.2em .4em;margin:0;font-size:85%;background-color:rgba(175,184,193,.2);border-radius:6px;color:#24292f}.v-data-table .v-data-footer .v-data-footer__select{margin-left:0;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__pagination{margin-left:auto;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__icons-before{margin-left:auto;margin-right:0}.v-data-table .v-data-footer .v-data-footer__icons-after{margin-left:0;margin-right:0}", ""]);
89280
+ exports.push([module.i, ".isabl-base-card .v-data-table th.column.sortable.active.desc button.sort-icon{-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.isabl-base-card .v-data-table th.column.sortable.active button.sort-icon{color:var(--v-primary-base)}.isabl-base-card .v-data-table th.column.sortable button{font-size:13px!important;margin-left:4px}.isabl-base-card .v-data-table .v-data-table__wrapper{max-height:300px;overflow-y:auto}.isabl-base-card .v-data-table .table-cell{height:25px!important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:300px;padding-left:5px!important}.isabl-base-card .v-data-table .table-cell .v-chip.v-size--small{height:20px}.isabl-base-card .v-data-table tr.table-headers.table-cell{position:sticky;top:0;background:#fff;cursor:pointer;height:32px;z-index:1}.isabl-base-card .v-data-table tr.table-headers.table-cell th{background:rgba(0,0,0,.04)}.isabl-base-card .v-data-table.theme--dark,.isabl-base-card .v-data-table.theme--dark tr.column-filters th,.isabl-base-card .v-data-table.theme--dark tr.table-headers.table-cell th{background:var(--v-surface-base)}.isabl-base-card .v-data-table th.column.sortable{padding:0 5px}.isabl-base-card .v-data-table tr.column-filters th{height:32px}.isabl-base-card .v-data-table .v-data-table__empty-wrapper>td{padding:0}.table-filter-input{min-width:150px}.table-filter-input .v-input__icon--append .v-icon{font-size:14px}.table-filter-input input{font-size:14px;font-weight:400;padding-left:6px!important}.table-filter-input label{font-size:13px;padding-left:6px}.column-filters{position:sticky;top:25px;background:#fff;z-index:1}.column-filters .v-select{margin:0}.column-filters .v-select .v-input__slot,.column-filters .v-select input{height:25px}.column-filters .v-select .v-icon{font-size:16px}.column-filters .v-select__selections{display:contents;max-width:120px;font-size:14px;font-weight:400}.column-filters .v-select__selections span,.column-filters .v-text-field .v-input__append-inner{padding:0}.v-list .v-list-item{min-height:25px}.v-list .v-list-item .v-list-item__title{font-size:14px;font-weight:400}.v-list .v-list-item .v-list-item__content{padding:0 10px}div.v-list--dense .v-list-item{min-height:25px;padding:0}div.v-list--dense .v-list-item .v-list-item__action{margin:0;padding:0 4px}div.v-list--dense .v-list-item .v-list-item__title{font-size:14px;font-weight:400}div.v-list--dense .v-list-item .v-list-item__content{padding:0}.v-select-list{overflow:hidden}.v-menu__content:not(.v-autocomplete__content) .v-list__tile{height:23px}table.v-table tbody tr{border:0!important}table.v-table thead tr{height:30px!important}table.v-table thead tr.v-datatable__progress{height:0!important;border-top:1px solid rgba(0,0,0,.05)}table.v-table thead th{padding-left:5px!important;padding-right:5px!important}div.v-data-table__actions{-ms-flex-wrap:nowrap;flex-wrap:nowrap}div.v-data-table__actions__pagination{width:100%;min-width:170px;margin:0 10px 0 10px}div.v-data-table__actions__select{white-space:normal;overflow:hidden;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;margin-right:5px;max-width:100px}div.v-data-table__actions__select .v-select{margin-left:25px;margin-right:0;margin-top:0;margin-bottom:0}div.v-data-table__actions__range-controls{width:100%}div.v-data-table__actions button{margin:0;margin-right:5px}.section-toggle{cursor:pointer}.isabl-base-card .v-data-footer{font-size:12px;padding:0}.isabl-base-card .v-data-footer div.v-select__selection{font-size:12px}.isabl-base-card .v-data-footer div.v-select{margin:4px 0 4px 16px}.v-data-footer__select .v-menu__content .v-list-item{min-height:25px;font-size:14px}.v-data-footer__select .v-menu__content .v-list-item .v-list-item__content{padding:0}code.markdown-style{padding:.2em .4em;margin:0;font-size:85%;background-color:rgba(175,184,193,.2);border-radius:6px;color:#24292f}.v-data-table .v-data-footer .v-data-footer__select{margin-left:0;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__pagination{margin-left:auto;margin-right:auto}.v-data-table .v-data-footer .v-data-footer__icons-before{margin-left:auto;margin-right:0}.v-data-table .v-data-footer .v-data-footer__icons-after{margin-left:0;margin-right:0}", ""]);
89281
89281
 
89282
89282
  // exports
89283
89283
 
@@ -91177,7 +91177,7 @@ module.exports = overArg;
91177
91177
  /***/ "9224":
91178
91178
  /***/ (function(module) {
91179
91179
 
91180
- module.exports = JSON.parse("{\"name\":\"@papaemmelab/isabl-web\",\"version\":\"0.3.16\",\"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\"}");
91180
+ module.exports = JSON.parse("{\"name\":\"@papaemmelab/isabl-web\",\"version\":\"0.3.18\",\"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\"}");
91181
91181
 
91182
91182
  /***/ }),
91183
91183
 
@@ -243679,8 +243679,8 @@ var BaseTabs_component = normalizeComponent(
243679
243679
  )
243680
243680
 
243681
243681
  /* harmony default export */ var BaseTabs = (BaseTabs_component.exports);
243682
- // 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/table/DataTable.vue?vue&type=template&id=31c65eb2&
243683
- var DataTablevue_type_template_id_31c65eb2_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-card',{class:['isabl-base-card no-shadow', _vm.cardClasses]},[_c('base-section-title',{attrs:{"show-more":_vm.showTable},on:{"toggle-show-more":function($event){_vm.showTable = !_vm.showTable}},scopedSlots:_vm._u([{key:"title",fn:function(){return [_vm._v("\n "+_vm._s(_vm._f("capitalize")(_vm.title || _vm.model))+"\n "),(_vm.infoText)?_c('v-tooltip',{attrs:{"top":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
243682
+ // 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/table/DataTable.vue?vue&type=template&id=57e40a80&
243683
+ var DataTablevue_type_template_id_57e40a80_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-card',{class:['isabl-base-card no-shadow', _vm.cardClasses]},[_c('base-section-title',{attrs:{"show-more":_vm.showTable},on:{"toggle-show-more":function($event){_vm.showTable = !_vm.showTable}},scopedSlots:_vm._u([{key:"title",fn:function(){return [_vm._v("\n "+_vm._s(_vm._f("capitalize")(_vm.title || _vm.model))+"\n "),(_vm.infoText)?_c('v-tooltip',{attrs:{"top":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
243684
243684
  var on = ref.on;
243685
243685
  return [_c('v-icon',_vm._g({staticClass:"pl-1",staticStyle:{"cursor":"help"},attrs:{"small":"","color":"grey lighten-2"}},on),[_vm._v("\n info\n ")])]}}],null,false,2192405103)},[_c('span',{attrs:{"text-center":""}},[_vm._v(_vm._s(_vm.infoText))])]):_vm._e()]},proxy:true},{key:"actions",fn:function(){return [(_vm.items)?_c('data-table-actions',{attrs:{"model":_vm.model,"items":_vm.items,"headers":_vm.headers,"global-search":_vm.globalSearch,"query-params":_vm.queryParams},on:{"fetch-data":_vm.updateSearchText}}):_vm._e()]},proxy:true}])}),_c('v-data-table',{directives:[{name:"show",rawName:"v-show",value:(_vm.showTable),expression:"showTable"}],attrs:{"headers":_vm.headers,"items":_vm.items,"server-items-length":_vm.totalItems,"loading":_vm.loading,"items-per-page":_vm.itemsPerPage,"page":_vm.page,"footer-props":{ itemsPerPageOptions: _vm.itemsPerPageItems, itemsPerPageText: '' },"loader-height":"2","calculate-widths":"","hide-default-header":"","dense":""},on:{"update:itemsPerPage":function($event){_vm.itemsPerPage=$event},"update:items-per-page":function($event){_vm.itemsPerPage=$event},"update:page":function($event){_vm.page=$event},"page-count":function($event){_vm.pageCount = $event}},scopedSlots:_vm._u([{key:"header",fn:function(ref){
243686
243686
  var props = ref.props;
@@ -243705,10 +243705,10 @@ return [_c('span',{class:[
243705
243705
  var pageStart = ref.pageStart;
243706
243706
  var pageStop = ref.pageStop;
243707
243707
  return [_c('span',{staticClass:"text-body-1"},[_vm._v("\n "+_vm._s(pageStart)+" - "+_vm._s(pageStop)+" of\n "),_c('span',{staticClass:"primary--text text-h6 mx-1"},[_vm._v(_vm._s(_vm._f("formatNumber")(_vm.totalItems)))])])]}}])})],1)}
243708
- var DataTablevue_type_template_id_31c65eb2_staticRenderFns = []
243708
+ var DataTablevue_type_template_id_57e40a80_staticRenderFns = []
243709
243709
 
243710
243710
 
243711
- // CONCATENATED MODULE: ./src/components/table/DataTable.vue?vue&type=template&id=31c65eb2&
243711
+ // CONCATENATED MODULE: ./src/components/table/DataTable.vue?vue&type=template&id=57e40a80&
243712
243712
 
243713
243713
  // 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/table/DataTableActions.vue?vue&type=template&id=0e1da098&
243714
243714
  var DataTableActionsvue_type_template_id_0e1da098_render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-row',{staticClass:"pa-0 ma-0 float-right"},[(_vm.searchText || _vm.showSearch)?_c('transition',{attrs:{"name":"slide"}},[_c('v-form',{on:{"submit":function($event){$event.preventDefault();}}},[_c('v-text-field',{ref:"input",staticClass:"pa-0 my-0 table-filter-input",attrs:{"autofocus":true,"append-icon":_vm.searchText ? 'close' : null,"label":"Search","data-test":"table-search-input","single-line":"","hide-details":"","dense":""},on:{"click:append":function($event){_vm.searchText ? (_vm.searchText = '') : null},"keyup":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }_vm.searchText = ''},"blur":_vm.onSearchInputBlur},model:{value:(_vm.searchText),callback:function ($$v) {_vm.searchText=$$v},expression:"searchText"}})],1)],1):_vm._e(),_c('v-speed-dial',{staticClass:"float-right",attrs:{"direction":"bottom","color":"primary","transition":"slide-y-transition","open-on-hover":""},scopedSlots:_vm._u([{key:"activator",fn:function(){return [_c('v-btn',{staticClass:"table-action-btn",attrs:{"fab":"","x-small":"","elevation":"0","color":"transparent"},on:{"click":function($event){_vm.showSearch = !_vm.showSearch}}},[(_vm.loading)?_c('v-progress-circular',{attrs:{"width":2,"size":18,"indeterminate":"","color":"primary"}}):(_vm.showActions || _vm.showSearch)?_c('v-icon',{attrs:{"small":""}},[_vm._v("\n search\n ")]):_c('v-icon',[_vm._v("\n more_vert\n ")])],1)]},proxy:true}]),model:{value:(_vm.showActions),callback:function ($$v) {_vm.showActions=$$v},expression:"showActions"}},[_c('JsonExcel',{attrs:{"fields":_vm.jsonHeaders,"fetch":_vm.fetchAllRecords,"worksheet":_vm.model,"name":_vm.exportedFilename,"before-finish":_vm.showFinishedAlert}},[_c('v-btn',{staticClass:"table-action-btn float-right",attrs:{"fab":"","x-small":""}},[_c('v-tooltip',{attrs:{"left":""},scopedSlots:_vm._u([{key:"activator",fn:function(ref){
@@ -247626,7 +247626,7 @@ var orderBy_default = /*#__PURE__*/__webpack_require__.n(orderBy);
247626
247626
  // 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/table/DataTable.vue?vue&type=script&lang=js&
247627
247627
  var cov_2h6d9k0h00 = function () {
247628
247628
  var path = "/Users/juanes/papaemmelab/isabl_web/src/components/table/DataTable.vue";
247629
- var hash = "235fafbf88a72a48e239d67dc7b99e287750338d";
247629
+ var hash = "d785cc7739c0c8a3532fce89055018d808c250a9";
247630
247630
  var global = new Function("return this")();
247631
247631
  var gcv = "__coverage__";
247632
247632
  var coverageData = {
@@ -251044,10 +251044,10 @@ var cov_2h6d9k0h00 = function () {
251044
251044
  mappings: ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+NA;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;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;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;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;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
251045
251045
  file: "DataTable.vue",
251046
251046
  sourceRoot: "src/components/table",
251047
- sourcesContent: ["<template>\n <v-card :class=\"['isabl-base-card no-shadow', cardClasses]\">\n <base-section-title\n :show-more=\"showTable\"\n @toggle-show-more=\"showTable = !showTable\"\n >\n <template v-slot:title>\n {{ title || model | capitalize }}\n <v-tooltip\n v-if=\"infoText\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n small\n style=\"cursor: help\"\n color=\"grey lighten-2\"\n class=\"pl-1\"\n v-on=\"on\"\n >\n info\n </v-icon>\n </template>\n <span text-center>{{ infoText }}</span>\n </v-tooltip>\n </template>\n <template v-slot:actions>\n <data-table-actions\n v-if=\"items\"\n :model=\"model\"\n :items=\"items\"\n :headers=\"headers\"\n :global-search=\"globalSearch\"\n :query-params=\"queryParams\"\n @fetch-data=\"updateSearchText\"\n />\n </template>\n </base-section-title>\n\n <v-data-table\n v-show=\"showTable\"\n :headers=\"headers\"\n :items=\"items\"\n :server-items-length=\"totalItems\"\n :loading=\"loading\"\n :items-per-page.sync=\"itemsPerPage\"\n :page.sync=\"page\"\n :footer-props=\"{ itemsPerPageOptions: itemsPerPageItems, itemsPerPageText: '' }\"\n loader-height=\"2\"\n calculate-widths\n hide-default-header\n dense\n @page-count=\"pageCount = $event\"\n >\n <template v-slot:header=\"{ props }\">\n <tr class=\"table-headers text-left table-cell py-0 font-normal\">\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n :class=\"[\n 'column sortable',\n sortByColumns.includes(header.value)\n ? 'asc active'\n : '',\n sortByColumns.includes(`-${header.value}`)\n ? 'desc active'\n : ''\n ]\"\n >\n <v-hover v-slot=\"{ hover }\">\n <span\n :class=\"[\n 'font-weight-medium',\n 'grey--text',\n ]\"\n >\n {{ header.text }}\n <v-icon\n :color=\"\n hover || sortByColumns.includes(header.value) || sortByColumns.includes(`-${header.value}`)\n ? 'text--darken-2'\n : 'transparent'\n \"\n class=\"sort-icon\"\n style=\"vertical-align: middle\"\n small\n @click=\"changeSort(header.value)\"\n >arrow_downward</v-icon>\n <v-icon\n :color=\"hover ? 'text--darken-2' : 'transparent'\"\n class=\"\"\n style=\"vertical-align: middle\"\n small\n @click=\"toggleColumnFilters\"\n >filter_list</v-icon>\n </span>\n </v-hover>\n </th>\n </tr>\n <tr\n v-if=\"showFilters\"\n class=\"column-filters\"\n >\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n class=\"pa-0 ma-0\"\n >\n <data-table-date-picker\n v-if=\"header.filterType === 'date'\"\n :header=\"header\"\n @filter-search=\"filterSearch\"\n />\n <data-table-select-filter\n v-else\n :header=\"header\"\n :model=\"title || model\"\n @filter-search=\"filterSearch\"\n />\n </th>\n </tr>\n </template>\n <template v-slot:item=\"attrs\">\n <tr>\n <td\n v-for=\"(header, index) in attrs.headers\"\n :key=\"index + header.verboseName\"\n class=\"text-left table-cell py-0 text-body-1\"\n >\n <!-- if value is a model(s) link -->\n <span v-if=\"header.model\">\n <span v-if=\"Array.isArray(getValue(attrs.item, header))\">\n <span\n v-for=\"(value, index) in getValue(attrs.item, header)\"\n :key=\"index\"\n class=\"active-link\"\n @click=\"onClickRecord(value, header.model)\"\n v-html=\"\n highlightText(value, header) +\n `${index + 1 < getValue(attrs.item, header).length ? ', ' : ''}`\n \"\n />\n </span>\n\n <span v-else>\n <span\n class=\"active-link\"\n @click=\"onClickRecord(getValue(attrs.item, header), header.model)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n </span>\n </span>\n\n <!-- if value is analysis' result -->\n <span\n v-else-if=\"header.field === 'status'\"\n :class=\"classValue(attrs.item, header.field)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n\n <div\n v-else-if=\"header.field === 'resultName'\"\n class=\"mr-2\"\n >\n <result-chip\n :result=\"attrs.item\"\n :result-index=\"itemsPerPage * (page - 1) + attrs.index\"\n show-all\n @display-result=\"$emit('display-result', $event)\"\n />\n </div>\n\n <span\n v-else-if=\"header.field === 'resultKey'\"\n class=\"mr-2\"\n >\n <code class=\"markdown-style\" v-html=\"tableValue(attrs.item, header)\"/>\n </span>\n\n <!-- any other case -->\n <span\n v-else\n v-html=\"tableValue(attrs.item, header)\"\n />\n </td>\n </tr>\n </template>\n\n <template v-slot:no-data>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : errorMessage || 'No records found.' }}</td>\n </template>\n\n <template v-slot:loading>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >Querying records...</td>\n </template>\n\n <template v-slot:no-results>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : 'No records found.' }}</td>\n </template>\n\n <template v-slot:footer.page-text=\"{ pageStart, pageStop }\">\n <span class=\"text-body-1\">\n {{ pageStart }} - {{ pageStop }} of\n <span\n class=\"primary--text text-h6 mx-1\"\n >{{ totalItems | formatNumber }}</span>\n </span>\n </template>\n\n </v-data-table>\n </v-card>\n</template>\n\n<script>\nimport { fetchListRecords } from '@/utils/api'\nimport { SHOW_ALERT } from '@/store/actions/alert'\nimport { SHOW_PANEL } from '@/store/actions/panels'\nimport { tableColumns } from '@/utils/tableColumns'\nimport BaseSectionTitle from '@/components/base/BaseSectionTitle.vue'\nimport DataTableActions from '@/components/table/DataTableActions.vue'\nimport DataTableSelectFilter from '@/components/table/DataTableSelectFilter.vue'\nimport DataTableDatePicker from '@/components/table/DataTableDatePicker.vue'\nimport ResultChip from '@/components/analyses/ResultChip'\nimport debounce from 'lodash/debounce'\nimport isEqual from 'lodash/isEqual'\nimport orderBy from 'lodash/orderBy'\n\nexport default {\n name: 'DataTable',\n components: {\n BaseSectionTitle,\n DataTableActions,\n DataTableSelectFilter,\n DataTableDatePicker,\n ResultChip,\n },\n props: {\n model: {\n type: String,\n required: false\n },\n title: {\n type: String,\n default: ''\n },\n globalSearch: {\n type: Boolean,\n default: false\n },\n params: {\n type: Object,\n default: () => ({})\n },\n // skip columns using the verbose name\n skipColumns: {\n type: Array,\n default: () => []\n },\n // columns using the verbose name\n headersKey: {\n type: String,\n default: ''\n },\n cardClasses: {\n type: String,\n default: ''\n },\n collapse: {\n type: Boolean,\n default: false\n },\n infoText: {\n type: String,\n default: ''\n },\n openRecordsInNewTab: {\n type: Boolean,\n default: false\n },\n data: {\n type: Array,\n default: () => []\n },\n filterRemotely: {\n type: Boolean,\n default: true,\n },\n initialSort: {\n type: Array,\n default: () => [\"-pk\"]\n },\n initialItemsPerPage: {\n type: Number,\n default: 5,\n }\n },\n data() {\n return {\n items: this.filterRemotely ? [] : this.data,\n totalItems: 0,\n loading: true,\n showTable: !this.collapse,\n showFilters: false,\n\n // table params\n headers: tableColumns[this.headersKey || this.model]\n .map(col => {\n col.text = col.verboseName\n col.value = col.field\n return col\n })\n .filter(col => !this.skipColumns.includes(col.verboseName)),\n page: 1,\n pageCount: 0,\n itemsPerPage: this.initialItemsPerPage,\n itemsPerPageItems: [3, 5, 10, 25, 50, 200, 500, 5000],\n sortByColumns: this.initialSort,\n\n // query params\n limit: null,\n offset: null,\n ordering: null,\n errorMessage: null,\n searchText: '',\n filterParams: {},\n queryParams: {}\n }\n },\n watch: {\n params(newParams, oldParams) {\n if (!isEqual(newParams, oldParams)) {\n this.fetchData()\n }\n },\n page() {\n this.updateTable()\n },\n sortByColumns() {\n this.updateTable()\n },\n itemsPerPage() {\n this.updateTable()\n },\n data() {\n this.updateTable()\n }\n },\n created() {\n this.fetchData = debounce(this._fetchData, 500)\n this.updateTable()\n },\n methods: {\n changeSort(column) {\n let sort = this.sortByColumns\n\n if (sort.includes(column)) {\n // Make ordering column -> None\n sort = sort.filter(columns => columns !== column)\n } else if (sort.includes(`-${column}`)) {\n // Make ordering -column -> column\n sort = sort.filter(columns => columns !== `-${column}`)\n sort.push(column)\n } else {\n // Make ordering None -> -column\n sort.push(`-${column}`)\n }\n\n // Move pk to last if exist\n sort.push(sort.splice(sort.indexOf('pk'), 1)[0])\n sort.push(sort.splice(sort.indexOf('-pk'), 1)[0])\n\n this.sortByColumns = sort\n },\n filterSearch(value, field, filter = 'icontains') {\n field = field.split('.').join('__')\n value = Array.isArray(value) ? value.join(',') : value\n\n // Ensure only one filter per key\n this.filterParams = Object.keys(this.filterParams)\n .filter(param => {\n const filterWithSameKey = `${field}__`\n return !param.includes(filterWithSameKey)\n })\n .reduce((obj, key) => {\n obj[key] = this.filterParams[key]\n return obj\n }, {})\n\n this.filterParams[`${field}__${filter}`] = value\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Filter from table column', {\n model: this.model,\n query: this.filterParams\n })\n },\n\n columnValueList(val) {\n return this.items.map(d => d[val])\n },\n\n updateSearchText(text) {\n this.searchText = text\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Searched From Table', {\n model: this.model,\n search: this.searchText,\n query: this.queryParams\n })\n },\n\n tableValue(item, header) {\n let value = this.getValue(item, header)\n return this.highlightText(value, header)\n },\n\n formatValue(value) {\n return this.highlightText(value)\n },\n\n getValue(item, header) {\n return this.$get(\n item,\n header.accessor || header.field,\n header.default || '-'\n )\n },\n\n isTableSmall() {\n let tables = document.getElementsByClassName('v-datatable__actions')\n return tables && tables.length > 0 && tables[0].offsetWidth < 400\n },\n\n classValue(item, accessor) {\n let value = this.$get(item, accessor)\n .toString()\n .toLowerCase()\n return `status-${value}`\n },\n\n highlightText(rawText, header) {\n header = header.value.split('.').join('__')\n const filterParams = {\n ...this.filterParams,\n search: this.searchText\n }\n let keywords = Object.entries(filterParams)\n .filter(([key, value]) => {\n return (\n value &&\n typeof value !== 'boolean' &&\n (key === 'search' || key.replace(/(__icontains)/, '') === header)\n )\n })\n .map(([, value]) => value.toString().toLowerCase())\n\n let { text, element } = this.$getInnerHtmlText(rawText)\n let shownText = text ? text.toString().slice(0, 41) : ''\n let highlightText = shownText\n\n // Search for match of full string if not each word\n let wordsToHighlight = []\n keywords.forEach(keyword => {\n keyword = keyword.trim()\n if (keyword && shownText.toLowerCase().includes(keyword)) {\n wordsToHighlight.push(keyword)\n } else {\n keyword.split(' ').forEach(word => {\n if (word && shownText.toLowerCase().includes(word)) {\n wordsToHighlight.push(word)\n }\n })\n }\n })\n\n // Highlight the matches\n if (wordsToHighlight.length) {\n const keywordRegex = new RegExp(`(${wordsToHighlight.join('|')})`, 'gi')\n highlightText = text\n .toString()\n .replace(keywordRegex, '<span class=\"highlight\">$1</span>')\n }\n return this.$setInnerHtmlText(element, highlightText)\n },\n\n updateTable() {\n this.limit = this.itemsPerPage\n this.offset = this.itemsPerPage * (this.page - 1)\n this.ordering = this.sortByColumns.join(',')\n\n if (this.filterRemotely) {\n // Make server-side filtering\n this.fetchData()\n } else {\n // Local Items\n this.loading = true\n let rows = this.data\n\n if (this.searchText) {\n rows = rows.filter((row) =>\n Object.values(row).some((column) =>\n column.toLowerCase().includes(this.searchText.toLowerCase())\n )\n )\n }\n if (this.sortByColumns.length) {\n const columns = []\n const order = []\n this.sortByColumns.forEach(param => {\n const [first, ...rest] = param\n if (first === '-') {\n columns.push(rest.join(''))\n order.push('desc')\n } else {\n columns.push(param)\n order.push('asc')\n }\n })\n rows = orderBy(rows, columns, order)\n }\n rows = rows.slice(this.offset, this.offset + this.limit)\n this.items = rows\n this.totalItems = this.data.length\n this.pages = Math.ceil(this.totalItems / this.items)\n this.loading = false\n }\n },\n\n _fetchData() {\n this.loading = true\n const {\n model,\n limit,\n offset,\n ordering,\n params,\n filterParams,\n searchText\n } = this\n\n this.queryParams = {\n ...params,\n ...filterParams,\n limit,\n offset,\n search: searchText,\n ordering,\n }\n\n this.$emit('fetch-data', this.queryParams)\n\n fetchListRecords(model, this.queryParams)\n .then(response => {\n if (searchText === this.searchText) {\n this.items = response.results\n this.totalItems = response.count\n this.pages = Math.ceil(response.count / limit)\n this.errorMessage = response.error || ''\n }\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 onClickRecord(value, model) {\n if (this.openRecordsInNewTab) {\n const queryParams = {\n individual: 'bioModel',\n sample: 'bioModel',\n experiment: 'bioModel'\n }\n const queryParam = this.$get(queryParams, model, model)\n window.open(`/?${queryParam}=${value}`, '_blank')\n } else {\n this.$store.dispatch(SHOW_PANEL, {\n [model]: value\n })\n }\n },\n\n toggleColumnFilters() {\n this.showFilters = !this.showFilters\n if (!this.showFilters) {\n this.filterParams = {}\n this.fetchData()\n }\n },\n }\n}\n</script>\n\n<style lang=\"scss\">\n\n.isabl-base-card .v-data-table {\n th.column.sortable.active.desc button.sort-icon {\n transform: rotate(-180deg);\n }\n th.column.sortable.active button.sort-icon {\n color: var(--v-primary-base);\n }\n th.column.sortable button {\n font-size: 13px !important;\n margin-left: 4px;\n }\n .v-data-table__wrapper {\n max-height: 300px;\n overflow-y: auto;\n }\n .table-cell {\n height: 25px !important;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 300px;\n padding-left: 5px !important;\n .v-chip.v-size--small {\n height: 20px;\n }\n }\n tr.table-headers.table-cell {\n position: sticky;\n top: 0;\n background: white;\n cursor: pointer;\n height: 32px;\n th {\n // border-bottom: thin solid rgba(0,0,0,.12);\n background: rgba(0,0,0,.04);\n }\n }\n &.theme--dark, &.theme--dark tr.table-headers.table-cell th {\n background: var(--v-surface-base);\n }\n &.theme--dark tr.column-filters th {\n background: var(--v-surface-base);\n }\n th.column.sortable {\n padding: 0px 5px;\n }\n tr.column-filters th {\n height: 32px;\n }\n .v-data-table__empty-wrapper>td {\n padding: 0px;\n }\n}\n\n.table-filter-input {\n min-width: 150px;\n .v-input__icon--append .v-icon {\n font-size: 14px;\n }\n input {\n font-size: 14px;\n font-weight: 400;\n padding-left: 6px !important;\n }\n label {\n font-size: 13px;\n padding-left: 6px;\n }\n}\n.column-filters {\n position: sticky;\n top: 25px;\n background: white;\n z-index: 10;\n .v-select {\n margin: 0px;\n .v-input__slot, input {\n height: 25px;\n }\n .v-icon {\n font-size: 16px;\n }\n }\n .v-select__selections {\n display: contents;\n max-width: 120px;\n font-size: 14px;\n font-weight: 400;\n span {\n padding: 0px;\n }\n }\n .v-text-field .v-input__append-inner {\n padding: 0px;\n }\n}\n\n.v-list .v-list-item {\n min-height: 25px;\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px 10px;\n }\n}\n\ndiv.v-list--dense .v-list-item {\n min-height: 25px;\n padding: 0px;\n .v-list-item__action {\n margin: 0px;\n padding: 0px 4px;\n }\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px;\n }\n}\n\n.v-select-list {\n overflow: hidden;\n}\n\n.v-menu__content:not(.v-autocomplete__content) {\n .v-list__tile {\n height: 23px;\n }\n}\ntable.v-table tbody tr {\n border: 0px !important;\n}\n\ntable.v-table thead {\n tr {\n height: 30px !important;\n }\n tr.v-datatable__progress {\n height: 0px !important;\n border-top: 1px solid rgba(0, 0, 0, 0.05);\n }\n th {\n padding-left: 5px !important;\n padding-right: 5px !important;\n }\n}\n\ndiv.v-data-table__actions {\n flex-wrap: nowrap;\n &__pagination {\n width: 100%;\n min-width: 170px;\n margin: 0 10px 0 10px;\n }\n &__select {\n white-space: normal;\n overflow: hidden;\n justify-content: flex-start;\n margin-right: 5px;\n max-width: 100px;\n .v-select {\n margin-left: 25px;\n margin-right: 0px;\n margin-top: 0px;\n margin-bottom: 0px;\n }\n }\n &__range-controls {\n width: 100%;\n }\n button {\n margin: 0px;\n margin-right: 5px;\n }\n}\n\n.section-toggle {\n cursor: pointer;\n}\n\n.isabl-base-card .v-data-footer {\n font-size: 12px;\n padding: 0px;\n div.v-select__selection {\n font-size: 12px;\n }\n div.v-select {\n margin: 4px 0px 4px 16px;\n }\n}\n.v-data-footer__select\n.v-menu__content .v-list-item {\n min-height: 25px;\n font-size: 14px;\n .v-list-item__content {\n padding: 0px;\n }\n}\n// Style taken from github\ncode.markdown-style {\n padding: 0.2em 0.4em;\n margin: 0;\n font-size: 85%;\n background-color: rgba(175,184,193,0.2);\n border-radius: 6px;\n color: #24292f;\n}\n\n.v-data-table .v-data-footer {\n .v-data-footer__select {\n margin-left: 0;\n margin-right: auto;\n }\n .v-data-footer__pagination {\n margin-left: auto;\n margin-right: auto;\n }\n .v-data-footer__icons-before {\n margin-left: auto;\n margin-right: 0;\n }\n .v-data-footer__icons-after {\n margin-left: 0;\n margin-right: 0;\n }\n}\n\n</style>\n"]
251047
+ sourcesContent: ["<template>\n <v-card :class=\"['isabl-base-card no-shadow', cardClasses]\">\n <base-section-title\n :show-more=\"showTable\"\n @toggle-show-more=\"showTable = !showTable\"\n >\n <template v-slot:title>\n {{ title || model | capitalize }}\n <v-tooltip\n v-if=\"infoText\"\n top\n >\n <template v-slot:activator=\"{ on }\">\n <v-icon\n small\n style=\"cursor: help\"\n color=\"grey lighten-2\"\n class=\"pl-1\"\n v-on=\"on\"\n >\n info\n </v-icon>\n </template>\n <span text-center>{{ infoText }}</span>\n </v-tooltip>\n </template>\n <template v-slot:actions>\n <data-table-actions\n v-if=\"items\"\n :model=\"model\"\n :items=\"items\"\n :headers=\"headers\"\n :global-search=\"globalSearch\"\n :query-params=\"queryParams\"\n @fetch-data=\"updateSearchText\"\n />\n </template>\n </base-section-title>\n\n <v-data-table\n v-show=\"showTable\"\n :headers=\"headers\"\n :items=\"items\"\n :server-items-length=\"totalItems\"\n :loading=\"loading\"\n :items-per-page.sync=\"itemsPerPage\"\n :page.sync=\"page\"\n :footer-props=\"{ itemsPerPageOptions: itemsPerPageItems, itemsPerPageText: '' }\"\n loader-height=\"2\"\n calculate-widths\n hide-default-header\n dense\n @page-count=\"pageCount = $event\"\n >\n <template v-slot:header=\"{ props }\">\n <tr class=\"table-headers text-left table-cell py-0 font-normal\">\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n :class=\"[\n 'column sortable',\n sortByColumns.includes(header.value)\n ? 'asc active'\n : '',\n sortByColumns.includes(`-${header.value}`)\n ? 'desc active'\n : ''\n ]\"\n >\n <v-hover v-slot=\"{ hover }\">\n <span\n :class=\"[\n 'font-weight-medium',\n 'grey--text',\n ]\"\n >\n {{ header.text }}\n <v-icon\n :color=\"\n hover || sortByColumns.includes(header.value) || sortByColumns.includes(`-${header.value}`)\n ? 'text--darken-2'\n : 'transparent'\n \"\n class=\"sort-icon\"\n style=\"vertical-align: middle\"\n small\n @click=\"changeSort(header.value)\"\n >arrow_downward</v-icon>\n <v-icon\n :color=\"hover ? 'text--darken-2' : 'transparent'\"\n class=\"\"\n style=\"vertical-align: middle\"\n small\n @click=\"toggleColumnFilters\"\n >filter_list</v-icon>\n </span>\n </v-hover>\n </th>\n </tr>\n <tr\n v-if=\"showFilters\"\n class=\"column-filters\"\n >\n <th\n v-for=\"header in props.headers\"\n :key=\"header.text\"\n class=\"pa-0 ma-0\"\n >\n <data-table-date-picker\n v-if=\"header.filterType === 'date'\"\n :header=\"header\"\n @filter-search=\"filterSearch\"\n />\n <data-table-select-filter\n v-else\n :header=\"header\"\n :model=\"title || model\"\n @filter-search=\"filterSearch\"\n />\n </th>\n </tr>\n </template>\n <template v-slot:item=\"attrs\">\n <tr>\n <td\n v-for=\"(header, index) in attrs.headers\"\n :key=\"index + header.verboseName\"\n class=\"text-left table-cell py-0 text-body-1\"\n >\n <!-- if value is a model(s) link -->\n <span v-if=\"header.model\">\n <span v-if=\"Array.isArray(getValue(attrs.item, header))\">\n <span\n v-for=\"(value, index) in getValue(attrs.item, header)\"\n :key=\"index\"\n class=\"active-link\"\n @click=\"onClickRecord(value, header.model)\"\n v-html=\"\n highlightText(value, header) +\n `${index + 1 < getValue(attrs.item, header).length ? ', ' : ''}`\n \"\n />\n </span>\n\n <span v-else>\n <span\n class=\"active-link\"\n @click=\"onClickRecord(getValue(attrs.item, header), header.model)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n </span>\n </span>\n\n <!-- if value is analysis' result -->\n <span\n v-else-if=\"header.field === 'status'\"\n :class=\"classValue(attrs.item, header.field)\"\n v-html=\"tableValue(attrs.item, header)\"\n />\n\n <div\n v-else-if=\"header.field === 'resultName'\"\n class=\"mr-2\"\n >\n <result-chip\n :result=\"attrs.item\"\n :result-index=\"itemsPerPage * (page - 1) + attrs.index\"\n show-all\n @display-result=\"$emit('display-result', $event)\"\n />\n </div>\n\n <span\n v-else-if=\"header.field === 'resultKey'\"\n class=\"mr-2\"\n >\n <code class=\"markdown-style\" v-html=\"tableValue(attrs.item, header)\"/>\n </span>\n\n <!-- any other case -->\n <span\n v-else\n v-html=\"tableValue(attrs.item, header)\"\n />\n </td>\n </tr>\n </template>\n\n <template v-slot:no-data>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : errorMessage || 'No records found.' }}</td>\n </template>\n\n <template v-slot:loading>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >Querying records...</td>\n </template>\n\n <template v-slot:no-results>\n <td\n :colspan=\"headers.length\"\n class=\"text-left table-cell pa-0 text-body-1\"\n >{{ loading ? 'Querying records...' : 'No records found.' }}</td>\n </template>\n\n <template v-slot:footer.page-text=\"{ pageStart, pageStop }\">\n <span class=\"text-body-1\">\n {{ pageStart }} - {{ pageStop }} of\n <span\n class=\"primary--text text-h6 mx-1\"\n >{{ totalItems | formatNumber }}</span>\n </span>\n </template>\n\n </v-data-table>\n </v-card>\n</template>\n\n<script>\nimport { fetchListRecords } from '@/utils/api'\nimport { SHOW_ALERT } from '@/store/actions/alert'\nimport { SHOW_PANEL } from '@/store/actions/panels'\nimport { tableColumns } from '@/utils/tableColumns'\nimport BaseSectionTitle from '@/components/base/BaseSectionTitle.vue'\nimport DataTableActions from '@/components/table/DataTableActions.vue'\nimport DataTableSelectFilter from '@/components/table/DataTableSelectFilter.vue'\nimport DataTableDatePicker from '@/components/table/DataTableDatePicker.vue'\nimport ResultChip from '@/components/analyses/ResultChip'\nimport debounce from 'lodash/debounce'\nimport isEqual from 'lodash/isEqual'\nimport orderBy from 'lodash/orderBy'\n\nexport default {\n name: 'DataTable',\n components: {\n BaseSectionTitle,\n DataTableActions,\n DataTableSelectFilter,\n DataTableDatePicker,\n ResultChip,\n },\n props: {\n model: {\n type: String,\n required: false\n },\n title: {\n type: String,\n default: ''\n },\n globalSearch: {\n type: Boolean,\n default: false\n },\n params: {\n type: Object,\n default: () => ({})\n },\n // skip columns using the verbose name\n skipColumns: {\n type: Array,\n default: () => []\n },\n // columns using the verbose name\n headersKey: {\n type: String,\n default: ''\n },\n cardClasses: {\n type: String,\n default: ''\n },\n collapse: {\n type: Boolean,\n default: false\n },\n infoText: {\n type: String,\n default: ''\n },\n openRecordsInNewTab: {\n type: Boolean,\n default: false\n },\n data: {\n type: Array,\n default: () => []\n },\n filterRemotely: {\n type: Boolean,\n default: true,\n },\n initialSort: {\n type: Array,\n default: () => [\"-pk\"]\n },\n initialItemsPerPage: {\n type: Number,\n default: 5,\n }\n },\n data() {\n return {\n items: this.filterRemotely ? [] : this.data,\n totalItems: 0,\n loading: true,\n showTable: !this.collapse,\n showFilters: false,\n\n // table params\n headers: tableColumns[this.headersKey || this.model]\n .map(col => {\n col.text = col.verboseName\n col.value = col.field\n return col\n })\n .filter(col => !this.skipColumns.includes(col.verboseName)),\n page: 1,\n pageCount: 0,\n itemsPerPage: this.initialItemsPerPage,\n itemsPerPageItems: [3, 5, 10, 25, 50, 200, 500, 5000],\n sortByColumns: this.initialSort,\n\n // query params\n limit: null,\n offset: null,\n ordering: null,\n errorMessage: null,\n searchText: '',\n filterParams: {},\n queryParams: {}\n }\n },\n watch: {\n params(newParams, oldParams) {\n if (!isEqual(newParams, oldParams)) {\n this.fetchData()\n }\n },\n page() {\n this.updateTable()\n },\n sortByColumns() {\n this.updateTable()\n },\n itemsPerPage() {\n this.updateTable()\n },\n data() {\n this.updateTable()\n }\n },\n created() {\n this.fetchData = debounce(this._fetchData, 500)\n this.updateTable()\n },\n methods: {\n changeSort(column) {\n let sort = this.sortByColumns\n\n if (sort.includes(column)) {\n // Make ordering column -> None\n sort = sort.filter(columns => columns !== column)\n } else if (sort.includes(`-${column}`)) {\n // Make ordering -column -> column\n sort = sort.filter(columns => columns !== `-${column}`)\n sort.push(column)\n } else {\n // Make ordering None -> -column\n sort.push(`-${column}`)\n }\n\n // Move pk to last if exist\n sort.push(sort.splice(sort.indexOf('pk'), 1)[0])\n sort.push(sort.splice(sort.indexOf('-pk'), 1)[0])\n\n this.sortByColumns = sort\n },\n filterSearch(value, field, filter = 'icontains') {\n field = field.split('.').join('__')\n value = Array.isArray(value) ? value.join(',') : value\n\n // Ensure only one filter per key\n this.filterParams = Object.keys(this.filterParams)\n .filter(param => {\n const filterWithSameKey = `${field}__`\n return !param.includes(filterWithSameKey)\n })\n .reduce((obj, key) => {\n obj[key] = this.filterParams[key]\n return obj\n }, {})\n\n this.filterParams[`${field}__${filter}`] = value\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Filter from table column', {\n model: this.model,\n query: this.filterParams\n })\n },\n\n columnValueList(val) {\n return this.items.map(d => d[val])\n },\n\n updateSearchText(text) {\n this.searchText = text\n this.offset = null\n this.page = 1\n this.fetchData()\n\n // Track when user makes any string search\n window.analytics.track('Searched From Table', {\n model: this.model,\n search: this.searchText,\n query: this.queryParams\n })\n },\n\n tableValue(item, header) {\n let value = this.getValue(item, header)\n return this.highlightText(value, header)\n },\n\n formatValue(value) {\n return this.highlightText(value)\n },\n\n getValue(item, header) {\n return this.$get(\n item,\n header.accessor || header.field,\n header.default || '-'\n )\n },\n\n isTableSmall() {\n let tables = document.getElementsByClassName('v-datatable__actions')\n return tables && tables.length > 0 && tables[0].offsetWidth < 400\n },\n\n classValue(item, accessor) {\n let value = this.$get(item, accessor)\n .toString()\n .toLowerCase()\n return `status-${value}`\n },\n\n highlightText(rawText, header) {\n header = header.value.split('.').join('__')\n const filterParams = {\n ...this.filterParams,\n search: this.searchText\n }\n let keywords = Object.entries(filterParams)\n .filter(([key, value]) => {\n return (\n value &&\n typeof value !== 'boolean' &&\n (key === 'search' || key.replace(/(__icontains)/, '') === header)\n )\n })\n .map(([, value]) => value.toString().toLowerCase())\n\n let { text, element } = this.$getInnerHtmlText(rawText)\n let shownText = text ? text.toString().slice(0, 41) : ''\n let highlightText = shownText\n\n // Search for match of full string if not each word\n let wordsToHighlight = []\n keywords.forEach(keyword => {\n keyword = keyword.trim()\n if (keyword && shownText.toLowerCase().includes(keyword)) {\n wordsToHighlight.push(keyword)\n } else {\n keyword.split(' ').forEach(word => {\n if (word && shownText.toLowerCase().includes(word)) {\n wordsToHighlight.push(word)\n }\n })\n }\n })\n\n // Highlight the matches\n if (wordsToHighlight.length) {\n const keywordRegex = new RegExp(`(${wordsToHighlight.join('|')})`, 'gi')\n highlightText = text\n .toString()\n .replace(keywordRegex, '<span class=\"highlight\">$1</span>')\n }\n return this.$setInnerHtmlText(element, highlightText)\n },\n\n updateTable() {\n this.limit = this.itemsPerPage\n this.offset = this.itemsPerPage * (this.page - 1)\n this.ordering = this.sortByColumns.join(',')\n\n if (this.filterRemotely) {\n // Make server-side filtering\n this.fetchData()\n } else {\n // Local Items\n this.loading = true\n let rows = this.data\n\n if (this.searchText) {\n rows = rows.filter((row) =>\n Object.values(row).some((column) =>\n column.toLowerCase().includes(this.searchText.toLowerCase())\n )\n )\n }\n if (this.sortByColumns.length) {\n const columns = []\n const order = []\n this.sortByColumns.forEach(param => {\n const [first, ...rest] = param\n if (first === '-') {\n columns.push(rest.join(''))\n order.push('desc')\n } else {\n columns.push(param)\n order.push('asc')\n }\n })\n rows = orderBy(rows, columns, order)\n }\n rows = rows.slice(this.offset, this.offset + this.limit)\n this.items = rows\n this.totalItems = this.data.length\n this.pages = Math.ceil(this.totalItems / this.items)\n this.loading = false\n }\n },\n\n _fetchData() {\n this.loading = true\n const {\n model,\n limit,\n offset,\n ordering,\n params,\n filterParams,\n searchText\n } = this\n\n this.queryParams = {\n ...params,\n ...filterParams,\n limit,\n offset,\n search: searchText,\n ordering,\n }\n\n this.$emit('fetch-data', this.queryParams)\n\n fetchListRecords(model, this.queryParams)\n .then(response => {\n if (searchText === this.searchText) {\n this.items = response.results\n this.totalItems = response.count\n this.pages = Math.ceil(response.count / limit)\n this.errorMessage = response.error || ''\n }\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 onClickRecord(value, model) {\n if (this.openRecordsInNewTab) {\n const queryParams = {\n individual: 'bioModel',\n sample: 'bioModel',\n experiment: 'bioModel'\n }\n const queryParam = this.$get(queryParams, model, model)\n window.open(`/?${queryParam}=${value}`, '_blank')\n } else {\n this.$store.dispatch(SHOW_PANEL, {\n [model]: value\n })\n }\n },\n\n toggleColumnFilters() {\n this.showFilters = !this.showFilters\n if (!this.showFilters) {\n this.filterParams = {}\n this.fetchData()\n }\n },\n }\n}\n</script>\n\n<style lang=\"scss\">\n\n.isabl-base-card .v-data-table {\n th.column.sortable.active.desc button.sort-icon {\n transform: rotate(-180deg);\n }\n th.column.sortable.active button.sort-icon {\n color: var(--v-primary-base);\n }\n th.column.sortable button {\n font-size: 13px !important;\n margin-left: 4px;\n }\n .v-data-table__wrapper {\n max-height: 300px;\n overflow-y: auto;\n }\n .table-cell {\n height: 25px !important;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 300px;\n padding-left: 5px !important;\n .v-chip.v-size--small {\n height: 20px;\n }\n }\n tr.table-headers.table-cell {\n position: sticky;\n top: 0;\n background: white;\n cursor: pointer;\n height: 32px;\n z-index: 1;\n th {\n // border-bottom: thin solid rgba(0,0,0,.12);\n background: rgba(0,0,0,.04);\n }\n }\n &.theme--dark, &.theme--dark tr.table-headers.table-cell th {\n background: var(--v-surface-base);\n }\n &.theme--dark tr.column-filters th {\n background: var(--v-surface-base);\n }\n th.column.sortable {\n padding: 0px 5px;\n }\n tr.column-filters th {\n height: 32px;\n }\n .v-data-table__empty-wrapper>td {\n padding: 0px;\n }\n}\n\n.table-filter-input {\n min-width: 150px;\n .v-input__icon--append .v-icon {\n font-size: 14px;\n }\n input {\n font-size: 14px;\n font-weight: 400;\n padding-left: 6px !important;\n }\n label {\n font-size: 13px;\n padding-left: 6px;\n }\n}\n.column-filters {\n position: sticky;\n top: 25px;\n background: white;\n z-index: 1;\n .v-select {\n margin: 0px;\n .v-input__slot, input {\n height: 25px;\n }\n .v-icon {\n font-size: 16px;\n }\n }\n .v-select__selections {\n display: contents;\n max-width: 120px;\n font-size: 14px;\n font-weight: 400;\n span {\n padding: 0px;\n }\n }\n .v-text-field .v-input__append-inner {\n padding: 0px;\n }\n}\n\n.v-list .v-list-item {\n min-height: 25px;\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px 10px;\n }\n}\n\ndiv.v-list--dense .v-list-item {\n min-height: 25px;\n padding: 0px;\n .v-list-item__action {\n margin: 0px;\n padding: 0px 4px;\n }\n .v-list-item__title {\n font-size: 14px;\n font-weight: 400;\n }\n .v-list-item__content {\n padding: 0px;\n }\n}\n\n.v-select-list {\n overflow: hidden;\n}\n\n.v-menu__content:not(.v-autocomplete__content) {\n .v-list__tile {\n height: 23px;\n }\n}\ntable.v-table tbody tr {\n border: 0px !important;\n}\n\ntable.v-table thead {\n tr {\n height: 30px !important;\n }\n tr.v-datatable__progress {\n height: 0px !important;\n border-top: 1px solid rgba(0, 0, 0, 0.05);\n }\n th {\n padding-left: 5px !important;\n padding-right: 5px !important;\n }\n}\n\ndiv.v-data-table__actions {\n flex-wrap: nowrap;\n &__pagination {\n width: 100%;\n min-width: 170px;\n margin: 0 10px 0 10px;\n }\n &__select {\n white-space: normal;\n overflow: hidden;\n justify-content: flex-start;\n margin-right: 5px;\n max-width: 100px;\n .v-select {\n margin-left: 25px;\n margin-right: 0px;\n margin-top: 0px;\n margin-bottom: 0px;\n }\n }\n &__range-controls {\n width: 100%;\n }\n button {\n margin: 0px;\n margin-right: 5px;\n }\n}\n\n.section-toggle {\n cursor: pointer;\n}\n\n.isabl-base-card .v-data-footer {\n font-size: 12px;\n padding: 0px;\n div.v-select__selection {\n font-size: 12px;\n }\n div.v-select {\n margin: 4px 0px 4px 16px;\n }\n}\n.v-data-footer__select\n.v-menu__content .v-list-item {\n min-height: 25px;\n font-size: 14px;\n .v-list-item__content {\n padding: 0px;\n }\n}\n// Style taken from github\ncode.markdown-style {\n padding: 0.2em 0.4em;\n margin: 0;\n font-size: 85%;\n background-color: rgba(175,184,193,0.2);\n border-radius: 6px;\n color: #24292f;\n}\n\n.v-data-table .v-data-footer {\n .v-data-footer__select {\n margin-left: 0;\n margin-right: auto;\n }\n .v-data-footer__pagination {\n margin-left: auto;\n margin-right: auto;\n }\n .v-data-footer__icons-before {\n margin-left: auto;\n margin-right: 0;\n }\n .v-data-footer__icons-after {\n margin-left: 0;\n margin-right: 0;\n }\n}\n\n</style>\n"]
251048
251048
  },
251049
251049
  _coverageSchema: "43e27e138ebf9cfc5966b082cf9a028302ed4184",
251050
- hash: "235fafbf88a72a48e239d67dc7b99e287750338d"
251050
+ hash: "d785cc7739c0c8a3532fce89055018d808c250a9"
251051
251051
  };
251052
251052
  var coverage = global[gcv] || (global[gcv] = {});
251053
251053
 
@@ -251906,8 +251906,8 @@ var DataTablevue_type_style_index_0_lang_scss_ = __webpack_require__("7bec");
251906
251906
 
251907
251907
  var DataTable_component = normalizeComponent(
251908
251908
  table_DataTablevue_type_script_lang_js_,
251909
- DataTablevue_type_template_id_31c65eb2_render,
251910
- DataTablevue_type_template_id_31c65eb2_staticRenderFns,
251909
+ DataTablevue_type_template_id_57e40a80_render,
251910
+ DataTablevue_type_template_id_57e40a80_staticRenderFns,
251911
251911
  false,
251912
251912
  null,
251913
251913
  null,