Skip to content

Admin records filters: Min/Max price range + replace bespoke format buckets with RecordType (rel #370) #371

Description

@holden

Context

The admin Value Explorer at /admin/records has two filter controls in app/views/admin/records/_filter_bar.html.erb that need work:

  1. Min $ — single number input; want to support a range (Min + Max).
  2. Format — uses a bespoke 7-bucket FORMAT_CATEGORY_MAP constant in Admin::RecordsController instead of the real record_types table that Records index: replace granular Format filter with Record Type (with later format sub-facet) #370 is migrating /records toward.

Bundled because both touch the same partial and controller, and shipping the format change without coordinating with #370 would leave admin and public on different taxonomies.


Change 1 — Min/Max price range

Today: a single <input type="number" name="min_value"> (app/views/admin/records/_filter_bar.html.erb:36-42), interpreted source-aware in the controller (app/controllers/admin/records_controller.rb:69-77). Both fields optional, default empty — same as today's Min $.

Recommendation: two adjacent number inputs (Min $ / Max $)

Simplest, most predictable, most accessible. Sliders look slicker but are wrong for this dataset:

  • Price distribution is heavily long-tailed ($0 to $5k+); a linear slider is unusable and a log slider is unintuitive for collectors entering specific thresholds.
  • A slider needs a known max, which forces an extra query per render.
  • The collector use-case is "show me $100–$500 records" — they want exact thresholds, not scrubbing.
  • Two number inputs are a one-line addition next to the existing Min $; no new JS.

UI sketch (replaces current Min $ block in the source row)

Source [Best Guide My$ Discogs]   Price  \$[ Min ] – \$[ Max ]   Show [All ▾]

Existing debounce/auto-submit behavior carries over (data-controller=\"debounce\").

Alternatives considered

Option Pros Cons
Dual number inputs (recommended) matches today's UX, no extra queries, a11y free least visual flair
Range slider (noUiSlider etc.) scrubbable, visual bad fit for long-tailed prices; needs a ceiling query; new JS dep
Preset buckets ($0–10, $10–50, …) one click hides the long tail; collectors want exact thresholds
Single "100-500" combined input compact error-prone parsing; not standard

Implementation notes

  • Add params[:max_value], applied source-aware mirroring the existing Min block (<= ?) in Admin::RecordsController#index lines 69–77.
  • Add :max_value to the Clear filters slice list (_filter_bar.html.erb:123).
  • CSV export inherits the filter automatically (same scope).

Change 2 — Replace bespoke format buckets with RecordType

Today: Admin::RecordsController::FORMAT_CATEGORY_MAP (lines 12–46) hand-buckets ~30 raw record_formats.name strings into 7 collector-facing categories (LP, 7", 12" Single, 10", 78, Picture Disc / Sleeve, Promo). This:

  • duplicates work the schema already does — record_formats.record_type_id → record_types, and Record has_one :record_type, through: :record_format already exists (app/models/record.rb:48)
  • diverges from /records (public), which is being migrated to record_types in Records index: replace granular Format filter with Record Type (with later format sub-facet) #370
  • silently absorbs typo variants (e.g. Singles: 7-inch vs Singles: 7-Inch) instead of surfacing the data-quality issue
  • requires manual updates whenever a new raw format string appears in production data

Recommendation

Mirror #370 Phase 1 here: drop FORMAT_CATEGORY_MAP, use record_types directly in the dropdown, filter via record_format.record_type_id. Same 5 buckets the public page will use; one source of truth.

If/when #370 Phase 2 (cascading Format sub-facet under a selected Type) ships on /records, the admin page should follow with the same component.

Implementation notes

  • load_filter_options (lines 263–288): replace the raw_formats + category_counts block with a RecordType.joins(record_formats: :records).where(records: { user_id: COLLECTION_USER_ID }).group(\"record_types.name\") query.
  • index (lines 95–99): replace the FORMAT_CATEGORY_MAP.select { ... } lookup with where(record_formats: { record_type_id: ... }).
  • Rename param format_categoryrecord_type_id (no external links rely on it).
  • Delete the FORMAT_CATEGORY_MAP constant.
  • Audit CSV export and any view code for stale references to the bucket name (none expected — bucket name was display-only).

Out of scope

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions