Files
fixin.me/app/controllers/measurements_controller.rb
barbie-bot bfd427c9b2 Add wide view and inline editing to Measurements page
The Measurements page gains a compact/wide view toggle (persisted in
localStorage). The wide view is a pivot table: rows = time points,
columns = quantity names (alphabetical), cells = value + delete button.

Clicking a value in either view opens an inline edit panel (Turbo Stream)
without leaving the page. The panel shows the quantity name, value input,
unit selector, taken_at picker, and Update/Cancel buttons.

Changes:
- MeasurementsController: add edit/update actions; order by taken_at desc
- measurements/index: compact table + wide container, view-toggle buttons
- measurements/_readout: data-* attributes for JS pivot builder; edit link
- measurements/_edit_panel, _edit_form, _edit_form_close,
  edit.turbo_stream, update.turbo_stream: inline edit views
- application.js: groupMeasurements, buildWideTable (alphabetical cols),
  getMeasurementsView / setMeasurementsView, editMeasurementWide,
  readoutUnitChanged, setDefaultUnit
- application.css: compact/wide visibility rules, .wide-cell flex layout,
  button.link reset, .items-table .form td alignment
- Pictograms: view-rows.svg, view-columns.svg (view-toggle icons)
- Locale: view_compact/view_wide toggle labels, edit link, update.success
- Tests: system tests for compact inline edit and wide view edit panel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 22:03:10 +00:00

54 lines
1.4 KiB
Ruby

class MeasurementsController < ApplicationController
before_action :find_readout, only: [:destroy, :edit, :update]
before_action except: :index do
raise AccessForbidden unless current_user.at_least(:active)
end
def index
@measurements = current_user.readouts.includes(:quantity, :unit).order(taken_at: :desc, id: :desc)
end
def new
@quantities = current_user.quantities.ordered
end
def create
taken_at = params.permit(:taken_at)[:taken_at]
readout_params = params.permit(readouts: Readout::ATTRIBUTES).fetch(:readouts, [])
@readouts = readout_params.map { |rp| current_user.readouts.build(rp.merge(taken_at: taken_at)) }
if @readouts.present? && @readouts.all?(&:valid?)
ActiveRecord::Base.transaction { @readouts.each(&:save!) }
flash.now[:notice] = t('.success', count: @readouts.size)
else
errors = @readouts.flat_map { |r| r.errors.full_messages }
flash.now[:alert] = errors.present? ? errors.first : t('.no_readouts')
end
end
def edit
@user_units = current_user.units.ordered
end
def update
if @readout.update(params.require(:readout).permit(:value, :unit_id, :taken_at))
flash.now[:notice] = t('.success')
else
@user_units = current_user.units.ordered
render :edit
end
end
def destroy
@readout.destroy!
flash.now[:notice] = t('.success')
end
private
def find_readout
@readout = current_user.readouts.find(params[:id])
end
end