diff --git a/app/controllers/quantities_controller.rb b/app/controllers/quantities_controller.rb index e92cee4..fe5213a 100644 --- a/app/controllers/quantities_controller.rb +++ b/app/controllers/quantities_controller.rb @@ -2,7 +2,7 @@ class QuantitiesController < ApplicationController before_action only: :new do find_quantity if params[:id].present? end - before_action :find_quantity, only: [:edit, :update, :rebase, :destroy] + before_action :find_quantity, only: [:edit, :update, :reparent, :destroy] before_action except: :index do raise AccessForbidden unless current_user.at_least(:active) @@ -39,6 +39,18 @@ class QuantitiesController < ApplicationController end end + def reparent + permitted = params.require(:quantity).permit(:parent_id) + @previous_ancestors = @quantity.ancestors + + @quantity.update!(permitted) + + @ancestors = @quantity.ancestors + @quantity.depth = @ancestors.length + @self_and_progenies = @quantity.progenies.unshift(@quantity) + @before = @self_and_progenies.last.successive + end + def destroy @quantity.destroy! @ancestors = @quantity.ancestors diff --git a/app/models/quantity.rb b/app/models/quantity.rb index ee4eabb..ebb22dd 100644 --- a/app/models/quantity.rb +++ b/app/models/quantity.rb @@ -29,8 +29,8 @@ class Quantity < ApplicationRecord numbered.project( numbered[Arel.star], numbered.cast(numbered[:child_number], 'BINARY').as('path'), - Arel::Nodes.build_quoted(0).as('depth') - ).where(numbered[:parent_id].eq(root)), + Arel::Nodes.build_quoted(root&.depth&.succ || 0).as('depth') + ).where(numbered[:parent_id].eq(root&.id)), numbered.project( numbered[Arel.star], arel_table[:path].concat(numbered[:child_number]), @@ -70,8 +70,8 @@ class Quantity < ApplicationRecord parent_id.nil? end - # Return: self, ancestors and successive record in order of appearance, - # including :depth attribute. Used for partial view reload. + # Return: successive record in order of appearance, including :depth + # attribute. Used for partial view reload. def successive quantities = Quantity.arel_table @@ -90,9 +90,13 @@ class Quantity < ApplicationRecord selected.project(selected[Arel.star]).where(selected[:id].eq(quantity.id)), selected.project(selected[Arel.star]) .join(arel_table).on(arel_table[:id].eq(selected[:parent_id])) - ]).ordered(root: quantity.id) + ]).ordered(root: quantity) } + def progenies + user.quantities.progenies(self).to_a + end + # Return: ancestors of (possibly destroyed) self; include depths, also on # self (unless destroyed) def ancestors @@ -111,7 +115,7 @@ class Quantity < ApplicationRecord )) ]).select(ancestors[Arel.star]).from(ancestors).to_a.then do |records| records.map(&:depth).min&.abs.then do |maxdepth| - self.depth = (maxdepth || -1) + 1 unless frozen? + self.depth = maxdepth&.succ || 0 unless frozen? records.each { |r| r.depth += maxdepth } end end diff --git a/app/views/quantities/reparent.turbo_stream.erb b/app/views/quantities/reparent.turbo_stream.erb new file mode 100644 index 0000000..3023389 --- /dev/null +++ b/app/views/quantities/reparent.turbo_stream.erb @@ -0,0 +1,9 @@ +<% @self_and_progenies.each do |q| %> + <%= turbo_stream.remove q %> +<% end %> +<% @previous_ancestors.union(@ancestors).map do |ancestor| %> + <%= turbo_stream.replace ancestor %> +<% end %> +<% @self_and_progenies.each do |q| %> + <%= @before.nil? ? turbo_stream.append(:quantities, q) : turbo_stream.before(@before, q) %> +<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 2f1bb22..041a972 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -68,6 +68,7 @@ en: destroy: Delete index: new_quantity: Add quantity + top_level_drop: Drop here to reposition into top-level quantity create: success: Created new quantity "%{quantity}" update: diff --git a/config/routes.rb b/config/routes.rb index 5bab666..25aa414 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,6 @@ Rails.application.routes.draw do resources :quantities, except: [:show], path_names: {new: '(/:id)/new'} do - member { post :rebase } + member { post :reparent } end resources :units, except: [:show], path_names: {new: '(/:id)/new'} do