Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/controllers/connections_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def edit # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
@coupled_frames = @frame.bay.frames
@possible_destination_servers = []
@all_servers_per_frame = []
if @from_port.is_power_input? && @from_server.is_not_a_pdu?
if @from_port.is_power? && @from_server.is_not_a_pdu?
# @coupled_frames.each { |frame| @possible_destination_servers << [frame.name, frame.pdus.collect { |v| [v.name, v.id] }] }
# Frame.order(:name).each { |frame| @all_servers_per_frame << [frame.name, frame.pdus.collect { |v| [v.name, v.id] }] }
else
Expand All @@ -46,7 +46,7 @@ def edit # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
# Destination server
@to_server = if @to_port.present?
@to_port.server
elsif @from_port.is_power_input?
elsif @from_port.is_power?
nil # @frame.pdus.first
else
@frame.servers.where("position IS NOT NULL AND modele_id IS NOT NULL").order(:position).first
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/port_types_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ def set_port_type

# Never trust parameters from the scary internet, only allow the white list through.
def port_type_params
params.expect(port_type: %i[name power])
params.expect(port_type: [:name, :is_power, { usable_by: [] }])
end
end
4 changes: 4 additions & 0 deletions app/decorators/card_type_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ class CardTypeDecorator < ApplicationDecorator
class << self
include ActionView::Helpers::FormOptionsHelper

def port_types_options_for_select
PortTypeDecorator.options_for_select(PortType.with_usable_by(:server))
end

def grouped_by_port_type_options_for_select(selected = nil)
grouped_card_types = CardType.includes(:port_type)
.sorted
Expand Down
8 changes: 8 additions & 0 deletions app/decorators/port_type_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ def self.options_for_select(collection = PortType)
collection.select(:id, :name).sorted.map { |p| [p.to_s, p.id] }
end

def self.usable_by_options_for_select
PortType::USABLE_BY_VALUES.map { |value| [PortType.human_attribute_name("usable_by.#{value}"), value] }
end

def human_usable_by
usable_by.map { |value| PortType.human_attribute_name("usable_by.#{value}") }.to_sentence
end

def css_class_name
case name
when "RJ", "XRJ"
Expand Down
4 changes: 2 additions & 2 deletions app/decorators/power_distribution_unit_socket_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

class PowerDistributionUnitSocketDecorator < ApplicationDecorator
class << self
def port_type_options_for_select
PortTypeDecorator.options_for_select(PortType.where(power: true))
def port_types_options_for_select
PortTypeDecorator.options_for_select(PortType.power_ones.with_usable_by(:pdu))
end
end
end
2 changes: 1 addition & 1 deletion app/models/cable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Cable < ApplicationRecord
after_update :touch_ports

scope :sorted, lambda {
alim_cables = joins(:port_types).where(port_types: PortType.where(name: "ALIM")).uniq
alim_cables = joins(:port_types).merge(PortType.power_ones).distinct
other_cables = order(:cards, ports: { position: :asc }).select { |c| alim_cables.exclude?(c) }

other_cables + alim_cables
Expand Down
2 changes: 1 addition & 1 deletion app/models/card.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Card < ApplicationRecord

belongs_to :card_type
delegate :port_quantity, to: :card_type, allow_nil: true
delegate :is_power_input?, to: :card_type, allow_nil: true
delegate :is_power?, to: :card_type, allow_nil: true

belongs_to :twin_card, class_name: "Card", optional: true
belongs_to :server, touch: true
Expand Down
2 changes: 1 addition & 1 deletion app/models/card_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class CardType < ApplicationRecord
has_changelog

belongs_to :port_type, counter_cache: true
delegate :is_power_input?, to: :port_type, allow_nil: true
delegate :is_power?, to: :port_type, allow_nil: true

has_many :cards, dependent: :restrict_with_error
has_many :servers, through: :cards
Expand Down
Empty file removed app/models/concerns/.keep
Empty file.
64 changes: 64 additions & 0 deletions app/models/concerns/enum/array.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

module Enum
module Array
extend ActiveSupport::Concern

MISSING_VALUE_MESSAGE = "%<value>s is not a valid value for %<attr>s" # rubocop:disable Style/FormatStringToken
private_constant :MISSING_VALUE_MESSAGE
Comment thread
nicolas-brousse marked this conversation as resolved.

class_methods do
def array_enum(name = nil, mapping = nil, validate: false)
name = name.to_s
mapping_hash = ActiveSupport::HashWithIndifferentAccess.new(mapping)

defined_enums[name] = mapping_hash

define_singleton_method(name.pluralize) do
mapping_hash
end

define_singleton_method("with_#{name}") do |*values|
db_values = values.map do |value|
raise_missing_value(name, value) unless mapping_hash.key?(value)

mapping_hash[value]
end

# get sql type to cast properly
# It returns the array's element type
element_type = columns_hash[name.to_s].sql_type

# encode array so it can be understood by PG
encoder = PG::TextEncoder::Array.new
encoded = encoder.encode(db_values)

where(
"#{name} @> ?::#{element_type}[]",
encoded,
)
Comment on lines +28 to +39

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does where("#{name} @> ARRAY[?]::varchar[]", db_values) works?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not if I'm right.
Like the DB fields is / (can be) a PG enum, @> will not accept another type as the exact field type.
A PG enum value isn't comparable to a varchar, the array elements can also be integers ...

The values are sent as text, and PG cast them. I haven't found any encoder for that column API

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discuss on chat, let's comment define_singleton_method("with_#{name}") do |*values| and use the method you previously done on model

end

define_method(name) do
Array(self[name]).map { |value| mapping_hash.key(value) || value }
end

define_method(:"#{name}=") do |values|
self[name] = Array(values).compact_blank.map do |value|
raise_missing_value(name, value) unless validate || mapping_hash.key?(value)

mapping_hash[value] || value
end.uniq
end

validates name, array_inclusion: { in: mapping_hash.keys } if validate
end

private

def raise_missing_value(name, value)
raise ArgumentError, format(MISSING_VALUE_MESSAGE, name:, value:)
end
end
end
end
2 changes: 1 addition & 1 deletion app/models/port.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Port < ApplicationRecord # rubocop:disable Metrics/ClassLength

delegate :server, to: :card, allow_nil: true
delegate :circuit, to: :power_distribution_unit_socket, allow_nil: true
delegate :is_power_input?, to: :card, allow_nil: true
delegate :is_power?, to: :card, allow_nil: true
delegate :paired_connection, to: :connection, allow_nil: true
delegate :color, to: :cable, prefix: true, allow_nil: true
delegate :name, to: :cable, prefix: true, allow_nil: true
Expand Down
10 changes: 6 additions & 4 deletions app/models/port_type.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
# frozen_string_literal: true

class PortType < ApplicationRecord
include Enum::Array

has_changelog

has_many :card_types, dependent: :restrict_with_error
has_many :sockets, class_name: "PowerDistributionUnit::Socket", dependent: :restrict_with_error

USABLE_BY_VALUES = %w[pdu server].freeze
array_enum :usable_by, USABLE_BY_VALUES.index_with(&:to_s), validate: true

scope :sorted, -> { order(name: :asc) }
scope :power_ones, -> { where(is_power: true) }

delegate :to_s, to: :name

def is_power_input?
name == "ALIM"
end
end
2 changes: 1 addition & 1 deletion app/services/import_equipment_by_csv.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def init_slots(data, server)
# SLOTS ALIM
valeur = "ALIM"
nb_ports = data["Alim"].to_s.gsub(valeur, "").to_i
port_type = PortType.find_or_create_by!(name: valeur)
port_type = PortType.find_or_create_by!(name: valeur, is_power: true)
card_alim = CardType.find_or_create_by!(name: "#{nb_ports}#{valeur}", port_quantity: nb_ports, port_type: port_type)
Card.find_or_create_by!(card_type: card_alim, server: server, composant: composant_slot_alim)
end
Expand Down
12 changes: 12 additions & 0 deletions app/validators/array_inclusion_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

class ArrayInclusionValidator < ActiveModel::EachValidator
def validate_each(record, attribute, values)
not_allowed_values = values - options[:in]

return if not_allowed_values.empty?

wrong_values = not_allowed_values.join(", ")
record.errors.add(attribute, :contains_unpermitted_values, wrong_values:)
end
end
2 changes: 1 addition & 1 deletion app/views/card_types/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fieldset class="col-12">
<%= f.label :port_type, class: "form-label" %>
<%= f.select :port_type_id,
PortType.sorted.map { |pt| [pt.name, pt.id] },
CardTypeDecorator.port_types_options_for_select,
{ prompt: true },
{
class: "form-select",
Expand Down
18 changes: 10 additions & 8 deletions app/views/card_types/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@

<div>
<fieldset class="form-floating">
<%= f.collection_select(:port_type_ids, PortType.sorted, :id, :name,
{ prompt: true, multiple: true },
{ class: "form-select",
data: {
controller: :select,
select_clear_button_title_value: t("action.clear_all")
}
}) %>
<%= f.select :port_type_ids,
CardTypeDecorator.port_types_options_for_select,
{ prompt: true, multiple: true },
{
class: "form-select",
data: {
controller: :select,
select_clear_button_title_value: t("action.clear_all"),
},
} %>
<%= f.label :port_type_ids %>
</fieldset>
</div>
Expand Down
14 changes: 12 additions & 2 deletions app/views/port_types/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,20 @@

<div class="col-12">
<fieldset class="form-check">
<%= f.check_box :power, class: "form-check-input" %>
<%= f.label :power, class: "form-check-label" %>
<%= f.check_box :is_power, class: "form-check-input" %>
<%= f.label :is_power, class: "form-check-label" %>
</fieldset>
</div>

<fieldset class="col-12 mt-4">
<%= f.label :usable_by, class: "form-check-label" %>
<%= f.select :usable_by, PortTypeDecorator.usable_by_options_for_select,
{ prompt: true, multiple: true },
{
class: "form-select",
data: { controller: :select, select_clear_button_title_value: t("action.clear_all"), }
} %>
</fieldset>
<% end %>
</div>
</div>
Expand Down
6 changes: 5 additions & 1 deletion app/views/port_types/index.html.erb
Comment thread
nicolas-brousse marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<% end %>

<% table.with_column(PortType.human_attribute_name(:power), sort_by: :power) do |port_type| %>
<%= t("boolean.#{port_type.power?}") %>
<%= t("boolean.#{port_type.is_power?}") %>
<% end %>

<% table.with_column(PortType.human_attribute_name(:usage), sort_by: :card_types_count) do |port_type| %>
Expand All @@ -40,6 +40,10 @@
<% end %>
<% end %>

<% table.with_column(PortType.human_attribute_name(:usable_by)) do |port_type| %>
<%= port_type.decorated.human_usable_by %>
<% end %>

<% table.with_column(style: "min-width: 70px; width: 70px;") do |port_type| %>
<div class="btn-group btn-group-sm" role="group" aria-label="...">
<% if allowed_to?(:update?, port_type) %>
Expand Down
11 changes: 8 additions & 3 deletions app/views/port_types/show.html.erb
Comment thread
nicolas-brousse marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<dl class="show-page_dl d-grid row-gap-2 mb-0">
<% %i[name].each do |attribute_name| %>
<dt class="pb-2"><%= Architecture.human_attribute_name(attribute_name) %></dt>
<dt class="pb-2"><%= PortType.human_attribute_name(attribute_name) %></dt>
<dd class="mb-0 pb-2 ps-3"><%= @port_type.public_send(attribute_name) %></dd>
<% end %>
</dl>
Expand All @@ -31,10 +31,15 @@
<% end %>

<dl class="show-page_dl d-grid row-gap-2 mb-0">
<% icon = @port_type.power ? "check" : "x" %>
<dt class="pb-2"><%= Architecture.human_attribute_name(:power) %></dt>
<% icon = @port_type.is_power? ? "check" : "x" %>
<dt class="pb-2"><%= PortType.human_attribute_name(:power) %></dt>
<dd class="mb-0 pb-2 ps-3"><span class="bi bi-<%= icon %>-square"></span></dd>
</dl>

<dl class="show-page_dl d-grid row-gap-2 mb-0">
<dt class="pb-2"><%= PortType.human_attribute_name(:usable_by) %></dt>
<dd class="mb-0 pb-2 ps-3"><%= @port_type.decorated.human_usable_by %></dd>
</dl>
<% end %>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/power_distribution_units/_socket_fields.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div class="d-flex flex-column">
<fieldset class="d-flex">
<%= f.select :port_type_id,
PowerDistributionUnitSocketDecorator.port_type_options_for_select,
PowerDistributionUnitSocketDecorator.port_types_options_for_select,
{ prompt: true },
{
class: "form-select form-select-sm",
Expand Down
Loading
Loading