3 Commits

22 changed files with 169 additions and 124 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);
@@ -86,9 +86,10 @@ input[type=submit] {
text-decoration: none; text-decoration: none;
white-space: nowrap; white-space: nowrap;
} }
/* [hidden] submit controls cannot have `display` set as it makes them visible */
.button, .button,
button, button:not([hidden]),
input[type=submit], input[type=submit]:not([hidden]),
.tab { .tab {
align-items: center; align-items: center;
color: var(--color-gray); color: var(--color-gray);
@@ -417,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 {
@@ -559,6 +560,12 @@ form table.items td:first-child {
display: flex; display: flex;
gap: 0.8em; gap: 0.8em;
} }
.hflex.centered {
justify-content: center;
}
.vexpand {
width: 100%;
}
.vflex { .vflex {
display: flex; display: flex;
gap: 0.8em; gap: 0.8em;

View File

@@ -1,36 +1,11 @@
class MeasurementsController < ApplicationController class MeasurementsController < ApplicationController
before_action :find_quantity, only: [:new, :discard]
before_action :find_prev_quantities, only: [:new, :discard]
def index def index
@quantities = current_user.quantities.ordered @measurements = []
#@measurements = current_user.units.ordered.includes(:base, :subunits)
end end
def new def new
quantities = @quantities = current_user.quantities.ordered
case params[:scope]
when 'children'
@quantity.subquantities
when 'subtree'
@quantity.progenies
else
[@quantity]
end
quantities -= @prev_quantities
@readouts = current_user.readouts.build(quantities.map { |q| {quantity: q} })
@units = current_user.units.ordered
all_quantities = @prev_quantities + quantities
@common_ancestor = current_user.quantities
.common_ancestors(all_quantities.map(&:parent_id)).first
end
def discard
@prev_quantities -= [@quantity]
@common_ancestor = current_user.quantities
.common_ancestors(@prev_quantities.map(&:parent_id)).first
end end
def create def create
@@ -38,15 +13,4 @@ class MeasurementsController < ApplicationController
def destroy def destroy
end end
private
def find_quantity
@quantity = current_user.quantities.find_by!(id: params[:id])
end
def find_prev_quantities
prev_quantity_ids = params[:readouts]&.map { |r| r[:quantity_id] } || []
@prev_quantities = current_user.quantities.find(prev_quantity_ids)
end
end end

View File

@@ -0,0 +1,42 @@
class ReadoutsController < ApplicationController
before_action :find_quantity, only: [:new, :discard]
before_action :find_prev_quantities, only: [:new, :discard]
def new
new_quantities =
case params[:button]
when 'children'
@quantity.subquantities
when 'subtree'
@quantity.progenies
else
[@quantity]
end
new_quantities -= @prev_quantities
@readouts = current_user.readouts.build(new_quantities.map { |q| {quantity: q} })
@user_units = current_user.units.ordered
quantities = @prev_quantities + new_quantities
@superquantity = current_user.quantities
.common_ancestors(quantities.map(&:parent_id)).first
end
def discard
@prev_quantities -= [@quantity]
@superquantity = current_user.quantities
.common_ancestors(@prev_quantities.map(&:parent_id)).first
end
private
def find_quantity
@quantity = current_user.quantities.find_by!(id: params[:id])
end
def find_prev_quantities
prev_quantity_ids = params[:readouts]&.map { |r| r[:quantity_id] } || []
@prev_quantities = current_user.quantities.find(prev_quantity_ids)
end
end

View File

@@ -0,0 +1,3 @@
class Measurement
include ActiveModel::Model
end

View File

@@ -100,6 +100,11 @@ class Quantity < ApplicationRecord
name name
end end
def to_s_with_depth
# em space, U+2003
'' * depth + name
end
def destroyable? def destroyable?
subquantities.empty? subquantities.empty?
end end

View File

@@ -1,25 +1,24 @@
<% @readouts.each do |readout| %> <%= tabular_form_with model: Measurement.new do |form| %>
<%= tabular_fields_for 'readouts[]', readout do |form| %> <fieldset>
<%- tag.tr id: dom_id(readout.quantity, :new, :readout), <table class="items centered">
onkeydown: 'processKey(event)' do %> <tbody id="readouts">
<%= tag.td id: dom_id(readout.quantity, nil, :pathname) do %> <tr id="readouts_form">
<%= readout.quantity.relative_pathname(@common_ancestor) %> <td colspan="4">
<%end%> <%= collection_select :quantity, :id, @quantities, :id, :to_s_with_depth,
<td> {prompt: t('.select_quantity'), disabled: '', selected: ''},
<%= form.number_field :value, required: true, autofocus: true, size: 10 %> {name: :id, class: 'quantity vexpand',
onchange: "this.form.requestSubmit(new_readout_submit);"} %>
<%= form.submit id: :new_readout_submit, name: nil, value: nil,
formaction: new_readout_path, formmethod: :get, formnovalidate: true,
hidden: true, data: {turbo_stream: true} %>
</td> </td>
<td> </tr>
<%= form.select :unit_id, options_from_collection_for_select( </tbody>
@units, :id, ->(u){ sanitize('&emsp;'*(u.base_id ? 1 : 0) + u.symbol) } </table>
) %> </fieldset>
</td> <div class="hflex centered">
<%= form.button -%>
<td class="actions"> <%= image_link_to t(:cancel), "close-outline", measurements_path, name: :cancel,
<%= image_button_tag '', 'delete-outline', class: 'dangerous', class: 'dangerous', onclick: render_turbo_stream('form_close') %>
formaction: discard_new_measurement_path(readout.quantity), </div>
formmethod: :get, formnovalidate: true, data: {turbo_stream: true} %>
<%= form.hidden_field :quantity_id %>
</td>
<% end %>
<% end %>
<% end %> <% end %>

View File

@@ -1,2 +1,2 @@
<%= turbo_stream.update :new_readouts_form %> <%= turbo_stream.update :measurement_form %>
<%= turbo_stream.update :flashes %> <%= turbo_stream.update :flashes %>

View File

@@ -1,16 +0,0 @@
<%= tabular_fields_for Readout.new do |form| %>
<fieldset>
<legend>
<%= tag.span id: :new_readouts_form_legend %>
<%= image_link_to '', "close-outline", measurements_path, name: :cancel,
class: 'dangerous', onclick: render_turbo_stream('form_close') %>
</legend>
<table class="items centered">
<tbody id="readouts">
<tr id="new_readouts_actions">
<td colspan="4"><div class="actions centered"><%= form.button %></div></td>
</tr>
</tbody>
</table>
</fieldset>
<% end %>

View File

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

View File

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

View File

@@ -1,20 +1,16 @@
<div class="topside vflex"> <%# TODO: show hint when no quantities/units defined %>
<div class="rightside buttongrid">
<% if current_user.at_least(:active) %> <% if current_user.at_least(:active) %>
<%# TODO: show hint when no quantities/units defined %> <%= image_link_to t('.new_measurement'), 'plus-outline', new_measurement_path,
<%= tabular_form_with url: new_measurement_path, id: :new_measurement_link, onclick: 'this.blur();',
html: {id: :new_readouts_form} do |f| %> data: {turbo_stream: true} %>
<% end %>
<div class="hflex">
<%= select_tag :id, options_from_collection_for_select(
@quantities, :id, ->(q){ sanitize('&emsp;' * q.depth + q.name) }
), form: :new_readouts_form %>
<% common_options = {form: :new_readouts_form, formmethod: :get,
formnovalidate: true, data: {turbo_stream: true}} %>
<%= image_button_tag t('.new_quantity'), 'plus-outline', **common_options -%>
<%= image_button_tag t('.new_children'), 'plus-multiple-outline',
formaction: new_measurement_path(:children), **common_options -%>
<%= image_button_tag t('.new_subtree'), 'plus-multiple-outline',
formaction: new_measurement_path(:subtree), **common_options -%>
</div>
<% end %> <% end %>
</div> </div>
<%= tag.div class: 'topside', id: :measurement_form %>
<table class="main">
<tbody id="measurements">
<%= render(@measurements) || render_no_items %>
</tbody>
</table>

View File

@@ -1,9 +1,4 @@
<%= turbo_stream.update :new_readouts_form do %> <%= turbo_stream.disable :new_measurement_link -%>
<%= render partial: 'form_frame' %> <%= turbo_stream.update :measurement_form do %>
<% end if @prev_quantities.empty? %>
<%= render partial: 'form_repath' %>
<%= turbo_stream.before :new_readouts_actions do %>
<%= render partial: 'form' %> <%= render partial: 'form' %>
<% end %> <% end %>

View File

@@ -1,7 +1,8 @@
<div class="rightside buttongrid"> <div class="rightside buttongrid">
<% if current_user.at_least(:active) %> <% if current_user.at_least(:active) %>
<%= image_link_to t('.new_quantity'), 'plus-outline', new_quantity_path, <%= image_link_to t('.new_quantity'), 'plus-outline', new_quantity_path,
id: dom_id(Quantity, :new, :link), onclick: 'this.blur();', data: {turbo_stream: true} %> id: dom_id(Quantity, :new, :link), onclick: 'this.blur();',
data: {turbo_stream: true} %>
<% end %> <% end %>
<%#= image_link_to t('.import_quantities'), 'download-outline', default_quantities_path, <%#= image_link_to t('.import_quantities'), 'download-outline', default_quantities_path,
class: 'tools' %> class: 'tools' %>

View File

@@ -0,0 +1,22 @@
<%# TODO: add readout reordering by dragging %>
<%= tabular_fields_for 'readouts[]', readout do |form| %>
<%- tag.tr id: dom_id(readout.quantity, :new, :readout),
onkeydown: 'processKey(event)' do %>
<td>
<%= readout.quantity.relative_pathname(@superquantity) %>
</td>
<td>
<%= form.number_field :value, required: true, autofocus: true, size: 10 %>
</td>
<td>
<%= form.hidden_field :quantity_id %>
<%= form.collection_select :unit_id, @user_units, :id,
->(u){ sanitize('&emsp;' * (u.base_id ? 1 : 0) + u.symbol) } %>
</td>
<td class="actions">
<%= image_button_tag '', 'delete-outline', class: 'dangerous', name: :discard,
formaction: discard_readouts_path(readout.quantity),
formmethod: :get, formnovalidate: true, data: {turbo_stream: true} %>
</td>
<% end %>
<% end %>

View File

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

View File

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

View File

@@ -0,0 +1,9 @@
<%= render partial: 'form_repath' %>
<%# is .one? proper condition? can @readouts be empty? %>
<%= turbo_stream.enable_all 'button[name="discard"]' if @prev_quantities.one? %>
<% @readouts.each do |r| %>
<%= turbo_stream.disable_all "select.quantity option[value='#{r.quantity_id}']" %>
<% end %>
<%= turbo_stream.before :readouts_form do %>
<%= render partial: 'form', collection: @readouts, as: :readout %>
<% end %>

View File

@@ -1,3 +1,4 @@
require 'core_ext/array_delete_bang'
require 'core_ext/big_decimal_scientific_notation' require 'core_ext/big_decimal_scientific_notation'
ActiveSupport.on_load :action_dispatch_system_test_case do ActiveSupport.on_load :action_dispatch_system_test_case do

View File

@@ -64,10 +64,14 @@ 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:
select_quantity: select the measured quantity...
index: index:
new_quantity: Selected new_measurement: Add measurement
readouts:
form:
new_children: Children 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,8 +1,8 @@
Rails.application.routes.draw do Rails.application.routes.draw do
resources :measurements, path_names: {new: '/new(/:scope)'}, resources :measurements
constraints: {scope: /children|subtree/}, defaults: {scope: nil} do
get 'discard/:id', on: :new, action: :discard, as: :discard resources :readouts, only: [:new] do
collection {get 'new/:id/discard', action: :discard, as: :discard}
end end
resources :quantities, except: [:show], path_names: {new: '(/:id)/new'} do resources :quantities, except: [:show], path_names: {new: '(/:id)/new'} do

View File

@@ -0,0 +1,10 @@
module CoreExt
module ArrayDeleteBang
def delete!(obj)
self.delete(obj)
self
end
end
end
Array.prepend CoreExt::ArrayDeleteBang