Skip to content

Commit e874ec8

Browse files
committed
demo display and cleaning up search query views
1 parent a8d6441 commit e874ec8

9 files changed

Lines changed: 190 additions & 27 deletions

File tree

client/src/components/LayerConfig.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export default defineComponent({
113113
</v-col>
114114

115115
<v-col
116-
v-if="proMode"
117116
title="Deselect"
118117
cols="1"
119118
>

client/src/components/Map.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export default defineComponent({
237237
watch(
238238
MapStore.hoveredFeatures,
239239
() => {
240-
if (map.value && MapStore.mapLayerFeatureGraphsVisible.value) {
240+
if (map.value && (MapStore.mapLayerFeatureGraphsVisible.value || MapStore.activeSideBarCard.value === 'searchableVectors')) {
241241
updateSelected(map.value);
242242
}
243243
},

client/src/components/VectorFeatureSearch/Editor/VectorFeatureSearchEditor.vue

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default defineComponent({
2121
mainTextSearchFields: [],
2222
configurableFilters: [],
2323
display: {
24-
titleKey: { key: '', showDisplayName: false },
24+
titleKey: '',
2525
subtitleKeys: [],
2626
detailStrings: [],
2727
sortableFields: [],
@@ -36,6 +36,13 @@ export default defineComponent({
3636
});
3737
const searchDialog = ref(false);
3838
const availableProperties: Ref<Record<string, AvailablePropertyDisplay>> = ref({});
39+
40+
const getDisplayName = (key: string) => {
41+
if (availableProperties.value[key]) {
42+
return availableProperties.value[key].displayName || key;
43+
}
44+
return key;
45+
};
3946
const loadInitialData = () => {
4047
const found = MapStore.selectedVectorMapLayers.value.find((item) => item.id === props.layerId);
4148
if (found) {
@@ -67,6 +74,8 @@ export default defineComponent({
6774
value: key,
6875
})));
6976
77+
const availableTitleKeys = computed(() => Object.keys(availableProperties.value || {}).map((key) => (getDisplayName(key))));
78+
7079
const availableSubtitleKeys = computed(() => Object.keys(availableProperties.value || {}).map((key) => ({
7180
title: availableProperties.value?.[key]?.displayName || key,
7281
value: key,
@@ -123,12 +132,14 @@ export default defineComponent({
123132
saveChanges,
124133
addKeyDialog,
125134
addingKeyType,
135+
availableTitleKeys,
126136
availableSubtitleKeys,
127137
availableDetailKeys,
128138
addingKey,
129139
addNewKey,
130140
saveNewKey,
131141
searchDialog,
142+
getDisplayName,
132143
};
133144
},
134145
});
@@ -147,6 +158,41 @@ export default defineComponent({
147158
Properties need to be configured before setting up search fields
148159
</v-alert>
149160
</v-row>
161+
<div v-if="localData && localData.mainTextSearchFields && localData.mainTextSearchFields.length > 0" class="my-1">
162+
<b class="mr-2">Searchable:</b>
163+
<v-chip
164+
v-for="(field, index) in localData.mainTextSearchFields"
165+
:key="index"
166+
size="x-small"
167+
>
168+
{{ field.title }}
169+
</v-chip>
170+
</div>
171+
<div v-if="localData && localData.display" class="my-1">
172+
<b class="mr-2">Title:</b>
173+
<span>{{ getDisplayName(localData.display.titleKey) }}</span>
174+
</div>
175+
<div v-if="localData && localData.display" class="my-1">
176+
<b class="mr-2">Subtitles:</b>
177+
<v-chip
178+
v-for="(field, index) in localData.display.subtitleKeys"
179+
:key="index"
180+
size="x-small"
181+
>
182+
{{ field.key }}
183+
</v-chip>
184+
</div>
185+
<div v-if="localData && localData.display" class="my-1">
186+
<b class="mr-2">Details:</b>
187+
<v-chip
188+
v-for="(field, index) in localData.display.detailStrings"
189+
:key="index"
190+
size="x-small"
191+
>
192+
{{ field.key }}
193+
</v-chip>
194+
</div>
195+
150196
<v-dialog v-model="searchDialog" width="800px">
151197
<v-card>
152198
<v-card-title>Edit Searchable Vector Data</v-card-title>
@@ -190,8 +236,7 @@ export default defineComponent({
190236
label="Zoom Button Enabled"
191237
/>
192238
<div v-if="localData.display.zoomButton">
193-
<v-select v-model="localData.display.zoomType" :items="['level', 'buffer']" label="Zoom Type" />
194-
<v-text-field v-model.number="localData.display.zoomBufferOrLevel" label="Zoom Value" />
239+
<v-text-field v-model.number="localData.display.zoomBufferOrLevel" label="Zoom Level" />
195240
</div>
196241
</v-expansion-panel-text>
197242
</v-expansion-panel>
@@ -200,7 +245,9 @@ export default defineComponent({
200245
<strong>Filters</strong>
201246
</v-expansion-panel-title>
202247
<v-expansion-panel-text>
248+
<p>Filters will be implmented in the future</p>
203249
<VectorFeatureSearchFilterItem
250+
v-if="false"
204251
v-model="localData.configurableFilters"
205252
:available-property-keys="availablePropertyKeys"
206253
/>
@@ -220,7 +267,7 @@ export default defineComponent({
220267
<strong>Title</strong>
221268
</v-expansion-panel-title>
222269
<v-expansion-panel-text>
223-
<v-select v-model="localData.display.titleKey" :items="availablePropertyKeys" label="Title Key" />
270+
<v-select v-model="localData.display.titleKey" :items="availableTitleKeys" label="Title Key" />
224271
</v-expansion-panel-text>
225272
</v-expansion-panel>
226273
<v-expansion-panel>

client/src/components/VectorFeatureSearch/Editor/VectorFeatureSearchFilterItem.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
66
export default defineComponent({
77
props: {
8-
value: {
8+
modelValue: {
99
type: Array as PropType<string[]>,
1010
required: true,
1111
},
@@ -14,12 +14,12 @@ export default defineComponent({
1414
required: true,
1515
},
1616
},
17-
emits: ['update'],
17+
emits: ['update:modelValue'],
1818
setup(props, { emit }) {
19-
const localFilters = ref(props.value);
19+
const localFilters = ref(props.modelValue);
2020
2121
watch(localFilters, () => {
22-
emit('update', localFilters.value);
22+
emit('update:modelValue', localFilters.value);
2323
}, { deep: true });
2424
2525
return {

client/src/components/VectorFeatureSearch/VectorFeatureSearch.vue

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
<!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events -->
2+
<!-- eslint-disable vuejs-accessibility/mouse-events-have-key-events -->
13
<script lang="ts">
24
import {
35
Ref,
4-
computed, defineComponent, ref, watch,
6+
computed, defineComponent, onMounted, onUnmounted, ref, watch,
57
} from 'vue';
68
import UVdatApi from '../../api/UVDATApi';
79
import MapStore from '../../MapStore';
@@ -15,6 +17,18 @@ export default defineComponent({
1517
const filterBBox = ref(false);
1618
const showFilters = ref(false);
1719
const selectedLayer = ref<number | null>(null);
20+
const availableProperties = computed(() => {
21+
if (selectedLayer.value !== null) {
22+
const found = MapStore.selectedVectorMapLayers.value.find((item) => item.id === selectedLayer.value);
23+
if (found) {
24+
if (found.default_style.properties?.availableProperties) {
25+
return found.default_style.properties.availableProperties;
26+
}
27+
}
28+
}
29+
return {};
30+
});
31+
1832
const availableLayers = computed(
1933
() => MapStore.mapLayerVectorSearchable.value.map((item) => ({ title: item.name, value: item.id })),
2034
);
@@ -26,6 +40,15 @@ export default defineComponent({
2640
});
2741
const searchResults: Ref<SearchableVectorFeatureResponse[]> = ref([]);
2842
43+
const displayKeys = computed(() => {
44+
if (selectedSearchSettings.value) {
45+
const subTitleKeys = selectedSearchSettings.value.display.subtitleKeys.filter((key) => key.showDisplayName).map((key) => key.key);
46+
const detailKeys = selectedSearchSettings.value.display.detailStrings.filter((key) => key.showDisplayName).map((key) => key.key);
47+
return { subTitleKeys, detailKeys };
48+
}
49+
return { subTitleKeys: [], detailKeys: [] };
50+
});
51+
2952
const updateSearch = async () => {
3053
if (selectedSearchSettings.value && selectedLayer.value !== null) {
3154
const data: SearchableVectorDataRequest = {
@@ -52,6 +75,20 @@ export default defineComponent({
5275
}
5376
};
5477
78+
onMounted(() => {
79+
if (availableLayers.value.length) {
80+
selectedLayer.value = availableLayers.value[0].value;
81+
}
82+
updateSearch();
83+
});
84+
85+
onUnmounted(() => {
86+
if (internalMap.value) {
87+
internalMap.value.off('moveend', onMapMoveEnd);
88+
internalMap.value.off('move', onMapMove);
89+
}
90+
});
91+
5592
watch(filterBBox, () => {
5693
if (filterBBox.value && internalMap.value) {
5794
internalMap.value.on('moveend', onMapMoveEnd);
@@ -67,6 +104,33 @@ export default defineComponent({
67104
updateSearch();
68105
});
69106
107+
const getPropertyDisplayName = (key: string) => {
108+
if (availableProperties.value[key]) {
109+
return availableProperties.value[key].displayName;
110+
}
111+
return key;
112+
};
113+
114+
const zoomToFeature = (id: number) => {
115+
const found = searchResults.value.find((item) => item.id === id);
116+
if (found && internalMap.value && selectedSearchSettings.value?.display.zoomBufferOrLevel) {
117+
internalMap.value.setCenter([found.center.lon, found.center.lat]);
118+
internalMap.value.setZoom(selectedSearchSettings.value.display.zoomBufferOrLevel);
119+
}
120+
};
121+
122+
const onCardHover = (vectorFeatureId: number) => {
123+
if (!MapStore.hoveredFeatures.value.includes(vectorFeatureId)) {
124+
MapStore.hoveredFeatures.value.push(vectorFeatureId);
125+
}
126+
};
127+
const onCardExit = (vectorFeatureId: number) => {
128+
const foundIndex = MapStore.hoveredFeatures.value.findIndex((item) => item === vectorFeatureId);
129+
if (foundIndex !== -1) {
130+
MapStore.hoveredFeatures.value.splice(foundIndex, 1);
131+
}
132+
};
133+
70134
return {
71135
search,
72136
filterBBox,
@@ -75,6 +139,11 @@ export default defineComponent({
75139
availableLayers,
76140
selectedSearchSettings,
77141
searchResults,
142+
getPropertyDisplayName,
143+
displayKeys,
144+
zoomToFeature,
145+
onCardHover,
146+
onCardExit,
78147
};
79148
},
80149
});
@@ -113,7 +182,8 @@ export default defineComponent({
113182
</v-icon>
114183
</template>
115184
</v-tooltip>
116-
<v-tooltip text="View metadata filters">
185+
<!-- Eventual Filters added to the system -->
186+
<v-tooltip v-if="false" text="View metadata filters">
117187
<template #activator="{ props }">
118188
<v-icon :color="showFilters ? 'primary' : ''" v-bind="props" @click="showFilters = !showFilters">
119189
mdi-filter
@@ -122,8 +192,6 @@ export default defineComponent({
122192
</v-tooltip>
123193
</v-row>
124194

125-
<!-- Selected Filters as Chips (Shown when filters are hidden) -->
126-
127195
<!-- Filters (Toggles Visibility) -->
128196
<v-expand-transition class="pt-2">
129197
<div v-if="showFilters && selectedSearchSettings?.configurableFilters.length">
@@ -135,17 +203,45 @@ export default defineComponent({
135203

136204
<!-- Filtered Layers -->
137205
<div v-if="searchResults">
138-
<v-card v-for="result in searchResults" :key="result.id">
139-
{{ result.title }}
140-
<v-list-item-subtitle>
141-
<div v-for="item in result.subtitles" :key="item">
142-
{{ item }}
206+
<v-card
207+
v-for="result in searchResults"
208+
:key="result.id"
209+
class="my-1 search-card"
210+
@mouseenter="onCardHover(result.id)"
211+
@focusin="onCardHover(result.id)"
212+
@focusout="onCardExit(result.id)"
213+
@mouseleave="onCardExit(result.id)"
214+
>
215+
<v-container>
216+
<v-row dense>
217+
<h4>{{ result.title }}</h4>
218+
<v-spacer />
219+
<v-tooltip v-if="selectedSearchSettings?.display.zoomButton" text="Zoom to Feature">
220+
<template #activator="{ props }">
221+
<v-icon v-bind="props" @click="zoomToFeature(result.id)">
222+
mdi-magnify
223+
</v-icon>
224+
</template>
225+
</v-tooltip>
226+
</v-row>
227+
<div v-for="item in result.subtitles" :key="item.key">
228+
<b v-if="displayKeys.subTitleKeys.includes(item.key)" class="mx-2">{{ getPropertyDisplayName(item.key) }}:</b>
229+
<span>{{ item.value }}</span>
143230
</div>
144-
</v-list-item-subtitle>
231+
<ul v-if="result.details.length" class="ml-8">
232+
<li v-for="item in result.details" :key="item.key">
233+
<b v-if="displayKeys.detailKeys.includes(item.key)" class="mx-2">{{ getPropertyDisplayName(item.key) }}:</b>
234+
<span>{{ item.value }}</span>
235+
</li>
236+
</ul>
237+
</v-container>
145238
</v-card>
146239
</div>
147240
</v-container>
148241
</template>
149242

150243
<style scoped>
244+
.search-card:hover {
245+
background-color: #adf4ff78;
246+
}
151247
</style>

client/src/map/mapColors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const chainSelected = (result: any[] = [], color = 'cyan', defaultColor = '') =>
5353
result.push('case');
5454
result.push(['in', ['get', 'vectorfeatureid'], ['literal', MapStore.selectedIds.value]]);
5555
result.push(color);
56-
if (MapStore.mapLayerFeatureGraphsVisible.value) {
56+
if (MapStore.mapLayerFeatureGraphsVisible.value || MapStore.activeSideBarCard.value === 'searchableVectors') {
5757
result.push(['in', ['get', 'vectorfeatureid'], ['literal', MapStore.hoveredFeatures.value]]);
5858
result.push(color);
5959
}

client/src/types.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ export interface SearchableVectorData {
864864
display: {
865865
geospatialFilterEnabled: boolean; // Filter results based on map display as well
866866
sortable: boolean; // Ability to sort items by something other than the name of the titleKey field.
867-
titleKey: SearchableVectorDisplayItem;
867+
titleKey: string; // key of property to display
868868
subtitleKeys: SearchableVectorDisplayItem[]; // Allows zero or multiple subtitles that will be in a single line
869869
detailStrings: SearchableVectorDisplayItem[];
870870
selectionButton: boolean;
@@ -896,6 +896,7 @@ export interface SearchableVectorDataRequest {
896896
export interface SearchableVectorFeatureResponse {
897897
id: number;
898898
title: string;
899-
subtitles: string[];
900-
details: string[];
899+
subtitles: { key: string; value: string }[];
900+
details: { key: string; value: string }[];
901+
center: { lat: number, lon: number };
901902
}

0 commit comments

Comments
 (0)