adds meilisearch

This commit is contained in:
Christian Beutel
2024-02-03 14:26:47 +01:00
parent 905995a01c
commit c370690747
14 changed files with 242 additions and 66 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.DS_Store
.vscode/
search/

View File

@@ -0,0 +1,50 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((db) => {
const dao = new Dao(db)
const collection = dao.findCollectionByNameOrId("e864strfxo14pm4")
// add
collection.schema.addField(new SchemaField({
"system": false,
"id": "eqeqja1s",
"name": "lat",
"type": "number",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"noDecimal": false
}
}))
// add
collection.schema.addField(new SchemaField({
"system": false,
"id": "y6dbfyw6",
"name": "lon",
"type": "number",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"noDecimal": false
}
}))
return dao.saveCollection(collection)
}, (db) => {
const dao = new Dao(db)
const collection = dao.findCollectionByNameOrId("e864strfxo14pm4")
// remove
collection.schema.removeField("eqeqja1s")
// remove
collection.schema.removeField("y6dbfyw6")
return dao.saveCollection(collection)
})

6
package-lock.json generated Normal file
View File

@@ -0,0 +1,6 @@
{
"name": "wanderer",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

1
package.json Normal file
View File

@@ -0,0 +1 @@
{}

55
web/package-lock.json generated
View File

@@ -15,6 +15,7 @@
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet-gpx": "^1.7.0", "leaflet-gpx": "^1.7.0",
"leaflet.awesome-markers": "^2.0.5", "leaflet.awesome-markers": "^2.0.5",
"meilisearch": "^0.37.0",
"photoswipe": "^5.4.3", "photoswipe": "^5.4.3",
"pocketbase": "^0.21.0", "pocketbase": "^0.21.0",
"yup": "^1.3.3" "yup": "^1.3.3"
@@ -1328,6 +1329,14 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cross-fetch": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
"dependencies": {
"node-fetch": "^2.6.12"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -2031,6 +2040,14 @@
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true "dev": true
}, },
"node_modules/meilisearch": {
"version": "0.37.0",
"resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.37.0.tgz",
"integrity": "sha512-LdbK6JmRghCawrmWKJSEQF0OiE82md+YqJGE/U2JcCD8ROwlhTx0KM6NX4rQt0u0VpV0QZVG9umYiu3CSSIJAQ==",
"dependencies": {
"cross-fetch": "^3.1.6"
}
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -2187,6 +2204,25 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
} }
}, },
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.14", "version": "2.0.14",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
@@ -3366,6 +3402,11 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-interface-checker": { "node_modules/ts-interface-checker": {
"version": "0.1.13", "version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -3624,6 +3665,20 @@
} }
} }
}, },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@@ -38,6 +38,7 @@
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet-gpx": "^1.7.0", "leaflet-gpx": "^1.7.0",
"leaflet.awesome-markers": "^2.0.5", "leaflet.awesome-markers": "^2.0.5",
"meilisearch": "^0.37.0",
"photoswipe": "^5.4.3", "photoswipe": "^5.4.3",
"pocketbase": "^0.21.0", "pocketbase": "^0.21.0",
"yup": "^1.3.3" "yup": "^1.3.3"

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { Trail } from "$lib/models/trail"; import type { Trail } from "$lib/models/trail";
import { currentUser } from "$lib/stores/user_store";
import { formatMeters, formatTimeHHMM } from "$lib/util/format_util"; import { formatMeters, formatTimeHHMM } from "$lib/util/format_util";
import Dropdown from "../base/dropdown.svelte"; import Dropdown from "../base/dropdown.svelte";
@@ -19,7 +20,9 @@
<div> <div>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<h4 class="font-semibold text-lg">{trail.name}</h4> <h4 class="font-semibold text-lg">{trail.name}</h4>
{#if $currentUser && $currentUser.id == trail.author}
<Dropdown on:change items={dropdownItems}></Dropdown> <Dropdown on:change items={dropdownItems}></Dropdown>
{/if}
</div> </div>
<h5><i class="fa fa-location-dot mr-3"></i>{trail.location}</h5> <h5><i class="fa fa-location-dot mr-3"></i>{trail.location}</h5>
</div> </div>

View File

@@ -0,0 +1,10 @@
import { PUBLIC_MEILISEARCH_URL } from '$env/static/public'
import { PUBLIC_MEILISEARCH_API_KEY } from '$env/static/public'
import { MeiliSearch } from 'meilisearch'
export function createInstance() {
return new MeiliSearch({ host: PUBLIC_MEILISEARCH_URL, apiKey: PUBLIC_MEILISEARCH_API_KEY })
}
export const ms = createInstance()

View File

@@ -11,6 +11,8 @@ class Trail {
distance?: number; distance?: number;
elevation_gain?: number; elevation_gain?: number;
duration?: number; duration?: number;
lat?: number;
lon?: number;
thumbnail?: string; thumbnail?: string;
photos: string[]; photos: string[];
gpx?: string; gpx?: string;
@@ -22,6 +24,7 @@ class Trail {
} }
tags?: string[]; tags?: string[];
description?: string; description?: string;
author?: string;
_photoFiles: File[] _photoFiles: File[]
@@ -33,6 +36,8 @@ class Trail {
distance?: number, distance?: number,
elevation_gain?: number, elevation_gain?: number,
duration?: number, duration?: number,
lat?:number,
lon?: number,
thumbnail?: string, thumbnail?: string,
photos?: string[], photos?: string[],
gpx?: string, gpx?: string,
@@ -51,6 +56,8 @@ class Trail {
this.distance = params?.distance; this.distance = params?.distance;
this.elevation_gain = params?.elevation_gain; this.elevation_gain = params?.elevation_gain;
this.duration = params?.duration; this.duration = params?.duration;
this.lat = params?.lat;
this.lon = params?.lon;
this.thumbnail = params?.thumbnail; this.thumbnail = params?.thumbnail;
this.photos = params?.photos ?? []; this.photos = params?.photos ?? [];
this.gpx = params?.gpx; this.gpx = params?.gpx;

View File

@@ -7,6 +7,7 @@ import { util } from "$lib/vendor/svelte-form-lib/util";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { summit_logs_create, summit_logs_delete, summit_logs_update } from "./summit_log_store"; import { summit_logs_create, summit_logs_delete, summit_logs_update } from "./summit_log_store";
import { waypoints_create, waypoints_delete, waypoints_update } from "./waypoint_store"; import { waypoints_create, waypoints_delete, waypoints_update } from "./waypoint_store";
import { ms } from "$lib/meilisearch";
export const trails: Writable<Trail[]> = writable([]) export const trails: Writable<Trail[]> = writable([])
export const trail: Writable<Trail> = writable(new Trail("")); export const trail: Writable<Trail> = writable(new Trail(""));
@@ -91,6 +92,8 @@ export async function trails_create(trail: Trail, formData: { [key: string]: any
.collection("trails") .collection("trails")
.update<Trail>(model.id!, { thumbnail: thumbnail }); .update<Trail>(model.id!, { thumbnail: thumbnail });
index_trail(model);
return model; return model;
} }
@@ -169,7 +172,9 @@ export async function trails_update(oldTrail: Trail, newTrail: Trail, formData:
trail.set(model); trail.set(model);
// return model; index_trail(model);
return model;
} }
@@ -231,3 +236,21 @@ function compareObjectArrays<T extends { id?: string }>(oldArray: T[], newArray:
}; };
} }
function index_trail(trail: Trail) {
ms.index('trails').addDocuments([
{
"id": trail.id,
"name": trail.name,
"description": trail.description,
"location": trail.location,
"distance": trail.distance,
"elevation_gain": trail.elevation_gain,
"duration": trail.duration,
"category": trail.expand.category?.name,
"_geo": {
"lat": trail.lat,
"lng": trail.lon,
}
}]);
}

View File

@@ -27,14 +27,14 @@
</script> </script>
<section class="hero flex justify-center items-center" style="height: 50vh"> <section class="hero flex justify-center items-center" style="height: 50vh">
<div class="relative text-gray-600"> <div class="relative text-gray-600 mx-4">
<span class="absolute inset-y-0 left-0 flex items-center pl-4"> <span class="absolute inset-y-0 left-0 flex items-center pl-4">
<i class="fa fa-search text-2xl"></i> <i class="fa fa-search text-2xl"></i>
</span> </span>
<input <input
type="search" type="search"
name="q" name="q"
class="py-4 rounded-2xl pl-14 focus:outline-none text-2xl text-primary" class="w-80 sm:w-96 md:w-[32rem] py-4 rounded-2xl pl-14 focus:outline-none text-xl text-primary "
placeholder="Search trails..." placeholder="Search trails..."
autocomplete="off" autocomplete="off"
/> />

View File

@@ -9,6 +9,7 @@
import SummitLogModal from "$lib/components/summit_log/summit_log_modal.svelte"; import SummitLogModal from "$lib/components/summit_log/summit_log_modal.svelte";
import WaypointCard from "$lib/components/waypoint/waypoint_card.svelte"; import WaypointCard from "$lib/components/waypoint/waypoint_card.svelte";
import WaypointModal from "$lib/components/waypoint/waypoint_modal.svelte"; import WaypointModal from "$lib/components/waypoint/waypoint_modal.svelte";
import { ms } from "$lib/meilisearch";
import { SummitLog } from "$lib/models/summit_log"; import { SummitLog } from "$lib/models/summit_log";
import { Trail, trailSchema } from "$lib/models/trail"; import { Trail, trailSchema } from "$lib/models/trail";
import { Waypoint } from "$lib/models/waypoint"; import { Waypoint } from "$lib/models/waypoint";
@@ -105,6 +106,7 @@
}); });
function addGPXLayer(gpx: string, addWaypoints: boolean = true) { function addGPXLayer(gpx: string, addWaypoints: boolean = true) {
return new Promise<void>(function (resolve, reject) {
gpxLayer?.remove(); gpxLayer?.remove();
gpxLayer = new L.GPX(gpx, { gpxLayer = new L.GPX(gpx, {
async: true, async: true,
@@ -144,6 +146,8 @@
.on("addpoint", function (e: any) { .on("addpoint", function (e: any) {
if (e.point_type === "start") { if (e.point_type === "start") {
e.point.setZIndexOffset(1000); e.point.setZIndexOffset(1000);
$form.lat = e.point._latlng.lat;
$form.lon = e.point._latlng.lng;
} else if (e.point_type === "waypoint") { } else if (e.point_type === "waypoint") {
const waypoint = new Waypoint( const waypoint = new Waypoint(
e.point._latlng.lat, e.point._latlng.lat,
@@ -160,8 +164,11 @@
$form.distance = e.target.get_distance(); $form.distance = e.target.get_distance();
$form.elevation_gain = e.target.get_elevation_gain(); $form.elevation_gain = e.target.get_elevation_gain();
$form.duration = e.target.get_total_time() / 1000 / 60; $form.duration = e.target.get_total_time() / 1000 / 60;
resolve();
}) })
.on("error", reject)
.addTo(map); .addTo(map);
});
} }
function openFileBrowser() { function openFileBrowser() {
@@ -184,9 +191,14 @@
reader.readAsText(selectedFile); reader.readAsText(selectedFile);
reader.onload = function (e) { reader.onload = async function (e) {
trail.set(new Trail("")); trail.set(new Trail(""));
addGPXLayer(e.target?.result as string); await addGPXLayer(e.target?.result as string);
console.log(await
ms.index("cities500").search("", {
filter: [`_geoRadius(${$form.lat}, ${$form.lon}, 100000000000)`],
}),
);
}; };
} }
@@ -368,6 +380,8 @@
> >
<input type="hidden" name="duration" value={$form.duration} /> <input type="hidden" name="duration" value={$form.duration} />
</div> </div>
<input type="hidden" name="lat" value={$form.lat} />
<input type="hidden" name="lon" value={$form.lon} />
</div> </div>
<TextField <TextField
name="name" name="name"

View File

@@ -11,7 +11,7 @@ export const load: Load = async ({ params }) => {
let trail: Trail; let trail: Trail;
if (params.id === "new") { if (params.id === "new") {
trail = new Trail("", { category: categories[0] }); trail = new Trail("", {category: categories[0]});
} else { } else {
trail = await trails_show(params.id, true); trail = await trails_show(params.id, true);
} }

View File

@@ -9,6 +9,7 @@
trails_delete, trails_delete,
trails_index, trails_index,
} from "$lib/stores/trail_store"; } from "$lib/stores/trail_store";
import { currentUser } from "$lib/stores/user_store";
import { formatMeters, formatTimeHHMM } from "$lib/util/format_util"; import { formatMeters, formatTimeHHMM } from "$lib/util/format_util";
import { createMarkerFromWaypoint } from "$lib/util/leaflet_util"; import { createMarkerFromWaypoint } from "$lib/util/leaflet_util";
import type { Icon, Marker } from "leaflet"; import type { Icon, Marker } from "leaflet";
@@ -150,6 +151,7 @@
{$trail.location} {$trail.location}
</h3> </h3>
</div> </div>
{#if $currentUser && $currentUser.id == $trail.author}
<div class="absolute text-white bottom-8 right-8"> <div class="absolute text-white bottom-8 right-8">
<Dropdown <Dropdown
size="2xl" size="2xl"
@@ -157,6 +159,7 @@
on:change={(e) => handleDropdownClick(e.detail)} on:change={(e) => handleDropdownClick(e.detail)}
></Dropdown> ></Dropdown>
</div> </div>
{/if}
</section> </section>
<section <section
class="grid grid-cols-2 sm:grid-cols-4 gap-y-4 justify-around py-8" class="grid grid-cols-2 sm:grid-cols-4 gap-y-4 justify-around py-8"