diff --git a/CHANGELOG.md b/CHANGELOG.md index 233e03ae..90fa2c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/). This release is focused on improving the visits experience. +Since previous implementation of visits was not working as expected, this release introduces a new approach. It is recommended to remove all _non-confirmed_ visits before or after updating to this version. + +There is a known issue when data migrations are not being run automatically on some systems. If you're experiencing issues when opening map page, trips page or when trying to see visits, try executing the following command in the [Console](https://dawarich.app/docs/FAQ/#how-to-enter-dawarich-console): + +```ruby +User.includes(:tracked_points, visits: :places).find_each do |user| + places_to_update = user.places.where(lonlat: nil) + + # For each place, set the lonlat value based on longitude and latitude + places_to_update.find_each do |place| + next if place.longitude.nil? || place.latitude.nil? + + # Set the lonlat to a PostGIS point with the proper SRID + # rubocop:disable Rails/SkipsModelValidations + place.update_column(:lonlat, "SRID=4326;POINT(#{place.longitude} #{place.latitude})") + # rubocop:enable Rails/SkipsModelValidations + end + + user.tracked_points.update_all('lonlat = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)') +end +``` + +With any errors, don't hesitate to ask for help in the [Discord server](https://discord.gg/pHsBjpt5J8). + + + ## Added - A new button to open the visits drawer. @@ -28,9 +54,12 @@ This release is focused on improving the visits experience. - Restrict access to Sidekiq in non self-hosted mode. - Restrict access to background jobs in non self-hosted mode. - Restrict access to users management in non self-hosted mode. +- Restrict access to API for inactive users. +- All users in self-hosted mode are active by default. - Points are now using `lonlat` column for storing longitude and latitude. - Semantic history points are now being imported much faster. - GPX files are now being imported much faster. +- Trips, places and points are now using PostGIS' database attributes for storing longitude and latitude. - Distance calculation are now using Postgis functions and expected to be more accurate. ## Fixed diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index e7913676..bd822bce 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -14,9 +14,90 @@ *= require_self */ -/* Loading spinner animation */ -@keyframes spinner { - to { - transform: rotate(360deg); - } + .emoji-icon { + font-size: 36px; /* Adjust size as needed */ + text-align: center; + line-height: 36px; /* Same as font-size for perfect centering */ +} + +.timeline-box { + overflow: visible !important; +} + +/* Style for the settings panel */ +.leaflet-settings-panel { + background-color: white; + padding: 10px; + border: 1px solid #ccc; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); +} + +.leaflet-settings-panel label { + display: block; + margin-bottom: 5px; +} + +.leaflet-settings-panel input { + width: 100%; + margin-bottom: 10px; + padding: 5px; + border: 1px solid #ccc; + border-radius: 3px; +} + +.leaflet-settings-panel button { + padding: 5px 10px; + background-color: #007bff; + color: white; + border: none; + border-radius: 3px; + cursor: pointer; +} + +.leaflet-settings-panel button:hover { + background-color: #0056b3; +} + +.photo-marker { + display: flex; + align-items: center; + justify-content: center; + background: transparent; + border: none; + border-radius: 50%; +} + +.photo-marker img { + border-radius: 50%; + width: 48px; + height: 48px; +} + +.leaflet-loading-control { + padding: 5px; + border-radius: 4px; + box-shadow: 0 1px 5px rgba(0,0,0,0.2); + margin: 10px; + width: 32px; + height: 32px; + background: white; +} + +.loading-spinner { + display: flex; + align-items: center; + gap: 8px; + font-size: 18px; + color: gray; +} + +.loading-spinner::before { + content: '🔵'; + font-size: 18px; + animation: spinner 1s linear infinite; +} + +.loading-spinner.done::before { + content: '✅'; + animation: none; } diff --git a/app/controllers/settings/users_controller.rb b/app/controllers/settings/users_controller.rb index 046d34ac..a3be28c6 100644 --- a/app/controllers/settings/users_controller.rb +++ b/app/controllers/settings/users_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class Settings::UsersController < ApplicationController - before_action :authenticate_admin! before_action :authenticate_self_hosted! + before_action :authenticate_admin! def index @users = User.order(created_at: :desc) diff --git a/app/javascript/maps/polylines.js b/app/javascript/maps/polylines.js index e48479d3..f1d9656f 100644 --- a/app/javascript/maps/polylines.js +++ b/app/javascript/maps/polylines.js @@ -3,46 +3,6 @@ import { formatDistance } from "../maps/helpers"; import { minutesToDaysHoursMinutes } from "../maps/helpers"; import { haversineDistance } from "../maps/helpers"; -function pointToLineDistance(point, lineStart, lineEnd) { - const x = point.lat; - const y = point.lng; - const x1 = lineStart.lat; - const y1 = lineStart.lng; - const x2 = lineEnd.lat; - const y2 = lineEnd.lng; - - const A = x - x1; - const B = y - y1; - const C = x2 - x1; - const D = y2 - y1; - - const dot = A * C + B * D; - const lenSq = C * C + D * D; - let param = -1; - - if (lenSq !== 0) { - param = dot / lenSq; - } - - let xx, yy; - - if (param < 0) { - xx = x1; - yy = y1; - } else if (param > 1) { - xx = x2; - yy = y2; - } else { - xx = x1 + param * C; - yy = y1 + param * D; - } - - const dx = x - xx; - const dy = y - yy; - - return Math.sqrt(dx * dx + dy * dy); -} - export function calculateSpeed(point1, point2) { if (!point1 || !point2 || !point1[4] || !point2[4]) { console.warn('Invalid points for speed calculation:', { point1, point2 }); diff --git a/app/javascript/maps/visits.js b/app/javascript/maps/visits.js index 266cde0d..3deea05d 100644 --- a/app/javascript/maps/visits.js +++ b/app/javascript/maps/visits.js @@ -17,7 +17,7 @@ export class VisitsManager { if (!map.getPane('suggestedVisitsPane')) { map.createPane('suggestedVisitsPane'); - map.getPane('suggestedVisitsPane').style.zIndex = 430; // Below confirmed visits but above base layers + map.getPane('suggestedVisitsPane').style.zIndex = 460; // Below confirmed visits but above base layers } this.visitCircles = L.layerGroup(); diff --git a/app/services/visits/merge_service.rb b/app/services/visits/merge_service.rb index 53f600dc..e2c971da 100644 --- a/app/services/visits/merge_service.rb +++ b/app/services/visits/merge_service.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Visits - # Service to handle merging multiple visits into one + # Service to handle merging multiple visits into one from the visits drawer class MergeService attr_reader :visits, :errors, :base_visit diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc deleted file mode 100644 index d7599a91..00000000 --- a/config/credentials.yml.enc +++ /dev/null @@ -1 +0,0 @@ -8VIWnwlEhKkoPvsVuDII3z+D/YN83w/iLZd69QIm4Z0FMrSt6LPidLsgnnW81Rx44Z+0al/MWDUNGpYKa4dCSy01g+Pjdez4BrNLR4qGlRXruAZkapI78/J9r1ynyGf9GRW7c+kimRngPTg/enInUlo8wGrW/P2KhKPqn1tcUzKl4pyy2eD+BELblrwG2k96FxA7NmR6NDvB1K9OlLpAHiA0AVxuSKlXweX/Q5lCZsAeWFN1tlieGJABeadG/AnpWT53vigyvdYyqGactxhh6kkFU+baNj0ELwrAqD3bjTD/haqgiH2ZqjlqjNxLVdJdcHUGqs6jS9MziwRouRo8AbYRZz++BH0ZHslkhdSWm68DH7xpLGL5MXTqBF6uHv8edcHleZM9ThfKsO68M7GADzHvsIBJYZEbeDPh--ggwrEpNtVdYbWPMO--NI2ABLK+rU+9YBFeVjWbEQ== \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 73945456..aec511e8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -179,6 +179,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_03_194043) do t.index ["reverse_geocoded_at"], name: "index_points_on_reverse_geocoded_at" t.index ["timestamp"], name: "index_points_on_timestamp" t.index ["trigger"], name: "index_points_on_trigger" + t.index ["user_id", "timestamp", "tracker_id"], name: "index_points_on_user_id_timestamp_tracker_id", unique: true t.index ["user_id"], name: "index_points_on_user_id" t.index ["visit_id"], name: "index_points_on_visit_id" end