summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorMehmet Beydogan <mehmet.beydogan@gmail.com>2016-03-10 16:26:56 +0200
committerRobert Speicher <rspeicher@gmail.com>2016-04-20 15:42:09 -0400
commit3afd08170da6f003b4f11ae1a3f737b14dedec40 (patch)
tree0e858cd1c275f7862743022e4c2b24bfef3b2148 /app
parent1e596fef1c42a1dd925636c48fea01be444dc3ab (diff)
downloadgitlab-ce-3afd08170da6f003b4f11ae1a3f737b14dedec40.tar.gz
Add due_date:time field to Issue model
Add due_date text field to sidebar issue#show Add ability sorting issues by due date ASC and DESC Add ability to filtering issues by No Due Date, Any Due Date, Due to tomorrow, Due in this week options Add handling issue due_date field for MergeRequest Update CHANGELOG Fix ambigous match for issues#show sidebar Fix SCREAMING_SNAKE_CASE offenses for due date contants Add specs for due date sorting and filtering on issues
Diffstat (limited to 'app')
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/finders/issuable_finder.rb22
-rw-r--r--app/helpers/issues_helper.rb11
-rw-r--r--app/helpers/sorting_helper.rb18
-rw-r--r--app/models/concerns/issuable.rb2
-rw-r--r--app/models/concerns/sortable.rb4
-rw-r--r--app/models/issue.rb3
-rw-r--r--app/views/projects/issues/_issue.html.haml4
-rw-r--r--app/views/shared/_sort_dropdown.html.haml4
-rw-r--r--app/views/shared/issuable/_filter.html.haml7
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml25
11 files changed, 101 insertions, 1 deletions
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index e86428147ef..b96ab91c17d 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -192,7 +192,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue_params
params.require(:issue).permit(
:title, :assignee_id, :position, :description, :confidential,
- :milestone_id, :state_event, :task_num, label_ids: []
+ :milestone_id, :due_date, :state_event, :task_num, label_ids: []
)
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 5eb1d3f5aac..5e08193b5cf 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -39,6 +39,7 @@ class IssuableFinder
items = by_assignee(items)
items = by_author(items)
items = by_label(items)
+ items = by_due_date(items)
sort(items)
end
@@ -112,6 +113,14 @@ class IssuableFinder
end
end
+ def due_date?
+ params[:due_date].present?
+ end
+
+ def filter_by_no_due_date?
+ due_date? && params[:due_date] == Issue::NO_DUE_DATE[1]
+ end
+
def labels?
params[:label_name].present?
end
@@ -283,6 +292,19 @@ class IssuableFinder
items.distinct
end
+ def by_due_date(items)
+ if due_date?
+ if filter_by_no_due_date?
+ items = items.no_due_date
+ else
+ items = items.has_due_date
+ # Must use issues prefix to avoid ambiguous match with Milestone#due_date
+ items = items.where("issues.due_date > ? AND issues.due_date <= ?", Date.today, params[:due_date])
+ end
+ end
+ items
+ end
+
def label_names
params[:label_name].split(',')
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 4cb8adcebad..2a193e12ec9 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -172,6 +172,17 @@ module IssuesHelper
end.to_h
end
+ def due_date_options
+ options = [
+ ["Due to tomorrow", 1.day.from_now.to_date],
+ ["Due in this week", 1.week.from_now.to_date]
+ ]
+ options.unshift(Issue::ANY_DUE_DATE)
+ options.unshift(Issue::NO_DUE_DATE)
+ options_for_select(options, params[:due_date])
+ end
+
+
# Required for Banzai::Filter::IssueReferenceFilter
module_function :url_for_issue
end
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 2f2d2721d6d..624cb7bb847 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -8,6 +8,8 @@ module SortingHelper
sort_value_oldest_created => sort_title_oldest_created,
sort_value_milestone_soon => sort_title_milestone_soon,
sort_value_milestone_later => sort_title_milestone_later,
+ sort_value_due_date_soon => sort_title_due_date_soon,
+ sort_value_due_date_later => sort_title_due_date_later,
sort_value_largest_repo => sort_title_largest_repo,
sort_value_recently_signin => sort_title_recently_signin,
sort_value_oldest_signin => sort_title_oldest_signin,
@@ -50,6 +52,14 @@ module SortingHelper
'Milestone due later'
end
+ def sort_title_due_date_soon
+ 'Due date soon'
+ end
+
+ def sort_title_due_date_later
+ 'Due date due later'
+ end
+
def sort_title_name
'Name'
end
@@ -98,6 +108,14 @@ module SortingHelper
'milestone_due_desc'
end
+ def sort_value_due_date_soon
+ 'due_date_asc'
+ end
+
+ def sort_value_due_date_later
+ 'due_date_desc'
+ end
+
def sort_value_name
'name_asc'
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index afa2ca039ae..691b7e104e4 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -39,6 +39,8 @@ module Issuable
scope :order_milestone_due_asc, -> { joins(:milestone).reorder('milestones.due_date ASC, milestones.id ASC') }
scope :with_label, ->(title) { joins(:labels).where(labels: { title: title }) }
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
+ scope :has_due_date, ->{ where("issues.due_date IS NOT NULL") }
+ scope :no_due_date, ->{ where("issues.due_date IS NULL")}
scope :join_project, -> { joins(:project) }
scope :references_project, -> { references(:project) }
diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb
index 8b47b9e0abd..c88a8f5ceb8 100644
--- a/app/models/concerns/sortable.rb
+++ b/app/models/concerns/sortable.rb
@@ -18,6 +18,8 @@ module Sortable
scope :order_updated_asc, -> { reorder(updated_at: :asc) }
scope :order_name_asc, -> { reorder(name: :asc) }
scope :order_name_desc, -> { reorder(name: :desc) }
+ scope :due_date_asc, -> { reorder(due_date: :asc) }
+ scope :due_date_desc, -> { reorder("due_date IS NULL, due_date DESC") }
end
module ClassMethods
@@ -31,6 +33,8 @@ module Sortable
when 'created_desc' then order_created_desc
when 'id_desc' then order_id_desc
when 'id_asc' then order_id_asc
+ when 'due_date_asc' then due_date_asc
+ when 'due_date_desc' then due_date_desc
else
all
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index a009e235b37..ee5be904330 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -28,6 +28,9 @@ class Issue < ActiveRecord::Base
include Sortable
include Taskable
+ NO_DUE_DATE = ['No Due Date', '0']
+ ANY_DUE_DATE = ['Any Due Date', '']
+
ActsAsTaggableOn.strict_case_match = true
belongs_to :project
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 7a8009f6da4..c4feb6d3e18 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -48,6 +48,10 @@
= link_to namespace_project_issues_path(issue.project.namespace, issue.project, milestone_title: issue.milestone.title) do
= icon('clock-o')
= issue.milestone.title
+ - if issue.due_date
+ &nbsp;
+ = icon('calendar')
+ = issue.due_date.to_s(:medium)
- if issue.labels.any?
&nbsp;
- issue.labels.each do |label|
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
index e3a6a5a68b6..80971309da7 100644
--- a/app/views/shared/_sort_dropdown.html.haml
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -20,6 +20,10 @@
= sort_title_milestone_soon
= link_to page_filter_path(sort: sort_value_milestone_later) do
= sort_title_milestone_later
+ = link_to page_filter_path(sort: sort_value_due_date_soon) do
+ = sort_title_due_date_soon if controller_name == "issues"
+ = link_to page_filter_path(sort: sort_value_due_date_later) do
+ = sort_title_due_date_later if controller_name == "issues"
= link_to page_filter_path(sort: sort_value_upvotes) do
= sort_title_upvotes
= link_to page_filter_path(sort: sort_value_downvotes) do
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index ade0a56b2e7..f832f430b2b 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -23,6 +23,13 @@
.filter-item.inline.labels-filter
= render "shared/issuable/label_dropdown"
+
+ - if controller.controller_name == 'issues'
+ .filter-item.inline.due_date-filter
+ = select_tag('due_date', due_date_options,
+ class: 'select2 trigger-submit', include_blank: true,
+ data: {placeholder: 'Due Date'})
+
.pull-right
= render 'shared/sort_dropdown'
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 03a615d191c..fb2c727d57a 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -74,6 +74,31 @@
.selectbox.hide-collapsed
= f.hidden_field 'milestone_id', value: issuable.milestone_id, id: nil
= dropdown_tag('Milestone', options: { title: 'Assign milestone', toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: 'Search milestones', data: { show_no: true, field_name: "#{issuable.to_ability_name}[milestone_id]", project_id: @project.id, issuable_id: issuable.id, milestones: namespace_project_milestones_path(@project.namespace, @project, :json), ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), use_id: true }})
+ - if issuable.has_attribute? :due_date
+ .block.due_date
+ .sidebar-collapsed-icon
+ = icon('calendar')
+ %span
+ - if issuable.due_date
+ = icon('calendar')
+ = issuable.due_date.to_s(:medium)
+ - else
+ .light None
+ .title.hide-collapsed
+ %label
+ Due Date
+ - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+ .pull-right
+ = link_to 'Edit', '#', class: 'edit-link'
+ .value.hide-collapsed
+ - if issuable.due_date
+ = icon('calendar')
+ = issuable.due_date.to_s(:medium)
+ - else
+ .light None
+ .selectbox.hide-collapsed
+ = f.text_field :due_date
+ = hidden_field_tag :issuable_context
- if issuable.project.labels.any?
.block.labels