1
0

Add Targets #show

Change css classes from subject-oriented to property-oriented
This commit is contained in:
cryptogopher 2021-05-05 12:42:30 +02:00
parent 8cac724694
commit e301665b6a
22 changed files with 132 additions and 130 deletions

View File

@ -5,8 +5,8 @@ class TargetsController < ApplicationController
include Concerns::Finders
before_action :find_goal_by_goal_id,
only: [:index, :new, :create, :edit, :update, :destroy, :reapply, :toggle_exposure]
before_action :find_goal_by_goal_id, only: [:index, :new, :create, :show, :edit, :update,
:destroy, :reapply, :toggle_exposure]
before_action :find_quantity_by_quantity_id, only: [:toggle_exposure, :subthresholds]
before_action :authorize
#before_action :set_view_params
@ -42,6 +42,24 @@ class TargetsController < ApplicationController
end
end
def show
# TODO: take into account nullified targets, after introduced
@effective_from = params[:date].to_date
targets = @goal.targets.joins(:quantity).where(
"(quantity_id, effective_from) IN (?)",
@goal.targets.select(:quantity_id, 'MAX(effective_from) as effective_from')
.where("effective_from <= ?", @effective_from).group(:quantity_id)
).reorder('quantities.depth DESC')
@quantities = {}
targets.each do |t|
unless @quantities.has_key?(t.quantity.parent)
t.quantity.ancestors.each { |q| @quantities[q] = nil }
end
@quantities[t.quantity] = t
end
end
def edit
@effective_from = params[:date].to_date
@targets = @goal.targets.joins(:quantity).where(effective_from: @effective_from)
@ -123,7 +141,7 @@ class TargetsController < ApplicationController
@targets_by_date = Hash.new { |h,k| h[k] = {} }
@goal.targets.includes(:item, thresholds: [:quantity]).reject(&:new_record?)
.each { |t| @targets_by_date[t.effective_from][t.thresholds.first.quantity] = t }
.each { |t| @targets_by_date[t.effective_from][t.quantity] = t }
end
def set_view_params

View File

@ -1,4 +1,17 @@
module TargetsHelper
def target_markup(date, quantity, target)
content = "#{'&emsp;'*quantity.depth}#{quantity.name} #{target.to_s}"
classes = []
if date == target&.effective_from
classes << 'bolded' if @goal.quantities.include?(quantity)
else
classes << 'dimmed'
end
content_tag(:span, content, {class: classes}, false)
end
def action_links(date)
link_to(l(:button_reapply), reapply_goal_target_path(@goal, date, @view_params),
{remote: true, class: "icon icon-reload"}) +

View File

@ -37,7 +37,8 @@ class Target < ActiveRecord::Base
end
def to_s
thresholds.last.quantity.description %
thresholds.map { |t| [t.quantity.name, "#{t.value} [#{t.unit.shortname}]"] }.to_h
thresholds.last.quantity.description % thresholds.map do |t|
[t.quantity.name.to_sym, "#{t.value} [#{t.unit.shortname}]"]
end.to_h
end
end

View File

@ -18,9 +18,8 @@
<tbody>
<% @foods.each do |f| %>
<% next if f.new_record? %>
<tr id="food-<%= f.id %>"
class="food primary<%= ' hidden' if f.hidden %>">
<td class="name ellipsible">
<tr id="food-<%= f.id %>" class="food primary<%= ' dimmed' if f.hidden %>">
<td class="topleft ellipsible">
<%= link_to '', toggle_food_path(f), {
remote: true,
method: :post,
@ -29,13 +28,13 @@
<%= f.name %>
</td>
<td class="notes ellipsible"><%= f.notes %></td>
<td class="reference value"><%= f.ref_amount %> [<%= f.ref_unit.shortname %>]</td>
<td class="reference right"><%= f.ref_amount %> [<%= f.ref_unit.shortname %>]</td>
<td class="group"><%= f.group %></td>
<td class="source">
<%= f.source.name if f.source.present? %>
<%= ", #{f.source_ident}" if f.source_ident.present? %>
</td>
<td class="action unwrappable"><%= action_links(f, :index) %></td>
<td class="right shrunk unwrappable"><%= action_links(f, :index) %></td>
</tr>
<% end %>
</tbody>

View File

@ -34,19 +34,19 @@
<tbody>
<% extra_quantities = @foods.values.first.keys - @quantities %>
<% @foods.each do |food, nutrients| %>
<% row_class = "food#{' hidden' if food.hidden} #{cycle('odd', 'even')}" %>
<% row_class = "food#{' dimmed' if food.hidden} #{cycle('odd', 'even')}" %>
<tr id="food-<%= food.id %>" class="primary <%= row_class %>">
<td class="name ellipsible" style="cursor: pointer;"
<td class="topleft ellipsible" style="cursor: pointer;"
onclick="$(this).closest('tr').toggle(); $(this).closest('tr').nextUntil('tr.primary', '.food').toggle(); return false;">
<span class="icon icon-bullet-closed"><%= food.name %></span>
</td>
<% @quantities.each do |q| %>
<td class="primary value ellipsible">
<td class="primary right ellipsible">
<%= format_value(nutrients[q], @food_summary[:precision][q],
@food_summary[:mfu_unit][q]) %>
</td>
<% end %>
<td class="action unwrappable"><%= action_links(food, :nutrients) %></td>
<td class="right shrunk unwrappable"><%= action_links(food, :nutrients) %></td>
</tr>
<tr class="<%= row_class %>" style="display:none">
@ -55,17 +55,17 @@
else
rows = 1
end %>
<td rowspan="<%= rows %>" class="name ellipsible" style="cursor: pointer;"
<td rowspan="<%= rows %>" class="topleft ellipsible" style="cursor: pointer;"
onclick="$(this).closest('tr').prev('tr.primary').toggle(); $(this).closest('tr').prev('tr.primary').nextUntil('tr.primary', '.food').toggle(); return false;">
<span class="icon icon-bullet-open"><%= food.name %></span>
</td>
<% @quantities.each do |q| %>
<td class="primary quantity ellipsible">
<td class="primary topleft ellipsible">
<%= q.name %>
<p class="value"><%= format_value(nutrients[q]) %></p>
<p class="right"><%= format_value(nutrients[q]) %></p>
</td>
<% end %>
<td rowspan="<%= rows %>" class="action unwrappable">
<td rowspan="<%= rows %>" class="right shrunk unwrappable">
<%= action_links(food, :nutrients) %>
</td>
</tr>
@ -74,9 +74,9 @@
<% extra_quantities.each_slice(@quantities.length) do |eqs| %>
<tr class="extra <%= row_class %>" style="display:none">
<% eqs.each do |q| %>
<td class="extra quantity ellipsible">
<td class="extra topleft ellipsible">
<%= q.name if nutrients[q] %>
<p class="value"><%= format_value(nutrients[q]) %></p>
<p class="right"><%= format_value(nutrients[q]) %></p>
</td>
<% end %>
<% if @quantities.length > eqs.length %>

View File

@ -10,7 +10,7 @@
<tbody>
<% @goals.each do |g| %>
<tr id="goal-<%= g.id %>" class="primary goal">
<td class="name unwrappable">
<td class="topleft unwrappable">
<div style="float:left;">
<%= checked_image g.is_binding %><%= link_to g.name, goal_targets_path(g) %>
</div>
@ -20,7 +20,7 @@
</div>
</td>
<td class="description ellipsible"><%= g.description %></td>
<td class="action unwrappable">
<td class="right shrunk">
<%= delete_link(g, {remote: true, data: {}}) unless g.is_binding %>
</td>
</tr>

View File

@ -1,6 +1,6 @@
<tr id="meal-<%= m.id %>" class="primary meal project idnt idnt-1"
style="background-color: #d0e0e3;">
<td class="name unwrappable" style="border-right: none;">
<td class="topleft unwrappable" style="border-right: none;">
<b><%= "#{t '.label_meal'} ##{index+1}" %></b>
<% if m.eaten_at %>
<%= " at #{m.eaten_at.strftime('%R')}" %>
@ -34,12 +34,12 @@
</td>
<% end %>
<td class="value ellipsible" style="border-left: none;"></td>
<td class="right ellipsible" style="border-left: none;"></td>
<% @quantities.each do |q| %>
<td class="value ellipsible">
<td class="right ellipsible">
<%= format_value(@ingredient_summary[m][q], @ingredient_summary[:precision][q]) %>
</td>
<% end %>
<td class="action unwrappable" style="width: 1%;"><%= meal_links(m) %></td>
<td class="right shrunk unwrappable"><%= meal_links(m) %></td>
</tr>

View File

@ -1,12 +1,12 @@
<tr id="date-<%= date.strftime('%Y%m%d') %>" class="date" style="background-color: #fff2cc;">
<td class="date" colspan="2" style="border-right: none;">
<td class="topleft" colspan="2" style="border-right: none;">
<h3 style="margin: 0;">
<%= date == Date.current ? 'Today' : date.strftime('%F') %>
</h3>
</td>
<td class="value ellipsible" style="border-left: none;"></td>
<td class="right ellipsible" style="border-left: none;"></td>
<% @quantities.each do |q| %>
<td class="value ellipsible">
<td class="right ellipsible">
<%= format_value(@ingredient_summary[date][q], @ingredient_summary[:precision][q]) %>
</td>
<% end %>

View File

@ -1,17 +1,15 @@
<tr id="ingredient-<%= i.id %>" class="ingredient project idnt idnt-2 buttonable">
<td class="name ellipsible" colspan="2"><%= i.food.name %></td>
<td class="value ellipsible">
<td class="topleft ellipsible" colspan="2"><%= i.food.name %></td>
<td class="right ellipsible">
<span><%= "%g" % i.amount %></span>
<%= "[#{i.food.ref_unit.shortname}]" unless i.food.ref_unit == @amount_mfu_unit %>
</td>
<% @quantities.each do |q| %>
<td class="value ellipsible">
<td class="right ellipsible">
<%= format_value(@ingredients[i][q], @ingredient_summary[:precision][q],
@ingredient_summary[:mfu_unit][q]) %>
</td>
<% end %>
<td class="action unwrappable" style="width: 1%; text-align: right;">
<%# Moved to helper to avoid spaces between buttons %>
<%= adjustment_buttons(i) %>
</td>
<%# Moved buttons to helper to avoid spaces between buttons %>
<td class="right shrunk unwrappable"><%= adjustment_buttons(i) %></td>
</tr>

View File

@ -18,8 +18,8 @@
<% @measurements.each do |m| %>
<% next if m.new_record? %>
<tr id="measurement-<%= m.id %>" class="primary measurement">
<td class="date unwrappable"><%= format_datetime(m) %></td>
<td class="name">
<td class="topleft unwrappable"><%= format_datetime(m) %></td>
<td class="topleft">
<div style="float:left;">
<%= link_to m.routine.name, readouts_measurement_routine_path(m.routine) %>
</div>
@ -29,7 +29,7 @@
</td>
<td class="notes ellipsible"><%= m.notes %></td>
<td class="source"><%= m.source.name if m.source.present? %></td>
<td class="action unwrappable"><%= action_links(m) %></td>
<td class="right shrunk unwrappable"><%= action_links(m) %></td>
</tr>
<% end %>
</tbody>

View File

@ -32,14 +32,14 @@
<% @measurements.each do |measurement, readouts| %>
<% row_class = "measurement #{cycle('odd', 'even')}" %>
<tr id="measurement-<%= measurement.id %>" class="primary <%= row_class %>">
<td class="date unwrappable" style="cursor: pointer;"
<td class="topleft unwrappable" style="cursor: pointer;"
onclick="$(this).closest('tr').toggle(); $(this).closest('tr').nextUntil('tr.primary', '.measurement').toggle(); return false;">
<span class="icon icon-bullet-closed"><%= format_datetime(measurement) %></span>
</td>
<% @quantities.each do |q| %>
<td class="primary value ellipsible"><%= format_value(readouts[q]) %></td>
<td class="primary right ellipsible"><%= format_value(readouts[q]) %></td>
<% end %>
<td class="action unwrappable"><%= action_links(measurement) %></td>
<td class="right shrunk unwrappable"><%= action_links(measurement) %></td>
</tr>
<tr class="<%= row_class %>" style="display:none">
@ -48,17 +48,17 @@
else
rows = 1
end %>
<td rowspan="<%= rows %>" class="date unwrappable" style="cursor: pointer;"
<td rowspan="<%= rows %>" class="topleft unwrappable" style="cursor: pointer;"
onclick="$(this).closest('tr').prev('tr.primary').toggle(); $(this).closest('tr').prev('tr.primary').nextUntil('tr.primary', '.measurement').toggle(); return false;">
<span class="icon icon-bullet-open"><%= format_datetime(measurement) %></span>
</td>
<% @quantities.each do |q| %>
<td class="primary quantity ellipsible">
<td class="primary topleft ellipsible">
<%= q.name %>
<p class="value"><%= format_value(readouts[q]) %></p>
<p class="right"><%= format_value(readouts[q]) %></p>
</td>
<% end %>
<td rowspan="<%= rows %>" class="action unwrappable">
<td rowspan="<%= rows %>" class="right shrunk unwrappable">
<%= action_links(measurement) %>
</td>
</tr>
@ -67,9 +67,9 @@
<% extra_quantities.each_slice(@quantities.length) do |eqs| %>
<tr class="extra <%= row_class %>" style="display:none">
<% eqs.each do |q| %>
<td class="extra quantity ellipsible">
<td class="extra topleft ellipsible">
<%= q.name if readouts[q] %>
<p class="value"><%= format_value(readouts[q]) %></p>
<p class="right"><%= format_value(readouts[q]) %></p>
</td>
<% end %>
<% if @quantities.length > eqs.length %>

View File

@ -15,23 +15,19 @@
</thead>
<tbody>
<% Quantity.each_with_level(@quantities) do |q, level| %>
<%
next if q.new_record?
quantity_class = "quantity"
quantity_class += " primary" unless q.exposures.empty?
quantity_class += " project idnt idnt-#{level+1}"
%>
<tr id="quantity-<%= q.id %>" class="<%= quantity_class %>">
<td class="name unwrappable">
<div class="icon <%= q.exposures.empty? ? 'icon-fav-off' : 'icon-fav' %>">
<% next if q.new_record? %>
<tr id="quantity-<%= q.id %>" class="quantity project idnt idnt-<%= level+1 -%>">
<%# NOTE: 'name' class only for proper indentation by 'idnt-N' %>
<td class="name topleft unwrappable<%= ' bolded' unless q.exposures.empty? -%>">
<div class="icon <%= q.exposures.empty? ? 'icon-fav-off' : 'icon-fav' -%>">
<%= q.name %>
</div>
</td>
<td class="order"><%= order_links(q) %></td>
<td class="domain"><%= q.domain %></td>
<td class="description"><%= q.description %></td>
<td class="description symmetric"><%= q.description %></td>
<td class="formula"><%= checked_image q.formula %></td>
<td class="action unwrappable"><%= action_links(q) %></td>
<td class="right shrunk unwrappable"><%= action_links(q) %></td>
</tr>
<% end %>
</tbody>

View File

@ -1,7 +1,7 @@
$('tr[id=quantity-<%= @quantity.id %>]').nextUntil('tr.quantity').remove();
var columns = $('table > thead > tr > th').length;
$('tr[id=quantity-<%= @quantity.id %>]').nextUntil('tr.quantity').addBack().last().after(
'<tr><td class="form" colspan="'+columns+'">' +
'<div id="edit-quantity"><%= j render partial: "quantities/edit_form" %></div>' +
'<tr><td class="topleft symmetric" colspan="'+columns+'">' +
'<div id="edit-quantity"><%= j render partial: "quantities/edit_form" %></div>' +
'</td></tr>'
);

View File

@ -33,9 +33,9 @@
<% @sources.each do |s| %>
<% next if s.new_record? %>
<tr id="source-<%= s.id %>" class="source">
<td class="name"><%= s.name %></td>
<td class="topleft"><%= s.name %></td>
<td class="description"><%= s.description %></td>
<td class="action"><%= delete_link source_path(s), data: {} %></td>
<td class="right shrunk"><%= delete_link source_path(s), data: {} %></td>
</tr>
<% end %>
</tbody>

View File

@ -9,7 +9,8 @@
<p>
<%= submit_tag l(:button_save) %>
<%= link_to l(:button_cancel), "#",
onclick: '$(this).closest("tr").remove(); return false;' %>
onclick: '$(this).closest("tr").nextUntil("tr.date", "tr.details").show()
.addBack().first().remove(); return false;' %>
</p>
</div>
<% end %>

View File

@ -15,7 +15,7 @@
<% header.each_with_index do |row, i| %>
<tr class="header">
<% if i == 0 %>
<th rowspan="<%= header.length %>" style="width:<%= 2 * 100/total_width %>%">
<th rowspan="<%= header.length %>" style="width:<%= 100/total_width %>%">
<%= l(:field_effective_from) %>
</th>
<% end %>
@ -56,53 +56,16 @@
<tbody>
<% @targets_by_date.each do |date, targets| %>
<% row_class = "date #{cycle('odd', 'even')}" %>
<tr id="date-<%= date %>" class="primary <%= row_class %>">
<td class="date unwrappable" style="cursor: pointer;"
onclick="$(this).closest('tr').toggle();
$(this).closest('tr').nextUntil('tr.primary', '.date').toggle();
return false;">
<span class="icon icon-bullet-closed"><%= format_date(date) %></span>
<tr id="date-<%= date %>" class="date <%= cycle('odd', 'even') %>">
<td class="topleft unwrappable">
<%= link_to(format_date(date), goal_target_path(@goal, date),
{remote: true, class: 'icon icon-arrow-right'}) %>
</td>
<% @quantities.each do |q| %>
<td class="primary value ellipsible"><%= targets[q] %></td>
<td class="primary right unwrappable"><%= raw targets[q].to_s %></td>
<% end %>
<td class="action unwrappable"><%= action_links(date) %></td>
<td class="right shrunk unwrappable"><%= action_links(date) %></td>
</tr>
<tr class="<%= row_class %>" style="display:none">
<% rows = @quantities.empty? ? 1 : (targets.length - 1) / @quantities.length + 1 %>
<td rowspan="<%= rows %>" class="date unwrappable" style="cursor: pointer;"
onclick="$(this).closest('tr').prev('tr.primary').toggle();
$(this).closest('tr').prev('tr.primary')
.nextUntil('tr.primary', '.date').toggle();
return false;">
<span class="icon icon-bullet-open"><%= format_date(date) %></span>
</td>
<% @quantities.each do |q| %>
<td class="primary quantity ellipsible">
<%= q.name %><p class="value"><%= targets.delete(q) %></p>
</td>
<% end %>
<td rowspan="<%= rows %>" class="action unwrappable">
<%= action_links(date) %>
</td>
</tr>
<% next if @quantities.empty? %>
<% targets.each_slice(@quantities.length) do |extras| %>
<tr class="extra <%= row_class %>" style="display:none">
<% extras.each do |q, t| %>
<td class="extra quantity ellipsible">
<%= q.name %><p class="value"><%= t %></p>
</td>
<% end %>
<% if @quantities.length > extras.length %>
<td class="space" colspan="<%= @quantities.length - extras.length %>"></td>
<% end %>
</tr>
<% end %>
<% end %>
</tbody>
</table>

View File

@ -0,0 +1,12 @@
<tr class="details">
<td class="topleft">
<%= link_to l(:button_close), "#", {class: 'icon icon-close',
onclick: '$(this).closest("tr").nextUntil("tr.date", "tr:not(.details)").show()
.addBack().first().remove(); return false;'} %>
</td>
<% content = @quantities.keys.sort_by(&:lft).inject('') do |output, q| %>
<% raw "#{output}#{target_markup(@effective_from, q, @quantities[q])}\n" %>
<% end %>
<td class="topleft" colspan="<%= @goal.exposures.length + 1 %>"
style="white-space:pre-line;"><%= content %></td>
</tr>

View File

@ -1,7 +1,9 @@
$('tr[id=date-<%= @effective_from %>]').nextUntil('tr.primary', ':not(.date)').remove();
var columns = $('table > thead > tr > th').length;
$('tr[id=date-<%= @effective_from %>]').nextUntil('tr.primary').addBack().last().after(
'<tr><td class="form" colspan="'+columns+'"><div id="edit-target">' +
'<%= j render partial: 'targets/edit_form' %>' +
'</div></td></tr>'
);
$('tr[id=date-<%= @effective_from %>]').nextUntil('tr.date').remove('tr:not(.details)')
.hide().addBack().first().after(
'<tr>' +
'<td class="topleft symmetric"' +
'colspan="'+$('table#targets tr:first-child td').length+'">' +
'<%= j render partial: 'targets/edit_form' %>' +
'</td>' +
'</tr>'
);

View File

@ -0,0 +1,4 @@
var row = $('tr[id=date-<%= @effective_from %>]');
row.nextUntil('tr.date').remove('tr.details').hide();
row.after('<%= j render partial: 'targets/show' %>').next()
.addClass(row.hasClass('even') ? 'even' : 'odd');

View File

@ -35,7 +35,7 @@
<tr id="unit-<%= u.id %>" class="unit">
<td class="shortname"><%= u.shortname %></td>
<td class="unitname"><%= u.name %></td>
<td class="action"><%= delete_link unit_path(u), data: {} %></td>
<td class="right shrunk"><%= delete_link unit_path(u), data: {} %></td>
</tr>
<% end %>
</tbody>

View File

@ -1,10 +1,6 @@
table.list tr.quantity.primary td.name {font-weight: bold;}
table.list .bolded {font-weight: bold;}
table.list .dimmed {opacity: 0.4}
table.list tr.food.hidden {opacity: 0.4}
table.list .date,
table.list .name,
table.list td.quantity {text-align: left;}
/* TODO: merge with .closable and/or remove .closable */
/* TODO: replace .quantity(head)(empty) with th.interim/.empty */
table.list .quantityhead {border-bottom: none;}
@ -12,8 +8,12 @@ table.list .quantityheadempty {border-top: none; border-bottom: none;}
table.list th.interim {border-bottom: none;}
table.list th.empty {border-top: none;}
table.list .action,
table.list .value {text-align: right; padding-right: 2px;}
table.list td.topleft {text-align: left; vertical-align: top; padding-left: 4px;}
table.list td.symmetric {padding-right: 4px;}
/* .right used with 'p' in _readouts/_nutrients; scope to 'td' after changing
* format of these views after _targets */
table.list .right {text-align: right; padding-right: 2px; padding-left: 4px;}
table.list td.shrunk {width: 1px;}
table.list .closable {padding-right: 0;}
table.list .unwrappable {white-space: nowrap;}
@ -25,11 +25,6 @@ table.list .ellipsible {
}
table.list tr.buttonable {line-height: 1.8em;}
table.list td.form {
padding-right: 2px;
text-align: left;
}
table.list tbody tr.header:hover {background-color: unset;}
table.list tbody tr.header:hover td {border: none;}

View File

@ -16,7 +16,7 @@ Redmine::Plugin.register :body_tracking do
permission :view_body_trackers, {
body_trackers: [:index],
goals: [:index],
targets: [:index],
targets: [:index, :show],
meals: [:index],
measurement_routines: [:show],
measurements: [:index, :readouts, :filter],