mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
serverside geocoding
This commit is contained in:
parent
719e1e16b5
commit
ca4d481acf
@ -269,6 +269,48 @@
|
||||
"operation": "43de95f1-d63b-4231-80c3-b399c45470f6",
|
||||
"_syncId": "d7e74f35-a19a-4a0b-9ae8-59af2fa0f081"
|
||||
},
|
||||
{
|
||||
"name": "Reverse Geocoder: Trigger Populare Items",
|
||||
"icon": "home_pin",
|
||||
"color": null,
|
||||
"description": "Set multiple items addresses at once",
|
||||
"status": "active",
|
||||
"trigger": "manual",
|
||||
"accountability": "all",
|
||||
"options": {
|
||||
"collections": [
|
||||
"items"
|
||||
],
|
||||
"requireConfirmation": true,
|
||||
"async": true,
|
||||
"location": "collection",
|
||||
"confirmationDescription": "Be aware that you can run into request limits on the external reverse geocoder"
|
||||
},
|
||||
"operation": "c7317e38-c026-4dc0-8b73-42340e205c33",
|
||||
"_syncId": "d8b14c06-fb08-4a27-8a4b-75e6a4cd7216"
|
||||
},
|
||||
{
|
||||
"name": "Reverse Geocoder: On Create and Update",
|
||||
"icon": "home_pin",
|
||||
"color": null,
|
||||
"description": "Requests the items address on update / create",
|
||||
"status": "active",
|
||||
"trigger": "event",
|
||||
"accountability": "all",
|
||||
"options": {
|
||||
"type": "filter",
|
||||
"scope": [
|
||||
"items.update",
|
||||
"items.create"
|
||||
],
|
||||
"collections": [
|
||||
"items"
|
||||
],
|
||||
"return": "$last"
|
||||
},
|
||||
"operation": "0d18abcf-70f9-4545-b583-e18e5ec533fa",
|
||||
"_syncId": "e28759ce-3995-4943-bbfc-f1ed08d42497"
|
||||
},
|
||||
{
|
||||
"name": "Slug Generation",
|
||||
"icon": "bolt",
|
||||
@ -288,5 +330,19 @@
|
||||
},
|
||||
"operation": "55857562-e0ab-49a5-a292-18f6c1cb075e",
|
||||
"_syncId": "f2beb617-9c21-48b2-a8ec-c04197d1b7d1"
|
||||
},
|
||||
{
|
||||
"name": "Reverse Geocoder: Single Item Address",
|
||||
"icon": "home_pin",
|
||||
"color": null,
|
||||
"description": "Single item address request",
|
||||
"status": "active",
|
||||
"trigger": "operation",
|
||||
"accountability": "all",
|
||||
"options": {
|
||||
"return": "$last"
|
||||
},
|
||||
"operation": "fa077e33-be44-48d4-b3a4-9f61c99c002c",
|
||||
"_syncId": "fbf2ab06-eab8-4dc4-8e25-101f6a4edba6"
|
||||
}
|
||||
]
|
||||
|
||||
@ -227,6 +227,48 @@
|
||||
"flow": "cc80ec73-ecf5-4789-bee5-1127fb1a6ed4",
|
||||
"_syncId": "06716525-6d29-46e2-bb01-0764bccd74e9"
|
||||
},
|
||||
{
|
||||
"name": "Run Script",
|
||||
"key": "exec_bouoe",
|
||||
"type": "exec",
|
||||
"position_x": 37,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"code": "module.exports = async function(data) {\n\treturn data['$last'].map((item) => {\n \treturn {\n \"position\" : item.position,\n \"id\" : item.id,\n };\n });\n}"
|
||||
},
|
||||
"resolve": "fdca64f4-41e2-4940-a813-0f7698f1580b",
|
||||
"reject": null,
|
||||
"flow": "d8b14c06-fb08-4a27-8a4b-75e6a4cd7216",
|
||||
"_syncId": "d3c50715-47c3-4763-832f-caf92d29331f"
|
||||
},
|
||||
{
|
||||
"name": "Run Script",
|
||||
"key": "exec_dsl0t",
|
||||
"type": "exec",
|
||||
"position_x": 56,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"code": "// Your function in the myScript operation\nmodule.exports = function (data) {\n const payload = {...data.$trigger.payload}\n payload.address = data.get_address_string.data.features[0].properties.city;\n return payload;\n};"
|
||||
},
|
||||
"resolve": null,
|
||||
"reject": null,
|
||||
"flow": "e28759ce-3995-4943-bbfc-f1ed08d42497",
|
||||
"_syncId": "d18a1aaf-77a6-453e-8142-5ca4f4181b05"
|
||||
},
|
||||
{
|
||||
"name": "Run Script",
|
||||
"key": "exec_kuwlb",
|
||||
"type": "exec",
|
||||
"position_x": 37,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"code": "module.exports = function(data) {\nif (data.$last.data.features[0].properties.type === \"city\") {\n return {\n \"address\" : data.$last.data.features[0].properties.name || null\n }\n} else {\n return {\n \"address\": data.$last.data.features[0].properties.city ?? data.$last.data.features[0].properties.town ?? data.$last.data.features[0].properties.village\n }\n}\n}"
|
||||
},
|
||||
"resolve": "daa7b615-11f3-4cd9-8713-494fded63757",
|
||||
"reject": null,
|
||||
"flow": "fbf2ab06-eab8-4dc4-8e25-101f6a4edba6",
|
||||
"_syncId": "dcf26e93-3b5c-44c3-b2fb-00c45d9a1fd6"
|
||||
},
|
||||
{
|
||||
"name": "Run Script",
|
||||
"key": "exec_p2t3z",
|
||||
@ -255,6 +297,36 @@
|
||||
"flow": "7b978be2-605f-4061-b5b3-46f151b1b80a",
|
||||
"_syncId": "67847550-3c95-4ee4-af02-32ebb69747d6"
|
||||
},
|
||||
{
|
||||
"name": "Get Address String",
|
||||
"key": "get_address_string",
|
||||
"type": "request",
|
||||
"position_x": 19,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"method": "GET",
|
||||
"url": "https://photon.komoot.io/reverse?lat={{$trigger.payload.position.coordinates[1]}}&lon={{$trigger.payload.position.coordinates[0]}}&lang=de&limit=1"
|
||||
},
|
||||
"resolve": "7e6101d2-3d8c-49e2-894e-3121c9eff06b",
|
||||
"reject": null,
|
||||
"flow": "e28759ce-3995-4943-bbfc-f1ed08d42497",
|
||||
"_syncId": "0d18abcf-70f9-4545-b583-e18e5ec533fa"
|
||||
},
|
||||
{
|
||||
"name": "Get Address String",
|
||||
"key": "get_address_string",
|
||||
"type": "request",
|
||||
"position_x": 19,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"method": "GET",
|
||||
"url": "https://photon.komoot.io/reverse?lat={{$trigger.position.coordinates[1]}}&lon={{$trigger.position.coordinates[0]}}&lang=de&limit=1"
|
||||
},
|
||||
"resolve": "dcf26e93-3b5c-44c3-b2fb-00c45d9a1fd6",
|
||||
"reject": null,
|
||||
"flow": "fbf2ab06-eab8-4dc4-8e25-101f6a4edba6",
|
||||
"_syncId": "fa077e33-be44-48d4-b3a4-9f61c99c002c"
|
||||
},
|
||||
{
|
||||
"name": "get Creator",
|
||||
"key": "get_creator",
|
||||
@ -733,6 +805,35 @@
|
||||
"flow": "a78d01a4-13b3-46a4-8938-9606bf26e329",
|
||||
"_syncId": "9838d2ca-3698-4d29-8429-038dfcaf7fab"
|
||||
},
|
||||
{
|
||||
"name": "Read Data",
|
||||
"key": "item_read_ceep3",
|
||||
"type": "item-read",
|
||||
"position_x": 19,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"permissions": "$trigger",
|
||||
"emitEvents": false,
|
||||
"collection": "items",
|
||||
"query": {
|
||||
"limit": -1,
|
||||
"fields": [
|
||||
"id",
|
||||
"position"
|
||||
],
|
||||
"filter": {
|
||||
"id": {
|
||||
"_in": "{{$trigger.body.keys}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"key": []
|
||||
},
|
||||
"resolve": "d3c50715-47c3-4763-832f-caf92d29331f",
|
||||
"reject": null,
|
||||
"flow": "d8b14c06-fb08-4a27-8a4b-75e6a4cd7216",
|
||||
"_syncId": "c7317e38-c026-4dc0-8b73-42340e205c33"
|
||||
},
|
||||
{
|
||||
"name": "Read Data",
|
||||
"key": "item_read_evgvk",
|
||||
@ -1054,6 +1155,28 @@
|
||||
"flow": "7b978be2-605f-4061-b5b3-46f151b1b80a",
|
||||
"_syncId": "017875a5-3736-478a-9bcc-ed473117c74d"
|
||||
},
|
||||
{
|
||||
"name": "Update Data",
|
||||
"key": "item_update_96g9y",
|
||||
"type": "item-update",
|
||||
"position_x": 56,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"permissions": "$trigger",
|
||||
"emitEvents": false,
|
||||
"collection": "items",
|
||||
"payload": {
|
||||
"address": "{{$last.address}}"
|
||||
},
|
||||
"key": [
|
||||
"{{$trigger.id}}"
|
||||
]
|
||||
},
|
||||
"resolve": null,
|
||||
"reject": null,
|
||||
"flow": "fbf2ab06-eab8-4dc4-8e25-101f6a4edba6",
|
||||
"_syncId": "daa7b615-11f3-4cd9-8713-494fded63757"
|
||||
},
|
||||
{
|
||||
"name": "Update Data",
|
||||
"key": "item_update_chszs",
|
||||
@ -1125,6 +1248,28 @@
|
||||
"flow": "cb772a2c-150c-4cca-bc2c-1f8498a5cd92",
|
||||
"_syncId": "b22755ba-4ec5-4e04-a3fe-a390a9bc75ab"
|
||||
},
|
||||
{
|
||||
"name": "Update Data",
|
||||
"key": "item_update_h2lfe",
|
||||
"type": "item-update",
|
||||
"position_x": 38,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"permissions": "$trigger",
|
||||
"emitEvents": false,
|
||||
"collection": "items",
|
||||
"key": [
|
||||
"{{$trigger.payload.id}}"
|
||||
],
|
||||
"payload": {
|
||||
"address": "{{$last.data.features[0].properties.city}}"
|
||||
}
|
||||
},
|
||||
"resolve": "d18a1aaf-77a6-453e-8142-5ca4f4181b05",
|
||||
"reject": null,
|
||||
"flow": "e28759ce-3995-4943-bbfc-f1ed08d42497",
|
||||
"_syncId": "7e6101d2-3d8c-49e2-894e-3121c9eff06b"
|
||||
},
|
||||
{
|
||||
"name": "Update Nomads Home",
|
||||
"key": "item_update_o6cn8",
|
||||
@ -1599,6 +1744,22 @@
|
||||
"flow": "9a1d1084-438f-471e-aac5-47e0749375e7",
|
||||
"_syncId": "95d762f9-4695-4168-aa65-5bd065b40742"
|
||||
},
|
||||
{
|
||||
"name": "Trigger Flow",
|
||||
"key": "trigger_uromw",
|
||||
"type": "trigger",
|
||||
"position_x": 55,
|
||||
"position_y": 1,
|
||||
"options": {
|
||||
"iterationMode": "parallel",
|
||||
"flow": "fbf2ab06-eab8-4dc4-8e25-101f6a4edba6",
|
||||
"payload": "{{ $last }}"
|
||||
},
|
||||
"resolve": null,
|
||||
"reject": null,
|
||||
"flow": "d8b14c06-fb08-4a27-8a4b-75e6a4cd7216",
|
||||
"_syncId": "fdca64f4-41e2-4940-a813-0f7698f1580b"
|
||||
},
|
||||
{
|
||||
"name": "Updated?",
|
||||
"key": "updated",
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
{
|
||||
"collection": "items",
|
||||
"field": "address",
|
||||
"type": "string",
|
||||
"meta": {
|
||||
"collection": "items",
|
||||
"conditions": null,
|
||||
"display": null,
|
||||
"display_options": null,
|
||||
"field": "address",
|
||||
"group": null,
|
||||
"hidden": false,
|
||||
"interface": "input",
|
||||
"note": null,
|
||||
"options": null,
|
||||
"readonly": false,
|
||||
"required": false,
|
||||
"sort": 34,
|
||||
"special": null,
|
||||
"translations": null,
|
||||
"validation": null,
|
||||
"validation_message": null,
|
||||
"width": "full"
|
||||
},
|
||||
"schema": {
|
||||
"name": "address",
|
||||
"table": "items",
|
||||
"data_type": "character varying",
|
||||
"default_value": null,
|
||||
"max_length": 255,
|
||||
"numeric_precision": null,
|
||||
"numeric_scale": null,
|
||||
"is_nullable": true,
|
||||
"is_unique": false,
|
||||
"is_indexed": false,
|
||||
"is_primary_key": false,
|
||||
"is_generated": false,
|
||||
"generation_expression": null,
|
||||
"has_auto_increment": false,
|
||||
"foreign_key_table": null,
|
||||
"foreign_key_column": null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
import { MapPinIcon } from '@heroicons/react/24/solid'
|
||||
|
||||
import { useGeoDistance } from '#components/Map/hooks/useGeoDistance'
|
||||
import { useReverseGeocode } from '#components/Map/hooks/useReverseGeocode'
|
||||
|
||||
import { useFormatDistance } from './hooks'
|
||||
|
||||
import type { Item } from '#types/Item'
|
||||
|
||||
interface ItemSubtitleProps {
|
||||
item: Item
|
||||
mode?: 'address' | 'custom' | 'none'
|
||||
truncate?: boolean
|
||||
showDistance?: boolean
|
||||
}
|
||||
|
||||
export function ItemSubtitle({
|
||||
item,
|
||||
mode = 'address',
|
||||
truncate = true,
|
||||
showDistance = true,
|
||||
}: ItemSubtitleProps) {
|
||||
const { distance } = useGeoDistance(item.position ?? undefined)
|
||||
const { formatDistance } = useFormatDistance()
|
||||
|
||||
// Use item.address from backend if available, otherwise use reverse geocoding
|
||||
const shouldReverseGeocode = mode === 'address' && (!item.address || item.address.trim() === '')
|
||||
|
||||
const { address: geocodedAddress } = useReverseGeocode(
|
||||
item.position?.coordinates as [number, number] | undefined,
|
||||
shouldReverseGeocode,
|
||||
'municipality',
|
||||
)
|
||||
|
||||
const address = item.address && item.address.trim() !== '' ? item.address : geocodedAddress
|
||||
const subtitle = item.subname
|
||||
|
||||
if (mode === 'address' && address) {
|
||||
return (
|
||||
<div className='tw:text-sm tw:flex tw:items-center tw:text-gray-500 tw:w-full'>
|
||||
<MapPinIcon className='tw:w-4 tw:mr-1 tw:flex-shrink-0' />
|
||||
<span title={address} className={truncate ? 'tw:truncate' : ''}>
|
||||
{address}
|
||||
{showDistance && distance && distance >= 0.1
|
||||
? ` (${formatDistance(distance) ?? ''})`
|
||||
: ''}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (mode === 'custom' && subtitle) {
|
||||
return (
|
||||
<div className={`tw:text-sm tw:opacity-50 tw:items-center ${truncate ? 'tw:truncate' : ''}`}>
|
||||
{subtitle}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@ -1,10 +1,6 @@
|
||||
import { MapPinIcon } from '@heroicons/react/24/solid'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { useGeoDistance } from '#components/Map/hooks/useGeoDistance'
|
||||
import { useReverseGeocode } from '#components/Map/hooks/useReverseGeocode'
|
||||
|
||||
import { useFormatDistance } from './hooks'
|
||||
import { ItemSubtitle } from './ItemSubtitle'
|
||||
|
||||
import type { Item } from '#types/Item'
|
||||
|
||||
@ -23,20 +19,11 @@ export function ItemTitle({
|
||||
subtitleMode = 'address',
|
||||
hasAvatar = false,
|
||||
}: ItemTitleProps) {
|
||||
const { distance } = useGeoDistance(item.position ?? undefined)
|
||||
const { formatDistance } = useFormatDistance()
|
||||
const titleRef = useRef<HTMLDivElement>(null)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const [fontSize, setFontSize] = useState<string>('tw:text-xl')
|
||||
|
||||
const { address } = useReverseGeocode(
|
||||
item.position?.coordinates as [number, number] | undefined,
|
||||
subtitleMode === 'address',
|
||||
'municipality',
|
||||
)
|
||||
|
||||
const title = item.name ?? item.layer?.item_default_name
|
||||
const subtitle = item.subname
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current || !title) {
|
||||
@ -111,22 +98,7 @@ export function ItemTitle({
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
{subtitleMode === 'address' && address && (
|
||||
<div className='tw:text-sm tw:flex tw:items-center tw:text-gray-500 tw:w-full'>
|
||||
<MapPinIcon className='tw:w-4 tw:mr-1 tw:flex-shrink-0' />
|
||||
<span title={address} className='tw:truncate'>
|
||||
{address}
|
||||
{distance && distance >= 0.1 ? ` (${formatDistance(distance) ?? ''})` : ''}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{subtitleMode === 'custom' && subtitle && (
|
||||
<div
|
||||
className={`tw:text-sm tw:opacity-50 tw:items-center ${truncateSubname ? 'tw:truncate' : ''}`}
|
||||
>
|
||||
{subtitle}
|
||||
</div>
|
||||
)}
|
||||
<ItemSubtitle item={item} mode={subtitleMode} truncate={truncateSubname} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ import { QRModal } from './QRModal'
|
||||
|
||||
import type { HeaderViewProps } from './types'
|
||||
|
||||
export { ItemSubtitle } from './ItemSubtitle'
|
||||
|
||||
export function HeaderView({
|
||||
item,
|
||||
api,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
|
||||
import { TextInput } from '#components/Input'
|
||||
import { ItemSubtitle } from '#components/Map/Subcomponents/ItemPopupComponents/HeaderView/ItemSubtitle'
|
||||
|
||||
import { AvatarWidget } from './AvatarWidget'
|
||||
import { ColorPicker } from './ColorPicker'
|
||||
@ -38,9 +39,7 @@ export const FormHeader = ({ item, state, setState }: Props) => {
|
||||
}
|
||||
className={'tw:-left-6 tw:top-14 tw:-mr-6'}
|
||||
/>
|
||||
<div
|
||||
className={`tw:grow tw:mr-4 ${item.layer?.itemType.subtitle_mode === 'custom' ? 'tw:pt-1' : 'tw:flex tw:items-center'}`}
|
||||
>
|
||||
<div className='tw:grow tw:mr-4 tw:pt-1'>
|
||||
<TextInput
|
||||
placeholder='Name'
|
||||
defaultValue={item.name ? item.name : ''}
|
||||
@ -68,6 +67,11 @@ export const FormHeader = ({ item, state, setState }: Props) => {
|
||||
inputStyle='tw:input-sm'
|
||||
/>
|
||||
)}
|
||||
{item.layer?.itemType.subtitle_mode === 'address' && (
|
||||
<div className='tw:px-4 tw:mt-2'>
|
||||
<ItemSubtitle item={item} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
1
lib/src/types/Item.d.ts
vendored
1
lib/src/types/Item.d.ts
vendored
@ -62,6 +62,7 @@ export interface Item {
|
||||
openCollectiveSlug?: string
|
||||
secrets?: ItemSecret[]
|
||||
extended?: JSON
|
||||
address?: string
|
||||
|
||||
// {
|
||||
// coordinates: [number, number]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user