Compare commits

..

79 commits

Author SHA1 Message Date
Eugene Burmakin
88ae7c43c6 Adjust calculate_duration_in_minutes to only count continuous presence within cities, excluding long gaps. 2026-01-04 17:12:39 +01:00
Eugene Burmakin
348bf96bfe Rework country tracked days calculation 2026-01-04 16:42:35 +01:00
Eugene Burmakin
1dc31a66d4 Update Gemfile and Gemfile.lock to pin connection_pool and sidekiq versions 2026-01-04 14:49:15 +01:00
Evgenii Burmakin
ec524d64a0
Update digest calculation to use actual time spent in countries based… (#2115)
* Update digest calculation to use actual time spent in countries based on consecutive points, avoiding double-counting days when crossing borders.

* Move methods to private
2026-01-04 12:45:30 +01:00
dependabot[bot]
594b7ffdd2
Bump sidekiq from 8.0.8 to 8.1.0 (#2084)
Bumps [sidekiq](https://github.com/sidekiq/sidekiq) from 8.0.8 to 8.1.0.
- [Changelog](https://github.com/sidekiq/sidekiq/blob/main/Changes.md)
- [Commits](https://github.com/sidekiq/sidekiq/compare/v8.0.8...v8.1.0)

---
updated-dependencies:
- dependency-name: sidekiq
  dependency-version: 8.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evgenii Burmakin <Freika@users.noreply.github.com>
2026-01-03 13:55:44 +01:00
dependabot[bot]
a4b9ed1087
Bump sentry-ruby from 6.0.0 to 6.2.0 (#2083)
Bumps [sentry-ruby](https://github.com/getsentry/sentry-ruby) from 6.0.0 to 6.2.0.
- [Release notes](https://github.com/getsentry/sentry-ruby/releases)
- [Changelog](https://github.com/getsentry/sentry-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-ruby/compare/6.0.0...6.2.0)

---
updated-dependencies:
- dependency-name: sentry-ruby
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evgenii Burmakin <Freika@users.noreply.github.com>
2026-01-03 13:54:54 +01:00
dependabot[bot]
966dc01651
Bump rubyzip from 3.2.0 to 3.2.2 (#2082)
Bumps [rubyzip](https://github.com/rubyzip/rubyzip) from 3.2.0 to 3.2.2.
- [Release notes](https://github.com/rubyzip/rubyzip/releases)
- [Changelog](https://github.com/rubyzip/rubyzip/blob/main/Changelog.md)
- [Commits](https://github.com/rubyzip/rubyzip/compare/v3.2.0...v3.2.2)

---
updated-dependencies:
- dependency-name: rubyzip
  dependency-version: 3.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-03 13:54:14 +01:00
dependabot[bot]
96a78881f1
Bump chartkick from 5.2.0 to 5.2.1 (#2081)
Bumps [chartkick](https://github.com/ankane/chartkick) from 5.2.0 to 5.2.1.
- [Changelog](https://github.com/ankane/chartkick/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ankane/chartkick/compare/v5.2.0...v5.2.1)

---
updated-dependencies:
- dependency-name: chartkick
  dependency-version: 5.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-03 13:53:48 +01:00
dependabot[bot]
aa3bf93a45
Bump rubocop-rails from 2.33.4 to 2.34.2 (#2080)
Bumps [rubocop-rails](https://github.com/rubocop/rubocop-rails) from 2.33.4 to 2.34.2.
- [Release notes](https://github.com/rubocop/rubocop-rails/releases)
- [Changelog](https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop/rubocop-rails/compare/v2.33.4...v2.34.2)

---
updated-dependencies:
- dependency-name: rubocop-rails
  dependency-version: 2.34.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-03 13:53:21 +01:00
Evgenii Burmakin
24cbabf3b7
Map v2 will no longer block the UI when Immich/Photoprism integration has a bad URL or is unreachable (#2113) 2026-01-03 13:45:12 +01:00
dependabot[bot]
8ecb2e3765
Bump trix from 2.1.15 to 2.1.16 in the npm_and_yarn group across 1 directory (#2098)
* 0.37.1 (#2092)

* fix: move foreman to global gems to fix startup crash (#1971)

* Update exporting code to stream points data to file in batches to red… (#1980)

* Update exporting code to stream points data to file in batches to reduce memory usage

* Update changelog

* Update changelog

* Feature/maplibre frontend (#1953)

* Add a plan to use MapLibre GL JS for the frontend map rendering, replacing Leaflet

* Implement phase 1

* Phases 1-3 + part of 4

* Fix e2e tests

* Phase 6

* Implement fog of war

* Phase 7

* Next step: fix specs, phase 7 done

* Use our own map tiles

* Extract v2 map logic to separate manager classes

* Update settings panel on v2 map

* Update v2 e2e tests structure

* Reimplement location search in maps v2

* Update speed routes

* Implement visits and places creation in v2

* Fix last failing test

* Implement visits merging

* Fix a routes e2e test and simplify the routes layer styling.

* Extract js to modules from maps_v2_controller.js

* Implement area creation

* Fix spec problem

* Fix some e2e tests

* Implement live mode in v2 map

* Update icons and panel

* Extract some styles

* Remove unused file

* Start adding dark theme to popups on MapLibre maps

* Make popups respect dark theme

* Move v2 maps to maplibre namespace

* Update v2 references to maplibre

* Put place, area and visit info into side panel

* Update API to use safe settings config method

* Fix specs

* Fix method name to config in SafeSettings and update usages accordingly

* Add missing public files

* Add handling for real time points

* Fix remembering enabled/disabled layers of the v2 map

* Fix lots of e2e tests

* Add settings to select map version

* Use maps/v2 as main path for MapLibre maps

* Update routing

* Update live mode

* Update maplibre controller

* Update changelog

* Remove some console.log statements

* Pull only necessary data for map v2 points

* Feature/raw data archive (#2009)

* 0.36.2 (#2007)

* fix: move foreman to global gems to fix startup crash (#1971)

* Update exporting code to stream points data to file in batches to red… (#1980)

* Update exporting code to stream points data to file in batches to reduce memory usage

* Update changelog

* Update changelog

* Feature/maplibre frontend (#1953)

* Add a plan to use MapLibre GL JS for the frontend map rendering, replacing Leaflet

* Implement phase 1

* Phases 1-3 + part of 4

* Fix e2e tests

* Phase 6

* Implement fog of war

* Phase 7

* Next step: fix specs, phase 7 done

* Use our own map tiles

* Extract v2 map logic to separate manager classes

* Update settings panel on v2 map

* Update v2 e2e tests structure

* Reimplement location search in maps v2

* Update speed routes

* Implement visits and places creation in v2

* Fix last failing test

* Implement visits merging

* Fix a routes e2e test and simplify the routes layer styling.

* Extract js to modules from maps_v2_controller.js

* Implement area creation

* Fix spec problem

* Fix some e2e tests

* Implement live mode in v2 map

* Update icons and panel

* Extract some styles

* Remove unused file

* Start adding dark theme to popups on MapLibre maps

* Make popups respect dark theme

* Move v2 maps to maplibre namespace

* Update v2 references to maplibre

* Put place, area and visit info into side panel

* Update API to use safe settings config method

* Fix specs

* Fix method name to config in SafeSettings and update usages accordingly

* Add missing public files

* Add handling for real time points

* Fix remembering enabled/disabled layers of the v2 map

* Fix lots of e2e tests

* Add settings to select map version

* Use maps/v2 as main path for MapLibre maps

* Update routing

* Update live mode

* Update maplibre controller

* Update changelog

* Remove some console.log statements

---------

Co-authored-by: Robin Tuszik <mail@robin.gg>

* Remove esbuild scripts from package.json

* Remove sideEffects field from package.json

* Raw data archivation

* Add tests

* Fix tests

* Fix tests

* Update ExceptionReporter

* Add schedule to run raw data archival job monthly

* Change file structure for raw data archival feature

* Update changelog and version for raw data archival feature

---------

Co-authored-by: Robin Tuszik <mail@robin.gg>

* Set raw_data to an empty hash instead of nil when archiving

* Fix storage configuration and file extraction

* Consider MIN_MINUTES_SPENT_IN_CITY during stats calculation (#2018)

* Consider MIN_MINUTES_SPENT_IN_CITY during stats calculation

* Remove raw data from visited cities api endpoint

* Use user timezone to show dates on maps (#2020)

* Fix/pre epoch time (#2019)

* Use user timezone to show dates on maps

* Limit timestamps to valid range to prevent database errors when users enter pre-epoch dates.

* Limit timestamps to valid range to prevent database errors when users enter pre-epoch dates.

* Fix tests failing due to new index on stats table

* Fix failing specs

* Update redis client configuration to support unix socket connection

* Update changelog

* Fix kml kmz import issues (#2023)

* Fix kml kmz import issues

* Refactor KML importer to improve readability and maintainability

* Implement moving points in map v2 and fix route rendering logic to ma… (#2027)

* Implement moving points in map v2 and fix route rendering logic to match map v1.

* Fix route spec

* fix(maplibre): update date format to ISO 8601 (#2029)

* Add verification step to raw data archival process (#2028)

* Add verification step to raw data archival process

* Add actual verification of raw data archives after creation, and only clear raw_data for verified archives.

* Fix failing specs

* Eliminate zip-bomb risk

* Fix potential memory leak in js

* Return .keep files

* Use Toast instead of alert for notifications

* Add help section to navbar dropdown

* Update changelog

* Remove raw_data_archival_job

* Ensure file is being closed properly after reading in Archivable concern

* Add composite index to stats table if not exists

* Update changelog

* Update entrypoint to always sync static assets (not only new ones)

* Add family layer to MapLibre maps (#2055)

* Add family layer to MapLibre maps

* Update migration

* Don't show family toggle if feature is disabled

* Update changelog

* Return changelog

* Update changelog

* Update tailwind file

* Bump sentry-rails from 6.0.0 to 6.1.0 (#1945)

Bumps [sentry-rails](https://github.com/getsentry/sentry-ruby) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/getsentry/sentry-ruby/releases)
- [Changelog](https://github.com/getsentry/sentry-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-ruby/compare/6.0.0...6.1.0)

---
updated-dependencies:
- dependency-name: sentry-rails
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump turbo-rails from 2.0.17 to 2.0.20 (#1944)

Bumps [turbo-rails](https://github.com/hotwired/turbo-rails) from 2.0.17 to 2.0.20.
- [Release notes](https://github.com/hotwired/turbo-rails/releases)
- [Commits](https://github.com/hotwired/turbo-rails/compare/v2.0.17...v2.0.20)

---
updated-dependencies:
- dependency-name: turbo-rails
  dependency-version: 2.0.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evgenii Burmakin <Freika@users.noreply.github.com>

* Bump webmock from 3.25.1 to 3.26.1 (#1943)

Bumps [webmock](https://github.com/bblimke/webmock) from 3.25.1 to 3.26.1.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.25.1...v3.26.1)

---
updated-dependencies:
- dependency-name: webmock
  dependency-version: 3.26.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evgenii Burmakin <Freika@users.noreply.github.com>

* Bump brakeman from 7.1.0 to 7.1.1 (#1942)

Bumps [brakeman](https://github.com/presidentbeef/brakeman) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/presidentbeef/brakeman/releases)
- [Changelog](https://github.com/presidentbeef/brakeman/blob/main/CHANGES.md)
- [Commits](https://github.com/presidentbeef/brakeman/compare/v7.1.0...v7.1.1)

---
updated-dependencies:
- dependency-name: brakeman
  dependency-version: 7.1.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump redis from 5.4.0 to 5.4.1 (#1941)

Bumps [redis](https://github.com/redis/redis-rb) from 5.4.0 to 5.4.1.
- [Changelog](https://github.com/redis/redis-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/redis-rb/compare/v5.4.0...v5.4.1)

---
updated-dependencies:
- dependency-name: redis
  dependency-version: 5.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Put import deletion into background job (#2045)

* Put import deletion into background job

* Update changelog

* fix null type error and update heatmap styling (#2037)

* fix: use constant weight for maplibre heatmap layer

* fix null type, update heatmap styling

* improve heatmap styling

* fix typo

* Fix stats calculation to recursively reduce H3 resolution when too ma… (#2065)

* Fix stats calculation to recursively reduce H3 resolution when too many hexagons are generated

* Update CHANGELOG.md

* Validate trip start and end dates (#2066)

* Validate trip start and end dates

* Update changelog

* Update migration to clean up duplicate stats before adding unique index

* Fix fog of war radius setting being ignored and applying settings causing errors (#2068)

* Update changelog

* Add Rack::Deflater middleware to config/application.rb to enable gzip compression for responses.

* Add composite index to points on user_id and timestamp

* Deduplicte points based on timestamp brought to unix time

* Fix/stats cache invalidation (#2072)

* Fix family layer toggle in Map v2 settings for non-selfhosted env

* Invalidate cache

* Remove comments

* Remove comment

* Add new indicies to improve performance and remove unused ones to opt… (#2078)

* Add new indicies to improve performance and remove unused ones to optimize database.

* Remove comments

* Update map search suggestions panel styling

* Add yearly digest (#2073)

* Add yearly digest

* Rename YearlyDigests to Users::Digests

* Minor changes

* Update yearly digest layout and styles

* Add flags and chart to email

* Update colors

* Fix layout of stats in yearly digest view

* Remove cron job for yearly digest scheduling

* Update CHANGELOG.md

* Update digest email setting handling

* Allow sharing digest for 1 week or 1 month

* Change Digests Distance to Bigint

* Fix settings page

* Update changelog

* Add RailsPulse (#2079)

* Add RailsPulse

* Add RailsPulse monitoring tool with basic HTTP authentication

* Bring points_count to integer

* Update migration and version

* Update rubocop issues

* Fix migrations and data verification to remove safety_assured blocks and handle missing points gracefully.

* Update version

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Robin Tuszik <mail@robin.gg>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump trix in the npm_and_yarn group across 1 directory

Bumps the npm_and_yarn group with 1 update in the / directory: [trix](https://github.com/basecamp/trix).


Updates `trix` from 2.1.15 to 2.1.16
- [Release notes](https://github.com/basecamp/trix/releases)
- [Commits](https://github.com/basecamp/trix/compare/v2.1.15...v2.1.16)

---
updated-dependencies:
- dependency-name: trix
  dependency-version: 2.1.16
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Evgenii Burmakin <Freika@users.noreply.github.com>
Co-authored-by: Robin Tuszik <mail@robin.gg>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-03 13:33:16 +01:00
Evgenii Burmakin
b037be3299
Update calculation of time spent in a country for year-end digest email (#2110)
* Update calculation of time spent in a country for year-end digest email

* Add a filter to exclude raw data points when calculating yearly digests.
2026-01-03 13:28:21 +01:00
Eugene Burmakin
b4c2def2be Merge remote-tracking branch 'origin' into dev 2025-12-30 19:05:30 +01:00
Eugene Burmakin
8a1e42a2e8 Update version 2025-12-30 19:04:15 +01:00
Eugene Burmakin
2f11003c29 Fix migrations and data verification to remove safety_assured blocks and handle missing points gracefully. 2025-12-30 19:02:38 +01:00
Eugene Burmakin
7f277612fc Update rubocop issues 2025-12-30 17:33:17 +01:00
Eugene Burmakin
2f5487cd35 Update migration and version 2025-12-30 16:57:17 +01:00
Eugene Burmakin
5455228b80 Bring points_count to integer 2025-12-30 16:57:17 +01:00
Evgenii Burmakin
26062a1278
Add RailsPulse (#2079)
* Add RailsPulse

* Add RailsPulse monitoring tool with basic HTTP authentication
2025-12-28 17:49:51 +01:00
Eugene Burmakin
14a0bb6478 Update changelog 2025-12-28 17:34:11 +01:00
Evgenii Burmakin
18b13fb915
Add yearly digest (#2073)
* Add yearly digest

* Rename YearlyDigests to Users::Digests

* Minor changes

* Update yearly digest layout and styles

* Add flags and chart to email

* Update colors

* Fix layout of stats in yearly digest view

* Remove cron job for yearly digest scheduling

* Update CHANGELOG.md

* Update digest email setting handling

* Allow sharing digest for 1 week or 1 month

* Change Digests Distance to Bigint

* Fix settings page
2025-12-28 17:33:35 +01:00
Evgenii Burmakin
e857f520cc
Add new indicies to improve performance and remove unused ones to opt… (#2078)
* Add new indicies to improve performance and remove unused ones to optimize database.

* Remove comments

* Update map search suggestions panel styling
2025-12-28 17:32:09 +01:00
Evgenii Burmakin
9e933aff9c
Fix/stats cache invalidation (#2072)
* Fix family layer toggle in Map v2 settings for non-selfhosted env

* Invalidate cache

* Remove comments

* Remove comment
2025-12-27 13:33:54 +01:00
Eugene Burmakin
a722e19a93 Deduplicte points based on timestamp brought to unix time 2025-12-26 19:10:02 +01:00
Eugene Burmakin
67d7123e47 Add composite index to points on user_id and timestamp 2025-12-26 18:21:06 +01:00
Eugene Burmakin
573d527455 Add Rack::Deflater middleware to config/application.rb to enable gzip compression for responses. 2025-12-26 17:49:19 +01:00
Eugene Burmakin
4be58d4b4c Update changelog 2025-12-26 17:07:48 +01:00
Evgenii Burmakin
3f436c1d3a
Fix fog of war radius setting being ignored and applying settings causing errors (#2068) 2025-12-26 17:06:56 +01:00
Eugene Burmakin
fe9d7d2f79 Merge remote-tracking branch 'origin' into dev 2025-12-26 17:05:26 +01:00
Eugene Burmakin
fab0121113 Update migration to clean up duplicate stats before adding unique index 2025-12-26 16:28:34 +01:00
Evgenii Burmakin
9805c5524c
Validate trip start and end dates (#2066)
* Validate trip start and end dates

* Update changelog
2025-12-26 16:16:49 +01:00
Evgenii Burmakin
f325fd7a4f
Fix stats calculation to recursively reduce H3 resolution when too ma… (#2065)
* Fix stats calculation to recursively reduce H3 resolution when too many hexagons are generated

* Update CHANGELOG.md
2025-12-26 15:42:32 +01:00
Robin Tuszik
3c1d17b806
fix null type error and update heatmap styling (#2037)
* fix: use constant weight for maplibre heatmap layer

* fix null type, update heatmap styling

* improve heatmap styling

* fix typo
2025-12-26 15:27:51 +01:00
Evgenii Burmakin
c9ba7914b6
Put import deletion into background job (#2045)
* Put import deletion into background job

* Update changelog
2025-12-26 15:27:09 +01:00
dependabot[bot]
03697ecef2
Bump redis from 5.4.0 to 5.4.1 (#1941)
Bumps [redis](https://github.com/redis/redis-rb) from 5.4.0 to 5.4.1.
- [Changelog](https://github.com/redis/redis-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/redis-rb/compare/v5.4.0...v5.4.1)

---
updated-dependencies:
- dependency-name: redis
  dependency-version: 5.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-26 15:23:39 +01:00
dependabot[bot]
7347be9a87
Bump brakeman from 7.1.0 to 7.1.1 (#1942)
Bumps [brakeman](https://github.com/presidentbeef/brakeman) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/presidentbeef/brakeman/releases)
- [Changelog](https://github.com/presidentbeef/brakeman/blob/main/CHANGES.md)
- [Commits](https://github.com/presidentbeef/brakeman/compare/v7.1.0...v7.1.1)

---
updated-dependencies:
- dependency-name: brakeman
  dependency-version: 7.1.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-26 15:23:19 +01:00
dependabot[bot]
ce74b3d846
Bump webmock from 3.25.1 to 3.26.1 (#1943)
Bumps [webmock](https://github.com/bblimke/webmock) from 3.25.1 to 3.26.1.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.25.1...v3.26.1)

---
updated-dependencies:
- dependency-name: webmock
  dependency-version: 3.26.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evgenii Burmakin <Freika@users.noreply.github.com>
2025-12-26 15:22:55 +01:00
dependabot[bot]
da9742bf4a
Bump turbo-rails from 2.0.17 to 2.0.20 (#1944)
Bumps [turbo-rails](https://github.com/hotwired/turbo-rails) from 2.0.17 to 2.0.20.
- [Release notes](https://github.com/hotwired/turbo-rails/releases)
- [Commits](https://github.com/hotwired/turbo-rails/compare/v2.0.17...v2.0.20)

---
updated-dependencies:
- dependency-name: turbo-rails
  dependency-version: 2.0.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evgenii Burmakin <Freika@users.noreply.github.com>
2025-12-26 15:22:05 +01:00
dependabot[bot]
e12b45f93e
Bump sentry-rails from 6.0.0 to 6.1.0 (#1945)
Bumps [sentry-rails](https://github.com/getsentry/sentry-ruby) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/getsentry/sentry-ruby/releases)
- [Changelog](https://github.com/getsentry/sentry-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-ruby/compare/6.0.0...6.1.0)

---
updated-dependencies:
- dependency-name: sentry-rails
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-26 15:21:25 +01:00
Eugene Burmakin
32f5d2f89a Update tailwind file 2025-12-26 14:57:12 +01:00
Eugene Burmakin
ad385f4464 Update changelog 2025-12-26 14:41:55 +01:00
Eugene Burmakin
d4e87ce830 Return changelog 2025-12-26 14:39:36 +01:00
Eugene Burmakin
04fbe4d564 Merge remote-tracking branch 'origin' into dev 2025-12-26 14:39:16 +01:00
Eugene Burmakin
1471e4de40 Update changelog 2025-12-26 14:33:56 +01:00
Evgenii Burmakin
9ef0da27d6
Add family layer to MapLibre maps (#2055)
* Add family layer to MapLibre maps

* Update migration

* Don't show family toggle if feature is disabled
2025-12-26 14:27:16 +01:00
Eugene Burmakin
87baf8bb11 Update entrypoint to always sync static assets (not only new ones) 2025-12-16 18:30:07 +01:00
Eugene Burmakin
d40b2a1959 Update changelog 2025-12-14 22:22:16 +01:00
Eugene Burmakin
35995e7be8 Add composite index to stats table if not exists 2025-12-14 22:19:58 +01:00
Eugene Burmakin
20a4553921 Ensure file is being closed properly after reading in Archivable concern 2025-12-14 11:40:33 +01:00
Eugene Burmakin
c1bb7f3d87 Remove raw_data_archival_job 2025-12-14 11:37:34 +01:00
Eugene Burmakin
0b6149bfc0 Update changelog 2025-12-14 11:34:50 +01:00
Eugene Burmakin
f2d96e50f0 Add help section to navbar dropdown 2025-12-14 11:31:40 +01:00
Eugene Burmakin
1090bcd6e8 Use Toast instead of alert for notifications 2025-12-14 00:32:12 +01:00
Eugene Burmakin
b7f0b7ebc2 Return .keep files 2025-12-14 00:05:34 +01:00
Eugene Burmakin
b81d2580e3 Fix potential memory leak in js 2025-12-14 00:04:42 +01:00
Eugene Burmakin
acee848e72 Eliminate zip-bomb risk 2025-12-13 23:52:47 +01:00
Evgenii Burmakin
88f5e2a6ea
Add verification step to raw data archival process (#2028)
* Add verification step to raw data archival process

* Add actual verification of raw data archives after creation, and only clear raw_data for verified archives.

* Fix failing specs
2025-12-13 21:25:06 +01:00
Robin Tuszik
353837e27f
fix(maplibre): update date format to ISO 8601 (#2029) 2025-12-12 00:21:21 +01:00
Evgenii Burmakin
2a4ed8bf82
Implement moving points in map v2 and fix route rendering logic to ma… (#2027)
* Implement moving points in map v2 and fix route rendering logic to match map v1.

* Fix route spec
2025-12-10 19:58:31 +01:00
Evgenii Burmakin
8af032a215
Fix kml kmz import issues (#2023)
* Fix kml kmz import issues

* Refactor KML importer to improve readability and maintainability
2025-12-09 19:37:27 +01:00
Eugene Burmakin
bb980f2210 Update changelog 2025-12-09 00:22:47 +01:00
Eugene Burmakin
c6d09c341d Update redis client configuration to support unix socket connection 2025-12-09 00:19:32 +01:00
Evgenii Burmakin
516cfabb06
Fix/pre epoch time (#2019)
* Use user timezone to show dates on maps

* Limit timestamps to valid range to prevent database errors when users enter pre-epoch dates.

* Limit timestamps to valid range to prevent database errors when users enter pre-epoch dates.

* Fix tests failing due to new index on stats table

* Fix failing specs
2025-12-09 00:17:24 +01:00
Evgenii Burmakin
9ac4566b5a
Use user timezone to show dates on maps (#2020) 2025-12-08 22:12:17 +01:00
Evgenii Burmakin
1c9843dde7
Consider MIN_MINUTES_SPENT_IN_CITY during stats calculation (#2018)
* Consider MIN_MINUTES_SPENT_IN_CITY during stats calculation

* Remove raw data from visited cities api endpoint
2025-12-08 21:38:56 +01:00
Eugene Burmakin
6cc8ba0fbd Merge branch 'master' into dev 2025-12-08 19:52:05 +01:00
Eugene Burmakin
913d60812a Fix storage configuration and file extraction 2025-12-08 19:51:28 +01:00
Eugene Burmakin
a7f77b042e Set raw_data to an empty hash instead of nil when archiving 2025-12-07 23:58:05 +01:00
Eugene Burmakin
cdf1428e35 Merge remote-tracking branch 'origin' into dev 2025-12-07 14:39:30 +01:00
Evgenii Burmakin
9661e8e7f7
Feature/raw data archive (#2009)
* 0.36.2 (#2007)

* fix: move foreman to global gems to fix startup crash (#1971)

* Update exporting code to stream points data to file in batches to red… (#1980)

* Update exporting code to stream points data to file in batches to reduce memory usage

* Update changelog

* Update changelog

* Feature/maplibre frontend (#1953)

* Add a plan to use MapLibre GL JS for the frontend map rendering, replacing Leaflet

* Implement phase 1

* Phases 1-3 + part of 4

* Fix e2e tests

* Phase 6

* Implement fog of war

* Phase 7

* Next step: fix specs, phase 7 done

* Use our own map tiles

* Extract v2 map logic to separate manager classes

* Update settings panel on v2 map

* Update v2 e2e tests structure

* Reimplement location search in maps v2

* Update speed routes

* Implement visits and places creation in v2

* Fix last failing test

* Implement visits merging

* Fix a routes e2e test and simplify the routes layer styling.

* Extract js to modules from maps_v2_controller.js

* Implement area creation

* Fix spec problem

* Fix some e2e tests

* Implement live mode in v2 map

* Update icons and panel

* Extract some styles

* Remove unused file

* Start adding dark theme to popups on MapLibre maps

* Make popups respect dark theme

* Move v2 maps to maplibre namespace

* Update v2 references to maplibre

* Put place, area and visit info into side panel

* Update API to use safe settings config method

* Fix specs

* Fix method name to config in SafeSettings and update usages accordingly

* Add missing public files

* Add handling for real time points

* Fix remembering enabled/disabled layers of the v2 map

* Fix lots of e2e tests

* Add settings to select map version

* Use maps/v2 as main path for MapLibre maps

* Update routing

* Update live mode

* Update maplibre controller

* Update changelog

* Remove some console.log statements

---------

Co-authored-by: Robin Tuszik <mail@robin.gg>

* Remove esbuild scripts from package.json

* Remove sideEffects field from package.json

* Raw data archivation

* Add tests

* Fix tests

* Fix tests

* Update ExceptionReporter

* Add schedule to run raw data archival job monthly

* Change file structure for raw data archival feature

* Update changelog and version for raw data archival feature

---------

Co-authored-by: Robin Tuszik <mail@robin.gg>
2025-12-07 14:33:23 +01:00
Eugene Burmakin
2debcd88fa Pull only necessary data for map v2 points 2025-12-06 21:23:17 +01:00
Evgenii Burmakin
672c308f67
Merge branch 'master' into dev 2025-12-06 20:54:29 +01:00
Eugene Burmakin
c5ef4d3861 Remove some console.log statements 2025-12-06 20:42:52 +01:00
Eugene Burmakin
9fb4bc517b Update changelog 2025-12-06 20:39:47 +01:00
Eugene Burmakin
97d52f9edc Update maplibre controller 2025-12-06 20:36:52 +01:00
Evgenii Burmakin
4421a5bf3c
Feature/maplibre frontend (#1953)
* Add a plan to use MapLibre GL JS for the frontend map rendering, replacing Leaflet

* Implement phase 1

* Phases 1-3 + part of 4

* Fix e2e tests

* Phase 6

* Implement fog of war

* Phase 7

* Next step: fix specs, phase 7 done

* Use our own map tiles

* Extract v2 map logic to separate manager classes

* Update settings panel on v2 map

* Update v2 e2e tests structure

* Reimplement location search in maps v2

* Update speed routes

* Implement visits and places creation in v2

* Fix last failing test

* Implement visits merging

* Fix a routes e2e test and simplify the routes layer styling.

* Extract js to modules from maps_v2_controller.js

* Implement area creation

* Fix spec problem

* Fix some e2e tests

* Implement live mode in v2 map

* Update icons and panel

* Extract some styles

* Remove unused file

* Start adding dark theme to popups on MapLibre maps

* Make popups respect dark theme

* Move v2 maps to maplibre namespace

* Update v2 references to maplibre

* Put place, area and visit info into side panel

* Update API to use safe settings config method

* Fix specs

* Fix method name to config in SafeSettings and update usages accordingly

* Add missing public files

* Add handling for real time points

* Fix remembering enabled/disabled layers of the v2 map

* Fix lots of e2e tests

* Add settings to select map version

* Use maps/v2 as main path for MapLibre maps

* Update routing

* Update live mode
2025-12-06 20:34:49 +01:00
Eugene Burmakin
cebbc28912 Update changelog 2025-11-29 19:58:57 +01:00
Evgenii Burmakin
ac9b668c30
Update exporting code to stream points data to file in batches to red… (#1980)
* Update exporting code to stream points data to file in batches to reduce memory usage

* Update changelog
2025-11-27 21:29:59 +01:00
Robin Tuszik
6772f2f7b7
fix: move foreman to global gems to fix startup crash (#1971) 2025-11-25 20:30:34 +01:00
19 changed files with 64 additions and 238 deletions

View file

@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
# [0.37.2] - 2026-01-04
# [0.37.2] - 2026-01-03
## Fixed
@ -12,7 +12,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Time spent in a country and city is now calculated correctly for the year-end digest email. #2104
- Updated Trix to fix a XSS vulnerability. #2102
- Map v2 UI no longer blocks when Immich/Photoprism integration has a bad URL or is unreachable. Added 10-second timeout to photo API requests and improved error handling to prevent UI freezing during initial load. #2085
- In Map v2 settings, you can now enable map to be rendered as a globe.
# [0.37.1] - 2025-12-30

View file

@ -31,7 +31,7 @@ class Api::V1::SettingsController < ApiController
:preferred_map_layer, :points_rendering_mode, :live_map_enabled,
:immich_url, :immich_api_key, :photoprism_url, :photoprism_api_key,
:speed_colored_routes, :speed_color_scale, :fog_of_war_threshold,
:maps_v2_style, :maps_maplibre_style, :globe_projection,
:maps_v2_style, :maps_maplibre_style,
enabled_map_layers: []
)
end

View file

@ -2,27 +2,6 @@
module Users
module DigestsHelper
PROGRESS_COLORS = %w[
progress-primary progress-secondary progress-accent
progress-info progress-success progress-warning
].freeze
def progress_color_for_index(index)
PROGRESS_COLORS[index % PROGRESS_COLORS.length]
end
def city_progress_value(city_count, max_cities)
return 0 unless max_cities&.positive?
(city_count.to_f / max_cities * 100).round
end
def max_cities_count(toponyms)
return 0 if toponyms.blank?
toponyms.map { |country| country['cities']&.length || 0 }.max
end
def distance_with_unit(distance_meters, unit)
value = Users::Digest.convert_distance(distance_meters, unit).round
"#{number_with_delimiter(value)} #{unit}"

View file

@ -16,35 +16,17 @@ export class MapInitializer {
mapStyle = 'streets',
center = [0, 0],
zoom = 2,
showControls = true,
globeProjection = false
showControls = true
} = settings
const style = await getMapStyle(mapStyle)
const mapOptions = {
const map = new maplibregl.Map({
container,
style,
center,
zoom
}
const map = new maplibregl.Map(mapOptions)
// Set globe projection after map loads
if (globeProjection === true || globeProjection === 'true') {
map.on('load', () => {
map.setProjection({ type: 'globe' })
// Add atmosphere effect
map.setSky({
'atmosphere-blend': [
'interpolate', ['linear'], ['zoom'],
0, 1, 5, 1, 7, 0
]
})
})
}
})
if (showControls) {
map.addControl(new maplibregl.NavigationControl(), 'top-right')

View file

@ -91,11 +91,6 @@ export class SettingsController {
mapStyleSelect.value = this.settings.mapStyle || 'light'
}
// Sync globe projection toggle
if (controller.hasGlobeToggleTarget) {
controller.globeToggleTarget.checked = this.settings.globeProjection || false
}
// Sync fog of war settings
const fogRadiusInput = controller.element.querySelector('input[name="fogOfWarRadius"]')
if (fogRadiusInput) {
@ -183,22 +178,6 @@ export class SettingsController {
}
}
/**
* Toggle globe projection
* Requires page reload to apply since projection is set at map initialization
*/
async toggleGlobe(event) {
const enabled = event.target.checked
await SettingsManager.updateSetting('globeProjection', enabled)
Toast.info('Globe view will be applied after page reload')
// Prompt user to reload
if (confirm('Globe view requires a page reload to take effect. Reload now?')) {
window.location.reload()
}
}
/**
* Update route opacity in real-time
*/

View file

@ -64,8 +64,6 @@ export default class extends Controller {
'speedColoredToggle',
'speedColorScaleContainer',
'speedColorScaleInput',
// Globe projection
'globeToggle',
// Family members
'familyMembersList',
'familyMembersContainer',
@ -149,8 +147,7 @@ export default class extends Controller {
*/
async initializeMap() {
this.map = await MapInitializer.initialize(this.containerTarget, {
mapStyle: this.settings.mapStyle,
globeProjection: this.settings.globeProjection
mapStyle: this.settings.mapStyle
})
}
@ -246,7 +243,6 @@ export default class extends Controller {
updateFogThresholdDisplay(event) { return this.settingsController.updateFogThresholdDisplay(event) }
updateMetersBetweenDisplay(event) { return this.settingsController.updateMetersBetweenDisplay(event) }
updateMinutesBetweenDisplay(event) { return this.settingsController.updateMinutesBetweenDisplay(event) }
toggleGlobe(event) { return this.settingsController.toggleGlobe(event) }
// Area Selection Manager methods
startSelectArea() { return this.areaSelectionManager.startSelectArea() }

View file

@ -14,8 +14,7 @@ const DEFAULT_SETTINGS = {
minutesBetweenRoutes: 60,
pointsRenderingMode: 'raw',
speedColoredRoutes: false,
speedColorScale: '0:#00ff00|15:#00ffff|30:#ff00ff|50:#ffff00|100:#ff3300',
globeProjection: false
speedColorScale: '0:#00ff00|15:#00ffff|30:#ff00ff|50:#ffff00|100:#ff3300'
}
// Mapping between v2 layer names and v1 layer names in enabled_map_layers array
@ -42,8 +41,7 @@ const BACKEND_SETTINGS_MAP = {
minutesBetweenRoutes: 'minutes_between_routes',
pointsRenderingMode: 'points_rendering_mode',
speedColoredRoutes: 'speed_colored_routes',
speedColorScale: 'speed_color_scale',
globeProjection: 'globe_projection'
speedColorScale: 'speed_color_scale'
}
export class SettingsManager {
@ -154,8 +152,6 @@ export class SettingsManager {
value = parseInt(value) || DEFAULT_SETTINGS.minutesBetweenRoutes
} else if (frontendKey === 'speedColoredRoutes') {
value = value === true || value === 'true'
} else if (frontendKey === 'globeProjection') {
value = value === true || value === 'true'
}
frontendSettings[frontendKey] = value
@ -223,8 +219,6 @@ export class SettingsManager {
value = parseInt(value).toString()
} else if (frontendKey === 'speedColoredRoutes') {
value = Boolean(value)
} else if (frontendKey === 'globeProjection') {
value = Boolean(value)
}
backendSettings[backendKey] = value

View file

@ -4,7 +4,6 @@ class Users::Digests::CalculatingJob < ApplicationJob
queue_as :digests
def perform(user_id, year)
recalculate_monthly_stats(user_id, year)
Users::Digests::CalculateYear.new(user_id, year).call
rescue StandardError => e
create_digest_failed_notification(user_id, e)
@ -12,12 +11,6 @@ class Users::Digests::CalculatingJob < ApplicationJob
private
def recalculate_monthly_stats(user_id, year)
(1..12).each do |month|
Stats::CalculateMonth.new(user_id, year, month).call
end
end
def create_digest_failed_notification(user_id, error)
user = User.find(user_id)

View file

@ -45,13 +45,18 @@ class User < ApplicationRecord # rubocop:disable Metrics/ClassLength
def countries_visited
Rails.cache.fetch("dawarich/user_#{id}_countries_visited", expires_in: 1.day) do
countries_visited_uncached
points
.without_raw_data
.where.not(country_name: [nil, ''])
.distinct
.pluck(:country_name)
.compact
end
end
def cities_visited
Rails.cache.fetch("dawarich/user_#{id}_cities_visited", expires_in: 1.day) do
cities_visited_uncached
points.where.not(city: [nil, '']).distinct.pluck(:city).compact
end
end
@ -134,47 +139,17 @@ class User < ApplicationRecord # rubocop:disable Metrics/ClassLength
Time.zone.name
end
# Aggregate countries from all stats' toponyms
# This is more accurate than raw point queries as it uses processed data
def countries_visited_uncached
countries = Set.new
stats.find_each do |stat|
toponyms = stat.toponyms
next unless toponyms.is_a?(Array)
toponyms.each do |toponym|
next unless toponym.is_a?(Hash)
countries.add(toponym['country']) if toponym['country'].present?
end
end
countries.to_a.sort
points
.without_raw_data
.where.not(country_name: [nil, ''])
.distinct
.pluck(:country_name)
.compact
end
# Aggregate cities from all stats' toponyms
# This respects MIN_MINUTES_SPENT_IN_CITY since toponyms are already filtered
def cities_visited_uncached
cities = Set.new
stats.find_each do |stat|
toponyms = stat.toponyms
next unless toponyms.is_a?(Array)
toponyms.each do |toponym|
next unless toponym.is_a?(Hash)
next unless toponym['cities'].is_a?(Array)
toponym['cities'].each do |city|
next unless city.is_a?(Hash)
cities.add(city['city']) if city['city'].present?
end
end
end
cities.to_a.sort
points.where.not(city: [nil, '']).distinct.pluck(:city).compact
end
def home_place_coordinates

View file

@ -162,9 +162,6 @@ class Users::Digest < ApplicationRecord
end
def total_tracked_minutes
# Use total_country_minutes if available (new digests),
# fall back to summing top_countries_by_time (existing digests)
time_spent_by_location['total_country_minutes'] ||
top_countries_by_time.sum { |country| country['minutes'].to_i }
top_countries_by_time.sum { |country| country['minutes'].to_i }
end
end

View file

@ -42,8 +42,7 @@ class Api::UserSerializer
photoprism_url: user.safe_settings.photoprism_url,
visits_suggestions_enabled: user.safe_settings.visits_suggestions_enabled?,
speed_color_scale: user.safe_settings.speed_color_scale,
fog_of_war_threshold: user.safe_settings.fog_of_war_threshold,
globe_projection: user.safe_settings.globe_projection
fog_of_war_threshold: user.safe_settings.fog_of_war_threshold
}
end

View file

@ -66,7 +66,7 @@ module Users
end
end
country_cities.sort_by { |_country, cities| -cities.size }.map do |country, cities|
country_cities.sort_by { |country, _| country }.map do |country, cities|
{
'country' => country,
'cities' => cities.to_a.sort.map { |city| { 'city' => city } }
@ -90,16 +90,15 @@ module Users
end
def calculate_time_spent
country_minutes = calculate_actual_country_minutes
{
'countries' => format_top_countries(country_minutes),
'cities' => calculate_city_time_spent,
'total_country_minutes' => country_minutes.values.sum
'countries' => calculate_country_time_spent,
'cities' => calculate_city_time_spent
}
end
def format_top_countries(country_minutes)
def calculate_country_time_spent
country_minutes = calculate_actual_country_minutes
country_minutes
.sort_by { |_, minutes| -minutes }
.first(10)
@ -216,8 +215,8 @@ module Users
def calculate_all_time_stats
{
'total_countries' => user.countries_visited_uncached.size,
'total_cities' => user.cities_visited_uncached.size,
'total_countries' => user.countries_visited.count,
'total_cities' => user.cities_visited.count,
'total_distance' => user.stats.sum(:distance).to_s
}
end

View file

@ -22,8 +22,7 @@ class Users::SafeSettings
'visits_suggestions_enabled' => 'true',
'enabled_map_layers' => %w[Routes Heatmap],
'maps_maplibre_style' => 'light',
'digest_emails_enabled' => true,
'globe_projection' => false
'digest_emails_enabled' => true
}.freeze
def initialize(settings = {})
@ -53,8 +52,7 @@ class Users::SafeSettings
speed_color_scale: speed_color_scale,
fog_of_war_threshold: fog_of_war_threshold,
enabled_map_layers: enabled_map_layers,
maps_maplibre_style: maps_maplibre_style,
globe_projection: globe_projection
maps_maplibre_style: maps_maplibre_style
}
end
# rubocop:enable Metrics/MethodLength
@ -143,10 +141,6 @@ class Users::SafeSettings
settings['maps_maplibre_style']
end
def globe_projection
ActiveModel::Type::Boolean.new.cast(settings['globe_projection'])
end
def digest_emails_enabled?
value = settings['digest_emails_enabled']
return true if value.nil?

View file

@ -365,19 +365,6 @@
</select>
</div>
<!-- Globe Projection -->
<div class="form-control">
<label class="label cursor-pointer justify-start gap-3">
<input type="checkbox"
name="globeProjection"
class="toggle toggle-primary"
data-maps--maplibre-target="globeToggle"
data-action="change->maps--maplibre#toggleGlobe" />
<span class="label-text font-medium">Globe View</span>
</label>
<p class="text-sm text-base-content/60 mt-1">Render map as a 3D globe (requires page reload)</p>
</div>
<div class="divider"></div>
<!-- Route Opacity -->

View file

@ -168,7 +168,14 @@
</h2>
<div class="space-y-4 w-full">
<% if @digest.toponyms.present? %>
<% max_cities = @digest.toponyms.map { |country| country['cities']&.length || 0 }.max %>
<% progress_colors = ['progress-primary', 'progress-secondary', 'progress-accent', 'progress-info', 'progress-success', 'progress-warning'] %>
<% @digest.toponyms.each_with_index do |country, index| %>
<% cities_count = country['cities']&.length || 0 %>
<% progress_value = max_cities&.positive? ? (cities_count.to_f / max_cities * 100).round : 0 %>
<% color_class = progress_colors[index % progress_colors.length] %>
<div class="space-y-2">
<div class="flex justify-between items-center">
<span class="font-semibold">
@ -176,10 +183,10 @@
<%= country['country'] %>
</span>
<span class="text-sm">
<%= pluralize(country['cities']&.length || 0, 'city') %>
<%= pluralize(cities_count, 'city') %>
</span>
</div>
<progress class="progress <%= progress_color_for_index(index) %> w-full" value="<%= city_progress_value(country['cities']&.length || 0, max_cities_count(@digest.toponyms)) %>" max="100"></progress>
<progress class="progress <%= color_class %> w-full" value="<%= progress_value %>" max="100"></progress>
</div>
<% end %>
<% else %>

View file

@ -1,5 +1,4 @@
import { test as setup, expect } from '@playwright/test';
import { disableGlobeProjection } from '../v2/helpers/setup.js';
const authFile = 'e2e/temp/.auth/user.json';
@ -20,9 +19,6 @@ setup('authenticate', async ({ page }) => {
// Wait for successful navigation to map (v1 or v2 depending on user preference)
await page.waitForURL(/\/map(\/v[12])?/, { timeout: 10000 });
// Disable globe projection to ensure consistent E2E test behavior
await disableGlobeProjection(page);
// Save authentication state
await page.context().storageState({ path: authFile });
});

View file

@ -2,33 +2,6 @@
* Helper functions for Maps V2 E2E tests
*/
/**
* Disable globe projection setting via API
* This ensures consistent map rendering for E2E tests
* @param {Page} page - Playwright page object
*/
export async function disableGlobeProjection(page) {
// Get API key from the page (requires being logged in)
const apiKey = await page.evaluate(() => {
const metaTag = document.querySelector('meta[name="api-key"]');
return metaTag?.content;
});
if (apiKey) {
await page.request.patch('/api/v1/settings', {
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
data: {
settings: {
globe_projection: false
}
}
});
}
}
/**
* Navigate to Maps V2 page
* @param {Page} page - Playwright page object

View file

@ -163,16 +163,12 @@ RSpec.describe User, type: :model do
describe '#countries_visited' do
subject { user.countries_visited }
let!(:stat) do
create(:stat, user:, toponyms: [
{ 'country' => 'Germany', 'cities' => [{ 'city' => 'Berlin', 'stayed_for' => 120 }] },
{ 'country' => 'France', 'cities' => [{ 'city' => 'Paris', 'stayed_for' => 90 }] },
{ 'country' => nil, 'cities' => [] },
{ 'country' => '', 'cities' => [] }
])
end
let!(:point1) { create(:point, user:, country_name: 'Germany') }
let!(:point2) { create(:point, user:, country_name: 'France') }
let!(:point3) { create(:point, user:, country_name: nil) }
let!(:point4) { create(:point, user:, country_name: '') }
it 'returns array of countries from stats toponyms' do
it 'returns array of countries' do
expect(subject).to include('Germany', 'France')
expect(subject.count).to eq(2)
end
@ -185,18 +181,12 @@ RSpec.describe User, type: :model do
describe '#cities_visited' do
subject { user.cities_visited }
let!(:stat) do
create(:stat, user:, toponyms: [
{ 'country' => 'Germany', 'cities' => [
{ 'city' => 'Berlin', 'stayed_for' => 120 },
{ 'city' => nil, 'stayed_for' => 60 },
{ 'city' => '', 'stayed_for' => 60 }
] },
{ 'country' => 'France', 'cities' => [{ 'city' => 'Paris', 'stayed_for' => 90 }] }
])
end
let!(:point1) { create(:point, user:, city: 'Berlin') }
let!(:point2) { create(:point, user:, city: 'Paris') }
let!(:point3) { create(:point, user:, city: nil) }
let!(:point4) { create(:point, user:, city: '') }
it 'returns array of cities from stats toponyms' do
it 'returns array of cities' do
expect(subject).to include('Berlin', 'Paris')
expect(subject.count).to eq(2)
end
@ -220,15 +210,11 @@ RSpec.describe User, type: :model do
describe '#total_countries' do
subject { user.total_countries }
let!(:stat) do
create(:stat, user:, toponyms: [
{ 'country' => 'Germany', 'cities' => [] },
{ 'country' => 'France', 'cities' => [] },
{ 'country' => nil, 'cities' => [] }
])
end
let!(:point1) { create(:point, user:, country_name: 'Germany') }
let!(:point2) { create(:point, user:, country_name: 'France') }
let!(:point3) { create(:point, user:, country_name: nil) }
it 'returns number of countries from stats toponyms' do
it 'returns number of countries' do
expect(subject).to eq(2)
end
end
@ -236,17 +222,11 @@ RSpec.describe User, type: :model do
describe '#total_cities' do
subject { user.total_cities }
let!(:stat) do
create(:stat, user:, toponyms: [
{ 'country' => 'Germany', 'cities' => [
{ 'city' => 'Berlin', 'stayed_for' => 120 },
{ 'city' => 'Paris', 'stayed_for' => 90 },
{ 'city' => nil, 'stayed_for' => 60 }
] }
])
end
let!(:point1) { create(:point, user:, city: 'Berlin') }
let!(:point2) { create(:point, user:, city: 'Paris') }
let!(:point3) { create(:point, user:, city: nil) }
it 'returns number of cities from stats toponyms' do
it 'returns number of cities' do
expect(subject).to eq(2)
end
end

View file

@ -31,8 +31,7 @@ RSpec.describe Users::SafeSettings do
speed_color_scale: nil,
fog_of_war_threshold: nil,
enabled_map_layers: %w[Routes Heatmap],
maps_maplibre_style: 'light',
globe_projection: false
maps_maplibre_style: 'light'
}
)
end
@ -83,8 +82,7 @@ RSpec.describe Users::SafeSettings do
'visits_suggestions_enabled' => false,
'enabled_map_layers' => %w[Points Routes Areas Photos],
'maps_maplibre_style' => 'light',
'digest_emails_enabled' => true,
'globe_projection' => false
'digest_emails_enabled' => true
}
)
end
@ -112,8 +110,7 @@ RSpec.describe Users::SafeSettings do
speed_color_scale: nil,
fog_of_war_threshold: nil,
enabled_map_layers: %w[Points Routes Areas Photos],
maps_maplibre_style: 'light',
globe_projection: false
maps_maplibre_style: 'light'
}
)
end