@abi-software/map-side-bar 2.7.2 → 2.7.3-beta.1

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.
@@ -0,0 +1,615 @@
1
+ <template>
2
+ <el-card :body-style="bodyStyle" class="content-card">
3
+ <template #header>
4
+ <div class="header">
5
+ <el-input
6
+ class="search-input"
7
+ placeholder="Search"
8
+ v-model="searchInput"
9
+ @keyup="searchEvent"
10
+ clearable
11
+ @clear="clearSearchClicked"
12
+ ></el-input>
13
+ <el-button
14
+ type="primary"
15
+ class="button"
16
+ @click="searchEvent"
17
+ size="large"
18
+ >
19
+ Search
20
+ </el-button>
21
+ <el-button
22
+ link
23
+ class="el-button-link"
24
+ @click="openSearch([], '')"
25
+ size="large"
26
+ >
27
+ Reset
28
+ </el-button>
29
+ </div>
30
+ </template>
31
+ <SearchFilters
32
+ class="filters"
33
+ ref="filtersRef"
34
+ :entry="filterEntry"
35
+ :envVars="envVars"
36
+ @filterResults="filterUpdate"
37
+ @numberPerPage="numberPerPageUpdate"
38
+ @loading="filtersLoading"
39
+ @cascaderReady="cascaderReady"
40
+ ></SearchFilters>
41
+ <SearchHistory
42
+ ref="searchHistory"
43
+ localStorageKey="sparc.science-connectivity-search-history"
44
+ @search="searchHistorySearch"
45
+ ></SearchHistory>
46
+ <div
47
+ class="content scrollbar"
48
+ v-loading="loadingCards || initLoading"
49
+ ref="content"
50
+ @mouseleave="hoverChanged(undefined)"
51
+ >
52
+ <div class="error-feedback" v-if="results.length === 0 && !loadingCards">
53
+ No results found - Please change your search / filter criteria.
54
+ </div>
55
+ <div
56
+ v-for="result in paginatedResults"
57
+ :key="result.id"
58
+ :ref="'stepItem-' + result.id"
59
+ class="step-item"
60
+ :class="{
61
+ 'is-active': expanded === result.id && result.loaded,
62
+ 'is-loading': expanded === result.id && !result.loaded,
63
+ }"
64
+ @mouseenter="hoverChanged(result)"
65
+ >
66
+ <ConnectivityCard
67
+ class="dataset-card"
68
+ :entry="result"
69
+ @connectivity-explorer-clicked="onConnectivityExplorerClicked"
70
+ />
71
+ <ConnectivityInfo
72
+ v-if="expanded === result.id"
73
+ :connectivityEntry="connectivityEntry"
74
+ :entryId="result.id"
75
+ :availableAnatomyFacets="availableAnatomyFacets"
76
+ :envVars="envVars"
77
+ :withCloseButton="true"
78
+ @show-connectivity="$emit('show-connectivity', $event)"
79
+ @show-reference-connectivities="$emit('show-reference-connectivities', $event)"
80
+ @connectivity-clicked="onConnectivityClicked"
81
+ @connectivity-hovered="$emit('connectivity-hovered', $event)"
82
+ @loaded="onConnectivityInfoLoaded(result)"
83
+ @close-connectivity="toggleConnectivityOpen(result)"
84
+ />
85
+ </div>
86
+ <el-pagination
87
+ class="pagination"
88
+ v-model:current-page="page"
89
+ hide-on-single-page
90
+ large
91
+ layout="prev, pager, next"
92
+ :page-size="numberPerPage"
93
+ :total="numberOfHits"
94
+ @current-change="pageChange"
95
+ ></el-pagination>
96
+ </div>
97
+ </el-card>
98
+ </template>
99
+
100
+ <script>
101
+ /* eslint-disable no-alert, no-console */
102
+ import {
103
+ ElButton as Button,
104
+ ElCard as Card,
105
+ ElIcon as Icon,
106
+ ElInput as Input,
107
+ ElPagination as Pagination,
108
+ } from "element-plus";
109
+ import SearchFilters from "./SearchFilters.vue";
110
+ import SearchHistory from "./SearchHistory.vue";
111
+ import ConnectivityCard from "./ConnectivityCard.vue";
112
+ import ConnectivityInfo from "./ConnectivityInfo.vue";
113
+
114
+ var initial_state = {
115
+ filters: [],
116
+ searchInput: "",
117
+ lastSearch: "",
118
+ results: [],
119
+ numberOfHits: 0,
120
+ filter: [],
121
+ loadingCards: false,
122
+ numberPerPage: 10,
123
+ page: 1,
124
+ start: 0,
125
+ };
126
+
127
+ export default {
128
+ components: {
129
+ SearchFilters,
130
+ SearchHistory,
131
+ ConnectivityCard,
132
+ ConnectivityInfo,
133
+ Button,
134
+ Card,
135
+ Icon,
136
+ Input,
137
+ Pagination,
138
+ },
139
+ name: "ConnectivityExplorer",
140
+ props: {
141
+ connectivityKnowledge: {
142
+ type: Array,
143
+ default: [],
144
+ },
145
+ entry: {
146
+ type: Object,
147
+ default: () => initial_state,
148
+ },
149
+ envVars: {
150
+ type: Object,
151
+ default: () => {},
152
+ },
153
+ connectivityEntry: {
154
+ type: Array,
155
+ default: [],
156
+ },
157
+ availableAnatomyFacets: {
158
+ type: Object,
159
+ default: [],
160
+ },
161
+ },
162
+ data: function () {
163
+ return {
164
+ ...this.entry,
165
+ bodyStyle: {
166
+ flex: "1 1 auto",
167
+ "flex-flow": "column",
168
+ display: "flex",
169
+ },
170
+ filterOptions: [
171
+ {
172
+ id: 3,
173
+ key: "flatmap.connectivity.source",
174
+ label: "Connectivity",
175
+ children: [
176
+ {
177
+ facetPropPath: "flatmap.connectivity.source",
178
+ id: 0,
179
+ label: "Origins",
180
+ },
181
+ {
182
+ facetPropPath: "flatmap.connectivity.source",
183
+ id: 1,
184
+ label: "Components",
185
+ },
186
+ {
187
+ facetPropPath: "flatmap.connectivity.source",
188
+ id: 2,
189
+ label: "Destinations",
190
+ },
191
+ ],
192
+ },
193
+ ],
194
+ cascaderIsReady: false,
195
+ displayConnectivity: false,
196
+ initLoading: true,
197
+ expanded: ""
198
+ };
199
+ },
200
+ computed: {
201
+ // This computed property populates filter data's entry object with $data from this sidebar
202
+ filterEntry: function () {
203
+ return {
204
+ numberOfHits: this.numberOfHits,
205
+ filterFacets: this.filter,
206
+ options: this.filterOptions,
207
+ showFilters: false
208
+ };
209
+ },
210
+ paginatedResults: function () {
211
+ return this.results.slice(this.start, this.start + this.numberPerPage);
212
+ },
213
+ },
214
+ watch: {
215
+ connectivityKnowledge: function (value) {
216
+ this.expanded = "";
217
+ this.results = value.map((item) => {
218
+ return {
219
+ ...item,
220
+ loaded: false,
221
+ };
222
+ });
223
+
224
+ this.numberOfHits = this.results.length;
225
+ this.initLoading = false;
226
+ this.loadingCards = false;
227
+
228
+ if (this.numberOfHits === 1) {
229
+ this.onConnectivityExplorerClicked(this.results[0]);
230
+ }
231
+ },
232
+ paginatedResults: function () {
233
+ this.loadingCards = false;
234
+ },
235
+ },
236
+ methods: {
237
+ onConnectivityClicked: function (data) {
238
+ this.searchInput = data.query;
239
+ this.filters = data.filter;
240
+ this.searchAndFilterUpdate();
241
+ },
242
+ toggleConnectivityOpen: function (data) {
243
+ if (this.expanded === data.id) {
244
+ this.expanded = "";
245
+ } else {
246
+ this.expanded = data.id;
247
+ }
248
+ },
249
+ onConnectivityExplorerClicked: function (data) {
250
+ data.loaded = false; // reset loading
251
+ this.toggleConnectivityOpen(data);
252
+ const entry = this.connectivityEntry.filter(entry => entry.featureId[0] === data.id);
253
+ if (entry.length === 0) {
254
+ this.$emit("connectivity-explorer-clicked", data);
255
+ }
256
+ },
257
+ hoverChanged: function (data) {
258
+ const payload = data ? { ...data, type: "connectivity" } : data;
259
+ this.$emit("hover-changed", payload);
260
+ },
261
+ resetSearch: function () {
262
+ this.numberOfHits = 0;
263
+ this.results = [];
264
+ this.loadingCards = false;
265
+ },
266
+ openSearch: function (filter, search = "", option = { withSearch: true }) {
267
+ this.searchInput = search;
268
+ this.resetPageNavigation();
269
+ //Proceed normally if cascader is ready
270
+ if (this.cascaderIsReady) {
271
+ this.filter =
272
+ this.$refs.filtersRef.getHierarchicalValidatedFilters(filter);
273
+ //Facets provided but cannot find at least one valid
274
+ //facet. Tell the users the search is invalid and reset
275
+ //facets check boxes.
276
+ if (
277
+ filter &&
278
+ filter.length > 0 &&
279
+ this.filter &&
280
+ this.filter.length === 0
281
+ ) {
282
+ this.$refs.filtersRef.checkShowAllBoxes();
283
+ this.resetSearch();
284
+ } else if (this.filter) {
285
+ if (option.withSearch) {
286
+ this.searchKnowledge(this.filter, search);
287
+ }
288
+ this.$refs.filtersRef.setCascader(this.filter);
289
+ }
290
+ } else {
291
+ //cascader is not ready, perform search if no filter is set,
292
+ //otherwise waith for cascader to be ready
293
+ this.filter = filter;
294
+ if ((!filter || filter.length == 0) && option.withSearch) {
295
+ this.searchKnowledge(this.filter, search);
296
+ }
297
+ }
298
+ },
299
+ addFilter: function (filter) {
300
+ if (this.cascaderIsReady) {
301
+ this.resetPageNavigation();
302
+ if (filter) {
303
+ if (this.$refs.filtersRef.addFilter(filter))
304
+ this.$refs.filtersRef.initiateSearch();
305
+ }
306
+ } else {
307
+ if (Array.isArray(this.filter)) {
308
+ this.filter.push(filter);
309
+ } else {
310
+ this.filter = [filter];
311
+ }
312
+ }
313
+ },
314
+ cascaderReady: function () {
315
+ this.cascaderIsReady = true;
316
+ this.openSearch(this.filter, this.searchInput);
317
+ },
318
+ clearSearchClicked: function () {
319
+ this.searchInput = "";
320
+ this.searchAndFilterUpdate();
321
+ this.$refs.filtersRef.checkShowAllBoxes();
322
+ },
323
+ searchEvent: function (event = false) {
324
+ if (event.keyCode === 13 || event instanceof MouseEvent) {
325
+ this.searchInput = this.searchInput.trim();
326
+ this.searchAndFilterUpdate();
327
+ if (!this.searchInput) {
328
+ this.$refs.filtersRef.checkShowAllBoxes();
329
+ }
330
+ }
331
+ },
332
+ filterUpdate: function (filters) {
333
+ this.filters = [...filters];
334
+ this.searchAndFilterUpdate();
335
+ this.$emit("search-changed", {
336
+ value: filters,
337
+ type: "filter-update",
338
+ });
339
+ },
340
+ /**
341
+ * Transform filters for third level items to perform search
342
+ * because cascader keeps adding it back.
343
+ */
344
+ transformFiltersBeforeSearch: function (filters) {
345
+ return filters.map((filter) => {
346
+ if (filter.facet2) {
347
+ filter.facet = filter.facet2;
348
+ delete filter.facet2;
349
+ }
350
+ return filter;
351
+ });
352
+ },
353
+ searchAndFilterUpdate: function () {
354
+ this.resetPageNavigation();
355
+ const transformedFilters = this.transformFiltersBeforeSearch(
356
+ this.filters
357
+ );
358
+ this.searchKnowledge(transformedFilters, this.searchInput);
359
+ },
360
+ searchKnowledge: function (filters, query = "") {
361
+ this.expanded = "";
362
+ this.$refs.searchHistory.selectValue = "Search history";
363
+ if (this.searchInput.trim()) {
364
+ this.$refs.searchHistory.addSearchToHistory(
365
+ this.filters,
366
+ this.searchInput
367
+ );
368
+ }
369
+ this.loadingCards = true;
370
+ this.scrollToTop();
371
+ this.$emit("search-changed", {
372
+ value: this.searchInput,
373
+ type: "query-update",
374
+ });
375
+ this.lastSearch = query;
376
+ },
377
+ filtersLoading: function (val) {
378
+ this.loadingCards = val;
379
+ },
380
+ numberPerPageUpdate: function (val) {
381
+ this.numberPerPage = val;
382
+ this.pageChange(1);
383
+ },
384
+ pageChange: function (page) {
385
+ this.start = (page - 1) * this.numberPerPage;
386
+ this.page = page;
387
+ this.searchKnowledge(this.filters, this.searchInput);
388
+ },
389
+ scrollToTop: function () {
390
+ if (this.$refs.content) {
391
+ this.$refs.content.scroll({ top: 0, behavior: "smooth" });
392
+ }
393
+ },
394
+ resetPageNavigation: function () {
395
+ this.start = 0;
396
+ this.page = 1;
397
+ },
398
+ searchHistorySearch: function (item) {
399
+ this.searchInput = item.search;
400
+ this.filters = item.filters;
401
+ this.searchAndFilterUpdate();
402
+ },
403
+ onConnectivityInfoLoaded: function (result) {
404
+ result.loaded = true;
405
+
406
+ const stepItemRef = this.$refs['stepItem-' + result.id];
407
+
408
+ this.$nextTick(() => {
409
+ if (stepItemRef && stepItemRef[0]) {
410
+ stepItemRef[0].scrollIntoViewIfNeeded(false);
411
+ }
412
+ });
413
+ },
414
+ },
415
+ mounted: function () {
416
+ localStorage.removeItem('connectivity-active-view');
417
+ this.openSearch(this.filter, this.searchInput);
418
+ },
419
+ };
420
+ </script>
421
+
422
+ <style lang="scss" scoped>
423
+ @import '../assets/pagination.scss';
424
+
425
+ .dataset-card {
426
+ position: relative;
427
+
428
+ &::before {
429
+ content: "";
430
+ display: block;
431
+ width: calc(100% - 15px);
432
+ height: 100%;
433
+ position: absolute;
434
+ top: 7px;
435
+ left: 7px;
436
+ border-style: solid;
437
+ border-radius: 5px;
438
+ border-color: transparent;
439
+ }
440
+
441
+ &:hover {
442
+ &::before {
443
+ border-color: var(--el-color-primary);
444
+ }
445
+
446
+ :deep(.connectivity-card .title) {
447
+ color: $app-primary-color;
448
+ }
449
+ }
450
+ }
451
+
452
+ .content-card {
453
+ height: 100%;
454
+ flex-flow: column;
455
+ display: flex;
456
+ border: 0;
457
+ border-top-right-radius: 0;
458
+ border-bottom-right-radius: 0;
459
+ }
460
+
461
+ .step-item {
462
+ font-size: 14px;
463
+ margin-bottom: 18px;
464
+ text-align: left;
465
+ max-height: 200px;
466
+ transition: all 0.3s ease;
467
+
468
+ .dataset-card {
469
+ opacity: 1;
470
+ visibility: visible;
471
+ transition: all 0.3s ease;
472
+ }
473
+
474
+ &.is-active {
475
+ max-height: 1800px;
476
+ background-color: #f7faff;
477
+ border: 2px solid $app-primary-color;
478
+ border-radius: var(--el-border-radius-base);
479
+
480
+ .dataset-card {
481
+ pointer-events: none;
482
+
483
+ &::before {
484
+ display: none;
485
+ }
486
+
487
+ + .main {
488
+ border: 0 none;
489
+ }
490
+ }
491
+
492
+ &:not(.is-loading) {
493
+ .dataset-card {
494
+ opacity: 0;
495
+ visibility: hidden;
496
+ height: 0;
497
+ }
498
+ }
499
+ }
500
+
501
+ &.is-loading {
502
+ opacity: 0.5;
503
+ pointer-events: none;
504
+
505
+ :deep(.connectivity-card .title) {
506
+ color: $app-primary-color;
507
+ font-size: 18px;
508
+ letter-spacing: normal;
509
+ }
510
+ }
511
+ }
512
+
513
+ .search-input {
514
+ width: 298px !important;
515
+ height: 40px;
516
+ padding-right: 14px;
517
+
518
+ :deep(.el-input__inner) {
519
+ font-family: inherit;
520
+ }
521
+ }
522
+
523
+ .header {
524
+ .el-button {
525
+ font-family: inherit;
526
+
527
+ &:hover,
528
+ &:focus {
529
+ background: $app-primary-color;
530
+ box-shadow: -3px 2px 4px #00000040;
531
+ color: #fff;
532
+ }
533
+ }
534
+ }
535
+
536
+ .error-feedback {
537
+ font-family: Asap;
538
+ font-size: 14px;
539
+ font-style: italic;
540
+ padding-top: 15px;
541
+ }
542
+
543
+ .content-card :deep(.el-card__header) {
544
+ background-color: #292b66;
545
+ padding: 1rem;
546
+ }
547
+
548
+ .content-card :deep(.el-card__body) {
549
+ background-color: #f7faff;
550
+ overflow-y: hidden;
551
+ padding: 1rem;
552
+ }
553
+
554
+ .content {
555
+ // width: 515px;
556
+ flex: 1 1 auto;
557
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
558
+ border: solid 1px #e4e7ed;
559
+ background-color: #ffffff;
560
+ overflow-y: scroll;
561
+ scrollbar-width: thin;
562
+ border-radius: var(--el-border-radius-base);
563
+ }
564
+
565
+ .content :deep(.el-loading-spinner .path) {
566
+ stroke: $app-primary-color;
567
+ }
568
+
569
+ .content :deep(.step-item:first-child .seperator-path) {
570
+ display: none;
571
+ }
572
+
573
+ .content :deep(.step-item:not(:first-child) .seperator-path) {
574
+ width: 455px;
575
+ height: 0px;
576
+ border: solid 1px #e4e7ed;
577
+ background-color: #e4e7ed;
578
+ }
579
+
580
+ .scrollbar::-webkit-scrollbar-track {
581
+ border-radius: 10px;
582
+ background-color: #f5f5f5;
583
+ }
584
+
585
+ .scrollbar::-webkit-scrollbar {
586
+ width: 12px;
587
+ right: -12px;
588
+ background-color: #f5f5f5;
589
+ }
590
+
591
+ .scrollbar::-webkit-scrollbar-thumb {
592
+ border-radius: 4px;
593
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.06);
594
+ background-color: #979797;
595
+ }
596
+
597
+ :deep(.el-input__suffix) {
598
+ padding-right: 0px;
599
+ }
600
+
601
+ :deep(.my-drawer) {
602
+ background: rgba(0, 0, 0, 0);
603
+ box-shadow: none;
604
+ }
605
+
606
+ .el-button-link {
607
+ color: white !important;
608
+ text-decoration: underline;
609
+ text-underline-offset: 2px;
610
+
611
+ &:hover {
612
+ text-decoration-color: transparent;
613
+ }
614
+ }
615
+ </style>