Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextLocator/implement literature search #172

Merged
merged 42 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
603f1e1
implement literature search for custom backend
warm-coolguy Sep 4, 2024
81a2ad4
change comment after discussion about linting rule
warm-coolguy Sep 4, 2024
98389f5
Merge branch 'main' into feature/text-locator-literature-search
warm-coolguy Sep 11, 2024
6dcacc1
Merge branch 'main' of https://github.com/Dataport/polar into feature…
warm-coolguy Sep 11, 2024
cb13fe1
Merge branch 'fix/ts-client-check-whoopsie' of https://github.com/Dat…
warm-coolguy Sep 11, 2024
ee67809
integrate type fixes for automated client checks
warm-coolguy Sep 11, 2024
4e5ba4c
Merge branch 'fix/ts-client-check-whoopsie' of https://github.com/Dat…
warm-coolguy Sep 12, 2024
f7b0566
Merge branch 'main' of https://github.com/Dataport/polar into feature…
warm-coolguy Sep 13, 2024
bdeb4eb
fix import path
warm-coolguy Sep 13, 2024
9b320de
add NOTE regarding next iteration
warm-coolguy Sep 13, 2024
e833120
remove outdated TODO
warm-coolguy Sep 13, 2024
9a28d8d
update TODO (now it's a NOTE)
warm-coolguy Sep 13, 2024
a450a13
refactor: replace watcher with action where needed
warm-coolguy Sep 13, 2024
7ae2f28
implement relaying literature search to display
warm-coolguy Sep 13, 2024
ce89fb9
remove some nbsp spacing
warm-coolguy Sep 13, 2024
b0442b9
Merge branch 'main' into feature/text-locator-literature-search
warm-coolguy Sep 18, 2024
0dba959
add changelog
warm-coolguy Sep 27, 2024
7876359
refactor & rework frontend to match new backend
warm-coolguy Sep 30, 2024
f46891a
Merge branch 'main' of https://github.com/Dataport/polar into feature…
warm-coolguy Sep 30, 2024
d801767
fix import
warm-coolguy Sep 30, 2024
08df3c0
Merge branch 'main' into feature/text-locator-literature-search
dopenguin Sep 30, 2024
8c5166a
adapt search selection method to new API
warm-coolguy Oct 1, 2024
a40b3e9
code golf
warm-coolguy Oct 1, 2024
e329bef
implement literature2toponyms re-search feature
warm-coolguy Oct 1, 2024
75278ec
Merge branch 'main' into feature/text-locator-literature-search
dopenguin Oct 1, 2024
b6c1f6b
Merge branch 'main' into feature/text-locator-literature-search
warm-coolguy Oct 8, 2024
59390b4
add new wildcard feature
warm-coolguy Oct 10, 2024
07dda26
Update packages/clients/textLocator/CHANGELOG.md
warm-coolguy Oct 11, 2024
30ff3de
Update packages/clients/textLocator/CHANGELOG.md
warm-coolguy Oct 11, 2024
75e6ae9
Update packages/clients/textLocator/CHANGELOG.md
warm-coolguy Oct 11, 2024
febe137
Update packages/clients/textLocator/CHANGELOG.md
warm-coolguy Oct 11, 2024
7fbb025
Update packages/clients/textLocator/src/components/ResultInfo.vue
warm-coolguy Oct 11, 2024
83f2765
scope the scopable class
warm-coolguy Oct 11, 2024
35484e6
merge duplicate locales
warm-coolguy Oct 11, 2024
5a80d9b
Update packages/clients/textLocator/src/utils/textLocatorBackend/urlS…
warm-coolguy Oct 11, 2024
263c35a
Update packages/clients/textLocator/src/utils/textLocatorBackend/find…
warm-coolguy Oct 11, 2024
76bb3d5
Update packages/clients/textLocator/src/utils/textLocatorBackend/find…
warm-coolguy Oct 11, 2024
d17e740
Update packages/clients/textLocator/src/utils/textLocatorBackend/find…
warm-coolguy Oct 11, 2024
d23055a
add some inline comments
warm-coolguy Oct 14, 2024
3785d4d
Merge branch 'feature/text-locator-literature-search' of https://gith…
warm-coolguy Oct 14, 2024
f0de101
Update packages/clients/textLocator/src/plugins/GeometrySearch/utils/…
warm-coolguy Oct 22, 2024
c5f42d9
Remove redundant property
dopenguin Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/clients/textLocator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

## unreleased

- BREAKING: Adapt client to new backend API. Previous versions are no longer runnable due the backend API change.
- Feature: Implemented 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.


## 1.0.0-alpha.0

Initial alpha release.
35 changes: 30 additions & 5 deletions packages/clients/textLocator/src/addPlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ import {
selectResult,
} from './utils/coastalGazetteer/searchToponym'
import { idRegister } from './services'
import { searchLiterature } from './utils/textLocatorBackend/findLiterature/searchLiterature'
import { selectLiterature } from './utils/textLocatorBackend/findLiterature/selectLiterature'

export const ids = {
groupId: 'groupTL',
categoryIdToponym: 'categoryToponym',
categoryIdLiterature: 'categoryLiterature',
typeGazetteer: 'coastalGazetteer',
typeLiterature: 'literature',
}

// this is fine for list-like setup functions
// eslint-disable-next-line max-lines-per-function
Expand All @@ -30,14 +40,29 @@ export const addPlugins = (core) => {
layoutTag: NineLayoutTag.TOP_LEFT,
addLoading: 'plugin/loadingIndicator/addLoadingKey',
removeLoading: 'plugin/loadingIndicator/removeLoadingKey',
// @ts-expect-error | Local parameter requirements diverge from type
customSearchMethods: {
// @ts-expect-error | Local parameter requirements diverge from type
coastalGazetteer: searchCoastalGazetteerByToponym,
[ids.typeGazetteer]: searchCoastalGazetteerByToponym,
[ids.typeLiterature]: searchLiterature,
},
customSelectResult: {
// it's defined like that
// eslint-disable-next-line @typescript-eslint/naming-convention
'': selectResult,
[ids.categoryIdToponym]: selectResult,
[ids.categoryIdLiterature]: selectLiterature,
},
groupProperties: {
[ids.groupId]: {
label: `textLocator.addressSearch.${ids.groupId}`,
resultDisplayMode: 'categorized',
limitResults: 3,
},
},
categoryProperties: {
[ids.categoryIdToponym]: {
label: 'textLocator.addressSearch.toponym',
},
[ids.categoryIdLiterature]: {
label: 'textLocator.addressSearch.literature',
},
},
afterResultComponent: ResultInfo,
}),
Expand Down
46 changes: 42 additions & 4 deletions packages/clients/textLocator/src/components/ResultInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
<v-icon small> fa-info-circle </v-icon>
</span>
</template>
<v-simple-table dense>
<p v-if="isLiterature" class="result-info-title-display">
{{ featureAsLiterature.title }}
</p>
<v-simple-table v-else dense>
<template #default>
<thead>
<tr>
Expand All @@ -30,8 +33,14 @@
</thead>
<tbody>
<tr
v-for="{ ObjectID, Name, Sprache, Typ, Start, Ende } in feature
.properties.names"
v-for="{
ObjectID,
Name,
Sprache,
Typ,
Start,
Ende,
} in featureAsGeometry.properties.names"
:key="ObjectID"
>
<td>{{ Name }}</td>
Expand All @@ -48,13 +57,15 @@
<script lang="ts">
import Vue, { PropType } from 'vue'
import { GeometrySearchState } from '../plugins/GeometrySearch/types'
import { LiteratureFeature } from '../types'

export default Vue.extend({
name: 'ResultInfo',
props: {
feature: {
type: Object as PropType<
GeometrySearchState['featureCollection']['features'][number]
| GeometrySearchState['featureCollection']['features'][number]
| LiteratureFeature
>,
required: true,
},
Expand All @@ -73,14 +84,41 @@ export default Vue.extend({
default: -1,
},
},
computed: {
// duck-typing
isLiterature(): boolean {
return Boolean(this.feature.properties.location_hits)
},
// required TS support missing in template; workaround ...
featureAsGeometry(): GeometrySearchState['featureCollection']['features'][number] {
return this
.feature as GeometrySearchState['featureCollection']['features'][number]
},
featureAsLiterature(): LiteratureFeature {
return this.feature as LiteratureFeature
},
},
})
</script>

<style scoped>
.v-icon {
margin-left: 0.5em;
}
</style>

<style>
/* suppress table wrap; table looks fine as an element in itself */
.v-tooltip__content:has(.v-data-table) {
padding: 0 !important;
margin: 0 !important;
border: 0 !important;
}

.result-info-title-display {
background: #f5f5f5;
color: #333;
max-width: 30ch;
padding: 0.5em 1em;
}
</style>
12 changes: 5 additions & 7 deletions packages/clients/textLocator/src/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ const locales: LanguageOption[] = [
type: 'de',
resources: {
textLocator: {
// TODO temporary key, should be removed when no longer needed
notImplemented: 'Diese Funktion ist noch nicht implementiert.',
layers: {
[openStreetMap]: 'OpenStreetMap',
[openSeaMap]: 'OpenSeaMap',
Expand All @@ -34,6 +32,9 @@ const locales: LanguageOption[] = [
language: 'Sprache',
timeFrame: 'Zeitraum',
},
groupTL: 'Literatur- und Ortssuche',
toponym: 'Ortssuche',
literature: 'Literatursuche',
},
attributions: {
[openStreetMap]: `$t(textLocator.layers.${openStreetMap}): © <a href='https://www.openstreetmap.org/copyright' target='_blank'>OpenStreetMap</a> contributors`,
Expand All @@ -59,11 +60,8 @@ const locales: LanguageOption[] = [
error: {
searchCoastalGazetteer:
'Die Suche ist mit einem unbekannten Fehler fehlgeschlagen. Bitte versuchen Sie es später erneut.',
},
},
plugins: {
addressSearch: {
defaultGroup: 'Ortssuche',
findLiterature:
'Die Suche ist mit einem unbekannten Fehler fehlgeschlagen. Bitte versuchen Sie es später erneut.',
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
</template>
{{ item.name }}
<template v-if="item.type === 'toponym' && item.feature">
&nbsp;
<ResultInfo
:tab-index="0"
:feature="item.feature"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
import { PolarActionContext, PolarStore } from '@polar/lib-custom-types'
import { PolarActionContext } from '@polar/lib-custom-types'
import { GeometrySearchGetters, GeometrySearchState } from '../../types'
import {
TitleLocationFrequency,
searchLiteratureByToponym,
} from '../../../../utils/literatureByToponym'

export function setupWatchers(
this: PolarStore<GeometrySearchState, GeometrySearchGetters>,
{
dispatch,
rootGetters,
}: PolarActionContext<GeometrySearchState, GeometrySearchGetters>
) {
// load titleLocationFrequency on each featureCollection update
this.watch(
() => rootGetters['plugin/geometrySearch/featureCollection'],
() => dispatch('updateFrequencies')
)
}
import { searchLiteratureByToponym } from '../../../../utils/textLocatorBackend/literatureByToponym'
import { TitleLocationFrequency } from '../../../../types'

const requestLiteraturePerFeature = (
featureCollection: GeometrySearchState['featureCollection'],
Expand All @@ -28,35 +12,33 @@ const requestLiteraturePerFeature = (
.filter((names) => names.length)
.map((names) => searchLiteratureByToponym(textLocatorBackendUrl, names))

const aggregatePerFeatureId =
(featureCollection: GeometrySearchState['featureCollection']) =>
(
featureFrequency: TitleLocationFrequency,
index: number
): TitleLocationFrequency =>
Object.fromEntries(
Object.entries(featureFrequency).map(([literatureTitle, frequency]) => [
literatureTitle,
{
[featureCollection.features[index].id as string]: Object.values(
frequency
).reduce((accumulator, current) => accumulator + current, 0),
},
])
const aggregateFeatureHitsByLocationOfLiterature = (
featureCollection: GeometrySearchState['featureCollection'],
titleLocationFrequencies: TitleLocationFrequency[]
): TitleLocationFrequency =>
titleLocationFrequencies.reduce((accumulator, current, index) => {
Object.entries(current).forEach(
([literatureId, { title, location_frequency: locationFrequency }]) => {
accumulator[literatureId] = {
title,
location_frequency: {
...(accumulator[literatureId]?.location_frequency || {}),
...Object.fromEntries(
Object.entries(locationFrequency).map((entry) => [
featureCollection.features[index].id as string,
entry[1] +
(locationFrequency[
featureCollection.features[index].id as string
] || 0),
])
),
},
}
}
)

const flattenFrequencies = (
accumulator: TitleLocationFrequency,
current: TitleLocationFrequency
) => {
Object.entries(current).forEach(([title, findings]) => {
accumulator[title] = {
...(accumulator[title] || {}),
...findings,
}
})
return accumulator
}
return accumulator
}, {} as TitleLocationFrequency)

export async function updateFrequencies({
commit,
Expand All @@ -78,7 +60,9 @@ export async function updateFrequencies({
dispatch('changeActiveData', null)
return
}
const titleLocationFrequency = (

const titleLocationFrequency = aggregateFeatureHitsByLocationOfLiterature(
featureCollection,
await Promise.all(
requestLiteraturePerFeature(
featureCollection,
Expand All @@ -87,8 +71,6 @@ export async function updateFrequencies({
)
)
)
.map(aggregatePerFeatureId(featureCollection))
.reduce(flattenFrequencies, {})

commit('setTitleLocationFrequency', titleLocationFrequency)
if (Object.keys(titleLocationFrequency).length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import { getEmptyFeatureCollection } from '../../../utils/coastalGazetteer/respo
import { makeTreeView } from '../utils/makeTreeView'
import { updateVectorLayer, vectorLayer } from '../utils/vectorDisplay'
import { geoJson } from '../../../utils/coastalGazetteer/common'
import { selectLiterature } from '../../../utils/textLocatorBackend/findLiterature/selectLiterature'
import { searchToponymByLiterature } from '../../../utils/textLocatorBackend/toponymByLiterature'
import { setupTooltip } from './actions/setupTooltip'
import { setupDrawReaction } from './actions/setupDrawReaction'
import { setupWatchers, updateFrequencies } from './actions/watchers'
import { updateFrequencies } from './actions/updateFrequencies'

let counter = 0
const searchLoadingKey = 'geometrySearchLoadingKey'
Expand All @@ -41,14 +43,11 @@ export const makeStoreModule = () => {
dispatch('setupDrawReaction')
dispatch('setupTooltip')
map.addLayer(vectorLayer)
// register watchers after store is ready (else immediate-like firing on not-really change)
setTimeout(() => dispatch('setupWatchers'), 0)
},
setupTooltip,
setupDrawReaction,
setupWatchers,
updateFrequencies,
searchGeometry({ rootGetters, commit }, feature: Feature) {
searchGeometry({ rootGetters, commit, dispatch }, feature: Feature) {
const loadingKey = getSearchLoadingKey()
commit('plugin/loadingIndicator/addLoadingKey', loadingKey, {
root: true,
Expand All @@ -61,7 +60,10 @@ export const makeStoreModule = () => {
rootGetters.configuration.geometrySearch.url,
rootGetters.configuration.epsg
)
.then((result) => commit('setFeatureCollection', result))
.then((result) => {
commit('setFeatureCollection', result)
dispatch('updateFrequencies')
})
.finally(() =>
commit('plugin/loadingIndicator/removeLoadingKey', loadingKey, {
root: true,
Expand All @@ -85,16 +87,23 @@ export const makeStoreModule = () => {
fullSearchOnToponym({ dispatch }, item: TreeViewItem) {
dispatch('searchGeometry', geoJson.readFeature(item.feature))
},
fullSearchLiterature({ dispatch }) {
dispatch(
'plugin/toast/addToast',
{
type: 'info',
text: 'common:textLocator.notImplemented',
timeout: 5000,
},
{ root: true }
async fullSearchLiterature(actionContext, item: TreeViewItem) {
const titleLocationFrequency = await searchToponymByLiterature(
// @ts-expect-error | added in polar-client.ts locally
actionContext.rootGetters.configuration.textLocatorBackendUrl,
item.id
)
selectLiterature.call(this, actionContext, {
categoryId: 0, // dummy to fit API
feature: {
type: 'Feature',
// fake geom to fit APIs; ignored by custom selectLiterature
geometry: { type: 'Point', coordinates: [0, 0] },
properties: titleLocationFrequency[item.id].location_frequency,
id: item.id,
title: item.name,
},
})
},
},
mutations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
GeoJsonProperties,
Geometry,
} from 'geojson'
import { TitleLocationFrequency } from '../../utils/literatureByToponym'
import { TitleLocationFrequency } from '../../types'
import { ResponseGeom, ResponseName } from '../../utils/coastalGazetteer/types'

export type TextLocatorCategories = 'text' | 'toponym'
Expand Down
Loading
Loading