diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 4c49e38..14ec9a7 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -410,7 +410,8 @@ table.items td.link a:hover:focus-visible { color: #006c9b; } -table.items td:not(:first-child) { +table.items td:not(:first-child), +.grayed { color: var(--color-table-gray); fill: var(--color-table-gray); } diff --git a/app/models/unit.rb b/app/models/unit.rb index e9025f8..53af7df 100644 --- a/app/models/unit.rb +++ b/app/models/unit.rb @@ -19,7 +19,7 @@ class Unit < ApplicationRecord bases_units = arel_table.alias('bases_units') other_units = arel_table.alias('other_units') other_bases_units = arel_table.alias('other_bases_units') - parent_units = arel_table.alias('parent_units') + sub_units = arel_table.alias('sub_units') Unit.with(units: self.with_defaults).left_joins(:base) # Exclude Units that are/have default counterpart @@ -32,20 +32,30 @@ class Unit < ApplicationRecord .and(other_units[:symbol].eq(arel_table[:symbol])) .and(other_units[:user_id].not_eq(arel_table[:user_id])) ).exists - # Decide if Unit can be im-/exported based on existing hierarchy - ).joins( - arel_table.create_join(parent_units, - arel_table.create_on( - parent_units[:symbol].eq(bases_units[:symbol]) - .and(parent_units[:user_id].not_eq(bases_units[:user_id])) - ), - Arel::Nodes::OuterJoin) + # Decide if Unit can be im-/exported based on existing hierarchy: + # * same base unit symbol has to exist + # * unit with subunits can only be ported to root ).select( arel_table[Arel.star], - Arel::Nodes::IsNotDistinctFrom.new(parent_units[:symbol], bases_units[:symbol]) - .as('portable') + arel_table[:base_id].eq(nil).or( + ( + Arel::SelectManager.new.project(1).from(other_units) + .join(sub_units).on(other_units[:id].eq(sub_units[:base_id])) + .where( + other_units[:symbol].eq(arel_table[:symbol]) + .and(other_units[:user_id].not_eq(arel_table[:user_id])) + ) + .exists.not + ).and( + Arel::SelectManager.new.project(1).from(other_bases_units) + .where( + other_bases_units[:symbol].eq(bases_units[:symbol]) + .and(other_bases_units[:user_id].not_eq(bases_units[:user_id])) + ) + .exists + ) + ).as('portable') ) - # complete portability check with children } scope :ordered, ->{ left_outer_joins(:base) diff --git a/app/views/default/units/_unit.html.erb b/app/views/default/units/_unit.html.erb index 53d8889..19af7a3 100644 --- a/app/views/default/units/_unit.html.erb +++ b/app/views/default/units/_unit.html.erb @@ -1,16 +1,17 @@ <%= tag.tr do %> - + <%= unit.symbol %> <% if current_user.at_least(:active) && unit.default? %> <%= image_button_to t('.import'), 'download-outline', import_default_unit_path(unit), - disabled: !unit.portable? %> + !unit.portable? ? {disabled: true, aria: {disabled: true}, tabindex: -1} : {} %> <% end %> <% if current_user.at_least(:admin) %> <% if !unit.default? %> - <%= image_button_to t('.export'), 'upload-outline', export_default_unit_path(unit) %> + <%= image_button_to t('.export'), 'upload-outline', export_default_unit_path(unit), + !unit.portable? ? {disabled: true, aria: {disabled: true}, tabindex: -1} : {} %> <% else %> <%= image_button_to t('.delete'), 'delete-outline', unit_path(unit), method: :delete %>