Skip to content

Commit 7afd7e5

Browse files
authored
Merge pull request #172 from Dataport/feature/text-locator-literature-search
TextLocator/implement literature search
2 parents 3c3a96a + c5f42d9 commit 7afd7e5

File tree

25 files changed

+425
-148
lines changed

25 files changed

+425
-148
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# CHANGELOG
22

3+
## unpublished
4+
5+
- Breaking: Adapt client to new backend API. Previous versions are no longer runnable due the backend API change.
6+
- Feature: Implement document search, that is, the AddressSearch bar now also offers results for documents and clicking on one will retrieve a list of toponyms from the backend and resolve them against the gazetteer. Previously, we had a "get all documents regarding place" functionality. Now, a "get all places regarding document" feature is implemented. Additionally to the AddressSearch, this can be triggered on documents found in the previously implemented way; the "get all places regarding document" functionality is available from within the GeoSearch result display.
7+
38
## 1.0.0-alpha.0
49

510
Initial alpha release.

packages/clients/textLocator/src/addPlugins.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ import {
1818
selectResult,
1919
} from './utils/coastalGazetteer/searchToponym'
2020
import { idRegister } from './services'
21+
import { searchLiterature } from './utils/textLocatorBackend/findLiterature/searchLiterature'
22+
import { selectLiterature } from './utils/textLocatorBackend/findLiterature/selectLiterature'
23+
24+
export const ids = {
25+
groupId: 'groupTL',
26+
categoryIdToponym: 'categoryToponym',
27+
categoryIdLiterature: 'categoryLiterature',
28+
typeGazetteer: 'coastalGazetteer',
29+
typeLiterature: 'literature',
30+
}
2131

2232
// this is fine for list-like setup functions
2333
// eslint-disable-next-line max-lines-per-function
@@ -30,14 +40,29 @@ export const addPlugins = (core) => {
3040
layoutTag: NineLayoutTag.TOP_LEFT,
3141
addLoading: 'plugin/loadingIndicator/addLoadingKey',
3242
removeLoading: 'plugin/loadingIndicator/removeLoadingKey',
43+
// @ts-expect-error | Local parameter requirements diverge from type
3344
customSearchMethods: {
34-
// @ts-expect-error | Local parameter requirements diverge from type
35-
coastalGazetteer: searchCoastalGazetteerByToponym,
45+
[ids.typeGazetteer]: searchCoastalGazetteerByToponym,
46+
[ids.typeLiterature]: searchLiterature,
3647
},
3748
customSelectResult: {
38-
// it's defined like that
39-
// eslint-disable-next-line @typescript-eslint/naming-convention
40-
'': selectResult,
49+
[ids.categoryIdToponym]: selectResult,
50+
[ids.categoryIdLiterature]: selectLiterature,
51+
},
52+
groupProperties: {
53+
[ids.groupId]: {
54+
label: `textLocator.addressSearch.${ids.groupId}`,
55+
resultDisplayMode: 'categorized',
56+
limitResults: 3,
57+
},
58+
},
59+
categoryProperties: {
60+
[ids.categoryIdToponym]: {
61+
label: 'textLocator.addressSearch.toponym',
62+
},
63+
[ids.categoryIdLiterature]: {
64+
label: 'textLocator.addressSearch.literature',
65+
},
4166
},
4267
afterResultComponent: ResultInfo,
4368
}),

packages/clients/textLocator/src/components/ResultInfo.vue

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
<v-icon small> fa-info-circle </v-icon>
1111
</span>
1212
</template>
13-
<v-simple-table dense>
13+
<p v-if="isLiterature" class="result-info-title-display">
14+
{{ featureAsLiterature.title }}
15+
</p>
16+
<v-simple-table v-else dense>
1417
<template #default>
1518
<thead>
1619
<tr>
@@ -30,8 +33,14 @@
3033
</thead>
3134
<tbody>
3235
<tr
33-
v-for="{ ObjectID, Name, Sprache, Typ, Start, Ende } in feature
34-
.properties.names"
36+
v-for="{
37+
ObjectID,
38+
Name,
39+
Sprache,
40+
Typ,
41+
Start,
42+
Ende,
43+
} in featureAsGeometry.properties.names"
3544
:key="ObjectID"
3645
>
3746
<td>{{ Name }}</td>
@@ -48,13 +57,15 @@
4857
<script lang="ts">
4958
import Vue, { PropType } from 'vue'
5059
import { GeometrySearchState } from '../plugins/GeometrySearch/types'
60+
import { LiteratureFeature } from '../types'
5161
5262
export default Vue.extend({
5363
name: 'ResultInfo',
5464
props: {
5565
feature: {
5666
type: Object as PropType<
57-
GeometrySearchState['featureCollection']['features'][number]
67+
| GeometrySearchState['featureCollection']['features'][number]
68+
| LiteratureFeature
5869
>,
5970
required: true,
6071
},
@@ -73,9 +84,34 @@ export default Vue.extend({
7384
default: -1,
7485
},
7586
},
87+
computed: {
88+
isLiterature() {
89+
return Boolean(this.feature.properties.location_hits)
90+
},
91+
featureAsGeometry() {
92+
return this
93+
.feature as GeometrySearchState['featureCollection']['features'][number]
94+
},
95+
featureAsLiterature() {
96+
return this.feature as LiteratureFeature
97+
},
98+
},
7699
})
77100
</script>
78101

102+
<style scoped>
103+
.v-icon {
104+
margin-left: 0.5em;
105+
}
106+
107+
.result-info-title-display {
108+
background: #f5f5f5;
109+
color: #333;
110+
max-width: 30ch;
111+
padding: 0.5em 1em;
112+
}
113+
</style>
114+
79115
<style>
80116
/* suppress table wrap; table looks fine as an element in itself */
81117
.v-tooltip__content:has(.v-data-table) {

packages/clients/textLocator/src/locales.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ const locales: LanguageOption[] = [
1515
type: 'de',
1616
resources: {
1717
textLocator: {
18-
// TODO temporary key, should be removed when no longer needed
19-
notImplemented: 'Diese Funktion ist noch nicht implementiert.',
2018
layers: {
2119
[openStreetMap]: 'OpenStreetMap',
2220
[openSeaMap]: 'OpenSeaMap',
@@ -34,6 +32,9 @@ const locales: LanguageOption[] = [
3432
language: 'Sprache',
3533
timeFrame: 'Zeitraum',
3634
},
35+
groupTL: 'Literatur- und Ortssuche',
36+
toponym: 'Ortssuche',
37+
literature: 'Literatursuche',
3738
},
3839
attributions: {
3940
[openStreetMap]: `$t(textLocator.layers.${openStreetMap}): © <a href='https://www.openstreetmap.org/copyright' target='_blank'>OpenStreetMap</a> contributors`,
@@ -57,15 +58,10 @@ const locales: LanguageOption[] = [
5758
'Es gibt viele Ergebnisse zu der letzten Anfrage. Der Ladevorgang kann einen Moment länger dauern.',
5859
},
5960
error: {
60-
searchCoastalGazetteer:
61+
search:
6162
'Die Suche ist mit einem unbekannten Fehler fehlgeschlagen. Bitte versuchen Sie es später erneut.',
6263
},
6364
},
64-
plugins: {
65-
addressSearch: {
66-
defaultGroup: 'Ortssuche',
67-
},
68-
},
6965
},
7066
},
7167
// NOTE: English translation not yet required and may be incomplete

packages/clients/textLocator/src/plugins/GeometrySearch/components/Tree.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
</template>
1313
{{ item.name }}
1414
<template v-if="item.type === 'toponym' && item.feature">
15-
&nbsp;
1615
<ResultInfo
1716
:tab-index="0"
1817
:feature="item.feature"

packages/clients/textLocator/src/plugins/GeometrySearch/store/actions/watchers.ts renamed to packages/clients/textLocator/src/plugins/GeometrySearch/store/actions/updateFrequencies.ts

Lines changed: 31 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,7 @@
1-
import { PolarActionContext, PolarStore } from '@polar/lib-custom-types'
1+
import { PolarActionContext } from '@polar/lib-custom-types'
22
import { GeometrySearchGetters, GeometrySearchState } from '../../types'
3-
import {
4-
TitleLocationFrequency,
5-
searchLiteratureByToponym,
6-
} from '../../../../utils/literatureByToponym'
7-
8-
export function setupWatchers(
9-
this: PolarStore<GeometrySearchState, GeometrySearchGetters>,
10-
{
11-
dispatch,
12-
rootGetters,
13-
}: PolarActionContext<GeometrySearchState, GeometrySearchGetters>
14-
) {
15-
// load titleLocationFrequency on each featureCollection update
16-
this.watch(
17-
() => rootGetters['plugin/geometrySearch/featureCollection'],
18-
() => dispatch('updateFrequencies')
19-
)
20-
}
3+
import { searchLiteratureByToponym } from '../../../../utils/textLocatorBackend/literatureByToponym'
4+
import { TitleLocationFrequency } from '../../../../types'
215

226
const requestLiteraturePerFeature = (
237
featureCollection: GeometrySearchState['featureCollection'],
@@ -28,35 +12,33 @@ const requestLiteraturePerFeature = (
2812
.filter((names) => names.length)
2913
.map((names) => searchLiteratureByToponym(textLocatorBackendUrl, names))
3014

31-
const aggregatePerFeatureId =
32-
(featureCollection: GeometrySearchState['featureCollection']) =>
33-
(
34-
featureFrequency: TitleLocationFrequency,
35-
index: number
36-
): TitleLocationFrequency =>
37-
Object.fromEntries(
38-
Object.entries(featureFrequency).map(([literatureTitle, frequency]) => [
39-
literatureTitle,
40-
{
41-
[featureCollection.features[index].id as string]: Object.values(
42-
frequency
43-
).reduce((accumulator, current) => accumulator + current, 0),
44-
},
45-
])
15+
const aggregateFeatureHitsByLocationOfLiterature = (
16+
featureCollection: GeometrySearchState['featureCollection'],
17+
titleLocationFrequencies: TitleLocationFrequency[]
18+
): TitleLocationFrequency =>
19+
titleLocationFrequencies.reduce((accumulator, current, index) => {
20+
Object.entries(current).forEach(
21+
([literatureId, { title, location_frequency: locationFrequency }]) => {
22+
accumulator[literatureId] = {
23+
title,
24+
location_frequency: {
25+
...(accumulator[literatureId]?.location_frequency || {}),
26+
...Object.fromEntries(
27+
Object.entries(locationFrequency).map((entry) => [
28+
featureCollection.features[index].id as string,
29+
entry[1] +
30+
(locationFrequency[
31+
featureCollection.features[index].id as string
32+
] || 0),
33+
])
34+
),
35+
},
36+
}
37+
}
4638
)
4739

48-
const flattenFrequencies = (
49-
accumulator: TitleLocationFrequency,
50-
current: TitleLocationFrequency
51-
) => {
52-
Object.entries(current).forEach(([title, findings]) => {
53-
accumulator[title] = {
54-
...(accumulator[title] || {}),
55-
...findings,
56-
}
57-
})
58-
return accumulator
59-
}
40+
return accumulator
41+
}, {} as TitleLocationFrequency)
6042

6143
export async function updateFrequencies({
6244
commit,
@@ -78,7 +60,9 @@ export async function updateFrequencies({
7860
dispatch('changeActiveData', null)
7961
return
8062
}
81-
const titleLocationFrequency = (
63+
64+
const titleLocationFrequency = aggregateFeatureHitsByLocationOfLiterature(
65+
featureCollection,
8266
await Promise.all(
8367
requestLiteraturePerFeature(
8468
featureCollection,
@@ -87,8 +71,6 @@ export async function updateFrequencies({
8771
)
8872
)
8973
)
90-
.map(aggregatePerFeatureId(featureCollection))
91-
.reduce(flattenFrequencies, {})
9274

9375
commit('setTitleLocationFrequency', titleLocationFrequency)
9476
if (Object.keys(titleLocationFrequency).length) {

packages/clients/textLocator/src/plugins/GeometrySearch/store/index.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import { getEmptyFeatureCollection } from '../../../utils/coastalGazetteer/respo
1414
import { makeTreeView } from '../utils/makeTreeView'
1515
import { updateVectorLayer, vectorLayer } from '../utils/vectorDisplay'
1616
import { geoJson } from '../../../utils/coastalGazetteer/common'
17+
import { selectLiterature } from '../../../utils/textLocatorBackend/findLiterature/selectLiterature'
18+
import { searchToponymByLiterature } from '../../../utils/textLocatorBackend/toponymByLiterature'
1719
import { setupTooltip } from './actions/setupTooltip'
1820
import { setupDrawReaction } from './actions/setupDrawReaction'
19-
import { setupWatchers, updateFrequencies } from './actions/watchers'
21+
import { updateFrequencies } from './actions/updateFrequencies'
2022

2123
let counter = 0
2224
const searchLoadingKey = 'geometrySearchLoadingKey'
@@ -41,14 +43,11 @@ export const makeStoreModule = () => {
4143
dispatch('setupDrawReaction')
4244
dispatch('setupTooltip')
4345
map.addLayer(vectorLayer)
44-
// register watchers after store is ready (else immediate-like firing on not-really change)
45-
setTimeout(() => dispatch('setupWatchers'), 0)
4646
},
4747
setupTooltip,
4848
setupDrawReaction,
49-
setupWatchers,
5049
updateFrequencies,
51-
searchGeometry({ rootGetters, commit }, feature: Feature) {
50+
searchGeometry({ rootGetters, commit, dispatch }, feature: Feature) {
5251
const loadingKey = getSearchLoadingKey()
5352
commit('plugin/loadingIndicator/addLoadingKey', loadingKey, {
5453
root: true,
@@ -61,7 +60,10 @@ export const makeStoreModule = () => {
6160
rootGetters.configuration.geometrySearch.url,
6261
rootGetters.configuration.epsg
6362
)
64-
.then((result) => commit('setFeatureCollection', result))
63+
.then((result) => {
64+
commit('setFeatureCollection', result)
65+
dispatch('updateFrequencies')
66+
})
6567
.finally(() =>
6668
commit('plugin/loadingIndicator/removeLoadingKey', loadingKey, {
6769
root: true,
@@ -85,16 +87,23 @@ export const makeStoreModule = () => {
8587
fullSearchOnToponym({ dispatch }, item: TreeViewItem) {
8688
dispatch('searchGeometry', geoJson.readFeature(item.feature))
8789
},
88-
fullSearchLiterature({ dispatch }) {
89-
dispatch(
90-
'plugin/toast/addToast',
91-
{
92-
type: 'info',
93-
text: 'common:textLocator.notImplemented',
94-
timeout: 5000,
95-
},
96-
{ root: true }
90+
async fullSearchLiterature(actionContext, item: TreeViewItem) {
91+
const titleLocationFrequency = await searchToponymByLiterature(
92+
// @ts-expect-error | added in polar-client.ts locally
93+
actionContext.rootGetters.configuration.textLocatorBackendUrl,
94+
item.id
9795
)
96+
selectLiterature.call(this, actionContext, {
97+
categoryId: 0, // dummy to fit API
98+
feature: {
99+
type: 'Feature',
100+
// fake geom to fit APIs; ignored by custom selectLiterature
101+
geometry: { type: 'Point', coordinates: [0, 0] },
102+
properties: titleLocationFrequency[item.id].location_frequency,
103+
id: item.id,
104+
title: item.name,
105+
},
106+
})
98107
},
99108
},
100109
mutations: {

packages/clients/textLocator/src/plugins/GeometrySearch/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
GeoJsonProperties,
55
Geometry,
66
} from 'geojson'
7-
import { TitleLocationFrequency } from '../../utils/literatureByToponym'
7+
import { TitleLocationFrequency } from '../../types'
88
import { ResponseGeom, ResponseName } from '../../utils/coastalGazetteer/types'
99

1010
export type TextLocatorCategories = 'text' | 'toponym'

0 commit comments

Comments
 (0)