Skip to content

feat: nearby-watch radius in the configured display unit - #413

Merged
dkastl merged 8 commits into
nextfrom
feat/watch-radius-unit
Jul 27, 2026
Merged

feat: nearby-watch radius in the configured display unit#413
dkastl merged 8 commits into
nextfrom
feat/watch-radius-unit

Conversation

@dkastl

@dkastl dkastl commented Jul 27, 2026

Copy link
Copy Markdown
Member

Part 3 of 3 for #10 (this PR completes it — the release PR can carry Closes #10), stacked on #411/#412.

This is the piece that motivated doing units before the 7.1.0 release: the #14 watch radius was stored in kilometers with a hardcoded "km" label. It now:

  • stores meters (the plugin's internal unit everywhere), via a gtt_watch_radius_in_unit virtual attribute the account form posts (unit → meters on write, meters → unit on read, garbage still rejected, blank clears); the raw meters key is no longer mass-assignable
  • displays and accepts the configured unit — label, max (1,000,000 m expressed in the unit) and fractional steps (0.5 km = 500 m) all derive from the setting
  • NEARBY_WATCH_MAX_RADIUS_M replaces the km constant; the watcher engine compares meters directly

Since #14 has never been released, there is no stored-preference migration — the semantics change while the feature is still only on next.

Verified: full plugin suite in the Redmine 7.0 mirror (101 runs, 539 assertions, 0 failures) and live in a browser with distance_unit=km: stored 25000 m renders as 25 km with max 1000; saving 30 stores "30000" meters and reads back as 30.

dkastl added 3 commits July 27, 2026 20:39
First part of #10: a distance_unit plugin setting (m, km, ft, mi, nm)
that drives what users see. Meters remain the internal unit everywhere
(storage, SQL, filter wire format, REST API).

- RedmineGtt::DistanceUnit: unit table, current/api_unit readers with
  fallback, to/from-meters conversion
- distance column: header carries the unit (caption proc), list and
  CSV cells render converted via a QueriesHelper prepend
- api_distance_unit setting reserved with meters as the only option,
  so the API contract can widen later without a settings migration
- settings UI selects + en/ja/de locales

The distance filter input and the nearby-watch radius field follow in
separate PRs.
Second part of #10. The distance filter row displays and accepts its
bounds in the configured unit: values coming from the server (meters)
convert for display, and a submit hook on #query_form converts back to
integer meters, so the wire format, saved queries and the API stay
metric. The unit label renders next to the inputs.

The hook binds via jQuery when present because core submits the form
with $('#query_form').submit(), which bypasses native listeners.
Final part of #10, and the reason to land units before #14 ships: the
watch radius is now stored in meters (the internal unit) and entered
and displayed in the configured display unit on My account.

- gtt_watch_radius stores meters; the account form goes through the
  gtt_watch_radius_in_unit virtual attribute (unit -> meters on write,
  meters -> unit on read); the raw key is no longer mass-assignable
- NEARBY_WATCH_MAX_RADIUS_KM becomes NEARBY_WATCH_MAX_RADIUS_M
  (1,000,000 m); NearbyWatchers compares meters directly
- the field's unit label and max derive from the setting; step allows
  fractions (0.5 km = 500 m)

Since #14 is unreleased, no stored-preference migration is needed.
dkastl added 4 commits July 27, 2026 20:53
- unknown units fall back to meters instead of raising KeyError (the
  setting can be hand-edited, callers may pass user-supplied strings)
- the CSV separator test derives its expectation from the locale
  instead of hardcoding '.'

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Completes the multi-unit distance work for #10 by introducing a shared meters↔display-unit conversion layer and applying it to the distance column, distance filter UI, and the nearby-watch radius preference (now stored in meters while displayed/edited in the configured unit).

Changes:

  • Add RedmineGtt::DistanceUnit (and matching frontend unit table) plus new plugin settings distance_unit and reserved api_distance_unit.
  • Convert distance column header/rendering and distance filter input to use the configured display unit while keeping wire/storage/API semantics in meters.
  • Change nearby-watch radius storage to meters with a virtual form attribute gtt_watch_radius_in_unit, updating UI + watcher engine + tests.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/unit/user_preference_patch_test.rb Updates/extends tests for meters-based nearby-watch radius + unit-facing virtual attribute.
test/unit/queries_helper_patch_test.rb Adds coverage for distance column/list + CSV rendering in configured units.
test/unit/nearby_watchers_test.rb Adjusts watcher tests to use meters radius values.
test/unit/distance_unit_test.rb Adds unit tests for RedmineGtt::DistanceUnit defaults, clamping, and conversions.
test/functional/my_account_watch_nearby_test.rb Updates account controller tests for the new form key gtt_watch_radius_in_unit and meters storage.
src/components/gtt-client/redmine/filters.ts Implements display-unit rendering + submit-time conversion for distance filter row.
src/components/gtt-client/redmine/filters.test.ts Adds frontend unit-table parity + conversion/noise-trimming tests.
lib/redmine_gtt/patches/user_preference_patch.rb Stores radius in meters and adds gtt_watch_radius_in_unit virtual attribute; updates safe attributes.
lib/redmine_gtt/patches/queries_helper_patch.rb Renders distance column/list + CSV values in configured display unit.
lib/redmine_gtt/patches/issue_query_patch.rb Updates distance column header caption to include configured unit.
lib/redmine_gtt/nearby_watchers.rb Compares distances directly in meters; uses meters max-radius constant.
lib/redmine_gtt/distance_unit.rb Introduces server-side conversion helpers + supported unit tables.
lib/redmine_gtt.rb Applies the new QueriesHelper patch during setup.
init.rb Adds default plugin settings for distance_unit and api_distance_unit.
config/locales/ja.yml Adds i18n strings for distance-unit settings and removes hardcoded watch-radius “km” label.
config/locales/en.yml Adds i18n strings for distance-unit settings and removes hardcoded watch-radius “km” label.
config/locales/de.yml Adds i18n strings for distance-unit settings and removes hardcoded watch-radius “km” label.
app/views/settings/gtt/_general.html.erb Adds settings UI for selecting display unit and (reserved) API unit.
app/views/redmine_gtt/hooks/_watch_nearby_preference.html.erb Updates watch-radius field to use unit-facing virtual attribute and display the configured unit.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/gtt-client/redmine/filters.ts
Comment thread lib/redmine_gtt/patches/user_preference_patch.rb
Comment thread app/views/redmine_gtt/hooks/_watch_nearby_preference.html.erb Outdated
- gtt_watch_radius_in_unit keeps 6 decimals for fractions (enough for
  1 m in any supported unit), so a read-save round trip cannot drift
  the stored meters; regression test with a non-round mile value
- the form's min is 1 meter expressed in the display unit instead of
  0, which the server would treat as unset
@dkastl
dkastl merged commit f46fd62 into next Jul 27, 2026
8 checks passed
@dkastl
dkastl deleted the feat/watch-radius-unit branch July 27, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants