@abi-software/map-side-bar 1.2.2 → 1.3.0

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.
@@ -1,457 +1,476 @@
1
- <template>
2
- <el-card :body-style="bodyStyle" class="content-card">
3
- <div slot="header" class="header">
4
- <context-card v-if="contextCardEntry && contextCardEnabled" :entry="contextCardEntry" />
5
- <el-input
6
- class="search-input"
7
- placeholder="Search"
8
- v-model="searchInput"
9
- @keyup.native="searchEvent"
10
- clearable
11
- @clear="clearSearchClicked"
12
- ></el-input>
13
- <el-button class="button" @click="searchEvent">Search</el-button>
14
- </div>
15
- <SearchFilters
16
- class="filters"
17
- ref="filtersRef"
18
- :entry="filterEntry"
19
- :envVars="envVars"
20
- @filterResults="filterUpdate"
21
- @numberPerPage="numberPerPageUpdate"
22
- @loading="filtersLoading"
23
- ></SearchFilters>
24
- <div class="content scrollbar" v-loading="loadingCards" ref="content">
25
- <div
26
- class="error-feedback"
27
- v-if="results.length === 0 && !loadingCards && !sciCrunchError"
28
- >No results found - Please change your search / filter criteria.</div>
29
- <div class="error-feedback" v-if="sciCrunchError">{{sciCrunchError}}</div>
30
- <div v-if="loadingScicrunch" class="loading-icon" v-loading="loadingScicrunch"></div>
31
- <div v-for="result in results" :key="result.id" class="step-item">
32
- <DatasetCard :entry="result" :envVars="envVars" @contextUpdate="contextCardUpdate"></DatasetCard>
33
- </div>
34
- <el-pagination
35
- class="pagination"
36
- :current-page.sync="page"
37
- hide-on-single-page
38
- large
39
- layout="prev, pager, next"
40
- :page-size="numberPerPage"
41
- :total="numberOfHits"
42
- @current-change="pageChange"
43
- ></el-pagination>
44
- </div>
45
- </el-card>
46
- </template>
47
-
48
-
49
- <script>
50
- /* eslint-disable no-alert, no-console */
51
- import Vue from "vue";
52
- import {
53
- Button,
54
- Card,
55
- Drawer,
56
- Icon,
57
- Input,
58
- Loading,
59
- Pagination
60
- } from "element-ui";
61
- import lang from "element-ui/lib/locale/lang/en";
62
- import locale from "element-ui/lib/locale";
63
- import SearchFilters from "./SearchFilters";
64
- import DatasetCard from "./DatasetCard";
65
- import ContextCard from "./ContextCard.vue";
66
-
67
- import {AlgoliaClient} from "../algolia/algolia.js";
68
- import {getFilters} from "../algolia/utils.js"
69
-
70
- locale.use(lang);
71
- Vue.use(Button);
72
- Vue.use(Card);
73
- Vue.use(Drawer);
74
- Vue.use(Icon);
75
- Vue.use(Input);
76
- Vue.use(Loading);
77
- Vue.use(Pagination);
78
-
79
- // handleErrors: A custom fetch error handler to recieve messages from the server
80
- // even when an error is found
81
- var handleErrors = async function(response) {
82
- if (!response.ok) {
83
- let parse = await response.json();
84
- if (parse) {
85
- throw new Error(parse.message);
86
- } else {
87
- throw new Error(response);
88
- }
89
- }
90
- return response;
91
- };
92
-
93
- var initial_state = {
94
- searchInput: "",
95
- lastSearch: "",
96
- results: [],
97
- numberOfHits: 0,
98
- filter: [],
99
- loadingCards: false,
100
- numberPerPage: 10,
101
- page: 1,
102
- pageModel: 1,
103
- start: 0,
104
- hasSearched: false,
105
- sciCrunchError: false,
106
- contextCardEntry: undefined,
107
- contextCardEnabled: true,
108
- loadingScicrunch: false,
109
- };
110
-
111
- export default {
112
- components: { SearchFilters, DatasetCard, ContextCard },
113
- name: "SideBarContent",
114
- props: {
115
- visible: {
116
- type: Boolean,
117
- default: false
118
- },
119
- isDrawer: {
120
- type: Boolean,
121
- default: true
122
- },
123
- entry: {
124
- type: Object,
125
- default: () => initial_state
126
- },
127
- envVars: {
128
- type: Object,
129
- default: () => {}
130
- },
131
- firstSearch: {
132
- type: String,
133
- default: ""
134
- }
135
- },
136
- data: function() {
137
- return {
138
- ...this.entry,
139
- bodyStyle: {
140
- flex: "1 1 auto",
141
- "flex-flow": "column",
142
- display: "flex"
143
- }
144
- };
145
- },
146
- computed: {
147
- // This computed property populates filter data's entry object with $data from this sidebar
148
- filterEntry: function() {
149
- return {
150
- numberOfHits: this.numberOfHits,
151
- filterFacets: this.filter
152
- };
153
- }
154
- },
155
- methods: {
156
- contextCardUpdate: function(val){
157
- this.contextCardEntry = val
158
- },
159
- openSearch: function(filter, search='') {
160
- this.searchInput = search;
161
- this.resetPageNavigation();
162
- this.searchAlgolia(filter, search);
163
- if (filter) {
164
- this.filter = [...filter];
165
- this.$refs.filtersRef.setCascader(this.filter);
166
- }
167
- },
168
- addFilter: function(filter) {
169
- this.resetPageNavigation();
170
- if (filter) {
171
- this.$refs.filtersRef.addFilter(filter);
172
- this.$refs.filtersRef.initiateSearch()
173
- }
174
- },
175
- clearSearchClicked: function() {
176
- this.searchInput = "";
177
- this.resetPageNavigation();
178
- this.searchAlgolia(this.filters, this.searchInput);
179
- },
180
- searchEvent: function(event = false) {
181
- if (event.keyCode === 13 || event instanceof MouseEvent) {
182
- this.resetPageNavigation();
183
- this.searchAlgolia(this.filters, this.searchInput);
184
- }
185
- },
186
- filterUpdate: function(filters) {
187
- this.filters = [...filters]
188
- this.resetPageNavigation()
189
- this.searchAlgolia(filters, this.searchInput)
190
- this.$emit("search-changed", {
191
- value: filters,
192
- type: "filter-update"
193
- });
194
- },
195
- searchAlgolia(filters, query=''){
196
- // Algolia search
197
- this.algoliaClient.search(getFilters(filters), query, this.numberPerPage, this.page).then(searchData => {
198
- this.numberOfHits = searchData.total
199
- this.discoverIds = searchData.discoverIds
200
- this.dois = searchData.dois
201
- this.results = searchData.items
202
- this.loadingCards = false
203
- this.searchSciCrunch({'dois': this.dois})
204
- })
205
- },
206
- filtersLoading: function (val) {
207
- this.loadingCards = val;
208
- },
209
- numberPerPageUpdate: function(val) {
210
- this.numberPerPage = val;
211
- this.pageChange(1);
212
- },
213
- pageChange: function(page) {
214
- this.start = (page - 1) * this.numberPerPage;
215
- this.page = page
216
- this.searchAlgolia(this.filters, this.searchInput, this.numberPerPage, this.page)
217
- },
218
- searchSciCrunch: function(params) {
219
- this.loadingScicrunch = true
220
- this.scrollToTop();
221
- this.$emit("search-changed", { value: this.searchInput, type: "query-update" });
222
- this.callSciCrunch(this.envVars.API_LOCATION, params)
223
- .then(result => {
224
- //Only process if the search term is the same as the last search term.
225
- //This avoid old search being displayed.
226
- this.sciCrunchError = false;
227
- this.resultsProcessing(result);
228
- this.$refs.content.style["overflow-y"] = "scroll";
229
- this.loadingCards = false;
230
- this.loadingScicrunch = false
231
- })
232
- .catch(result => {
233
- if (result.name !== 'AbortError') {
234
- this.loadingCards = false;
235
- this.loadingScicrunch = false
236
- this.sciCrunchError = result.message;
237
- }
238
- })
239
- },
240
- scrollToTop: function() {
241
- if (this.$refs.content) {
242
- this.$refs.content.scroll({ top: 0, behavior: "smooth" });
243
- }
244
- },
245
- resetPageNavigation: function() {
246
- this.start = 0;
247
- this.page = 1;
248
- },
249
- resultsProcessing: function(data) {
250
- this.lastSearch = this.searchInput;
251
-
252
- if (data.results.length === 0) {
253
- return;
254
- }
255
- data.results.forEach(element => {
256
-
257
- // match the scicrunch result with algolia result
258
- let i = this.results.findIndex(res=> res.name === element.name)
259
-
260
-
261
- // Assign scicrunch results to the object
262
- Object.assign(this.results[i], element)
263
-
264
- // Assign the attributes that need some processing
265
- Object.assign(this.results[i],{
266
- numberSamples: element.sampleSize
267
- ? parseInt(element.sampleSize)
268
- : 0,
269
- numberSubjects: element.subjectSize
270
- ? parseInt(element.subjectSize)
271
- : 0,
272
- updated: element.updated[0].timestamp.split("T")[0],
273
- url: element.uri[0],
274
- datasetId: element.identifier,
275
- organs: (element.organs && element.organs.length > 0)
276
- ? [...new Set(element.organs.map(v => v.name))]
277
- : undefined,
278
- species: element.organisms
279
- ? element.organisms[0].species
280
- ? [...new Set(element.organisms.map((v) =>v.species ? v.species.name : null))]
281
- : undefined
282
- : undefined, // This processing only includes each gender once into 'sexes'
283
- scaffolds: element['abi-scaffold-metadata-file'] ? element['abi-scaffold-metadata-file'] : undefined,
284
- contextualInformation: element['abi-contextual-information'].length > 0 ? element['abi-contextual-information'] : undefined,
285
- simulation: element['abi-simulation-file'],
286
- });
287
-
288
- Vue.set(this.results, i, this.results[i])
289
- });
290
- },
291
- createfilterParams: function(params) {
292
- let p = new URLSearchParams();
293
- //Check if field is array or value
294
- for (const key in params) {
295
- if (Array.isArray(params[key])) {
296
- params[key].forEach(e => {
297
- p.append(key, e);
298
- });
299
- } else {
300
- p.append(key, params[key]);
301
- }
302
- }
303
- return p.toString();
304
- },
305
- callSciCrunch: function(apiLocation, params = {}) {
306
- return new Promise((resolve, reject) => {
307
- // the following controller will abort current search
308
- // if a new one has been started
309
- if (this._controller) this._controller.abort();
310
- this._controller = new AbortController();
311
- let signal = this._controller.signal;
312
- // Add parameters if we are sent them
313
- let fullEndpoint = this.envVars.API_LOCATION + this.searchEndpoint + "?" + this.createfilterParams(params);
314
- fetch(fullEndpoint, { signal })
315
- .then(handleErrors)
316
- .then(response => response.json())
317
- .then(data => resolve(data))
318
- .catch(data => reject(data));
319
- });
320
- }
321
- },
322
- mounted: function() {
323
- // initialise algolia
324
- this.algoliaClient = new AlgoliaClient(this.envVars.ALGOLIA_ID, this.envVars.ALGOLIA_KEY, this.envVars.PENNSIEVE_API_LOCATION);
325
- this.algoliaClient.initIndex(this.envVars.ALGOLIA_INDEX);
326
- console.log('Algolia initialised in sidebar')
327
-
328
- // temporarily disable flatmap search since there are no datasets
329
- if (this.firstSearch === "Flatmap" || this.firstSearch === "flatmap") {
330
- this.openSearch(undefined, '')
331
- } else {
332
- this.openSearch(undefined, '');
333
- }
334
- },
335
- created: function() {
336
- //Create non-reactive local variables
337
- this.searchEndpoint = "dataset_info/using_multiple_dois/";
338
- }
339
- };
340
- </script>
341
-
342
- <!-- Add "scoped" attribute to limit CSS to this component only -->
343
- <style scoped>
344
- .content-card {
345
- height: 100%;
346
- flex-flow: column;
347
- display: flex;
348
- }
349
-
350
- .button {
351
- background-color: #8300bf;
352
- border: #8300bf;
353
- color: white;
354
- }
355
-
356
- .step-item {
357
- font-size: 14px;
358
- margin-bottom: 18px;
359
- text-align: left;
360
- }
361
-
362
- .search-input {
363
- width: 298px !important;
364
- height: 40px;
365
- padding-right: 14px;
366
- align-items: left;
367
- }
368
-
369
- .header {
370
- border: solid 1px #292b66;
371
- background-color: #292b66;
372
- text-align: left;
373
- }
374
-
375
- .pagination {
376
- padding-bottom: 16px;
377
- background-color: white;
378
- text-align: center;
379
- }
380
-
381
- .loading-icon {
382
- position: absolute;
383
- display: flex;
384
- float: right;
385
- right: 40px;
386
- z-index: 20;
387
- width: 40px;
388
- height: 40px;
389
- }
390
-
391
- .loading-icon >>> .el-loading-mask {
392
- background-color: rgba(117, 190, 218, 0.0) !important;
393
- }
394
-
395
- .pagination >>> button {
396
- background-color: white !important;
397
- }
398
- .pagination >>> li {
399
- background-color: white !important;
400
- }
401
- .pagination >>> li.active {
402
- color: #8300bf;
403
- }
404
-
405
- .error-feedback {
406
- font-family: Asap;
407
- font-size: 14px;
408
- font-style: italic;
409
- padding-top: 15px;
410
- }
411
-
412
- .content-card >>> .el-card__header {
413
- background-color: #292b66;
414
- border: solid 1px #292b66;
415
- }
416
-
417
- .content-card >>> .el-card__body {
418
- background-color: #f7faff;
419
- overflow-y: hidden;
420
- }
421
-
422
- .content {
423
- width: 518px;
424
- flex: 1 1 auto;
425
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
426
- border: solid 1px #e4e7ed;
427
- background-color: #ffffff;
428
- overflow-y: scroll;
429
- scrollbar-width: thin;
430
- }
431
-
432
- .scrollbar::-webkit-scrollbar-track {
433
- border-radius: 10px;
434
- background-color: #f5f5f5;
435
- }
436
-
437
- .scrollbar::-webkit-scrollbar {
438
- width: 12px;
439
- right: -12px;
440
- background-color: #f5f5f5;
441
- }
442
-
443
- .scrollbar::-webkit-scrollbar-thumb {
444
- border-radius: 4px;
445
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.06);
446
- background-color: #979797;
447
- }
448
-
449
- >>> .el-input__suffix {
450
- padding-right: 10px;
451
- }
452
-
453
- >>> .my-drawer {
454
- background: rgba(0, 0, 0, 0);
455
- box-shadow: none;
456
- }
457
- </style>
1
+ <template>
2
+ <el-card :body-style="bodyStyle" class="content-card">
3
+ <div slot="header" class="header">
4
+ <context-card v-if="contextCardEntry && contextCardEnabled" :entry="contextCardEntry" />
5
+ <el-input
6
+ class="search-input"
7
+ placeholder="Search"
8
+ v-model="searchInput"
9
+ @keyup.native="searchEvent"
10
+ clearable
11
+ @clear="clearSearchClicked"
12
+ ></el-input>
13
+ <el-button class="button" @click="searchEvent">Search</el-button>
14
+ </div>
15
+ <SearchFilters
16
+ class="filters"
17
+ ref="filtersRef"
18
+ :entry="filterEntry"
19
+ :envVars="envVars"
20
+ @filterResults="filterUpdate"
21
+ @numberPerPage="numberPerPageUpdate"
22
+ @loading="filtersLoading"
23
+ ></SearchFilters>
24
+ <div class="content scrollbar" v-loading="loadingCards" ref="content">
25
+ <div
26
+ class="error-feedback"
27
+ v-if="results.length === 0 && !loadingCards"
28
+ >No results found - Please change your search / filter criteria.</div>
29
+ <div v-for="result in results" :key="result.doi" class="step-item">
30
+ <DatasetCard :entry="result" :envVars="envVars" @contextUpdate="contextCardUpdate"></DatasetCard>
31
+ </div>
32
+ <el-pagination
33
+ class="pagination"
34
+ :current-page.sync="page"
35
+ hide-on-single-page
36
+ large
37
+ layout="prev, pager, next"
38
+ :page-size="numberPerPage"
39
+ :total="numberOfHits"
40
+ @current-change="pageChange"
41
+ ></el-pagination>
42
+ </div>
43
+ </el-card>
44
+ </template>
45
+
46
+
47
+ <script>
48
+ /* eslint-disable no-alert, no-console */
49
+ import Vue from "vue";
50
+ import {
51
+ Button,
52
+ Card,
53
+ Drawer,
54
+ Icon,
55
+ Input,
56
+ Loading,
57
+ Pagination
58
+ } from "element-ui";
59
+ import lang from "element-ui/lib/locale/lang/en";
60
+ import locale from "element-ui/lib/locale";
61
+ import SearchFilters from "./SearchFilters";
62
+ import DatasetCard from "./DatasetCard";
63
+ import ContextCard from "./ContextCard.vue";
64
+
65
+ import {AlgoliaClient} from "../algolia/algolia.js";
66
+ import {getFilters} from "../algolia/utils.js"
67
+
68
+ locale.use(lang);
69
+ Vue.use(Button);
70
+ Vue.use(Card);
71
+ Vue.use(Drawer);
72
+ Vue.use(Icon);
73
+ Vue.use(Input);
74
+ Vue.use(Loading);
75
+ Vue.use(Pagination);
76
+
77
+ // handleErrors: A custom fetch error handler to recieve messages from the server
78
+ // even when an error is found
79
+ var handleErrors = async function(response) {
80
+ if (!response.ok) {
81
+ let parse = await response.json();
82
+ if (parse) {
83
+ throw new Error(parse.message);
84
+ } else {
85
+ throw new Error(response);
86
+ }
87
+ }
88
+ return response;
89
+ };
90
+
91
+ var initial_state = {
92
+ searchInput: "",
93
+ lastSearch: "",
94
+ results: [],
95
+ numberOfHits: 0,
96
+ filter: [],
97
+ loadingCards: false,
98
+ numberPerPage: 10,
99
+ page: 1,
100
+ pageModel: 1,
101
+ start: 0,
102
+ hasSearched: false,
103
+ contextCardEntry: undefined,
104
+ contextCardEnabled: true,
105
+ };
106
+
107
+ export default {
108
+ components: { SearchFilters, DatasetCard, ContextCard },
109
+ name: "SideBarContent",
110
+ props: {
111
+ visible: {
112
+ type: Boolean,
113
+ default: false
114
+ },
115
+ isDrawer: {
116
+ type: Boolean,
117
+ default: true
118
+ },
119
+ entry: {
120
+ type: Object,
121
+ default: () => initial_state
122
+ },
123
+ envVars: {
124
+ type: Object,
125
+ default: () => {}
126
+ },
127
+ firstSearch: {
128
+ type: String,
129
+ default: ""
130
+ }
131
+ },
132
+ data: function() {
133
+ return {
134
+ ...this.entry,
135
+ bodyStyle: {
136
+ flex: "1 1 auto",
137
+ "flex-flow": "column",
138
+ display: "flex"
139
+ }
140
+ };
141
+ },
142
+ computed: {
143
+ // This computed property populates filter data's entry object with $data from this sidebar
144
+ filterEntry: function() {
145
+ return {
146
+ numberOfHits: this.numberOfHits,
147
+ filterFacets: this.filter
148
+ };
149
+ }
150
+ },
151
+ methods: {
152
+ contextCardUpdate: function(val){
153
+ this.contextCardEntry = val
154
+ },
155
+ openSearch: function(filter, search='') {
156
+ this.searchInput = search;
157
+ this.resetPageNavigation();
158
+ this.searchAlgolia(filter, search);
159
+ if (filter) {
160
+ this.filter = [...filter];
161
+ this.$refs.filtersRef.setCascader(this.filter);
162
+ }
163
+ },
164
+ addFilter: function(filter) {
165
+ this.resetPageNavigation();
166
+ if (filter) {
167
+ this.$refs.filtersRef.addFilter(filter);
168
+ this.$refs.filtersRef.initiateSearch()
169
+ }
170
+ },
171
+ clearSearchClicked: function() {
172
+ this.searchInput = "";
173
+ this.resetPageNavigation();
174
+ this.searchAlgolia(this.filters, this.searchInput);
175
+ },
176
+ searchEvent: function(event = false) {
177
+ if (event.keyCode === 13 || event instanceof MouseEvent) {
178
+ this.resetPageNavigation();
179
+ this.searchAlgolia(this.filters, this.searchInput);
180
+ }
181
+ },
182
+ filterUpdate: function(filters) {
183
+ this.filters = [...filters]
184
+ this.resetPageNavigation()
185
+ this.searchAlgolia(filters, this.searchInput)
186
+ this.$emit("search-changed", {
187
+ value: filters,
188
+ type: "filter-update"
189
+ });
190
+ },
191
+ searchAlgolia(filters, query=''){
192
+ // Algolia search
193
+ this.loadingCards = true
194
+ this.algoliaClient.search(getFilters(filters), query, this.numberPerPage, this.page).then(searchData => {
195
+ this.numberOfHits = searchData.total
196
+ this.discoverIds = searchData.discoverIds
197
+ this._dois = searchData.dois
198
+ this.results = searchData.items
199
+ this.loadingCards = false
200
+ this.scrollToTop()
201
+ this.$emit("search-changed", { value: this.searchInput, type: "query-update" })
202
+ if (this._abortController)
203
+ this._abortController.abort()
204
+ this._abortController = new AbortController()
205
+ const signal = this._abortController.signal
206
+ //Search ongoing, let the current flow progress
207
+ this.perItemSearch(signal, { count: 0 })
208
+ })
209
+ },
210
+ filtersLoading: function (val) {
211
+ this.loadingCards = val;
212
+ },
213
+ numberPerPageUpdate: function(val) {
214
+ this.numberPerPage = val;
215
+ this.pageChange(1);
216
+ },
217
+ pageChange: function(page) {
218
+ this.start = (page - 1) * this.numberPerPage;
219
+ this.page = page
220
+ this.searchAlgolia(this.filters, this.searchInput, this.numberPerPage, this.page)
221
+ },
222
+ handleMissingData: function(doi) {
223
+ let i = this.results.findIndex(res=> res.doi === doi)
224
+ if (this.results[i])
225
+ this.results[i].detailsReady = true;
226
+ },
227
+ perItemSearch: function(signal, data) {
228
+ //Maximum 10 downloads at once to prevent long waiting time
229
+ //between unfinished search and new search
230
+ const maxDownloads = 10;
231
+ if (maxDownloads > data.count) {
232
+ const doi = this._dois.shift();
233
+ if (doi) {
234
+ data.count++;
235
+ this.callSciCrunch(this.envVars.API_LOCATION, {'dois': [doi]}, signal)
236
+ .then(result => {
237
+ if (result.numberOfHits === 0)
238
+ this.handleMissingData(doi);
239
+ else
240
+ this.resultsProcessing(result);
241
+ this.$refs.content.style["overflow-y"] = "scroll";
242
+ data.count--;
243
+ //Async::Download finished, get the next one
244
+ this.perItemSearch(signal, data);
245
+ })
246
+ .catch(result => {
247
+ if (result.name !== 'AbortError') {
248
+ this.handleMissingData(doi);
249
+ data.count--;
250
+ //Async::Download not aborted, get the next one
251
+ this.perItemSearch(signal, data);
252
+ }
253
+ });
254
+ //Check and make another request until it gets to max downloads
255
+ this.perItemSearch(signal, data);
256
+ }
257
+ }
258
+ },
259
+ scrollToTop: function() {
260
+ if (this.$refs.content) {
261
+ this.$refs.content.scroll({ top: 0, behavior: "smooth" });
262
+ }
263
+ },
264
+ resetPageNavigation: function() {
265
+ this.start = 0;
266
+ this.page = 1;
267
+ },
268
+ resultsProcessing: function(data) {
269
+ this.lastSearch = this.searchInput;
270
+
271
+ if (data.results.length === 0) {
272
+ return;
273
+ }
274
+ data.results.forEach(element => {
275
+ // match the scicrunch result with algolia result
276
+ let i = this.results.findIndex(res=> res.name === element.name)
277
+ // Assign scicrunch results to the object
278
+ Object.assign(this.results[i], element)
279
+ // Assign the attributes that need some processing
280
+ Object.assign(this.results[i],{
281
+ numberSamples: element.sampleSize
282
+ ? parseInt(element.sampleSize)
283
+ : 0,
284
+ numberSubjects: element.subjectSize
285
+ ? parseInt(element.subjectSize)
286
+ : 0,
287
+ updated: element.updated[0].timestamp.split("T")[0],
288
+ url: element.uri[0],
289
+ datasetId: element.dataset_identifier,
290
+ datasetRevision: element.dataset_revision,
291
+ datasetVersion: element.dataset_version,
292
+ organs: (element.organs && element.organs.length > 0)
293
+ ? [...new Set(element.organs.map(v => v.name))]
294
+ : undefined,
295
+ species: element.organisms
296
+ ? element.organisms[0].species
297
+ ? [...new Set(element.organisms.map((v) =>v.species ? v.species.name : null))]
298
+ : undefined
299
+ : undefined, // This processing only includes each gender once into 'sexes'
300
+ scaffolds: element['abi-scaffold-metadata-file'],
301
+ thumbnails: element['abi-thumbnail'] ? element['abi-thumbnail']: element['abi-scaffold-thumbnail'],
302
+ scaffoldViews: element['abi-scaffold-view-file'],
303
+ videos: element.video,
304
+ plots: element['abi-plot'],
305
+ images: element['common-images'],
306
+ contextualInformation: element['abi-contextual-information'].length > 0 ? element['abi-contextual-information'] : undefined,
307
+ segmentation: element['mbf-segmentation'],
308
+ simulation: element['abi-simulation-file'],
309
+ additionalLinks: element.additionalLinks,
310
+ detailsReady: true,
311
+ })
312
+ Vue.set(this.results, i, this.results[i])
313
+ });
314
+ },
315
+ createfilterParams: function(params) {
316
+ let p = new URLSearchParams();
317
+ //Check if field is array or value
318
+ for (const key in params) {
319
+ if (Array.isArray(params[key])) {
320
+ params[key].forEach(e => {
321
+ p.append(key, e);
322
+ });
323
+ } else {
324
+ p.append(key, params[key]);
325
+ }
326
+ }
327
+ return p.toString();
328
+ },
329
+ callSciCrunch: function(apiLocation, params = {}, signal) {
330
+ return new Promise((resolve, reject) => {
331
+ // Add parameters if we are sent them
332
+ let fullEndpoint = this.envVars.API_LOCATION + this.searchEndpoint + "?" + this.createfilterParams(params);
333
+ fetch(fullEndpoint, {signal})
334
+ .then(handleErrors)
335
+ .then(response => response.json())
336
+ .then(data => resolve(data))
337
+ .catch(data => reject(data));
338
+ });
339
+ },
340
+ },
341
+ mounted: function() {
342
+ // initialise algolia
343
+ this.algoliaClient = new AlgoliaClient(this.envVars.ALGOLIA_ID, this.envVars.ALGOLIA_KEY, this.envVars.PENNSIEVE_API_LOCATION);
344
+ this.algoliaClient.initIndex(this.envVars.ALGOLIA_INDEX);
345
+
346
+ // temporarily disable flatmap search since there are no datasets
347
+ if (this.firstSearch === "Flatmap" || this.firstSearch === "flatmap") {
348
+ this.openSearch(undefined, '')
349
+ } else {
350
+ this.openSearch(undefined, '');
351
+ }
352
+ },
353
+ created: function() {
354
+ //Create non-reactive local variables
355
+ this.searchEndpoint = "dataset_info/using_multiple_dois/";
356
+ }
357
+ };
358
+ </script>
359
+
360
+ <!-- Add "scoped" attribute to limit CSS to this component only -->
361
+ <style scoped>
362
+ .content-card {
363
+ height: 100%;
364
+ flex-flow: column;
365
+ display: flex;
366
+ }
367
+
368
+ .button {
369
+ background-color: #8300bf;
370
+ border: #8300bf;
371
+ color: white;
372
+ }
373
+
374
+ .step-item {
375
+ font-size: 14px;
376
+ margin-bottom: 18px;
377
+ text-align: left;
378
+ }
379
+
380
+ .search-input {
381
+ width: 298px !important;
382
+ height: 40px;
383
+ padding-right: 14px;
384
+ align-items: left;
385
+ }
386
+
387
+ .header {
388
+ border: solid 1px #292b66;
389
+ background-color: #292b66;
390
+ text-align: left;
391
+ }
392
+
393
+ .pagination {
394
+ padding-bottom: 16px;
395
+ background-color: white;
396
+ text-align: center;
397
+ }
398
+
399
+ .pagination >>> button {
400
+ background-color: white !important;
401
+ }
402
+ .pagination >>> li {
403
+ background-color: white !important;
404
+ }
405
+ .pagination >>> li.active {
406
+ color: #8300bf;
407
+ }
408
+
409
+ .error-feedback {
410
+ font-family: Asap;
411
+ font-size: 14px;
412
+ font-style: italic;
413
+ padding-top: 15px;
414
+ }
415
+
416
+ .content-card >>> .el-card__header {
417
+ background-color: #292b66;
418
+ border: solid 1px #292b66;
419
+ }
420
+
421
+ .content-card >>> .el-card__body {
422
+ background-color: #f7faff;
423
+ overflow-y: hidden;
424
+ }
425
+
426
+ .content {
427
+ width: 518px;
428
+ flex: 1 1 auto;
429
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
430
+ border: solid 1px #e4e7ed;
431
+ background-color: #ffffff;
432
+ overflow-y: scroll;
433
+ scrollbar-width: thin;
434
+ }
435
+
436
+ .content >>> .el-loading-spinner .path {
437
+ stroke: #8300bf;
438
+ }
439
+
440
+ .content >>> .step-item:first-child .seperator-path{
441
+ display: none;
442
+ }
443
+
444
+ .content >>> .step-item:not(:first-child) .seperator-path{
445
+ width: 486px;
446
+ height: 0px;
447
+ border: solid 1px #e4e7ed;
448
+ background-color: #e4e7ed;
449
+ }
450
+
451
+ .scrollbar::-webkit-scrollbar-track {
452
+ border-radius: 10px;
453
+ background-color: #f5f5f5;
454
+ }
455
+
456
+ .scrollbar::-webkit-scrollbar {
457
+ width: 12px;
458
+ right: -12px;
459
+ background-color: #f5f5f5;
460
+ }
461
+
462
+ .scrollbar::-webkit-scrollbar-thumb {
463
+ border-radius: 4px;
464
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.06);
465
+ background-color: #979797;
466
+ }
467
+
468
+ >>> .el-input__suffix {
469
+ padding-right: 10px;
470
+ }
471
+
472
+ >>> .my-drawer {
473
+ background: rgba(0, 0, 0, 0);
474
+ box-shadow: none;
475
+ }
476
+ </style>