@abi-software/map-side-bar 2.19.1-demo.0 → 2.20.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/map-side-bar",
3
- "version": "2.19.1-demo.0",
3
+ "version": "2.20.0",
4
4
  "license": "Apache-2.0",
5
5
  "engines": {
6
6
  "node": "^24.20.0"
@@ -49,8 +49,8 @@
49
49
  "./src/*": "./src/*"
50
50
  },
51
51
  "dependencies": {
52
- "@abi-software/gallery": "1.6.0",
53
- "@abi-software/map-utilities": "1.12.0",
52
+ "@abi-software/gallery": "1.7.0",
53
+ "@abi-software/map-utilities": "1.13.0",
54
54
  "@abi-software/svg-sprite": "1.4.0",
55
55
  "@element-plus/icons-vue": "^2.3.2",
56
56
  "algoliasearch": "^4.27.0",
package/src/App.vue CHANGED
@@ -15,7 +15,6 @@
15
15
  <el-button @click="getFacets">Get facets</el-button>
16
16
  <el-button @click="toggleCreateData">Create Data/Annotation</el-button>
17
17
  <el-button @click="openConnectivitySearch()">Connectivity Search</el-button>
18
- <el-button @click="showCellCardExplorer()">Show Cell Card Explorer</el-button>
19
18
  </div>
20
19
  <SideBar
21
20
  :envVars="envVars"
@@ -27,7 +26,6 @@
27
26
  :connectivityEntry="connectivityEntry"
28
27
  :connectivityKnowledge="connectivityKnowledge"
29
28
  :showVisibilityFilter="true"
30
- :showCellCards="showCellCards"
31
29
  @search-changed="searchChanged($event)"
32
30
  @hover-changed="hoverChanged($event)"
33
31
  @connectivity-hovered="onConnectivityHovered"
@@ -42,7 +40,8 @@
42
40
  import SideBar from './components/SideBar.vue';
43
41
  import EventBus from './components/EventBus.js';
44
42
  import exampleConnectivityInput from './exampleConnectivityInput.js';
45
- import { capitalise } from './utils/common.js';
43
+
44
+ const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
46
45
 
47
46
  const flatmapQuery = (flatmapApi, sql) => {
48
47
  const data = { sql: sql };
@@ -135,7 +134,6 @@ export default {
135
134
  BL_SERVER_URL: import.meta.env.VITE_BL_SERVER_URL,
136
135
  ROOT_URL: import.meta.env.VITE_ROOT_URL,
137
136
  FLATMAPAPI_LOCATION: import.meta.env.VITE_FLATMAPAPI_LOCATION,
138
- CELL_CARDS_API: import.meta.env.VITE_APP_CELL_CARDS_API,
139
137
  },
140
138
  connectivityEntry: [],
141
139
  createData: {
@@ -152,7 +150,6 @@ export default {
152
150
  query: '',
153
151
  filter: [],
154
152
  target: [],
155
- showCellCards: false,
156
153
  };
157
154
  },
158
155
  methods: {
@@ -367,11 +364,6 @@ export default {
367
364
  onConnectivityCollapseChange: function () {
368
365
  this.connectivityEntry = [...exampleConnectivityInput];
369
366
  },
370
- showCellCardExplorer: function () {
371
- this.showCellCards = true;
372
- this.$refs.sideBar.tabClicked({ id: 4, type: 'cellCardExplorer' });
373
- this.$refs.sideBar.setDrawerOpen(true);
374
- },
375
367
  },
376
368
  mounted: async function () {
377
369
  console.log('mounted app');
@@ -33,7 +33,6 @@
33
33
 
34
34
  <script>
35
35
  import EventBus from './EventBus';
36
- import { capitalise as capitaliseText } from '../utils/common.js';
37
36
 
38
37
  export default {
39
38
  name: 'ConnectivityCard',
@@ -82,7 +81,8 @@ export default {
82
81
  },
83
82
  methods: {
84
83
  capitalise: function (text) {
85
- return capitaliseText(text);
84
+ if (text) return text.charAt(0).toUpperCase() + text.slice(1);
85
+ return '';
86
86
  },
87
87
  cardClicked: function (data) {
88
88
  if (!this.loading) {
@@ -343,11 +343,6 @@ import {
343
343
  ExternalResourceCard,
344
344
  } from '@abi-software/map-utilities';
345
345
  import '@abi-software/map-utilities/dist/style.css';
346
- import {
347
- capitalise,
348
- formatAlertText as formatAlertTextUtil,
349
- scrollToRef,
350
- } from '../utils/common.js';
351
346
 
352
347
  const titleCase = (str) => {
353
348
  return str.replace(/\w\S*/g, (t) => {
@@ -355,6 +350,11 @@ const titleCase = (str) => {
355
350
  });
356
351
  };
357
352
 
353
+ const capitalise = function (str) {
354
+ if (str) return str.charAt(0).toUpperCase() + str.slice(1);
355
+ return '';
356
+ };
357
+
358
358
  export default {
359
359
  name: 'ConnectivityInfo',
360
360
  components: {
@@ -1162,10 +1162,40 @@ export default {
1162
1162
  EventBus.emit('trackEvent', data);
1163
1163
  },
1164
1164
  showAlertMessage: function () {
1165
- scrollToRef(this, 'alertElement');
1165
+ // scroll to alert message
1166
+ this.$nextTick(() => {
1167
+ const alertElement = this.$refs.alertElement;
1168
+ if (alertElement) {
1169
+ alertElement.scrollIntoView({
1170
+ behavior: 'smooth',
1171
+ block: 'start',
1172
+ inline: 'nearest',
1173
+ });
1174
+ }
1175
+ });
1166
1176
  },
1167
1177
  formatAlertText: function (text) {
1168
- return formatAlertTextUtil(text, { formatLines: true });
1178
+ if (!text) return '';
1179
+ const escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1180
+ const linkified = escaped.replace(/(https?:\/\/[^\s"<>[]+)/g, (url) => {
1181
+ const parts = url.match(/^(.*?)([\].,;:!?]*)$/);
1182
+ const cleanUrl = parts ? parts[1] : url;
1183
+ const suffix = parts ? parts[2] : '';
1184
+ return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer">${cleanUrl}</a>${suffix}`;
1185
+ });
1186
+
1187
+ const normalised = linkified
1188
+ .replace(/\\n/g, '\n')
1189
+ .replace(/\r\n/g, '\n')
1190
+ .replace(/\r/g, '\n');
1191
+
1192
+ return normalised
1193
+ .split('\n')
1194
+ .map((line) => {
1195
+ const withBoldLabel = line.replace(/^\s*([A-Za-z][^:<]{0,120}:)/, '<strong>$1</strong>');
1196
+ return `<div class="alert-line">${withBoldLabel}</div>`;
1197
+ })
1198
+ .join('\n');
1169
1199
  },
1170
1200
  },
1171
1201
  mounted: function () {
@@ -143,7 +143,10 @@ import '@abi-software/svg-sprite/dist/style.css';
143
143
  import { AlgoliaClient } from '../algolia/algolia.js';
144
144
  import { facetPropPathMapping } from '../algolia/utils.js';
145
145
  import EventBus from './EventBus.js';
146
- import { capitalise } from '../utils/common.js';
146
+
147
+ const capitalise = function (txt) {
148
+ return txt.charAt(0).toUpperCase() + txt.slice(1);
149
+ };
147
150
 
148
151
  const convertReadableLabel = function (original) {
149
152
  const name = original.toLowerCase();
@@ -270,22 +273,16 @@ export default {
270
273
  return value;
271
274
  },
272
275
  createChildrenCascaderValue: function (children, facet, facets) {
273
- const parentKey = facet.key;
274
-
275
276
  if (children?.length) {
276
277
  for (let i = 0; i < children.length; i++) {
277
278
  const facetItem = children[i];
278
279
  //copy the facets into
279
280
  if (children[i].facetPropPath !== 'supportingAwards.consortium.name') {
280
- // `sourceNomenclatureLabel` is from cell card explorer filters
281
- if (parentKey === 'sourceNomenclatureLabel') {
282
- children[i].label = facetItem.label;
283
- } else {
284
- children[i].label = convertReadableLabel(facetItem.label);
285
- }
281
+ children[i].label = convertReadableLabel(facetItem.label);
286
282
  }
287
- if (facetItem.key && parentKey.includes('flatmap.connectivity.source.')) {
283
+ if (facetItem.key && facet.key.includes('flatmap.connectivity.source.')) {
288
284
  const childKey = facetItem.key;
285
+ const parentKey = facet.key;
289
286
  const key = childKey.replace(`${parentKey}.`, '');
290
287
  children[i].value = this.createCascaderItemValue([facet.label, key]);
291
288
  } else {
@@ -125,10 +125,23 @@
125
125
 
126
126
  <script>
127
127
  import EventBus from './EventBus.js';
128
- import { generateUUID } from '../utils/common.js';
129
128
 
130
129
  const MAX_SEARCH_HISTORY = 12;
131
130
 
131
+ function generateUUID() {
132
+ const arr = new Uint8Array(16);
133
+ window.crypto.getRandomValues(arr);
134
+
135
+ arr[6] = (arr[6] & 0x0f) | 0x40;
136
+ arr[8] = (arr[8] & 0x3f) | 0x80;
137
+
138
+ const hex = Array.from(arr)
139
+ .map((byte) => byte.toString(16).padStart(2, '0'))
140
+ .join('');
141
+
142
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
143
+ }
144
+
132
145
  export default {
133
146
  name: 'SearchHistory',
134
147
  props: {
@@ -304,14 +317,7 @@ export default {
304
317
  getParentComponentName: function () {
305
318
  const isConnectivity = this.localStorageKey?.indexOf('connectivity') !== -1;
306
319
  const isDataset = this.localStorageKey?.indexOf('dataset') !== -1;
307
- const isCellCard = this.localStorageKey?.indexOf('cell-card') !== -1;
308
- const location = isConnectivity
309
- ? 'connectivity'
310
- : isDataset
311
- ? 'dataset'
312
- : isCellCard
313
- ? 'cell_card'
314
- : '';
320
+ const location = isConnectivity ? 'connectivity' : isDataset ? 'dataset' : '';
315
321
  return location;
316
322
  },
317
323
  search: function (item) {
@@ -65,20 +65,6 @@
65
65
  @connectivity-item-close="onConnectivityItemClose"
66
66
  />
67
67
  </template>
68
- <template v-else-if="tab.type === 'cellCardExplorer' && showCellCards">
69
- <CellCardExplorer
70
- :ref="'cellCardExplorerTab_' + tab.id"
71
- class="sidebar-content-container"
72
- v-show="tab.id === activeTabId"
73
- :envVars="envVars"
74
- :activeSpecies="activeSpeciesForEntries"
75
- @search-changed="searchChanged(tab.id, $event)"
76
- @dataset-search="openDatasetSearchFromCellCard($event)"
77
- @connectivity-search="openConnectivitySearch($event.facets, $event.query)"
78
- @soma-location-hovered="showSomaLocation"
79
- @soma-locations-ready="onSomaLocationsReady"
80
- />
81
- </template>
82
68
  <template v-else>
83
69
  <DatasetExplorer
84
70
  class="sidebar-content-container"
@@ -107,7 +93,6 @@ import EventBus from './EventBus.js';
107
93
  import Tabs from './Tabs.vue';
108
94
  import AnnotationTool from './AnnotationTool.vue';
109
95
  import ConnectivityExplorer from './ConnectivityExplorer.vue';
110
- import CellCardExplorer from './CellCardExplorer.vue';
111
96
  import { removeShowAllFacets } from '../algolia/utils.js';
112
97
 
113
98
  /**
@@ -121,7 +106,6 @@ export default {
121
106
  ElIconArrowRight,
122
107
  AnnotationTool,
123
108
  ConnectivityExplorer,
124
- CellCardExplorer,
125
109
  },
126
110
  name: 'SideBar',
127
111
  props: {
@@ -131,7 +115,6 @@ export default {
131
115
  { title: 'Dataset Explorer', id: 1, type: 'datasetExplorer', closable: false },
132
116
  { title: 'Connectivity Explorer', id: 2, type: 'connectivityExplorer', closable: false },
133
117
  { title: 'Annotation', id: 3, type: 'annotation', closable: true },
134
- { title: 'Cell Card Explorer', id: 4, type: 'cellCardExplorer', closable: false },
135
118
  ],
136
119
  },
137
120
  /**
@@ -197,10 +180,6 @@ export default {
197
180
  type: Boolean,
198
181
  default: false,
199
182
  },
200
- showCellCards: {
201
- type: Boolean,
202
- default: false,
203
- },
204
183
  },
205
184
  data: function () {
206
185
  return {
@@ -209,7 +188,6 @@ export default {
209
188
  activeTabId: 1,
210
189
  activeAnnotationData: { tabType: 'annotation' },
211
190
  activeConnectivityData: { tabType: 'connectivity' },
212
- activeSpeciesForEntries: [],
213
191
  state: {
214
192
  dataset: {
215
193
  search: '',
@@ -219,10 +197,6 @@ export default {
219
197
  search: '',
220
198
  filters: [],
221
199
  },
222
- cellCards: {
223
- search: '',
224
- filters: [],
225
- },
226
200
  connectivityEntries: [],
227
201
  annotationEntries: [],
228
202
  activeTabId: this.activeTabId,
@@ -257,16 +231,6 @@ export default {
257
231
  this.activeAnnotationData = data;
258
232
  }
259
233
  },
260
- /**
261
- * This event is emitted when the mouse hover on or off a soma location in cell card explorer.
262
- * @param name Soma location
263
- */
264
- showSomaLocation: function (name) {
265
- this.$emit('soma-location-hovered', name);
266
- },
267
- onSomaLocationsReady: function (somaLocations) {
268
- this.$emit('soma-locations-ready', somaLocations);
269
- },
270
234
  /**
271
235
  * This event is emitted when the show connectivity button is clicked.
272
236
  * @arg featureIds
@@ -331,42 +295,6 @@ export default {
331
295
  datasetExplorerTabRef.openSearch(facets, query);
332
296
  });
333
297
  },
334
- openCellCardExplorerSearch: function (filters, query) {
335
- this.drawerOpen = true;
336
- // Because refs are in v-for, nextTick is needed here
337
- this.$nextTick(() => {
338
- const cellCardExplorerTabRef = this.getTabRef(undefined, 'cellCardExplorer', true);
339
- if (cellCardExplorerTabRef && typeof cellCardExplorerTabRef.openSearch === 'function') {
340
- cellCardExplorerTabRef.openSearch(filters, query);
341
- }
342
- });
343
- },
344
- openDatasetSearchFromCellCard: function (payload) {
345
- if (!payload || typeof payload !== 'object') {
346
- this.openSearch([], payload);
347
- return;
348
- }
349
-
350
- const facets = [];
351
- if (payload.species) {
352
- facets.push({
353
- facet: payload.species,
354
- term: 'Species',
355
- facetPropPath: 'organisms.primary.species.name',
356
- });
357
- }
358
-
359
- if (payload.location) {
360
- facets.push({
361
- facet: payload.location,
362
- term: 'Anatomical structure',
363
- facetPropPath: 'anatomy.organ.category.name',
364
- AND: true,
365
- });
366
- }
367
-
368
- this.openSearch(facets, '');
369
- },
370
298
  /**
371
299
  * Get the ref id of the tab by id and type.
372
300
  */
@@ -504,13 +432,6 @@ export default {
504
432
  this.state.connectivity.filters = connectivityExplorerTabRef.getFilters();
505
433
  }
506
434
 
507
- // Update cell card explorer state if available
508
- const cellCardExplorerTabRef = this.getTabRef(undefined, 'cellCardExplorer');
509
- if (cellCardExplorerTabRef) {
510
- this.state.cellCards.search = cellCardExplorerTabRef.getSearch();
511
- this.state.cellCards.filters = cellCardExplorerTabRef.getFilters();
512
- }
513
-
514
435
  // Update connectivity entries if available
515
436
  if (this.connectivityEntry && this.connectivityEntry.length > 0) {
516
437
  this.state.connectivityEntries = this.connectivityEntry.map((entry) => entry.id);
@@ -540,15 +461,11 @@ export default {
540
461
  setState: function (state) {
541
462
  // if state is not provided or formatted incorrectly, do nothing
542
463
  if (!state || !state.dataset || !state.connectivity) return;
543
- // Create a deep copy while preserving the original state structure for future extensibility
544
- const newState = JSON.parse(JSON.stringify(state));
545
- this.state = { ...this.state, ...newState };
546
- const datasetFilters = this.state.dataset.filters;
547
- const connectivityFilters = this.state.connectivity.filters;
548
- const datasetSearch = this.state.dataset.search;
549
- const connectivitySearch = this.state.connectivity.search;
550
- const cellCardFilters = this.state.cellCards.filters || [];
551
- const cellCardSearch = this.state.cellCards.search || '';
464
+ this.state = JSON.parse(JSON.stringify(state)); // deep copy to avoid reference issues
465
+ const datasetFilters = state.dataset.filters;
466
+ const connectivityFilters = state.connectivity.filters;
467
+ const datasetSearch = state.dataset.search;
468
+ const connectivitySearch = state.connectivity.search;
552
469
 
553
470
  if (datasetFilters.length || datasetSearch) {
554
471
  this.openSearch(datasetFilters, datasetSearch);
@@ -558,10 +475,6 @@ export default {
558
475
  this.openConnectivitySearch(connectivityFilters, connectivitySearch);
559
476
  }
560
477
 
561
- if (cellCardFilters.length || cellCardSearch) {
562
- this.openCellCardExplorerSearch(cellCardFilters, cellCardSearch);
563
- }
564
-
565
478
  if (state.activeTabId) {
566
479
  this.$nextTick(() => {
567
480
  const hasTab = this.tabEntries.find((t) => t.id === state.activeTabId);
@@ -584,16 +497,6 @@ export default {
584
497
  };
585
498
  this.$emit('trackEvent', taggingData);
586
499
  },
587
- /**
588
- * @public
589
- * Update the active species to use in filters.
590
- * Used by SplitFlow component.
591
- * @param activeSpecies
592
- */
593
- updateActiveSpeciesForEntries: function (activeSpecies) {
594
- const speciesEntries = Array.isArray(activeSpecies) ? activeSpecies : [activeSpecies];
595
- this.activeSpeciesForEntries = [...new Set(speciesEntries.filter(Boolean))];
596
- },
597
500
  },
598
501
  computed: {
599
502
  // This should respect the information provided by the property
@@ -602,8 +505,7 @@ export default {
602
505
  (tab) =>
603
506
  tab.type === 'datasetExplorer' ||
604
507
  tab.type === 'connectivityExplorer' ||
605
- (tab.type === 'annotation' && this.annotationEntry && this.annotationEntry.length > 0) ||
606
- (tab.type === 'cellCardExplorer' && this.showCellCards),
508
+ (tab.type === 'annotation' && this.annotationEntry && this.annotationEntry.length > 0),
607
509
  );
608
510
  },
609
511
  },
@@ -4,7 +4,7 @@
4
4
  class="tab"
5
5
  v-for="tab in tabs"
6
6
  :key="tab.id"
7
- :class="{ 'active-tab': tab.id == activeId, 'closable-tab': tab.closable }"
7
+ :class="{ 'active-tab': tab.id == activeId }"
8
8
  @click="tabClicked(tab)"
9
9
  >
10
10
  <span class="tab-title">{{ tab.title }}</span>
@@ -98,23 +98,14 @@ export default {
98
98
  .tab-title {
99
99
  text-align: center;
100
100
  font-size: 14px;
101
- padding: 0 0.75rem;
102
-
103
- .closable-tab & {
104
- padding-right: 0.25rem;
105
- }
101
+ padding: 0 1rem;
106
102
  }
107
103
 
108
104
  .tab-close-icon {
109
- width: 18px !important;
110
- height: 18px !important;
111
- font-size: 18px !important;
112
- margin-right: 4px !important;
105
+ width: 20px !important;
106
+ height: 20px !important;
107
+ font-size: 20px !important;
108
+ padding-right: 4px !important;
113
109
  color: $app-primary-color !important;
114
- border-radius: 2px;
115
-
116
- &:hover {
117
- background-color: rgba($app-primary-color, 0.15) !important;
118
- }
119
110
  }
120
111
  </style>
@@ -13,8 +13,6 @@ declare module 'vue' {
13
13
  export interface GlobalComponents {
14
14
  AnnotationTool: typeof import('./components/AnnotationTool.vue')['default']
15
15
  BadgesGroup: typeof import('./components/BadgesGroup.vue')['default']
16
- CellCard: typeof import('./components/CellCard.vue')['default']
17
- CellCardExplorer: typeof import('./components/CellCardExplorer.vue')['default']
18
16
  ConnectivityCard: typeof import('./components/ConnectivityCard.vue')['default']
19
17
  ConnectivityExplorer: typeof import('./components/ConnectivityExplorer.vue')['default']
20
18
  ConnectivityInfo: typeof import('./components/ConnectivityInfo.vue')['default']
@@ -50,7 +48,6 @@ declare module 'vue' {
50
48
  ElRow: typeof import('element-plus/es')['ElRow']
51
49
  ElSelect: typeof import('element-plus/es')['ElSelect']
52
50
  ElTag: typeof import('element-plus/es')['ElTag']
53
- IconOpenExternal: typeof import('./components/icons/IconOpenExternal.vue')['default']
54
51
  ImageGallery: typeof import('./components/ImageGallery.vue')['default']
55
52
  SearchFilters: typeof import('./components/SearchFilters.vue')['default']
56
53
  SearchHistory: typeof import('./components/SearchHistory.vue')['default']