Some frontend fixes

This commit is contained in:
Eugene Burmakin 2025-05-15 18:23:24 +02:00
parent 5fbc1fb884
commit a48cff098b
12 changed files with 76 additions and 72 deletions

View file

@ -5,24 +5,32 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
# 0.26.1 - 2025-05-12
# 0.26.1 - 2025-05-15
Geodata on demand
## Geodata on demand
- [x] Introduce a `STORE_GEODATA` environment variable to control whether to store geodata in the database.
- [ ] When `STORE_GEODATA` is disabled, each feature that uses geodata will now make a direct request to the geocoding service to calculate required data.
Geodata is being used:
- [ ] Fetching places geodata
- [x] Fetching countries for a trip
- [x] Suggesting place name for a visit
- [x] When `STORE_GEODATA` is disabled, points are not being reverse geocoded on creation.
- [x] When `STORE_GEODATA` is disabled, countries for a trip are being pulled from the geocoding service.
- [x] When `STORE_GEODATA` is enabled, points are being reverse geocoded upon creation and stored in the database.
- [ ] Each feature that uses geodata will check if an entity (point, place, etc.) has geodata stored in the database and use it if available. If not, it will make a direct request to the geocoding service to calculate required data.
This release introduces a new environment variable `STORE_GEODATA` to control whether to store geodata in the database.
When `STORE_GEODATA` is disabled, each feature that uses geodata will now make a direct request to the geocoding service to calculate required data.
Geodata is being used:
- Fetching places geodata
- Fetching countries for a trip
- Suggesting place name for a visit
If you prefer to keep the old behavior, you can set `STORE_GEODATA` to `true`. By default, starting this release, it's set to `false`.
If you're running your own Photon instance, you can safely set `STORE_GEODATA` to `false`, otherwise it'd be better to keep it enabled, because that way Dawarich will be using existing geodata for its calculations.
## Added
- Map page now has a button to go to the previous and next day. #296 #631 #904
## Changed
- Reverse geocoding is now working as on-demand job instead of storing the result in the database.
- Stats cards now show the last update time. #733
## Fixed

File diff suppressed because one or more lines are too long

View file

@ -5,7 +5,7 @@ class StatsController < ApplicationController
before_action :authenticate_active_user!, only: %i[update update_all]
def index
@stats = current_user.stats.group_by(&:year).sort.reverse
@stats = current_user.stats.group_by(&:year).transform_values { |stats| stats.sort_by(&:updated_at).reverse }.sort.reverse
@points_total = current_user.tracked_points.count
@points_reverse_geocoded = current_user.total_reverse_geocoded_points
@points_reverse_geocoded_without_data = current_user.total_reverse_geocoded_points_without_data

View file

@ -15,9 +15,9 @@ class Api::PlaceSerializer
country: place.country,
source: place.source,
geodata: place.geodata,
reverse_geocoded_at: place.reverse_geocoded_at,
created_at: place.created_at,
updated_at: place.updated_at
updated_at: place.updated_at,
reverse_geocoded_at: place.reverse_geocoded_at
}
end

View file

@ -21,10 +21,8 @@ class Trips::Countries
batches = split_into_batches(all_points, @batch_count)
threads_results = process_batches_in_threads(batches, total_points)
country_counts = merge_thread_results(threads_results)
log_results(country_counts, total_points)
country_counts.sort_by { |_country, count| -count }.to_h
merge_thread_results(threads_results).uniq.compact
end
private
@ -39,10 +37,9 @@ class Trips::Countries
threads_results = []
threads = []
batches.each_with_index do |batch, batch_index|
start_index = batch_index * batch.size + 1
batches.each do |batch|
threads << Thread.new do
threads_results << process_batch(batch, start_index, total_points)
threads_results << process_batch(batch)
end
end
@ -51,63 +48,32 @@ class Trips::Countries
end
def merge_thread_results(threads_results)
country_counts = {}
countries = []
threads_results.each do |result|
result.each do |country, count|
country_counts[country] ||= 0
country_counts[country] += count
end
countries.concat(result)
end
country_counts
countries
end
def log_results(country_counts, total_points)
total_counted = country_counts.values.sum
Rails.logger.info("Processed #{total_points} points and found #{country_counts.size} countries")
Rails.logger.info("Points counted: #{total_counted} out of #{total_points}")
end
def process_batch(points, start_index, total_points)
country_counts = {}
points.each_with_index do |point, idx|
current_index = start_index + idx
country_code = geocode_point(point, current_index, total_points)
def process_batch(points)
points.map do |point|
country_code = geocode_point(point)
next unless country_code
country_counts[country_code] ||= 0
country_counts[country_code] += 1
country_code
end
end
country_counts
end
def geocode_point(point, current_index, total_points)
def geocode_point(point)
lonlat = point.lonlat
return nil unless lonlat
latitude = lonlat.y
longitude = lonlat.x
log_processing_point(current_index, total_points, latitude, longitude)
country_code = fetch_country_code(latitude, longitude)
log_found_country(country_code, latitude, longitude) if country_code
country_code
end
def log_processing_point(current_index, total_points, latitude, longitude)
thread_id = Thread.current.object_id
Rails.logger.info(
"Thread #{thread_id}: Processing point #{current_index} of #{total_points}: lat=#{latitude}, lon=#{longitude}"
)
end
def log_found_country(country_code, latitude, longitude)
thread_id = Thread.current.object_id
Rails.logger.info("Thread #{thread_id}: Found country: #{country_code} for point at #{latitude}, #{longitude}")
fetch_country_code(latitude, longitude)
end
def fetch_country_code(latitude, longitude)

View file

@ -5,18 +5,36 @@
<div class="flex flex-col space-y-4 mb-4 w-full">
<%= form_with url: map_path(import_id: params[:import_id]), method: :get do |f| %>
<div class="flex flex-col space-y-4 sm:flex-row sm:space-y-0 sm:space-x-4 sm:items-end">
<div class="w-full sm:w-2/12 md:w-1/12 lg:w-3/12">
<div class="w-full sm:w-1/12 md:w-1/12 lg:w-1/12">
<div class="flex flex-col space-y-2">
<span class="tooltip" data-tip="<%= human_date(@start_at - 1.day) %>">
<%= link_to map_path(start_at: @start_at - 1.day, end_at: @end_at - 1.day, import_id: params[:import_id]), class: "btn btn-neutral hover:btn-ghost w-full" do %>
◀️
<% end %>
</span>
</div>
</div>
<div class="w-full sm:w-2/12 md:w-1/12 lg:w-2/12">
<div class="flex flex-col space-y-2">
<%= f.label :start_at, class: "text-sm font-semibold" %>
<%= f.datetime_local_field :start_at, include_seconds: false, class: "input input-bordered hover:cursor-pointer hover:input-primary", value: @start_at %>
</div>
</div>
<div class="w-full sm:w-2/12 md:w-1/12 lg:w-3/12">
<div class="w-full sm:w-2/12 md:w-1/12 lg:w-2/12">
<div class="flex flex-col space-y-2">
<%= f.label :end_at, class: "text-sm font-semibold" %>
<%= f.datetime_local_field :end_at, include_seconds: false, class: "input input-bordered hover:cursor-pointer hover:input-primary", value: @end_at %>
</div>
</div>
<div class="w-full sm:w-1/12 md:w-1/12 lg:w-1/12">
<div class="flex flex-col space-y-2">
<span class="tooltip" data-tip="<%= human_date(@start_at + 1.day) %>">
<%= link_to map_path(start_at: @start_at + 1.day, end_at: @end_at + 1.day, import_id: params[:import_id]), class: "btn btn-neutral hover:btn-ghost w-full" do %>
▶️
<% end %>
</span>
</div>
</div>
<div class="w-full sm:w-6/12 md:w-2/12 lg:w-1/12">
<div class="flex flex-col space-y-2">
<%= f.submit "Search", class: "btn btn-primary hover:btn-info" %>

View file

@ -7,11 +7,12 @@
<% end %>
</h2>
<div class="flex items-center gap-2">
<%= link_to '[Update]', update_year_month_stats_path(stat.year, stat.month), data: { turbo_method: :put }, class: 'text-sm text-gray-500 hover:underline' %>
<div class="gap-2">
<span class='text-xs text-gray-500'>Last update <%= human_date(stat.updated_at) %></span>
<%= link_to '🔄', update_year_month_stats_path(stat.year, stat.month), data: { turbo_method: :put }, class: 'text-sm text-gray-500 hover:underline' %>
</div>
</div>
<p><%= stat.distance %><%= DISTANCE_UNIT %></p>
<p><%= number_with_delimiter stat.distance %><%= DISTANCE_UNIT %></p>
<% if DawarichSettings.reverse_geocoding_enabled? %>
<div class="card-actions justify-end">
<%= countries_and_cities_stat_for_month(stat) %>

View file

@ -32,7 +32,10 @@
<%= link_to year, "/stats/#{year}", class: 'underline hover:no-underline' %>
<%= link_to '[Map]', map_url(year_timespan(year)), class: 'underline hover:no-underline' %>
</div>
<%= link_to '[Update]', update_year_month_stats_path(year, :all), data: { turbo_method: :put }, class: 'text-sm text-gray-500 hover:underline' %>
<div class="gap-2">
<span class='text-xs text-gray-500'>Last updated: <%= human_date(stats.first.updated_at) %></span>
<%= link_to '🔄', update_year_month_stats_path(year, :all), data: { turbo_method: :put }, class: 'text-sm text-gray-500 hover:underline' %>
</div>
</h2>
<p>
<% cache [current_user, 'year_distance_stat', year], skip_digest: true do %>

View file

@ -70,6 +70,7 @@ services:
PROMETHEUS_EXPORTER_PORT: 9394
SECRET_KEY_BASE: 1234567890
RAILS_LOG_TO_STDOUT: "true"
STORE_GEODATA: "false"
logging:
driver: "json-file"
options:
@ -124,6 +125,7 @@ services:
PROMETHEUS_EXPORTER_PORT: 9394
SECRET_KEY_BASE: 1234567890
RAILS_LOG_TO_STDOUT: "true"
STORE_GEODATA: "false"
logging:
driver: "json-file"
options:

View file

@ -70,6 +70,7 @@ services:
PROMETHEUS_EXPORTER_HOST: 0.0.0.0
PROMETHEUS_EXPORTER_PORT: 9394
SELF_HOSTED: "true"
STORE_GEODATA: "false"
logging:
driver: "json-file"
options:
@ -122,6 +123,7 @@ services:
PROMETHEUS_EXPORTER_HOST: dawarich_app
PROMETHEUS_EXPORTER_PORT: 9394
SELF_HOSTED: "true"
STORE_GEODATA: "false"
logging:
driver: "json-file"
options:

View file

@ -7,6 +7,7 @@ MIN_MINUTES_SPENT_IN_CITY=60
APPLICATION_HOSTS=dawarich.example.synology.me
TIME_ZONE=Europe/Berlin
BACKGROUND_PROCESSING_CONCURRENCY=10
STORE_GEODATA=false
###################################################################################
# Database

View file

@ -9,8 +9,11 @@ RSpec.describe ReverseGeocoding::Points::FetchData do
context 'when Geocoder returns city and country' do
before do
allow(Geocoder).to receive(:search).and_return([double(city: 'City', country: 'Country',
data: { 'address' => 'Address' })])
allow(Geocoder).to receive(:search).and_return(
[
double(city: 'City', country: 'Country',data: { 'address' => 'Address' })
]
)
end
context 'when point does not have city and country' do