Module: Taskable

Included in:
Issuable
Defined in:
app/models/concerns/taskable.rb

Overview

Contains functionality for objects that can have task lists in their descriptions. Task list items can be added with Markdown like “* [x] Fix bugs”.

Used by MergeRequest and Issue

Constant Summary collapse

COMPLETED =
'completed'
INCOMPLETE =
'incomplete'
COMPLETE_PATTERN =
/(\[[xX]\])/.freeze
INCOMPLETE_PATTERN =
/(\[[\s]\])/.freeze
ITEM_PATTERN =
%r{
  ^
  (?:(?:>\s{0,4})*)          # optional blockquote characters
  (?:\s*(?:[-+*]|(?:\d+\.)))+  # list prefix (one or more) required - task item has to be always in a list
  \s+                        # whitespace prefix has to be always presented for a list item
  (\[\s\]|\[[xX]\])          # checkbox
  (\s.+)                     # followed by whitespace and some text.
}x.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_tasks(content) ⇒ Object


25
26
27
28
29
30
# File 'app/models/concerns/taskable.rb', line 25

def self.get_tasks(content)
  content.to_s.scan(ITEM_PATTERN).map do |checkbox, label|
    # ITEM_PATTERN strips out the hyphen, but Item requires it. Rabble rabble.
    TaskList::Item.new("- #{checkbox}", label.strip)
  end
end

.get_updated_tasks(old_content:, new_content:) ⇒ Object


32
33
34
35
36
37
38
39
40
41
# File 'app/models/concerns/taskable.rb', line 32

def self.get_updated_tasks(old_content:, new_content:)
  old_tasks, new_tasks = get_tasks(old_content), get_tasks(new_content)

  new_tasks.select.with_index do |new_task, i|
    old_task = old_tasks[i]
    next unless old_task

    new_task.source == old_task.source && new_task.complete? != old_task.complete?
  end
end

Instance Method Details

#task_completion_statusObject


80
81
82
83
84
85
# File 'app/models/concerns/taskable.rb', line 80

def task_completion_status
  @task_completion_status ||= {
      count: tasks.summary.item_count,
      completed_count: tasks.summary.complete_count
  }
end

#task_list_itemsObject

Called by `TaskList::Summary`


44
45
46
47
48
# File 'app/models/concerns/taskable.rb', line 44

def task_list_items
  return [] if description.blank?

  @task_list_items ||= Taskable.get_tasks(description) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end

#task_status(short: false) ⇒ Object

Return a string that describes the current state of this Taskable's task list items, e.g. “12 of 20 tasks completed”


61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/models/concerns/taskable.rb', line 61

def task_status(short: false)
  return '' if description.blank?

  prep, completed = if short
                      ['/', '']
                    else
                      [' of ', ' completed']
                    end

  sum = tasks.summary
  "#{sum.complete_count}#{prep}#{sum.item_count} #{'task'.pluralize(sum.item_count)}#{completed}"
end

#task_status_shortObject

Return a short string that describes the current state of this Taskable's task list items – for small screens


76
77
78
# File 'app/models/concerns/taskable.rb', line 76

def task_status_short
  task_status(short: true)
end

#tasksObject


50
51
52
# File 'app/models/concerns/taskable.rb', line 50

def tasks
  @tasks ||= TaskList.new(self)
end

#tasks?Boolean

Return true if this object's description has any task list items.

Returns:

  • (Boolean)

55
56
57
# File 'app/models/concerns/taskable.rb', line 55

def tasks?
  tasks.summary.items?
end