Class: Plutonium::Kanban::Column

Inherits:
Object
  • Object
show all
Defined in:
lib/plutonium/kanban/column.rb

Constant Summary collapse

ROLE_PRESETS =
{
  backlog: {add: true},
  # Terminal columns: collapsed by default, colour signals the outcome.
  # :done is the positive close (green); :lost is the negative close
  # (red) — the natural pair for won/lost pipelines (leads, deals, tickets).
  done: {color: :green, collapsed: true},
  lost: {color: :red, collapsed: true}
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, label: nil, color: nil, wip: nil, scope: nil, on_enter: nil, on_exit: nil, on_drop: nil, collapsed: nil, add: nil, accepts: nil, locked: nil, role: nil, enter_interaction: nil, drop_interaction: nil) ⇒ Column

Returns a new instance of Column.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/plutonium/kanban/column.rb', line 17

def initialize(key, label: nil, color: nil, wip: nil, scope: nil, on_enter: nil, on_exit: nil, on_drop: nil,
  collapsed: nil, add: nil, accepts: nil, locked: nil, role: nil, enter_interaction: nil, drop_interaction: nil)
  # on_drop:/drop_interaction: were renamed to on_enter:/enter_interaction:.
  # Resolve the deprecated aliases first (dev/test raise; deployed envs warn
  # and map — see resolve_renamed_option) so the rest of initialize only
  # ever sees the new names.
  on_enter = resolve_renamed_option(:on_drop, on_drop, :on_enter, on_enter)
  enter_interaction = resolve_renamed_option(:drop_interaction, drop_interaction, :enter_interaction, enter_interaction)

  preset = role ? ROLE_PRESETS.fetch(role) { raise ArgumentError, "Unknown column role: #{role.inspect}. Valid: #{ROLE_PRESETS.keys.inspect}" } : {}
  if enter_interaction && !(enter_interaction.is_a?(Class) && enter_interaction < Plutonium::Resource::Interaction)
    raise ArgumentError, "enter_interaction: must be a Plutonium::Resource::Interaction subclass, got #{enter_interaction.inspect}"
  end
  # An enter_interaction acts on the SINGLE dropped card — the move handler
  # binds it as `resource:`. It must therefore be record-shaped (declare a
  # `resource` attribute), never collection/bulk-shaped (`resources`). Reject
  # anything else at definition time so a mis-shaped interaction can't (a) blow
  # up at drop time on the `resource=` assignment, or (b) get auto-classified
  # by Action::Interactive::Factory as a bulk action and leak into the
  # bulk-actions bar (which does not filter kanban_drop actions).
  if enter_interaction && !enter_interaction.attribute_names.map(&:to_sym).include?(:resource)
    raise ArgumentError, "enter_interaction: #{enter_interaction} must operate on a single record (declare `attribute :resource`); collection/bulk interactions cannot be used as an enter_interaction."
  end
  # accepts: is purely structural (topology + client drop hints): true/false
  # or an Array of source keys. The Proc form was removed — record/user
  # conditions belong in the kanban_move? policy, which sees the record and
  # the from/to columns. Fail loud rather than silently treating a stale Proc
  # as permissive (which would OPEN UP a column that used to restrict drops).
  if accepts.is_a?(Proc)
    raise ArgumentError, "kanban column `accepts:` no longer accepts a Proc; use true/false or an Array of source keys, and put record/user conditions in the kanban_move? policy."
  end
  @key = key.to_sym
  @label = label || key.to_s.titleize
  @color = color.nil? ? preset[:color] : color
  @wip = wip
  @scope = scope
  @on_enter = on_enter
  @on_exit = on_exit
  @collapsed = collapsed.nil? ? preset[:collapsed] : collapsed
  @add = add.nil? ? preset[:add] : add
  @accepts = accepts.nil? || accepts
  @locked = locked || false
  @enter_interaction = enter_interaction
  @actions = []
end

Instance Attribute Details

#acceptsObject (readonly)

Returns the value of attribute accepts.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def accepts
  @accepts
end

#actionsObject (readonly)

Returns the value of attribute actions.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def actions
  @actions
end

#colorObject (readonly)

Returns the value of attribute color.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def color
  @color
end

#enter_interactionObject (readonly)

Returns the value of attribute enter_interaction.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def enter_interaction
  @enter_interaction
end

#keyObject (readonly)

Returns the value of attribute key.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def key
  @key
end

#labelObject (readonly)

Returns the value of attribute label.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def label
  @label
end

#on_enterObject (readonly)

Returns the value of attribute on_enter.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def on_enter
  @on_enter
end

#on_exitObject (readonly)

Returns the value of attribute on_exit.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def on_exit
  @on_exit
end

#scopeObject (readonly)

Returns the value of attribute scope.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def scope
  @scope
end

#wipObject (readonly)

Returns the value of attribute wip.



15
16
17
# File 'lib/plutonium/kanban/column.rb', line 15

def wip
  @wip
end

Instance Method Details

#accepts?(source_key) ⇒ Boolean

Whether a card from source_key may be dropped into this column. Purely structural — @accepts is normalized to true/false or an Array of source keys (the constructor rejects a Proc). Drives both the server-side gate in the move handler and the client-side drop hint (data-kanban-accepts).

Returns:

  • (Boolean)


94
95
96
97
98
99
# File 'lib/plutonium/kanban/column.rb', line 94

def accepts?(source_key)
  case @accepts
  when Array then @accepts.include?(source_key)
  else @accepts # true or false
  end
end

#action(key, interaction:, on: :all, label: nil, icon: nil, confirmation: nil) ⇒ Object



82
83
84
# File 'lib/plutonium/kanban/column.rb', line 82

def action(key, interaction:, on: :all, label: nil, icon: nil, confirmation: nil)
  @actions << Action.new(key: key.to_sym, interaction:, on:, label:, icon:, confirmation:)
end

#add?Boolean

Returns:

  • (Boolean)


87
# File 'lib/plutonium/kanban/column.rb', line 87

def add? = !!@add

#collapsed?Boolean

Returns:

  • (Boolean)


86
# File 'lib/plutonium/kanban/column.rb', line 86

def collapsed? = !!@collapsed

#enter_interaction?Boolean

A column may run an input-collecting Interaction when a card ENTERS it (e.g. "mark lead as lost with a reason"). When set, the drop opens the interaction's form as a modal before the move is committed.

Returns:

  • (Boolean)


66
# File 'lib/plutonium/kanban/column.rb', line 66

def enter_interaction? = !!@enter_interaction

#enter_interaction_keyObject

Internal action-registration key for the enter interaction, scoped to the column: :blocked → :blocked_enter_interaction. Nil when unset.

Column-scoped (not class-name-derived) so it is unique by construction — a column has at most one enter_interaction, so two columns can never collide even if they reuse the same interaction class. This key is ONLY an internal form/param routing handle; it is NOT an authorization name. The move (and therefore the interaction) is authorized solely by kanban_move? — the interaction has no policy method of its own.



77
78
79
80
# File 'lib/plutonium/kanban/column.rb', line 77

def enter_interaction_key
  return nil unless @enter_interaction
  :"#{key}_enter_interaction"
end

#locked?Boolean

Returns:

  • (Boolean)


88
# File 'lib/plutonium/kanban/column.rb', line 88

def locked? = @locked