mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Add notes to places and manage place tags
This commit is contained in:
parent
c711bed383
commit
2ab24201c1
7 changed files with 78 additions and 11 deletions
|
|
@ -21,6 +21,10 @@ OIDC_REDIRECT_URI=https://your-dawarich-url.com/users/auth/openid_connect/callba
|
||||||
|
|
||||||
- Support for KML file uploads. #350
|
- Support for KML file uploads. #350
|
||||||
- Added a commented line in the `docker-compose.yml` file to use an alternative PostGIS image for ARM architecture.
|
- Added a commented line in the `docker-compose.yml` file to use an alternative PostGIS image for ARM architecture.
|
||||||
|
- User can now create a place directly from the map and add tags and notes to it. If reverse geocoding is enabled, list of nearby places will be shown as suggestions.
|
||||||
|
- User can create and manage tags for places.
|
||||||
|
- [ ] Tags can be added when creating or editing a place.
|
||||||
|
- User can enable or disable places layers on the map to show/hide all or just some of their places based on tags.
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ module Api
|
||||||
end
|
end
|
||||||
|
|
||||||
def place_params
|
def place_params
|
||||||
params.require(:place).permit(:name, :latitude, :longitude, :source)
|
params.require(:place).permit(:name, :latitude, :longitude, :source, :note)
|
||||||
end
|
end
|
||||||
|
|
||||||
def tag_ids
|
def tag_ids
|
||||||
|
|
@ -102,6 +102,7 @@ module Api
|
||||||
latitude: place.latitude,
|
latitude: place.latitude,
|
||||||
longitude: place.longitude,
|
longitude: place.longitude,
|
||||||
source: place.source,
|
source: place.source,
|
||||||
|
note: place.note,
|
||||||
icon: place.tags.first&.icon,
|
icon: place.tags.first&.icon,
|
||||||
color: place.tags.first&.color,
|
color: place.tags.first&.color,
|
||||||
visits_count: place.visits.count,
|
visits_count: place.visits.count,
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ export class PlacesManager {
|
||||||
<div class="place-popup" style="min-width: 200px;">
|
<div class="place-popup" style="min-width: 200px;">
|
||||||
<h3 class="font-bold text-lg mb-2">${place.name}</h3>
|
<h3 class="font-bold text-lg mb-2">${place.name}</h3>
|
||||||
${tags ? `<div class="mb-2">${tags}</div>` : ''}
|
${tags ? `<div class="mb-2">${tags}</div>` : ''}
|
||||||
|
${place.note ? `<p class="text-sm text-gray-600 mb-2 italic">${this.escapeHtml(place.note)}</p>` : ''}
|
||||||
${place.visits_count ? `<p class="text-sm">Visits: ${place.visits_count}</p>` : ''}
|
${place.visits_count ? `<p class="text-sm">Visits: ${place.visits_count}</p>` : ''}
|
||||||
<div class="mt-2 flex gap-2">
|
<div class="mt-2 flex gap-2">
|
||||||
<button class="btn btn-xs btn-error" data-place-id="${place.id}" data-action="delete-place">
|
<button class="btn btn-xs btn-error" data-place-id="${place.id}" data-action="delete-place">
|
||||||
|
|
@ -153,6 +154,12 @@ export class PlacesManager {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
escapeHtml(text) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = text;
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
setupMapClickHandler() {
|
setupMapClickHandler() {
|
||||||
this.map.on('click', (e) => {
|
this.map.on('click', (e) => {
|
||||||
if (this.creationMode) {
|
if (this.creationMode) {
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,46 @@ export class PrivacyZoneManager {
|
||||||
filterPoints(points) {
|
filterPoints(points) {
|
||||||
if (!this.zones || this.zones.length === 0) return points;
|
if (!this.zones || this.zones.length === 0) return points;
|
||||||
|
|
||||||
return points.filter(point => {
|
// Filter points and ensure polylines break at privacy zone boundaries
|
||||||
// Point format: [lat, lng, ...]
|
// We need to manipulate timestamps to force polyline breaks
|
||||||
|
const filteredPoints = [];
|
||||||
|
let lastWasPrivate = false;
|
||||||
|
let privacyZoneEncountered = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
const point = points[i];
|
||||||
const lat = point[0];
|
const lat = point[0];
|
||||||
const lng = point[1];
|
const lng = point[1];
|
||||||
return !this.isPointInPrivacyZone(lat, lng);
|
const isPrivate = this.isPointInPrivacyZone(lat, lng);
|
||||||
});
|
|
||||||
|
if (!isPrivate) {
|
||||||
|
// Point is not in privacy zone, include it
|
||||||
|
const newPoint = [...point]; // Clone the point array
|
||||||
|
|
||||||
|
// If we just exited a privacy zone, force a polyline break by adding
|
||||||
|
// a large time gap that exceeds minutes_between_routes threshold
|
||||||
|
if (privacyZoneEncountered && filteredPoints.length > 0) {
|
||||||
|
// Add 2 hours (120 minutes) to timestamp to force a break
|
||||||
|
// This is larger than default minutes_between_routes (30 min)
|
||||||
|
const lastPoint = filteredPoints[filteredPoints.length - 1];
|
||||||
|
if (newPoint[4]) { // If timestamp exists (index 4)
|
||||||
|
newPoint[4] = lastPoint[4] + (120 * 60); // Add 120 minutes in seconds
|
||||||
|
}
|
||||||
|
privacyZoneEncountered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredPoints.push(newPoint);
|
||||||
|
lastWasPrivate = false;
|
||||||
|
} else {
|
||||||
|
// Point is in privacy zone - skip it
|
||||||
|
if (!lastWasPrivate) {
|
||||||
|
privacyZoneEncountered = true;
|
||||||
|
}
|
||||||
|
lastWasPrivate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
filterTracks(tracks) {
|
filterTracks(tracks) {
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,30 @@
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="label-text font-semibold">Place Name *</span>
|
<span class="label-text font-semibold">Place Name *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
placeholder="Enter place name..."
|
placeholder="Enter place name..."
|
||||||
class="input input-bordered w-full"
|
class="input input-bordered w-full"
|
||||||
data-place-creation-target="nameInput"
|
data-place-creation-target="nameInput"
|
||||||
required>
|
required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold">Note</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
name="note"
|
||||||
|
placeholder="Add a personal note about this place..."
|
||||||
|
class="textarea textarea-bordered w-full bg-base-100"
|
||||||
|
rows="3"
|
||||||
|
data-place-creation-target="noteInput"></textarea>
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text-alt">Optional - Add any notes or details about this place</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="label-text font-semibold">Tags</span>
|
<span class="label-text font-semibold">Tags</span>
|
||||||
|
|
|
||||||
5
db/migrate/20251118210506_add_note_to_places.rb
Normal file
5
db/migrate/20251118210506_add_note_to_places.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddNoteToPlaces < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
add_column :places, :note, :text
|
||||||
|
end
|
||||||
|
end
|
||||||
3
db/schema.rb
generated
3
db/schema.rb
generated
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.0].define(version: 2025_11_18_204141) do
|
ActiveRecord::Schema[8.0].define(version: 2025_11_18_210506) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pg_catalog.plpgsql"
|
enable_extension "pg_catalog.plpgsql"
|
||||||
enable_extension "postgis"
|
enable_extension "postgis"
|
||||||
|
|
@ -181,6 +181,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_18_204141) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.geography "lonlat", limit: {srid: 4326, type: "st_point", geographic: true}
|
t.geography "lonlat", limit: {srid: 4326, type: "st_point", geographic: true}
|
||||||
t.bigint "user_id"
|
t.bigint "user_id"
|
||||||
|
t.text "note"
|
||||||
t.index "(((geodata -> 'properties'::text) ->> 'osm_id'::text))", name: "index_places_on_geodata_osm_id"
|
t.index "(((geodata -> 'properties'::text) ->> 'osm_id'::text))", name: "index_places_on_geodata_osm_id"
|
||||||
t.index ["lonlat"], name: "index_places_on_lonlat", using: :gist
|
t.index ["lonlat"], name: "index_places_on_lonlat", using: :gist
|
||||||
t.index ["user_id"], name: "index_places_on_user_id"
|
t.index ["user_id"], name: "index_places_on_user_id"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue