Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
iv
gitlab-ce
Commits
82d8c74f
Commit
82d8c74f
authored
Apr 20, 2016
by
Robert Speicher
Committed by
Yorick Peterse
Apr 21, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Merge branch 'due-date-frontend' into 'master'
Add due date to issues Closes: #12709 See merge request !3614
parent
7046aedd
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
441 additions
and
18 deletions
+441
-18
CHANGELOG
CHANGELOG
+1
-0
app/assets/javascripts/due_date_select.js.coffee
app/assets/javascripts/due_date_select.js.coffee
+64
-0
app/assets/javascripts/issuable_context.js.coffee
app/assets/javascripts/issuable_context.js.coffee
+0
-1
app/assets/stylesheets/framework/dropdowns.scss
app/assets/stylesheets/framework/dropdowns.scss
+128
-2
app/assets/stylesheets/framework/variables.scss
app/assets/stylesheets/framework/variables.scss
+5
-0
app/assets/stylesheets/pages/issuable.scss
app/assets/stylesheets/pages/issuable.scss
+2
-2
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+1
-1
app/finders/issuable_finder.rb
app/finders/issuable_finder.rb
+37
-0
app/helpers/issues_helper.rb
app/helpers/issues_helper.rb
+13
-1
app/helpers/sorting_helper.rb
app/helpers/sorting_helper.rb
+18
-0
app/models/issue.rb
app/models/issue.rb
+27
-0
app/views/projects/issues/_issue.html.haml
app/views/projects/issues/_issue.html.haml
+5
-0
app/views/shared/_sort_dropdown.html.haml
app/views/shared/_sort_dropdown.html.haml
+5
-0
app/views/shared/issuable/_filter.html.haml
app/views/shared/issuable/_filter.html.haml
+1
-0
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+34
-5
db/migrate/20160310124959_add_due_date_to_issues.rb
db/migrate/20160310124959_add_due_date_to_issues.rb
+6
-0
db/schema.rb
db/schema.rb
+2
-0
spec/features/issues_spec.rb
spec/features/issues_spec.rb
+92
-6
No files found.
CHANGELOG
View file @
82d8c74f
...
...
@@ -16,6 +16,7 @@ v 8.7.0 (unreleased)
- Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea)
- Do not include award_emojis in issue and merge_request comment_count !3610 (Lucas Charles)
- Restrict user profiles when public visibility level is restricted.
- Add ability set due date to issues, sort and filter issues by due date (Mehmet Beydogan)
- All images in discussions and wikis now link to their source files !3464 (Connor Shea).
- Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu)
- Add setting for customizing the list of trusted proxies !3524
...
...
app/assets/javascripts/due_date_select.js.coffee
0 → 100644
View file @
82d8c74f
class
@
DueDateSelect
constructor
:
->
$loading
=
$
(
'.js-issuable-update .due_date'
)
.
find
(
'.block-loading'
)
.
hide
()
$
(
'.js-due-date-select'
).
each
(
i
,
dropdown
)
->
$dropdown
=
$
(
dropdown
)
$dropdownParent
=
$dropdown
.
closest
(
'.dropdown'
)
$datePicker
=
$dropdownParent
.
find
(
'.js-due-date-calendar'
)
$block
=
$dropdown
.
closest
(
'.block'
)
$selectbox
=
$dropdown
.
closest
(
'.selectbox'
)
$value
=
$block
.
find
(
'.value'
)
$sidebarValue
=
$
(
'.js-due-date-sidebar-value'
,
$block
)
fieldName
=
$dropdown
.
data
(
'field-name'
)
abilityName
=
$dropdown
.
data
(
'ability-name'
)
issueUpdateURL
=
$dropdown
.
data
(
'issue-update'
)
$dropdown
.
glDropdown
(
hidden
:
->
$selectbox
.
hide
()
$value
.
removeAttr
(
'style'
)
)
addDueDate
=
->
# Create the post date
value
=
$
(
"input[name='
#{
fieldName
}
']"
).
val
()
date
=
new
Date
value
.
replace
(
new
RegExp
(
'-'
,
'g'
),
','
)
mediumDate
=
$
.
datepicker
.
formatDate
'M d, yy'
,
date
data
=
{}
data
[
abilityName
]
=
{}
data
[
abilityName
].
due_date
=
value
$
.
ajax
(
type
:
'PUT'
url
:
issueUpdateURL
data
:
data
beforeSend
:
->
$loading
.
fadeIn
()
$dropdown
.
trigger
(
'loading.gl.dropdown'
)
$selectbox
.
hide
()
$value
.
removeAttr
(
'style'
)
$value
.
html
(
mediumDate
)
$sidebarValue
.
html
(
mediumDate
)
).
done
(
data
)
->
$dropdown
.
trigger
(
'loaded.gl.dropdown'
)
$dropdown
.
dropdown
(
'toggle'
)
$loading
.
fadeOut
()
$datePicker
.
datepicker
(
dateFormat
:
'yy-mm-dd'
,
defaultDate
:
$
(
"input[name='
#{
fieldName
}
']"
).
val
()
altField
:
"input[name='
#{
fieldName
}
']"
onSelect
:
->
addDueDate
()
)
$
(
document
)
.
off
'click'
,
'.ui-datepicker-header a'
.
on
'click'
,
'.ui-datepicker-header a'
,
(
e
)
->
e
.
stopImmediatePropagation
()
app/assets/javascripts/issuable_context.js.coffee
View file @
82d8c74f
...
...
@@ -33,7 +33,6 @@ class @IssuableContext
$block
.
find
(
'.dropdown-menu-toggle'
).
trigger
'click'
,
0
$
(
".right-sidebar"
).
niceScroll
()
initParticipants
:
->
...
...
app/assets/stylesheets/framework/dropdowns.scss
View file @
82d8c74f
...
...
@@ -248,7 +248,7 @@
.dropdown-title
{
position
:
relative
;
padding
:
0
25px
1
5
px
;
padding
:
0
25px
1
0
px
;
margin
:
0
10px
10px
;
font-weight
:
600
;
line-height
:
1
;
...
...
@@ -278,7 +278,7 @@
right
:
5px
;
width
:
20px
;
height
:
20px
;
top
:
-
1
px
;
top
:
-
3
px
;
}
.dropdown-menu-back
{
...
...
@@ -358,6 +358,13 @@
border-top
:
1px
solid
$dropdown-divider-color
;
}
.dropdown-due-date-footer
{
padding-top
:
0
;
margin-left
:
10px
;
margin-right
:
10px
;
border-top
:
0
;
}
.dropdown-footer-list
{
font-size
:
14px
;
...
...
@@ -395,3 +402,122 @@
height
:
15px
;
border-radius
:
$border-radius-base
;
}
.dropdown-menu-due-date
{
.dropdown-content
{
max-height
:
230px
;
}
.ui-widget
{
table
{
margin
:
0
;
}
&
.ui-datepicker-inline
{
padding
:
0
10px
;
border
:
0
;
width
:
100%
;
}
.ui-datepicker-header
{
padding
:
0
8px
10px
;
border
:
0
;
.ui-icon
{
background
:
none
;
font-size
:
20px
;
text-indent
:
0
;
&
:before
{
display
:
block
;
position
:
relative
;
top
:
-2px
;
color
:
$dropdown-title-btn-color
;
font
:
normal
normal
normal
14px
/
1
FontAwesome
;
font-size
:
inherit
;
text-rendering
:
auto
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
}
}
}
.ui-state-active
,
.ui-state-hover
{
color
:
$md-link-color
;
background-color
:
$calendar-hover-bg
;
}
.ui-datepicker-prev
,
.ui-datepicker-next
{
top
:
0
;
height
:
15px
;
cursor
:
pointer
;
&
:hover
{
background-color
:
transparent
;
border
:
0
;
.ui-icon
:before
{
color
:
$md-link-color
;
}
}
}
.ui-datepicker-prev
{
left
:
0
;
.ui-icon
:before
{
content
:
'\f104'
;
text-align
:
left
;
}
}
.ui-datepicker-next
{
right
:
0
;
.ui-icon
:before
{
content
:
'\f105'
;
text-align
:
right
;
}
}
td
{
padding
:
0
;
border
:
1px
solid
$calendar-border-color
;
&
:first-child
{
border-left
:
0
;
}
&
:last-child
{
border-right
:
0
;
}
a
{
line-height
:
17px
;
border
:
0
;
border-radius
:
0
;
}
}
.ui-datepicker-title
{
color
:
$gl-gray
;
font-size
:
15px
;
line-height
:
1
;
font-weight
:
normal
;
}
}
th
{
padding
:
2px
0
;
color
:
$calendar-header-color
;
font-weight
:
normal
;
text-transform
:
lowercase
;
border-top
:
1px
solid
$calendar-border-color
;
}
.ui-datepicker-unselectable
{
background-color
:
$calendar-unselectable-bg
;
}
}
app/assets/stylesheets/framework/variables.scss
View file @
82d8c74f
...
...
@@ -241,3 +241,8 @@ $note-form-border-color: #e5e5e5;
$note-toolbar-color
:
#959494
;
$zen-control-hover-color
:
#111
;
$calendar-header-color
:
#b8b8b8
;
$calendar-hover-bg
:
#ecf3fe
;
$calendar-border-color
:
rgba
(
#000
,
.1
);
$calendar-unselectable-bg
:
#faf9f9
;
app/assets/stylesheets/pages/issuable.scss
View file @
82d8c74f
...
...
@@ -242,7 +242,7 @@
}
}
.
btn
{
.
issuable-pager
{
background
:
$gray-normal
;
border
:
1px
solid
$border-gray-normal
;
&
:hover
{
...
...
@@ -251,7 +251,7 @@
}
}
a
:not
(
.
btn
)
{
a
:not
(
.
issuable-pager
)
{
&
:hover
{
color
:
$md-link-color
;
text-decoration
:
none
;
...
...
app/controllers/projects/issues_controller.rb
View file @
82d8c74f
...
...
@@ -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
...
...
app/finders/issuable_finder.rb
View file @
82d8c74f
...
...
@@ -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
...
...
@@ -283,6 +284,42 @@ class IssuableFinder
items
.
distinct
end
def
by_due_date
(
items
)
if
due_date?
if
filter_by_no_due_date?
items
=
items
.
without_due_date
elsif
filter_by_overdue?
items
=
items
.
due_before
(
Date
.
today
)
elsif
filter_by_due_this_week?
items
=
items
.
due_between
(
Date
.
today
.
beginning_of_week
,
Date
.
today
.
end_of_week
)
elsif
filter_by_due_this_month?
items
=
items
.
due_between
(
Date
.
today
.
beginning_of_month
,
Date
.
today
.
end_of_month
)
end
end
items
end
def
filter_by_no_due_date?
due_date?
&&
params
[
:due_date
]
==
Issue
::
NoDueDate
.
name
end
def
filter_by_overdue?
due_date?
&&
params
[
:due_date
]
==
Issue
::
Overdue
.
name
end
def
filter_by_due_this_week?
due_date?
&&
params
[
:due_date
]
==
Issue
::
DueThisWeek
.
name
end
def
filter_by_due_this_month?
due_date?
&&
params
[
:due_date
]
==
Issue
::
DueThisMonth
.
name
end
def
due_date?
params
[
:due_date
].
present?
&&
klass
.
column_names
.
include?
(
'due_date'
)
end
def
label_names
params
[
:label_name
].
split
(
','
)
end
...
...
app/helpers/issues_helper.rb
View file @
82d8c74f
...
...
@@ -131,7 +131,7 @@ module IssuesHelper
class:
"icon emoji-icon emoji-
#{
unicode
}
"
,
title:
name
,
data:
data
else
else
# Emoji icons displayed separately, used for the awards already given
# to an issue or merge request.
content_tag
:img
,
""
,
...
...
@@ -172,6 +172,18 @@ module IssuesHelper
end
.
to_h
end
def
due_date_options
options
=
[
Issue
::
AnyDueDate
,
Issue
::
NoDueDate
,
Issue
::
DueThisWeek
,
Issue
::
DueThisMonth
,
Issue
::
Overdue
]
options_from_collection_for_select
(
options
,
'name'
,
'title'
,
params
[
:due_date
])
end
# Required for Banzai::Filter::IssueReferenceFilter
module_function
:url_for_issue
end
app/helpers/sorting_helper.rb
View file @
82d8c74f
...
...
@@ -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 soon'
end
def
sort_title_due_date_later
'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
...
...
app/models/issue.rb
View file @
82d8c74f
...
...
@@ -28,6 +28,13 @@ class Issue < ActiveRecord::Base
include
Sortable
include
Taskable
DueDateStruct
=
Struct
.
new
(
:title
,
:name
).
freeze
NoDueDate
=
DueDateStruct
.
new
(
'No Due Date'
,
'0'
).
freeze
AnyDueDate
=
DueDateStruct
.
new
(
'Any Due Date'
,
''
).
freeze
Overdue
=
DueDateStruct
.
new
(
'Overdue'
,
'overdue'
).
freeze
DueThisWeek
=
DueDateStruct
.
new
(
'Due This Week'
,
'week'
).
freeze
DueThisMonth
=
DueDateStruct
.
new
(
'Due This Month'
,
'month'
).
freeze
ActsAsTaggableOn
.
strict_case_match
=
true
belongs_to
:project
...
...
@@ -39,6 +46,13 @@ class Issue < ActiveRecord::Base
scope
:open_for
,
->
(
user
)
{
opened
.
assigned_to
(
user
)
}
scope
:in_projects
,
->
(
project_ids
)
{
where
(
project_id:
project_ids
)
}
scope
:without_due_date
,
->
{
where
(
due_date:
nil
)
}
scope
:due_before
,
->
(
date
)
{
where
(
'issues.due_date < ?'
,
date
)
}
scope
:due_between
,
->
(
from_date
,
to_date
)
{
where
(
'issues.due_date >= ?'
,
from_date
).
where
(
'issues.due_date <= ?'
,
to_date
)
}
scope
:order_due_date_asc
,
->
{
reorder
(
'issues.due_date IS NULL, issues.due_date ASC'
)
}
scope
:order_due_date_desc
,
->
{
reorder
(
'issues.due_date IS NULL, issues.due_date DESC'
)
}
state_machine
:state
,
initial: :opened
do
event
:close
do
transition
[
:reopened
,
:opened
]
=>
:closed
...
...
@@ -82,6 +96,15 @@ class Issue < ActiveRecord::Base
@link_reference_pattern
||=
super
(
"issues"
,
/(?<issue>\d+)/
)
end
def
self
.
sort
(
method
)
case
method
.
to_s
when
'due_date_asc'
then
order_due_date_asc
when
'due_date_desc'
then
order_due_date_desc
else
super
end
end
def
to_reference
(
from_project
=
nil
)
reference
=
"
#{
self
.
class
.
reference_prefix
}#{
iid
}
"
...
...
@@ -169,4 +192,8 @@ class Issue < ActiveRecord::Base
self
.
related_branches
(
current_user
).
empty?
&&
self
.
closed_by_merge_requests
(
current_user
).
empty?
end
def
overdue?
due_date
.
try
(
:past?
)
||
false
end
end
app/views/projects/issues/_issue.html.haml
View file @
82d8c74f
...
...
@@ -48,6 +48,11 @@
=
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
%span
{
class:
"#{'cred' if issue.overdue?}"
}
=
icon
(
'calendar'
)
=
issue
.
due_date
.
to_s
(
:medium
)
-
if
issue
.
labels
.
any?
-
issue
.
labels
.
each
do
|
label
|
...
...
app/views/shared/_sort_dropdown.html.haml
View file @
82d8c74f
...
...
@@ -20,6 +20,11 @@
=
sort_title_milestone_soon
=
link_to
page_filter_path
(
sort:
sort_value_milestone_later
)
do
=
sort_title_milestone_later
-
if
controller
.
controller_name
==
'issues'
||
controller
.
action_name
==
'issues'
=
link_to
page_filter_path
(
sort:
sort_value_due_date_soon
)
do
=
sort_title_due_date_soon
=
link_to
page_filter_path
(
sort:
sort_value_due_date_later
)
do
=
sort_title_due_date_later
=
link_to
page_filter_path
(
sort:
sort_value_upvotes
)
do
=
sort_title_upvotes
=
link_to
page_filter_path
(
sort:
sort_value_downvotes
)
do
...
...
app/views/shared/issuable/_filter.html.haml
View file @
82d8c74f
...
...
@@ -23,6 +23,7 @@
.filter-item.inline.labels-filter
=
render
"shared/issuable/label_dropdown"
.pull-right
=
render
'shared/sort_dropdown'
...
...
app/views/shared/issuable/_sidebar.html.haml
View file @
82d8c74f
...
...
@@ -10,14 +10,14 @@
=
sidebar_gutter_toggle_icon
.issuable-nav.hide-collapsed.pull-right.btn-group
{
role:
'group'
,
"aria-label"
=>
'...'
}
-
if
prev_issuable
=
prev_issuable_for
(
issuable
)
=
link_to
'Prev'
,
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
prev_issuable
],
class:
'btn btn-default prev-btn'
=
link_to
'Prev'
,
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
prev_issuable
],
class:
'btn btn-default prev-btn
issuable-pager
'
-
else
%a
.btn.btn-default.disabled
{
href:
'#'
}
%a
.btn.btn-default.
issuable-pager.
disabled
{
href:
'#'
}
Prev
-
if
next_issuable
=
next_issuable_for
(
issuable
)
=
link_to
'Next'
,
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
next_issuable
],
class:
'btn btn-default next-btn'
=
link_to
'Next'
,
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
next_issuable
],
class:
'btn btn-default next-btn
issuable-pager
'
-
else
%a
.btn.btn-default.disabled
{
href:
'#'
}
%a
.btn.btn-default.
issuable-pager.
disabled
{
href:
'#'
}
Next
=
form_for
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
issuable
],
remote:
true
,
html:
{
class:
'issuable-context-form inline-update js-issuable-update'
}
do
|
f
|
...
...
@@ -58,7 +58,7 @@
-
if
issuable
.
milestone
=
issuable
.
milestone
.
title
-
else
No
No
ne
.title.hide-collapsed
Milestone
=
icon
(
'spinner spin'
,
class:
'block-loading'
)
...
...
@@ -75,6 +75,34 @@
=
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
.js-due-date-sidebar-value
=
issuable
.
due_date
.
try
(
:to_s
,
:medium
)
||
'None'
.title.hide-collapsed
Due date
=
icon
(
'spinner spin'
,
class:
'block-loading'
)
-
if
can?
(
current_user
,
:"admin_
#{
issuable
.
to_ability_name
}
"
,
@project
)
=
link_to
'Edit'
,
'#'
,
class:
'edit-link pull-right'
.value.bold.hide-collapsed
-
if
issuable
.
due_date
=
issuable
.
due_date
.
to_s
(
:medium
)
-
else
.light
None
-
if
can?
(
current_user
,
:"admin_
#{
issuable
.
to_ability_name
}
"
,
@project
)
.selectbox.hide-collapsed
=
f
.
hidden_field
:due_date
,
value:
issuable
.
due_date
.dropdown
%button
.dropdown-menu-toggle.js-due-date-select
{
type:
'button'
,
data:
{
toggle:
'dropdown'
,
field_name:
"#{issuable.to_ability_name}[due_date]"
,
ability_name:
issuable
.
to_ability_name
,
issue_update:
issuable_json_path
(
issuable
)
}
}
%span
.dropdown-toggle-text
Due date
=
icon
(
'chevron-down'
)
.dropdown-menu.dropdown-menu-due-date
=
dropdown_title
(
'Due date'
)
=
dropdown_content
do
.js-due-date-calendar
-
if
issuable
.
project
.
labels
.
any?
.block.labels
.sidebar-collapsed-icon
...
...
@@ -154,3 +182,4 @@
new
IssuableContext
(
'
#{
escape_javascript
(
current_user
.
to_json
(
only:
[
:username
,
:id
,
:name
]))
}
'
);
new
Subscription
(
'
.subscription
'
)
new
Sidebar
();
new
DueDateSelect
();
db/migrate/20160310124959_add_due_date_to_issues.rb
0 → 100644
View file @
82d8c74f
class
AddDueDateToIssues
<
ActiveRecord
::
Migration
def
change
add_column
:issues
,
:due_date
,
:date
add_index
:issues
,
:due_date
end
end
db/schema.rb
View file @
82d8c74f
...
...
@@ -422,6 +422,7 @@ ActiveRecord::Schema.define(version: 20160419120017) do
t
.
integer
"moved_to_id"
t
.
boolean
"confidential"
,
default:
false
t
.
datetime
"deleted_at"
t
.
date
"due_date"
end
add_index
"issues"
,
[
"assignee_id"
],
name:
"index_issues_on_assignee_id"
,
using: :btree
...
...
@@ -431,6 +432,7 @@ ActiveRecord::Schema.define(version: 20160419120017) do
add_index
"issues"
,
[
"created_at"
],
name:
"index_issues_on_created_at"
,
using: :btree
add_index
"issues"
,
[
"deleted_at"
],
name:
"index_issues_on_deleted_at"
,
using: :btree
add_index
"issues"
,
[
"description"
],
name:
"index_issues_on_description_trigram"
,
using: :gin
,
opclasses:
{
"description"
=>
"gin_trgm_ops"
}
add_index
"issues"
,
[
"due_date"
],
name:
"index_issues_on_due_date"
,
using: :btree
add_index
"issues"
,
[
"milestone_id"
],
name:
"index_issues_on_milestone_id"
,
using: :btree
add_index
"issues"
,
[
"project_id"
,
"iid"
],
name:
"index_issues_on_project_id_and_iid"
,
unique:
true
,
using: :btree
add_index
"issues"
,
[
"project_id"
],
name:
"index_issues_on_project_id"
,
using: :btree
...
...
spec/features/issues_spec.rb
View file @
82d8c74f
...
...
@@ -112,7 +112,7 @@ describe 'Issues', feature: true do
end
describe
'filter issue'
do
titles
=
[
'foo'
,
'bar'
,
'baz'
]
titles
=
%w[foo bar baz
]
titles
.
each_with_index
do
|
title
,
index
|
let!
(
title
.
to_sym
)
do
create
(
:issue
,
title:
title
,
...
...
@@ -153,8 +153,94 @@ describe 'Issues', feature: true do
expect
(
first_issue
).
to
include
(
'baz'
)
end
describe
'sorting by due date'
do
before
do
foo
.
update
(
due_date:
1
.
day
.
from_now
)
bar
.
update
(
due_date:
6
.
days
.
from_now
)
end
it
'sorts by recently due date'
do
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
sort:
sort_value_due_date_soon
)
expect
(
first_issue
).
to
include
(
'foo'
)
end
it
'sorts by least recently due date'
do
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
sort:
sort_value_due_date_later
)
expect
(
first_issue
).
to
include
(
'bar'
)
end
it
'sorts by least recently due date by excluding nil due dates'
do
bar
.
update
(
due_date:
nil
)
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
sort:
sort_value_due_date_later
)
expect
(
first_issue
).
to
include
(
'foo'
)
end
end
describe
'filtering by due date'
do
before
do
foo
.
update
(
due_date:
1
.
day
.
from_now
)
bar
.
update
(
due_date:
6
.
days
.
from_now
)
end
it
'filters by none'
do
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
due_date:
Issue
::
NoDueDate
.
name
)
expect
(
page
).
not_to
have_content
(
'foo'
)
expect
(
page
).
not_to
have_content
(
'bar'
)
expect
(
page
).
to
have_content
(
'baz'
)
end
it
'filters by any'
do
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
due_date:
Issue
::
AnyDueDate
.
name
)
expect
(
page
).
to
have_content
(
'foo'
)
expect
(
page
).
to
have_content
(
'bar'
)
expect
(
page
).
to
have_content
(
'baz'
)
end
it
'filters by due this week'
do
foo
.
update
(
due_date:
Date
.
today
.
beginning_of_week
+
2
.
days
)
bar
.
update
(
due_date:
Date
.
today
.
end_of_week
)
baz
.
update
(
due_date:
Date
.
today
-
8
.
days
)
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
due_date:
Issue
::
DueThisWeek
.
name
)
expect
(
page
).
to
have_content
(
'foo'
)
expect
(
page
).
to
have_content
(
'bar'
)
expect
(
page
).
not_to
have_content
(
'baz'
)
end
it
'filters by due this month'
do
foo
.
update
(
due_date:
Date
.
today
.
beginning_of_month
+
2
.
days
)
bar
.
update
(
due_date:
Date
.
today
.
end_of_month
)
baz
.
update
(
due_date:
Date
.
today
-
50
.
days
)
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
due_date:
Issue
::
DueThisMonth
.
name
)
expect
(
page
).
to
have_content
(
'foo'
)
expect
(
page
).
to
have_content
(
'bar'
)
expect
(
page
).
not_to
have_content
(
'baz'
)
end
it
'filters by overdue'
do
foo
.
update
(
due_date:
Date
.
today
+
2
.
days
)
bar
.
update
(
due_date:
Date
.
today
+
20
.
days
)
baz
.
update
(
due_date:
Date
.
yesterday
)
visit
namespace_project_issues_path
(
project
.
namespace
,
project
,
due_date:
Issue
::
Overdue
.
name
)
expect
(
page
).
not_to
have_content
(
'foo'
)
expect
(
page
).
not_to
have_content
(
'bar'
)
expect
(
page
).
to
have_content
(
'baz'
)
end
end
describe
'sorting by milestone'
do
before
:each
do
before
do
foo
.
milestone
=
newer_due_milestone
foo
.
save
bar
.
milestone
=
later_due_milestone
...
...
@@ -177,7 +263,7 @@ describe 'Issues', feature: true do
describe
'combine filter and sort'
do
let
(
:user2
)
{
create
(
:user
)
}
before
:each
do
before
do
foo
.
assignee
=
user2
foo
.
save
bar
.
assignee
=
user2
...
...
@@ -224,7 +310,7 @@ describe 'Issues', feature: true do
let
(
:guest
)
{
create
(
:user
)
}
before
:each
do
before
do
project
.
team
<<
[[
guest
],
:guest
]
end
...
...
@@ -267,7 +353,7 @@ describe 'Issues', feature: true do
context
'by unauthorized user'
do
let
(
:guest
)
{
create
(
:user
)
}
before
:each
do
before
do
project
.
team
<<
[
guest
,
:guest
]
issue
.
milestone
=
milestone
issue
.
save
...
...
@@ -285,7 +371,7 @@ describe 'Issues', feature: true do
describe
'removing assignee'
do
let
(
:user2
)
{
create
(
:user
)
}
before
:each
do
before
do
issue
.
assignee
=
user2
issue
.
save
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment