mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 01:31:39 -05:00
Some frontend fixes
This commit is contained in:
parent
5fbc1fb884
commit
a48cff098b
12 changed files with 76 additions and 72 deletions
32
CHANGELOG.md
32
CHANGELOG.md
|
|
@ -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/).
|
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.
|
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:
|
When `STORE_GEODATA` is disabled, each feature that uses geodata will now make a direct request to the geocoding service to calculate required data.
|
||||||
- [ ] Fetching places geodata
|
|
||||||
- [x] Fetching countries for a trip
|
Geodata is being used:
|
||||||
- [x] Suggesting place name for a visit
|
|
||||||
- [x] When `STORE_GEODATA` is disabled, points are not being reverse geocoded on creation.
|
- Fetching places geodata
|
||||||
- [x] When `STORE_GEODATA` is disabled, countries for a trip are being pulled from the geocoding service.
|
- Fetching countries for a trip
|
||||||
- [x] When `STORE_GEODATA` is enabled, points are being reverse geocoded upon creation and stored in the database.
|
- Suggesting place name for a visit
|
||||||
- [ ] 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.
|
|
||||||
|
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
|
## Changed
|
||||||
|
|
||||||
- Reverse geocoding is now working as on-demand job instead of storing the result in the database.
|
- 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
|
## Fixed
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -5,7 +5,7 @@ class StatsController < ApplicationController
|
||||||
before_action :authenticate_active_user!, only: %i[update update_all]
|
before_action :authenticate_active_user!, only: %i[update update_all]
|
||||||
|
|
||||||
def index
|
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_total = current_user.tracked_points.count
|
||||||
@points_reverse_geocoded = current_user.total_reverse_geocoded_points
|
@points_reverse_geocoded = current_user.total_reverse_geocoded_points
|
||||||
@points_reverse_geocoded_without_data = current_user.total_reverse_geocoded_points_without_data
|
@points_reverse_geocoded_without_data = current_user.total_reverse_geocoded_points_without_data
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ class Api::PlaceSerializer
|
||||||
country: place.country,
|
country: place.country,
|
||||||
source: place.source,
|
source: place.source,
|
||||||
geodata: place.geodata,
|
geodata: place.geodata,
|
||||||
reverse_geocoded_at: place.reverse_geocoded_at,
|
|
||||||
created_at: place.created_at,
|
created_at: place.created_at,
|
||||||
updated_at: place.updated_at
|
updated_at: place.updated_at,
|
||||||
|
reverse_geocoded_at: place.reverse_geocoded_at
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,8 @@ class Trips::Countries
|
||||||
|
|
||||||
batches = split_into_batches(all_points, @batch_count)
|
batches = split_into_batches(all_points, @batch_count)
|
||||||
threads_results = process_batches_in_threads(batches, total_points)
|
threads_results = process_batches_in_threads(batches, total_points)
|
||||||
country_counts = merge_thread_results(threads_results)
|
|
||||||
|
|
||||||
log_results(country_counts, total_points)
|
merge_thread_results(threads_results).uniq.compact
|
||||||
country_counts.sort_by { |_country, count| -count }.to_h
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -39,10 +37,9 @@ class Trips::Countries
|
||||||
threads_results = []
|
threads_results = []
|
||||||
threads = []
|
threads = []
|
||||||
|
|
||||||
batches.each_with_index do |batch, batch_index|
|
batches.each do |batch|
|
||||||
start_index = batch_index * batch.size + 1
|
|
||||||
threads << Thread.new do
|
threads << Thread.new do
|
||||||
threads_results << process_batch(batch, start_index, total_points)
|
threads_results << process_batch(batch)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -51,63 +48,32 @@ class Trips::Countries
|
||||||
end
|
end
|
||||||
|
|
||||||
def merge_thread_results(threads_results)
|
def merge_thread_results(threads_results)
|
||||||
country_counts = {}
|
countries = []
|
||||||
|
|
||||||
threads_results.each do |result|
|
threads_results.each do |result|
|
||||||
result.each do |country, count|
|
countries.concat(result)
|
||||||
country_counts[country] ||= 0
|
|
||||||
country_counts[country] += count
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
country_counts
|
countries
|
||||||
end
|
end
|
||||||
|
|
||||||
def log_results(country_counts, total_points)
|
def process_batch(points)
|
||||||
total_counted = country_counts.values.sum
|
points.map do |point|
|
||||||
Rails.logger.info("Processed #{total_points} points and found #{country_counts.size} countries")
|
country_code = geocode_point(point)
|
||||||
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)
|
|
||||||
next unless country_code
|
next unless country_code
|
||||||
|
|
||||||
country_counts[country_code] ||= 0
|
country_code
|
||||||
country_counts[country_code] += 1
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
country_counts
|
def geocode_point(point)
|
||||||
end
|
|
||||||
|
|
||||||
def geocode_point(point, current_index, total_points)
|
|
||||||
lonlat = point.lonlat
|
lonlat = point.lonlat
|
||||||
return nil unless lonlat
|
return nil unless lonlat
|
||||||
|
|
||||||
latitude = lonlat.y
|
latitude = lonlat.y
|
||||||
longitude = lonlat.x
|
longitude = lonlat.x
|
||||||
|
|
||||||
log_processing_point(current_index, total_points, latitude, longitude)
|
fetch_country_code(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}")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_country_code(latitude, longitude)
|
def fetch_country_code(latitude, longitude)
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,36 @@
|
||||||
<div class="flex flex-col space-y-4 mb-4 w-full">
|
<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| %>
|
<%= 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="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">
|
<div class="flex flex-col space-y-2">
|
||||||
<%= f.label :start_at, class: "text-sm font-semibold" %>
|
<%= 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 %>
|
<%= 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>
|
</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">
|
<div class="flex flex-col space-y-2">
|
||||||
<%= f.label :end_at, class: "text-sm font-semibold" %>
|
<%= 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 %>
|
<%= 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>
|
</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="w-full sm:w-6/12 md:w-2/12 lg:w-1/12">
|
||||||
<div class="flex flex-col space-y-2">
|
<div class="flex flex-col space-y-2">
|
||||||
<%= f.submit "Search", class: "btn btn-primary hover:btn-info" %>
|
<%= f.submit "Search", class: "btn btn-primary hover:btn-info" %>
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,12 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="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' %>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<p><%= stat.distance %><%= DISTANCE_UNIT %></p>
|
<p><%= number_with_delimiter stat.distance %><%= DISTANCE_UNIT %></p>
|
||||||
<% if DawarichSettings.reverse_geocoding_enabled? %>
|
<% if DawarichSettings.reverse_geocoding_enabled? %>
|
||||||
<div class="card-actions justify-end">
|
<div class="card-actions justify-end">
|
||||||
<%= countries_and_cities_stat_for_month(stat) %>
|
<%= countries_and_cities_stat_for_month(stat) %>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@
|
||||||
<%= link_to year, "/stats/#{year}", class: 'underline hover:no-underline' %>
|
<%= link_to year, "/stats/#{year}", class: 'underline hover:no-underline' %>
|
||||||
<%= link_to '[Map]', map_url(year_timespan(year)), class: 'underline hover:no-underline' %>
|
<%= link_to '[Map]', map_url(year_timespan(year)), class: 'underline hover:no-underline' %>
|
||||||
</div>
|
</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>
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
<% cache [current_user, 'year_distance_stat', year], skip_digest: true do %>
|
<% cache [current_user, 'year_distance_stat', year], skip_digest: true do %>
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ services:
|
||||||
PROMETHEUS_EXPORTER_PORT: 9394
|
PROMETHEUS_EXPORTER_PORT: 9394
|
||||||
SECRET_KEY_BASE: 1234567890
|
SECRET_KEY_BASE: 1234567890
|
||||||
RAILS_LOG_TO_STDOUT: "true"
|
RAILS_LOG_TO_STDOUT: "true"
|
||||||
|
STORE_GEODATA: "false"
|
||||||
logging:
|
logging:
|
||||||
driver: "json-file"
|
driver: "json-file"
|
||||||
options:
|
options:
|
||||||
|
|
@ -124,6 +125,7 @@ services:
|
||||||
PROMETHEUS_EXPORTER_PORT: 9394
|
PROMETHEUS_EXPORTER_PORT: 9394
|
||||||
SECRET_KEY_BASE: 1234567890
|
SECRET_KEY_BASE: 1234567890
|
||||||
RAILS_LOG_TO_STDOUT: "true"
|
RAILS_LOG_TO_STDOUT: "true"
|
||||||
|
STORE_GEODATA: "false"
|
||||||
logging:
|
logging:
|
||||||
driver: "json-file"
|
driver: "json-file"
|
||||||
options:
|
options:
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ services:
|
||||||
PROMETHEUS_EXPORTER_HOST: 0.0.0.0
|
PROMETHEUS_EXPORTER_HOST: 0.0.0.0
|
||||||
PROMETHEUS_EXPORTER_PORT: 9394
|
PROMETHEUS_EXPORTER_PORT: 9394
|
||||||
SELF_HOSTED: "true"
|
SELF_HOSTED: "true"
|
||||||
|
STORE_GEODATA: "false"
|
||||||
logging:
|
logging:
|
||||||
driver: "json-file"
|
driver: "json-file"
|
||||||
options:
|
options:
|
||||||
|
|
@ -122,6 +123,7 @@ services:
|
||||||
PROMETHEUS_EXPORTER_HOST: dawarich_app
|
PROMETHEUS_EXPORTER_HOST: dawarich_app
|
||||||
PROMETHEUS_EXPORTER_PORT: 9394
|
PROMETHEUS_EXPORTER_PORT: 9394
|
||||||
SELF_HOSTED: "true"
|
SELF_HOSTED: "true"
|
||||||
|
STORE_GEODATA: "false"
|
||||||
logging:
|
logging:
|
||||||
driver: "json-file"
|
driver: "json-file"
|
||||||
options:
|
options:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ MIN_MINUTES_SPENT_IN_CITY=60
|
||||||
APPLICATION_HOSTS=dawarich.example.synology.me
|
APPLICATION_HOSTS=dawarich.example.synology.me
|
||||||
TIME_ZONE=Europe/Berlin
|
TIME_ZONE=Europe/Berlin
|
||||||
BACKGROUND_PROCESSING_CONCURRENCY=10
|
BACKGROUND_PROCESSING_CONCURRENCY=10
|
||||||
|
STORE_GEODATA=false
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
# Database
|
# Database
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,11 @@ RSpec.describe ReverseGeocoding::Points::FetchData do
|
||||||
|
|
||||||
context 'when Geocoder returns city and country' do
|
context 'when Geocoder returns city and country' do
|
||||||
before do
|
before do
|
||||||
allow(Geocoder).to receive(:search).and_return([double(city: 'City', country: 'Country',
|
allow(Geocoder).to receive(:search).and_return(
|
||||||
data: { 'address' => 'Address' })])
|
[
|
||||||
|
double(city: 'City', country: 'Country',data: { 'address' => 'Address' })
|
||||||
|
]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when point does not have city and country' do
|
context 'when point does not have city and country' do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue