1 Commits

Author SHA1 Message Date
207699584b Back to single-select form w/ multiple select actions 2025-12-27 01:38:11 +01:00
14 changed files with 85 additions and 53 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="icon" viewBox="0 0 24 24"><path d="M14.06,9L15,9.94L5.92,19H5V18.08L14.06,9M17.66,3C17.41,3 17.15,3.1 16.96,3.29L15.13,5.12L18.88,8.87L20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18.17,3.09 17.92,3 17.66,3M14.06,6.19L3,17.25V21H6.75L17.81,9.94L14.06,6.19Z" /></svg>

After

Width:  |  Height:  |  Size: 316 B

View File

@@ -56,7 +56,7 @@ body {
grid-template-areas: grid-template-areas:
"header header header" "header header header"
"nav nav nav" "nav nav nav"
"leftempty topside rightempty" "leftside topside rightside"
"leftside main rightside"; "leftside main rightside";
grid-template-columns: 1fr auto 1fr; grid-template-columns: 1fr auto 1fr;
grid-template-rows: repeat(4, auto); grid-template-rows: repeat(4, auto);
@@ -418,10 +418,10 @@ table.items td.link a::after {
table.items td:first-child { table.items td:first-child {
padding-inline-start: calc(1em + var(--depth) * 0.8em); padding-inline-start: calc(1em + var(--depth) * 0.8em);
} }
table.items td:has(input, textarea) { table.items td:has(input, select, textarea) {
padding-inline-start: calc(0.6em - 0.9px); padding-inline-start: calc(0.6em - 0.9px);
} }
table.items td:first-child:has(input, textarea) { table.items td:first-child:has(input, select, textarea) {
padding-inline-start: calc(0.6em + var(--depth) * 0.8em - 0.9px); padding-inline-start: calc(0.6em + var(--depth) * 0.8em - 0.9px);
} }
table.items th:last-child { table.items th:last-child {
@@ -560,6 +560,9 @@ form table.items td:first-child {
display: flex; display: flex;
gap: 0.8em; gap: 0.8em;
} }
.hflex.centered {
justify-content: center;
}
.vflex { .vflex {
display: flex; display: flex;
gap: 0.8em; gap: 0.8em;

View File

@@ -1,5 +1,7 @@
class MeasurementsController < ApplicationController class MeasurementsController < ApplicationController
def index def index
@measurements = []
#@measurements = current_user.units.ordered.includes(:base, :subunits)
end end
def new def new

View File

@@ -4,7 +4,7 @@ class ReadoutsController < ApplicationController
def new def new
new_quantities = new_quantities =
case params[:scope] case params[:button]
when 'children' when 'children'
@quantity.subquantities @quantity.subquantities
when 'subtree' when 'subtree'
@@ -15,18 +15,17 @@ class ReadoutsController < ApplicationController
new_quantities -= @prev_quantities new_quantities -= @prev_quantities
@readouts = current_user.readouts.build(new_quantities.map { |q| {quantity: q} }) @readouts = current_user.readouts.build(new_quantities.map { |q| {quantity: q} })
@user_quantities = current_user.quantities.ordered
@user_units = current_user.units.ordered @user_units = current_user.units.ordered
@quantities = @prev_quantities + new_quantities quantities = @prev_quantities + new_quantities
# @common_ancestor = current_user.quantities @superquantity = current_user.quantities
# .common_ancestors(all_quantities.map(&:parent_id)).first .common_ancestors(quantities.map(&:parent_id)).first
end end
def discard def discard
@prev_quantities -= [@quantity] @prev_quantities -= [@quantity]
@common_ancestor = current_user.quantities @superquantity = current_user.quantities
.common_ancestors(@prev_quantities.map(&:parent_id)).first .common_ancestors(@prev_quantities.map(&:parent_id)).first
end end

View File

@@ -1,7 +1,17 @@
module QuantitiesHelper module QuantitiesHelper
def quantity_options(quantities, selected: nil) def quantity_option_text(quantity, checked = nil)
values = quantities.map { |q| [sanitize('&emsp;' * q.depth + q.name), q.id] } prefix = case checked
values.unshift([t('.select_quantity'), nil, {hidden: true}]) when true
options_for_select(values, selected: selected) # Use color and gray unicode emoji to assure same width.
# Avoid shapes similar to inputs (chackboxes, radio buttons etc.)
# (U+27A1 U+FE0F)/U+1F7E6/U+2705/U+1F499 U+2004
'💙 '
when false
# U+2B1C/U+1F90D U+2004
'🤍 '
else
''
end
sanitize('&emsp;' * quantity.depth + prefix + quantity.name)
end end
end end

View File

@@ -1,29 +1,40 @@
<%= tabular_form_with model: Measurement.new do |form| %> <%= tabular_form_with model: Measurement.new do |form| %>
<fieldset> <fieldset>
<legend> <legend>
<%= tag.span id: :measurement_form_legend %> <%= tag.span t('.no_items'), id: :measurement_form_legend %>
<%= image_link_to '', "close-outline", measurements_path, name: :cancel, <%= image_link_to '', "pencil-outline", measurements_path,
class: 'dangerous', onclick: render_turbo_stream('form_close') %> data: {turbo_stream: true} %>
</legend> </legend>
<table class="items"> <table class="items">
<tbody id="readouts"> <tbody id="readouts">
<tr id="readouts_form"> <tr id="readouts_form">
<td> <td>
<%= select_tag :id, quantity_options(@quantities), onchange: <%= select_tag :id,
"this.form.requestSubmit(document.getElementById('readout_submit'));", options_from_collection_for_select(
class: 'quantity' %> @quantities, :id, ->(q){ quantity_option_text(q, false) }
<%= form.submit id: :readout_submit, name: nil, value: nil, ), class: 'quantity' %>
formaction: new_readout_path, formmethod: :get, formnovalidate: true, </td>
hidden: true, data: {turbo_stream: true} %> <td colspan="3">
<div class="actions">
<% opts = {formaction: new_readout_path, formmethod: :get,
formnovalidate: true, data: {turbo_stream: true}} %>
<%= image_button_tag t('.new_readout'), 'plus-outline', id: :new_readout,
value: nil, **opts -%>
<%= image_button_tag t('.new_children'), 'plus-multiple-outline',
value: :children, **opts -%>
<%#= image_button_tag t('.new_subtree'), 'plus-multiple-outline',
value: :subtree, **opts -%>
<%= image_button_tag t('.new_leaves'), 'plus-multiple-outline',
value: :leaves, **opts -%>
</div>
</td> </td>
<td></td>
<td></td>
<td></td>
</tr>
<tr id="measurement_form_actions">
<td colspan="4"><div class="actions centered"><%= form.button %></div></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</fieldset> </fieldset>
<div class="hflex centered">
<%= form.button -%>
<%= image_link_to t(:cancel), "close-outline", measurements_path, name: :cancel,
class: 'dangerous', onclick: render_turbo_stream('form_close') %>
</div>
<% end %> <% end %>

View File

@@ -7,4 +7,10 @@
<% end %> <% end %>
</div> </div>
<%= tag.div class: 'main', id: :measurement_form %> <%= tag.div class: 'topside', id: :measurement_form %>
<table class="main">
<tbody id="measurements">
<%= render(@measurements) || render_no_items %>
</tbody>
</table>

View File

@@ -1,28 +1,20 @@
<%# TODO: add readout reordering by dragging %>
<%= tabular_fields_for 'readouts[]', readout do |form| %> <%= tabular_fields_for 'readouts[]', readout do |form| %>
<%- tag.tr id: dom_id(readout.quantity, :new, :readout), <%- tag.tr id: dom_id(readout.quantity, :new, :readout),
onkeydown: 'processKey(event)' do %> onkeydown: 'processKey(event)' do %>
<td> <td>
<%#= readout.quantity.relative_pathname(@common_ancestor) %> <%= readout.quantity.relative_pathname(@superquantity) %>
<%= form.collection_select :quantity_id, @user_quantities,
:id, ->(q){ sanitize('&emsp;' * q.depth + q.name) },
{disabled: @quantities.map(&:id).delete!(form.object.quantity.id)},
{class: 'quantity'} %>
</td> </td>
<td> <td>
<%= form.number_field :value, required: true, autofocus: true, size: 10 %> <%= form.number_field :value, required: true, autofocus: true, size: 10 %>
</td> </td>
<td> <td>
<%= form.hidden_field :quantity_id %>
<%= form.collection_select :unit_id, @user_units, :id, <%= form.collection_select :unit_id, @user_units, :id,
->(u){ sanitize('&emsp;' * (u.base_id ? 1 : 0) + u.symbol) } %> ->(u){ sanitize('&emsp;' * (u.base_id ? 1 : 0) + u.symbol) } %>
</td> </td>
<td class="actions"> <td class="actions">
<%= image_button_tag t('.new_children'), 'plus-multiple-outline', <%= image_button_tag '', 'delete-outline', class: 'dangerous', name: :discard,
formaction: new_measurement_path(readout.quantity, :children),
formmethod: :get, formnovalidate: true, data: {turbo_stream: true} %>
<%#= image_button_tag t('.new_subtree'), 'plus-multiple-outline',
formaction: new_measurement_path(:subtree), **common_options -%>
<%= image_button_tag '', 'delete-outline', class: 'dangerous',
formaction: discard_readouts_path(readout.quantity), formaction: discard_readouts_path(readout.quantity),
formmethod: :get, formnovalidate: true, data: {turbo_stream: true} %> formmethod: :get, formnovalidate: true, data: {turbo_stream: true} %>
</td> </td>

View File

@@ -1,2 +0,0 @@
<%= turbo_stream.remove dom_id(@quantity, :new, :readout) %>
<%= render partial: 'form_repath' %>

View File

@@ -1,7 +1,7 @@
<%= turbo_stream.update(:measurement_form_legend) { @common_ancestor&.pathname } %> <%= turbo_stream.update(:measurement_form_legend) { @superquantity&.pathname } %>
<% @prev_quantities.each do |pq| %> <% @prev_quantities.each do |pq| %>
<%= turbo_stream.update dom_id(pq, nil, :pathname) do %> <%= turbo_stream.update dom_id(pq, nil, :pathname) do %>
<%= pq.relative_pathname(@common_ancestor) %> <%= pq.relative_pathname(@superquantity) %>
<% end %> <% end %>
<% end %> <% end %>

View File

@@ -0,0 +1,5 @@
<%= turbo_stream.remove dom_id(@quantity, :new, :readout) %>
<%= turbo_stream.disable_all 'button[name="discard"]' if @prev_quantities.one? %>
<%= turbo_stream.update_all "#id option[value=\"#{@quantity.id}\"]",
quantity_option_text(@quantity, false) %>
<%= render partial: 'form_repath' %>

View File

@@ -1,7 +1,10 @@
<%#= render partial: 'form_repath' %> <%= render partial: 'form_repath' %>
<%= turbo_stream.enable_all 'button[name="discard"]' if @prev_quantities.one? %>
<%# TODO: disable Add actions accordingly (e.g. disable Children if childless or all
children already added), then disable option once all actions unavailable %>
<% @readouts.each do |r| %> <% @readouts.each do |r| %>
<%= turbo_stream.disable_all "select.quantity option[value='#{r.quantity_id}']" %> <%= turbo_stream.update_all "#id option[value=\"#{r.quantity_id}\"]",
quantity_option_text(r.quantity, true) %>
<% end %> <% end %>
<%= turbo_stream.before :readouts_form do %> <%= turbo_stream.before :readouts_form do %>
<%= render partial: 'form', collection: @readouts, as: :readout %> <%= render partial: 'form', collection: @readouts, as: :readout %>

View File

@@ -64,14 +64,18 @@ en:
source_code: Get code source_code: Get code
measurements: measurements:
navigation: Measurements navigation: Measurements
no_items: There are no measurements taken. You can Add some now.
form: form:
new_readout: Add
new_children: Children
new_subtree: Subtree
new_leaves: Leaves
no_items: Select and add desired quantities...
select_quantity: select quantity... select_quantity: select quantity...
index: index:
new_measurement: Add measurement new_measurement: Add measurement
readouts: readouts:
form: form:
new_children: Children
new_subtree: Subtree
quantities: quantities:
navigation: Quantities navigation: Quantities
no_items: There are no configured quantities. You can Add some or Import from defaults. no_items: There are no configured quantities. You can Add some or Import from defaults.

View File

@@ -1,9 +1,7 @@
Rails.application.routes.draw do Rails.application.routes.draw do
resources :measurements resources :measurements
resources :readouts, only: [:new], path_names: {new: '/new(/:id/:scope)'}, resources :readouts, only: [:new] do
constraints: {scope: /children|subtree|leaves/} do
collection {get 'new/:id/discard', action: :discard, as: :discard} collection {get 'new/:id/discard', action: :discard, as: :discard}
end end