@abi-software/map-side-bar 2.7.0-beta.0 → 2.7.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.7.0-beta.0",
3
+ "version": "2.7.0",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@abi-software/gallery": "^1.1.2",
42
- "@abi-software/map-utilities": "^1.4.0-beta.0",
42
+ "@abi-software/map-utilities": "^1.4.0",
43
43
  "@abi-software/svg-sprite": "^1.0.1",
44
44
  "@element-plus/icons-vue": "^2.3.1",
45
45
  "algoliasearch": "^4.10.5",
package/src/App.vue CHANGED
@@ -114,6 +114,7 @@ export default {
114
114
  { title: 'Flatmap', id: 1, type: 'search'},
115
115
  { title: 'Connectivity', id: 2, type: 'connectivity' },
116
116
  { title: 'Annotation', id: 3, type: 'annotation' },
117
+ { title: 'Connectivity Explorer', id: 4, type: 'connectivityExplorer' }
117
118
  ],
118
119
  sideBarVisibility: true,
119
120
  envVars: {
@@ -0,0 +1,163 @@
1
+ <template>
2
+ <div class="dataset-card-container" ref="container">
3
+ <div class="dataset-card" ref="card">
4
+ <div class="seperator-path"></div>
5
+ <div class="card"
6
+ @click="cardClicked(entry)"
7
+ @mouseover="cardHovered(entry)"
8
+ @mouseleave="cardHovered(undefined)"
9
+ >
10
+ <div class="card-right">
11
+ <div class="title">{{ entry.label }}</div>
12
+ <template v-for="field in displayFields" :key="field">
13
+ <div class="details" v-if="entry[field]">
14
+ <strong>{{ field }}:</strong> {{ entry[field] }}
15
+ </div>
16
+ </template>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </template>
22
+
23
+ <script>
24
+ import EventBus from './EventBus.js'
25
+ /* eslint-disable no-alert, no-console */
26
+
27
+ export default {
28
+ data() {
29
+ return {
30
+ displayFields: [
31
+ "label",
32
+ "id",
33
+ ]
34
+ }
35
+ },
36
+ name: 'ConnectivityCard',
37
+ props: {
38
+ /**
39
+ * Object containing information for
40
+ * the required viewing.
41
+ */
42
+ entry: {
43
+ type: Object,
44
+ default: () => {},
45
+ },
46
+ },
47
+ methods: {
48
+ cardClicked: function (data) {
49
+ EventBus.emit('connectivity-clicked', data);
50
+ },
51
+ cardHovered: function (data) {
52
+ EventBus.emit('connectivity-hovered', data);
53
+ },
54
+ }
55
+ }
56
+ </script>
57
+
58
+ <style lang="scss" scoped>
59
+ .dataset-card {
60
+ padding-left: 5px;
61
+ padding-right: 5px;
62
+ position: relative;
63
+ min-height: 17rem;
64
+ }
65
+
66
+ .title {
67
+ padding-bottom: 0.75rem;
68
+ font-family: Asap;
69
+ font-size: 14px;
70
+ font-weight: bold;
71
+ font-stretch: normal;
72
+ font-style: normal;
73
+ line-height: 1.5;
74
+ letter-spacing: 1.05px;
75
+ color: #484848;
76
+ cursor: pointer;
77
+ }
78
+ .card {
79
+ padding-top: 18px;
80
+ position: relative;
81
+ display: flex;
82
+ }
83
+
84
+ .card-left {
85
+ flex: 1;
86
+ }
87
+
88
+ .card-right {
89
+ flex: 1.3;
90
+ padding-left: 6px;
91
+ }
92
+
93
+ .button {
94
+ z-index: 10;
95
+ font-family: Asap;
96
+ font-size: 14px;
97
+ font-weight: normal;
98
+ font-stretch: normal;
99
+ font-style: normal;
100
+ line-height: normal;
101
+ letter-spacing: normal;
102
+ background-color: $app-primary-color;
103
+ border: $app-primary-color;
104
+ color: white;
105
+ cursor: pointer;
106
+ margin-top: 8px;
107
+ }
108
+
109
+ .button:hover {
110
+ background-color: $app-primary-color;
111
+ color: white;
112
+ }
113
+
114
+ .banner-img {
115
+ width: 128px;
116
+ height: 128px;
117
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
118
+ background-color: #ffffff;
119
+ cursor: pointer;
120
+ }
121
+ .details {
122
+ font-family: Asap;
123
+ font-size: 14px;
124
+ font-weight: normal;
125
+ font-stretch: normal;
126
+ font-style: normal;
127
+ line-height: 1.5;
128
+ letter-spacing: 1.05px;
129
+ color: #484848;
130
+ }
131
+
132
+ .badges-container {
133
+ margin-top: 0.75rem;
134
+ }
135
+
136
+ .loading-icon {
137
+ z-index: 20;
138
+ width: 40px;
139
+ height: 40px;
140
+ left: 80px;
141
+ }
142
+
143
+ .loading-icon :deep(.el-loading-mask) {
144
+ background-color: rgba(117, 190, 218, 0) !important;
145
+ }
146
+
147
+ .loading-icon :deep(.el-loading-spinner .path) {
148
+ stroke: $app-primary-color;
149
+ }
150
+
151
+ .float-button-container {
152
+ position: absolute;
153
+ bottom: 8px;
154
+ right: 16px;
155
+ opacity: 0;
156
+ visibility: hidden;
157
+
158
+ .card:hover & {
159
+ opacity: 1;
160
+ visibility: visible;
161
+ }
162
+ }
163
+ </style>
@@ -0,0 +1,352 @@
1
+ <template>
2
+ <div v-if="flatmapKnowledge" class="main">
3
+ <div class="header">
4
+ <el-input
5
+ class="search-input"
6
+ placeholder="Search"
7
+ v-model="searchInput"
8
+ @keyup="search(searchInput)"
9
+ clearable
10
+ @clear="clearSearchClicked"
11
+ ></el-input>
12
+ <el-button
13
+ v-show="false"
14
+ type="primary"
15
+ class="button"
16
+ @click="search(searchInput)"
17
+ size="large"
18
+ >
19
+ Search
20
+ </el-button>
21
+ </div>
22
+ <div class="content scrollbar" ref="content">
23
+ <div v-for="result in paginatedResults" :key="result.id" class="step-item">
24
+ <connectivity-card
25
+ class="dataset-card"
26
+ :entry="result"
27
+ @mouseenter="hoverChanged(result)"
28
+ @mouseleave="hoverChanged(undefined)"
29
+ />
30
+ </div>
31
+ <el-pagination
32
+ class="pagination"
33
+ v-model:current-page="page"
34
+ hide-on-single-page
35
+ large
36
+ layout="prev, pager, next"
37
+ :page-size="numberPerPage"
38
+ :total="numberOfHits"
39
+ @current-change="pageChange"
40
+ ></el-pagination>
41
+ </div>
42
+ </div>
43
+ </template>
44
+
45
+
46
+
47
+ <script>
48
+
49
+ const flatmapQuery = (flatmapApi, sql) => {
50
+ const data = { sql: sql }
51
+ return fetch(`${flatmapApi}knowledge/query/`, {
52
+ method: 'POST',
53
+ headers: {
54
+ 'Content-Type': 'application/json',
55
+ },
56
+ body: JSON.stringify(data),
57
+ })
58
+ .then((response) => response.json())
59
+ .catch((error) => {
60
+ console.error('Error:', error)
61
+ })
62
+ }
63
+
64
+ const filterKnowledge = (knowledge, sckanVersion) => {
65
+ const result = knowledge.filter((item) => {
66
+ if (item?.source && item.source === sckanVersion) {
67
+ if ("connectivity" in item) {
68
+ return true
69
+ }
70
+ }
71
+ return false
72
+ })
73
+ return result
74
+ }
75
+
76
+
77
+ /* eslint-disable no-alert, no-console */
78
+ import {
79
+ ElButton as Button,
80
+ ElCard as Card,
81
+ ElDrawer as Drawer,
82
+ ElIcon as Icon,
83
+ ElInput as Input,
84
+ ElPagination as Pagination,
85
+ } from 'element-plus'
86
+ import ConnectivityCard from './ConnectivityCard.vue'
87
+
88
+ export default {
89
+ components: {
90
+ ConnectivityCard,
91
+ Button,
92
+ Card,
93
+ Drawer,
94
+ Icon,
95
+ Input,
96
+ Pagination
97
+ },
98
+ name: 'ConnectivityExplorer',
99
+ props: {
100
+ sckanVersion: {
101
+ type: String,
102
+ default: "sckan-2024-09-21-npo",
103
+ },
104
+ envVars: {
105
+ type: Object,
106
+ default: () => {},
107
+ },
108
+ },
109
+ data: function () {
110
+ return {
111
+ mapServer: "",
112
+ flatmapKnowledge: [],
113
+ results: [],
114
+ paginatedResults: [],
115
+ searchInput: "",
116
+ lastSearch: "",
117
+ numberOfHits: 0,
118
+ numberPerPage: 10,
119
+ page: 1,
120
+ previousSearch: undefined
121
+ }
122
+ },
123
+ methods: {
124
+ hoverChanged: function (data) {
125
+ this.$emit('hover-changed', data)
126
+ },
127
+ resetSearch: function () {
128
+ this.numberOfHits = 0
129
+ this.search(this.searchInput)
130
+ },
131
+ clearSearchClicked: function () {
132
+ this.searchInput = '';
133
+ this.search("");
134
+ },
135
+ search: function(input) {
136
+ this.results = []
137
+ if (input !== this.previousSearch) {
138
+ if (input === "") {
139
+ this.results = this.flatmapKnowledge
140
+ } else {
141
+ for (const value of this.flatmapKnowledge) {
142
+ const lowerCase = input.toLowerCase()
143
+ const myJSON = JSON.stringify(value).toLowerCase()
144
+ if (myJSON.includes(lowerCase)) {
145
+ this.results.push(value)
146
+ }
147
+ }
148
+ }
149
+ }
150
+ console.log(this.flatmapKnowledge, this.results)
151
+ const start = this.numberPerPage * (this.page - 1)
152
+ this.paginatedResults = this.results.slice(start, start + this.numberPerPage)
153
+ this.numberOfHits = this.results.length
154
+ this.searchInput = input
155
+ this.lastSearch = input
156
+ console.log(this.numberOfHits)
157
+ },
158
+ numberPerPageUpdate: function (val) {
159
+ this.numberPerPage = val
160
+ this.pageChange(1)
161
+ },
162
+ pageChange: function (page) {
163
+ this.page = page
164
+ this.search( this.searchInput)
165
+ },
166
+ scrollToTop: function () {
167
+ if (this.$refs.content) {
168
+ this.$refs.content.scroll({ top: 0, behavior: 'smooth' })
169
+ }
170
+ },
171
+ resetPageNavigation: function () {
172
+ this.page = 1
173
+ },
174
+ },
175
+ mounted: function () {
176
+ this.mapServer = this.envVars.FLATMAPAPI_LOCATION
177
+ console.log(this.mapServer)
178
+ if (this.mapServer) {
179
+ const sql = `select knowledge from knowledge
180
+ where source="${this.sckanVersion}"
181
+ order by source desc`;
182
+ flatmapQuery(this.mapServer, sql).then((response) => {
183
+ const mappedData = response.values.map(x => x[0])
184
+ const parsedData = mappedData.map(x => JSON.parse(x))
185
+ this.flatmapKnowledge = filterKnowledge(parsedData, this.sckanVersion)
186
+ this.search("");
187
+ });
188
+ }
189
+ },
190
+ }
191
+ </script>
192
+
193
+ <style lang="scss" scoped>
194
+ .dataset-card {
195
+ position: relative;
196
+
197
+ &::before {
198
+ content: "";
199
+ display: block;
200
+ width: calc(100% - 15px);
201
+ height: 100%;
202
+ position: absolute;
203
+ top: 7px;
204
+ left: 7px;
205
+ border-style: solid;
206
+ border-radius: 5px;
207
+ border-color: transparent;
208
+ }
209
+
210
+ &:hover {
211
+ &::before {
212
+ border-color: var(--el-color-primary);
213
+ }
214
+ }
215
+ }
216
+
217
+ .main {
218
+ font-size: 14px;
219
+ text-align: left;
220
+ line-height: 1.5em;
221
+ font-family: Asap, sans-serif, Helvetica;
222
+ font-weight: 400;
223
+ /* outline: thin red solid; */
224
+ overflow-y: auto;
225
+ scrollbar-width: thin;
226
+ min-width: 16rem;
227
+ background-color: #f7faff;
228
+ height: 100%;
229
+ border-left: 1px solid var(--el-border-color);
230
+ border-top: 1px solid var(--el-border-color);
231
+ display: flex;
232
+ flex-direction: column;
233
+ gap: 1.75rem;
234
+ padding: 1rem;
235
+ }
236
+
237
+ .step-item {
238
+ font-size: 14px;
239
+ margin-bottom: 18px;
240
+ text-align: left;
241
+ }
242
+
243
+ .search-input {
244
+ width: 298px !important;
245
+ height: 40px;
246
+ padding-right: 14px;
247
+
248
+ :deep(.el-input__inner) {
249
+ font-family: inherit;
250
+ }
251
+ }
252
+
253
+ .header {
254
+ .el-button {
255
+ font-family: inherit;
256
+
257
+ &:hover,
258
+ &:focus {
259
+ background: $app-primary-color;
260
+ box-shadow: -3px 2px 4px #00000040;
261
+ color: #fff;
262
+ }
263
+ }
264
+ }
265
+
266
+ .pagination {
267
+ padding-bottom: 16px;
268
+ background-color: white;
269
+ padding-left: 95px;
270
+ font-weight: bold;
271
+ }
272
+
273
+ .pagination :deep(button) {
274
+ background-color: white !important;
275
+ }
276
+ .pagination :deep(li) {
277
+ background-color: white !important;
278
+ }
279
+ .pagination :deep(li.is-active) {
280
+ color: $app-primary-color;
281
+ }
282
+
283
+ .error-feedback {
284
+ font-family: Asap;
285
+ font-size: 14px;
286
+ font-style: italic;
287
+ padding-top: 15px;
288
+ }
289
+
290
+ .content-card :deep(.el-card__header) {
291
+ background-color: #292b66;
292
+ padding: 1rem;
293
+ }
294
+
295
+ .content-card :deep(.el-card__body) {
296
+ background-color: #f7faff;
297
+ overflow-y: hidden;
298
+ padding: 1rem;
299
+ }
300
+
301
+ .content {
302
+ // width: 515px;
303
+ flex: 1 1 auto;
304
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
305
+ border: solid 1px #e4e7ed;
306
+ background-color: #ffffff;
307
+ overflow-y: scroll;
308
+ scrollbar-width: thin;
309
+ border-radius: var(--el-border-radius-base);
310
+ }
311
+
312
+ .content :deep(.el-loading-spinner .path) {
313
+ stroke: $app-primary-color;
314
+ }
315
+
316
+ .content :deep(.step-item:first-child .seperator-path) {
317
+ display: none;
318
+ }
319
+
320
+ .content :deep(.step-item:not(:first-child) .seperator-path) {
321
+ width: 455px;
322
+ height: 0px;
323
+ border: solid 1px #e4e7ed;
324
+ background-color: #e4e7ed;
325
+ }
326
+
327
+ .scrollbar::-webkit-scrollbar-track {
328
+ border-radius: 10px;
329
+ background-color: #f5f5f5;
330
+ }
331
+
332
+ .scrollbar::-webkit-scrollbar {
333
+ width: 12px;
334
+ right: -12px;
335
+ background-color: #f5f5f5;
336
+ }
337
+
338
+ .scrollbar::-webkit-scrollbar-thumb {
339
+ border-radius: 4px;
340
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.06);
341
+ background-color: #979797;
342
+ }
343
+
344
+ :deep(.el-input__suffix) {
345
+ padding-right: 0px;
346
+ }
347
+
348
+ :deep(.my-drawer) {
349
+ background: rgba(0, 0, 0, 0);
350
+ box-shadow: none;
351
+ }
352
+ </style>
@@ -209,6 +209,7 @@
209
209
  <div class="content-container" v-show="activeView === 'graphView'">
210
210
  <template v-if="graphViewLoaded">
211
211
  <connectivity-graph
212
+ :key="entry.featureId[0]"
212
213
  :entry="entry.featureId[0]"
213
214
  :mapServer="envVars.FLATMAPAPI_LOCATION"
214
215
  :sckanVersion="sckanVersion"
@@ -54,16 +54,23 @@
54
54
  @confirm-delete="$emit('confirm-delete', $event)"
55
55
  />
56
56
  </template>
57
+ <template v-else-if="tab.type === 'connectivityExplorer'">
58
+ <connectivity-explorer
59
+ :ref="'connectivityExplorerTab_' + tab.id"
60
+ v-show="tab.id === activeTabId"
61
+ :envVars="envVars"
62
+ />
63
+ </template>
57
64
  <template v-else>
58
- <SidebarContent
59
- class="sidebar-content-container"
60
- v-show="tab.id === activeTabId"
61
- :contextCardEntry="tab.contextCard"
62
- :envVars="envVars"
63
- :ref="'searchTab_' + tab.id"
64
- @search-changed="searchChanged(tab.id, $event)"
65
- @hover-changed="hoverChanged($event)"
66
- />
65
+ <SidebarContent
66
+ class="sidebar-content-container"
67
+ v-show="tab.id === activeTabId"
68
+ :contextCardEntry="tab.contextCard"
69
+ :envVars="envVars"
70
+ :ref="'searchTab_' + tab.id"
71
+ @search-changed="searchChanged(tab.id, $event)"
72
+ @hover-changed="hoverChanged($event)"
73
+ />
67
74
  </template>
68
75
  </template>
69
76
  </div>
@@ -84,6 +91,7 @@ import EventBus from './EventBus.js'
84
91
  import Tabs from './Tabs.vue'
85
92
  import AnnotationTool from './AnnotationTool.vue'
86
93
  import ConnectivityInfo from './ConnectivityInfo.vue'
94
+ import ConnectivityExplorer from './ConnectivityExplorer.vue'
87
95
 
88
96
  /**
89
97
  * Aims to provide a sidebar for searching capability for SPARC portal.
@@ -98,6 +106,7 @@ export default {
98
106
  Icon,
99
107
  ConnectivityInfo,
100
108
  AnnotationTool,
109
+ ConnectivityExplorer,
101
110
  },
102
111
  name: 'SideBar',
103
112
  props: {
@@ -126,7 +135,8 @@ export default {
126
135
  default: () => [
127
136
  { id: 1, title: 'Search', type: 'search' },
128
137
  { id: 2, title: 'Connectivity', type: 'connectivity' },
129
- { id: 3, title: 'Annotation', type: 'annotation' }
138
+ { id: 3, title: 'Annotation', type: 'annotation' },
139
+ { id: 4, title: 'Connectivity Explorer', type: 'connectivityExplorer' }
130
140
  ],
131
141
  },
132
142
  /**
@@ -239,8 +249,8 @@ export default {
239
249
  getTabByIdAndType: function (id, type) {
240
250
  const tabId = id || this.activeTabId;
241
251
  const tabType = type || 'search'; // default to search tab
242
- const tabObj = this.tabs.find((tab) => tab.id === tabId && tab.type === tabType);
243
- const firstAvailableTab = this.tabs[0];
252
+ const tabObj = this.activeTabs.find((tab) => tab.id === tabId && tab.type === tabType);
253
+ const firstAvailableTab = this.activeTabs[0];
244
254
  return tabObj || firstAvailableTab;
245
255
  },
246
256
  /**
@@ -252,6 +262,8 @@ export default {
252
262
  refIdPrefix = 'connectivityTab_';
253
263
  } else if (type === 'annotation') {
254
264
  refIdPrefix = 'annotationTab_';
265
+ } else if (type === 'connectivityExplorer') {
266
+ refIdPrefix = 'connectivityExplorerTab_';
255
267
  }
256
268
  const tabObj = this.getTabByIdAndType(id, type);
257
269
  const tabRefId = refIdPrefix + tabObj.id;
@@ -323,16 +335,22 @@ export default {
323
335
  },
324
336
  },
325
337
  computed: {
338
+ // This should respect the information provided by the property
326
339
  activeTabs: function() {
327
- const tabs = [
328
- { id: 1, title: 'Search', type: 'search' }
329
- ];
330
- if (this.connectivityInfo) {
331
- tabs.push({ id: 2, title: 'Connectivity', type: 'connectivity' });
332
- }
333
- if (this.annotationEntry && Object.keys(this.annotationEntry).length > 0) {
334
- tabs.push({ id: 3, title: 'Annotation', type: 'annotation' });
335
- }
340
+ const tabs = []
341
+ this.tabs.forEach((tab) => {
342
+ if (tab.type === "search" || tab.type === "connectivityExplorer") {
343
+ tabs.push(tab)
344
+ } else if (tab.type === "connectivity") {
345
+ if (this.connectivityInfo) {
346
+ tabs.push(tab);
347
+ }
348
+ } else if (tab.type === "annotation") {
349
+ if (this.annotationEntry && Object.keys(this.annotationEntry).length > 0) {
350
+ tabs.push(tab);
351
+ }
352
+ }
353
+ })
336
354
  return tabs;
337
355
  },
338
356
  },
@@ -9,6 +9,8 @@ declare module 'vue' {
9
9
  export interface GlobalComponents {
10
10
  AnnotationTool: typeof import('./components/AnnotationTool.vue')['default']
11
11
  BadgesGroup: typeof import('./components/BadgesGroup.vue')['default']
12
+ ConnectivityCard: typeof import('./components/ConnectivityCard.vue')['default']
13
+ ConnectivityExplorer: typeof import('./components/ConnectivityExplorer.vue')['default']
12
14
  ConnectivityInfo: typeof import('./components/ConnectivityInfo.vue')['default']
13
15
  DatasetCard: typeof import('./components/DatasetCard.vue')['default']
14
16
  ElButton: typeof import('element-plus/es')['ElButton']