forked from fixin.me/fixin.me
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>
This commit is contained in:
24
app/views/measurements/_edit_form.html.erb
Normal file
24
app/views/measurements/_edit_form.html.erb
Normal file
@@ -0,0 +1,24 @@
|
||||
<%= tabular_fields_for @readout, form: form_tag do |form| %>
|
||||
<%- tag.tr id: row, class: "form", onkeydown: "formProcessKey(event)",
|
||||
data: {form: form_tag, hidden_row: hidden_row, link: link} do %>
|
||||
<td><%= @readout.quantity %></td>
|
||||
<td class="ralign">
|
||||
<%= form.number_field :value, required: true, autofocus: true %>
|
||||
</td>
|
||||
<td>
|
||||
<%= form.collection_select :unit_id, @user_units, :id,
|
||||
->(u){ sanitize(' ' * (u.base_id? ? 1 : 0) + u.symbol) },
|
||||
{}, required: true %>
|
||||
</td>
|
||||
<td>
|
||||
<%= form.datetime_field :taken_at %>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="flex">
|
||||
<%= form.button %>
|
||||
<%= image_link_to t(:cancel), "close-outline", measurements_path,
|
||||
class: 'dangerous', name: :cancel,
|
||||
onclick: render_turbo_stream('edit_form_close', {row: row}) %>
|
||||
</td>
|
||||
<% end %>
|
||||
<% end %>
|
||||
2
app/views/measurements/_edit_form_close.html.erb
Normal file
2
app/views/measurements/_edit_form_close.html.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<%= turbo_stream.close_form row %>
|
||||
<%= turbo_stream.update :flashes %>
|
||||
33
app/views/measurements/_edit_panel.html.erb
Normal file
33
app/views/measurements/_edit_panel.html.erb
Normal file
@@ -0,0 +1,33 @@
|
||||
<% form_tag = dom_id(@readout, :edit, :form) %>
|
||||
<% row = dom_id(@readout, :edit) %>
|
||||
<% hidden_row = dom_id(@readout) %>
|
||||
|
||||
<%= tabular_form_with model: @readout, url: measurement_path(@readout),
|
||||
id: form_tag do |form| %>
|
||||
<table class="items-table">
|
||||
<tbody>
|
||||
<%= tag.tr id: row, class: "form", onkeydown: "formProcessKey(event)",
|
||||
data: {form: form_tag, hidden_row: hidden_row} do %>
|
||||
<td><%= @readout.quantity %></td>
|
||||
<td class="ralign">
|
||||
<%= form.number_field :value, required: true, autofocus: true %>
|
||||
</td>
|
||||
<td>
|
||||
<%= form.collection_select :unit_id, @user_units, :id,
|
||||
->(u){ sanitize(' ' * (u.base_id? ? 1 : 0) + u.symbol) },
|
||||
{}, required: true %>
|
||||
</td>
|
||||
<td>
|
||||
<%= form.datetime_field :taken_at %>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="flex">
|
||||
<%= form.button %>
|
||||
<%= image_link_to t(:cancel), "close-outline", measurements_path,
|
||||
class: 'dangerous', name: :cancel,
|
||||
onclick: render_turbo_stream('edit_form_close', {row: row}) %>
|
||||
</td>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
22
app/views/measurements/_readout.html.erb
Normal file
22
app/views/measurements/_readout.html.erb
Normal file
@@ -0,0 +1,22 @@
|
||||
<%= tag.tr id: dom_id(readout), data: {taken_at: readout.taken_at&.iso8601,
|
||||
quantity_id: readout.quantity_id, quantity_name: readout.quantity.name,
|
||||
value: format("%.10g", readout.value), unit: readout.unit.symbol} do %>
|
||||
<td>
|
||||
<% if current_user.at_least(:active) %>
|
||||
<%= link_to readout.quantity, edit_measurement_path(readout),
|
||||
class: 'link', onclick: 'this.blur();', data: {turbo_stream: true} %>
|
||||
<% else %>
|
||||
<%= readout.quantity %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="ralign"><%= format("%.10g", readout.value) %></td>
|
||||
<td><%= readout.unit %></td>
|
||||
<td class="taken-at"><%= l(readout.taken_at) if readout.taken_at %></td>
|
||||
<td class="created-at"><%= l(readout.created_at) %></td>
|
||||
<% if current_user.at_least(:active) %>
|
||||
<td class="flex">
|
||||
<%= image_button_to t('.destroy'), 'delete-outline', measurement_path(readout),
|
||||
method: :delete, data: {turbo_stream: true} %>
|
||||
</td>
|
||||
<% end %>
|
||||
<% end %>
|
||||
18
app/views/measurements/edit.turbo_stream.erb
Normal file
18
app/views/measurements/edit.turbo_stream.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
<% ids = {row: dom_id(@readout, :edit),
|
||||
hidden_row: dom_id(@readout),
|
||||
link: nil,
|
||||
form_tag: dom_id(@readout, :edit, :form)} %>
|
||||
|
||||
<% if params[:view] == 'wide' %>
|
||||
<%= turbo_stream.update :measurement_edit_form, partial: 'edit_panel' %>
|
||||
<%= turbo_stream.hide ids[:hidden_row] %>
|
||||
<% else %>
|
||||
<%= turbo_stream.append :measurement_edit_form do %>
|
||||
<%- tabular_form_with model: @readout, url: measurement_path(@readout),
|
||||
html: {id: ids[:form_tag]} do %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= turbo_stream.hide ids[:hidden_row] %>
|
||||
<%= turbo_stream.remove ids[:row] %>
|
||||
<%= turbo_stream.after @readout, partial: 'edit_form', locals: ids -%>
|
||||
<% end %>
|
||||
@@ -5,10 +5,34 @@
|
||||
id: :new_measurement_link, onclick: 'this.blur();',
|
||||
data: {turbo_stream: true} %>
|
||||
<% end %>
|
||||
<%= image_button_tag '', 'view-rows', name: nil, type: 'button',
|
||||
class: 'view-toggle', title: t('.view_compact'),
|
||||
data: {view: 'compact'}, onclick: "setMeasurementsView('compact')" %>
|
||||
<%= image_button_tag '', 'view-columns', name: nil, type: 'button',
|
||||
class: 'view-toggle', title: t('.view_wide'),
|
||||
data: {view: 'wide'}, onclick: "setMeasurementsView('wide')" %>
|
||||
</div>
|
||||
|
||||
<div class="main-area measurements-section">
|
||||
<%= tag.div id: :measurement_edit_form %>
|
||||
<table class="items-table measurements-compact">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= Quantity.model_name.human %></th>
|
||||
<th><%= Readout.human_attribute_name(:value) %></th>
|
||||
<th><%= Unit.model_name.human %></th>
|
||||
<th><%= Readout.human_attribute_name(:taken_at) %></th>
|
||||
<th><%= Readout.human_attribute_name(:created_at) %></th>
|
||||
<% if current_user.at_least(:active) %>
|
||||
<th></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="measurements">
|
||||
<%= render(partial: 'readout', collection: @measurements, as: :readout) || render_no_items %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div id="measurements-wide" class="measurements-wide"></div>
|
||||
</div>
|
||||
|
||||
<table class="main-area">
|
||||
<tbody id="measurements">
|
||||
<%= render(@measurements) || render_no_items %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
2
app/views/measurements/update.turbo_stream.erb
Normal file
2
app/views/measurements/update.turbo_stream.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<%= turbo_stream.close_form dom_id(@readout, :edit) %>
|
||||
<%= turbo_stream.replace @readout, partial: 'measurements/readout', locals: {readout: @readout} %>
|
||||
Reference in New Issue
Block a user