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
Boxiang Sun
gitlab-ce
Commits
f2b34fb2
Commit
f2b34fb2
authored
Jun 02, 2017
by
Winnie Hellmann
Committed by
Phil Hughes
Jun 02, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Show current user immediately in issuable filters
parent
5cb8ad6c
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
266 additions
and
22 deletions
+266
-22
app/assets/javascripts/droplab/keyboard.js
app/assets/javascripts/droplab/keyboard.js
+1
-1
app/assets/javascripts/droplab/plugins/ajax_filter.js
app/assets/javascripts/droplab/plugins/ajax_filter.js
+3
-0
app/assets/javascripts/filtered_search/dropdown_user.js
app/assets/javascripts/filtered_search/dropdown_user.js
+8
-0
app/helpers/avatars_helper.rb
app/helpers/avatars_helper.rb
+15
-5
app/views/shared/issuable/_search_bar.html.haml
app/views/shared/issuable/_search_bar.html.haml
+13
-16
app/views/shared/issuable/_user_dropdown_item.html.haml
app/views/shared/issuable/_user_dropdown_item.html.haml
+11
-0
changelogs/unreleased/winh-current-user-filter.yml
changelogs/unreleased/winh-current-user-filter.yml
+4
-0
spec/features/issues/filtered_search/dropdown_assignee_spec.rb
...features/issues/filtered_search/dropdown_assignee_spec.rb
+19
-0
spec/features/issues/filtered_search/dropdown_author_spec.rb
spec/features/issues/filtered_search/dropdown_author_spec.rb
+19
-0
spec/helpers/avatars_helper_spec.rb
spec/helpers/avatars_helper_spec.rb
+101
-0
spec/javascripts/droplab/plugins/ajax_filter_spec.js
spec/javascripts/droplab/plugins/ajax_filter_spec.js
+72
-0
No files found.
app/assets/javascripts/droplab/keyboard.js
View file @
f2b34fb2
...
@@ -8,7 +8,7 @@ const Keyboard = function () {
...
@@ -8,7 +8,7 @@ const Keyboard = function () {
var
isUpArrow
=
false
;
var
isUpArrow
=
false
;
var
isDownArrow
=
false
;
var
isDownArrow
=
false
;
var
removeHighlight
=
function
removeHighlight
(
list
)
{
var
removeHighlight
=
function
removeHighlight
(
list
)
{
var
itemElements
=
Array
.
prototype
.
slice
.
call
(
list
.
list
.
querySelectorAll
(
'
li:not(.divider)
'
),
0
);
var
itemElements
=
Array
.
prototype
.
slice
.
call
(
list
.
list
.
querySelectorAll
(
'
li:not(.divider)
:not(.hidden)
'
),
0
);
var
listItems
=
[];
var
listItems
=
[];
for
(
var
i
=
0
;
i
<
itemElements
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
itemElements
.
length
;
i
++
)
{
var
listItem
=
itemElements
[
i
];
var
listItem
=
itemElements
[
i
];
...
...
app/assets/javascripts/droplab/plugins/ajax_filter.js
View file @
f2b34fb2
...
@@ -63,6 +63,9 @@ const AjaxFilter = {
...
@@ -63,6 +63,9 @@ const AjaxFilter = {
return
AjaxCache
.
retrieve
(
url
)
return
AjaxCache
.
retrieve
(
url
)
.
then
((
data
)
=>
{
.
then
((
data
)
=>
{
this
.
_loadData
(
data
,
config
);
this
.
_loadData
(
data
,
config
);
if
(
config
.
onLoadingFinished
)
{
config
.
onLoadingFinished
(
data
);
}
})
})
.
catch
(
config
.
onError
);
.
catch
(
config
.
onError
);
},
},
...
...
app/assets/javascripts/filtered_search/dropdown_user.js
View file @
f2b34fb2
...
@@ -18,6 +18,9 @@ class DropdownUser extends gl.FilteredSearchDropdown {
...
@@ -18,6 +18,9 @@ class DropdownUser extends gl.FilteredSearchDropdown {
},
},
searchValueFunction
:
this
.
getSearchInput
.
bind
(
this
),
searchValueFunction
:
this
.
getSearchInput
.
bind
(
this
),
loadingTemplate
:
this
.
loadingTemplate
,
loadingTemplate
:
this
.
loadingTemplate
,
onLoadingFinished
:
()
=>
{
this
.
hideCurrentUser
();
},
onError
()
{
onError
()
{
/* eslint-disable no-new */
/* eslint-disable no-new */
new
Flash
(
'
An error occured fetching the dropdown data.
'
);
new
Flash
(
'
An error occured fetching the dropdown data.
'
);
...
@@ -28,6 +31,11 @@ class DropdownUser extends gl.FilteredSearchDropdown {
...
@@ -28,6 +31,11 @@ class DropdownUser extends gl.FilteredSearchDropdown {
this
.
tokenKeys
=
tokenKeys
;
this
.
tokenKeys
=
tokenKeys
;
}
}
hideCurrentUser
()
{
const
currenUserItem
=
this
.
dropdown
.
querySelector
(
'
.js-current-user
'
);
currenUserItem
.
classList
.
add
(
'
hidden
'
);
}
itemClicked
(
e
)
{
itemClicked
(
e
)
{
super
.
itemClicked
(
e
,
super
.
itemClicked
(
e
,
selected
=>
selected
.
querySelector
(
'
.dropdown-light-content
'
).
innerText
.
trim
());
selected
=>
selected
.
querySelector
(
'
.dropdown-light-content
'
).
innerText
.
trim
());
...
...
app/helpers/avatars_helper.rb
View file @
f2b34fb2
...
@@ -8,18 +8,28 @@ module AvatarsHelper
...
@@ -8,18 +8,28 @@ module AvatarsHelper
}))
}))
end
end
def
user_avatar
(
options
=
{})
def
user_avatar
_without_link
(
options
=
{})
avatar_size
=
options
[
:size
]
||
16
avatar_size
=
options
[
:size
]
||
16
user_name
=
options
[
:user
].
try
(
:name
)
||
options
[
:user_name
]
user_name
=
options
[
:user
].
try
(
:name
)
||
options
[
:user_name
]
css_class
=
options
[
:css_class
]
||
''
css_class
=
options
[
:css_class
]
||
''
avatar_url
=
options
[
:url
]
||
avatar_icon
(
options
[
:user
]
||
options
[
:user_email
],
avatar_size
)
avatar
=
image_tag
(
data_attributes
=
{
container:
'body'
}
avatar_icon
(
options
[
:user
]
||
options
[
:user_email
],
avatar_size
),
if
options
[
:lazy
]
data_attributes
[
:src
]
=
avatar_url
end
image_tag
(
options
[
:lazy
]
?
''
:
avatar_url
,
class:
"avatar has-tooltip s
#{
avatar_size
}
#{
css_class
}
"
,
class:
"avatar has-tooltip s
#{
avatar_size
}
#{
css_class
}
"
,
alt:
"
#{
user_name
}
's avatar"
,
alt:
"
#{
user_name
}
's avatar"
,
title:
user_name
,
title:
user_name
,
data:
{
container:
'body'
}
data:
data_attributes
)
)
end
def
user_avatar
(
options
=
{})
avatar
=
user_avatar_without_link
(
options
)
if
options
[
:user
]
if
options
[
:user
]
link_to
(
avatar
,
user_path
(
options
[
:user
]))
link_to
(
avatar
,
user_path
(
options
[
:user
]))
...
...
app/views/shared/issuable/_search_bar.html.haml
View file @
f2b34fb2
...
@@ -46,30 +46,27 @@
...
@@ -46,30 +46,27 @@
%span
.js-filter-tag.dropdown-light-content
%span
.js-filter-tag.dropdown-light-content
{{tag}}
{{tag}}
#js-dropdown-author
.filtered-search-input-dropdown-menu.dropdown-menu
#js-dropdown-author
.filtered-search-input-dropdown-menu.dropdown-menu
-
if
current_user
%ul
{
data:
{
dropdown:
true
}
}
=
render
'shared/issuable/user_dropdown_item'
,
user:
current_user
%ul
.filter-dropdown
{
data:
{
dynamic:
true
,
dropdown:
true
}
}
%ul
.filter-dropdown
{
data:
{
dynamic:
true
,
dropdown:
true
}
}
%li
.filter-dropdown-item
=
render
'shared/issuable/user_dropdown_item'
,
%button
.btn.btn-link.dropdown-user
user:
User
.
new
(
username:
'{{username}}'
,
name:
'{{name}}'
),
%img
.avatar
{
alt:
'
{{
name
}}\
's avatar'
,
width:
'30'
,
data:
{
src:
'
{{
avatar_url
}}
'
}
}
avatar:
{
lazy:
true
,
url:
'{{avatar_url}}'
}
.dropdown-user-details
%span
{{name}}
%span
.dropdown-light-content
@{{username}}
#js-dropdown-assignee
.filtered-search-input-dropdown-menu.dropdown-menu
#js-dropdown-assignee
.filtered-search-input-dropdown-menu.dropdown-menu
%ul
{
data:
{
dropdown:
true
}
}
%ul
{
data:
{
dropdown:
true
}
}
%li
.filter-dropdown-item
{
data:
{
value:
'none'
}
}
%li
.filter-dropdown-item
{
data:
{
value:
'none'
}
}
%button
.btn.btn-link
%button
.btn.btn-link
No Assignee
No Assignee
%li
.divider
%li
.divider
-
if
current_user
=
render
'shared/issuable/user_dropdown_item'
,
user:
current_user
%ul
.filter-dropdown
{
data:
{
dynamic:
true
,
dropdown:
true
}
}
%ul
.filter-dropdown
{
data:
{
dynamic:
true
,
dropdown:
true
}
}
%li
.filter-dropdown-item
=
render
'shared/issuable/user_dropdown_item'
,
%button
.btn.btn-link.dropdown-user
user:
User
.
new
(
username:
'{{username}}'
,
name:
'{{name}}'
),
%img
.avatar
{
alt:
'
{{
name
}}\
's avatar'
,
width:
'30'
,
data:
{
src:
'
{{
avatar_url
}}
'
}
}
avatar:
{
lazy:
true
,
url:
'{{avatar_url}}'
}
.dropdown-user-details
%span
{{name}}
%span
.dropdown-light-content
@{{username}}
#js-dropdown-milestone
.filtered-search-input-dropdown-menu.dropdown-menu
#js-dropdown-milestone
.filtered-search-input-dropdown-menu.dropdown-menu
%ul
{
data:
{
dropdown:
true
}
}
%ul
{
data:
{
dropdown:
true
}
}
%li
.filter-dropdown-item
{
data:
{
value:
'none'
}
}
%li
.filter-dropdown-item
{
data:
{
value:
'none'
}
}
...
...
app/views/shared/issuable/_user_dropdown_item.html.haml
0 → 100644
View file @
f2b34fb2
-
user
=
local_assigns
.
fetch
(
:user
)
-
avatar
=
local_assigns
.
fetch
(
:avatar
,
{
})
%li
.filter-dropdown-item
{
class:
(
'js-current-user'
if
user
==
current_user
)
}
%button
.btn.btn-link.dropdown-user
{
type: :button
}
=
user_avatar_without_link
(
user:
user
,
lazy:
avatar
[
:lazy
],
url:
avatar
[
:url
],
size:
30
)
.dropdown-user-details
%span
=
user
.
name
%span
.dropdown-light-content
=
user
.
to_reference
changelogs/unreleased/winh-current-user-filter.yml
0 → 100644
View file @
f2b34fb2
---
title
:
Show current user immediately in issuable filters
merge_request
:
11630
author
:
spec/features/issues/filtered_search/dropdown_assignee_spec.rb
View file @
f2b34fb2
...
@@ -157,6 +157,25 @@ describe 'Dropdown assignee', :feature, :js do
...
@@ -157,6 +157,25 @@ describe 'Dropdown assignee', :feature, :js do
end
end
end
end
describe
'selecting from dropdown without Ajax call'
do
before
do
Gitlab
::
Testing
::
RequestBlockerMiddleware
.
block_requests!
filtered_search
.
set
(
'assignee:'
)
end
after
do
Gitlab
::
Testing
::
RequestBlockerMiddleware
.
allow_requests!
end
it
'selects current user'
do
find
(
'#js-dropdown-assignee .filter-dropdown-item'
,
text:
user
.
username
).
click
expect
(
page
).
to
have_css
(
js_dropdown_assignee
,
visible:
false
)
expect_tokens
([{
name:
'assignee'
,
value:
user
.
username
}])
expect_filtered_search_input_empty
end
end
describe
'input has existing content'
do
describe
'input has existing content'
do
it
'opens assignee dropdown with existing search term'
do
it
'opens assignee dropdown with existing search term'
do
filtered_search
.
set
(
'searchTerm assignee:'
)
filtered_search
.
set
(
'searchTerm assignee:'
)
...
...
spec/features/issues/filtered_search/dropdown_author_spec.rb
View file @
f2b34fb2
...
@@ -135,6 +135,25 @@ describe 'Dropdown author', js: true, feature: true do
...
@@ -135,6 +135,25 @@ describe 'Dropdown author', js: true, feature: true do
end
end
end
end
describe
'selecting from dropdown without Ajax call'
do
before
do
Gitlab
::
Testing
::
RequestBlockerMiddleware
.
block_requests!
filtered_search
.
set
(
'author:'
)
end
after
do
Gitlab
::
Testing
::
RequestBlockerMiddleware
.
allow_requests!
end
it
'selects current user'
do
find
(
'#js-dropdown-author .filter-dropdown-item'
,
text:
user
.
username
).
click
expect
(
page
).
to
have_css
(
js_dropdown_author
,
visible:
false
)
expect_tokens
([{
name:
'author'
,
value:
user
.
username
}])
expect_filtered_search_input_empty
end
end
describe
'input has existing content'
do
describe
'input has existing content'
do
it
'opens author dropdown with existing search term'
do
it
'opens author dropdown with existing search term'
do
filtered_search
.
set
(
'searchTerm author:'
)
filtered_search
.
set
(
'searchTerm author:'
)
...
...
spec/helpers/avatars_helper_spec.rb
View file @
f2b34fb2
require
'rails_helper'
require
'rails_helper'
describe
AvatarsHelper
do
describe
AvatarsHelper
do
include
ApplicationHelper
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
describe
'#user_avatar'
do
describe
'#user_avatar'
do
...
@@ -18,4 +20,103 @@ describe AvatarsHelper do
...
@@ -18,4 +20,103 @@ describe AvatarsHelper do
is_expected
.
to
include
(
CGI
.
escapeHTML
(
user
.
avatar_url
(
size:
16
)))
is_expected
.
to
include
(
CGI
.
escapeHTML
(
user
.
avatar_url
(
size:
16
)))
end
end
end
end
describe
'#user_avatar_without_link'
do
let
(
:options
)
{
{
user:
user
}
}
subject
{
helper
.
user_avatar_without_link
(
options
)
}
it
'displays user avatar'
do
is_expected
.
to
eq
image_tag
(
avatar_icon
(
user
,
16
),
class:
'avatar has-tooltip s16 '
,
alt:
"
#{
user
.
name
}
's avatar"
,
title:
user
.
name
,
data:
{
container:
'body'
}
)
end
context
'with css_class parameter'
do
let
(
:options
)
{
{
user:
user
,
css_class:
'.cat-pics'
}
}
it
'uses provided css_class'
do
is_expected
.
to
eq
image_tag
(
avatar_icon
(
user
,
16
),
class:
"avatar has-tooltip s16
#{
options
[
:css_class
]
}
"
,
alt:
"
#{
user
.
name
}
's avatar"
,
title:
user
.
name
,
data:
{
container:
'body'
}
)
end
end
context
'with lazy parameter'
do
let
(
:options
)
{
{
user:
user
,
lazy:
true
}
}
it
'uses data-src instead of src'
do
is_expected
.
to
eq
image_tag
(
''
,
class:
'avatar has-tooltip s16 '
,
alt:
"
#{
user
.
name
}
's avatar"
,
title:
user
.
name
,
data:
{
container:
'body'
,
src:
avatar_icon
(
user
,
16
)
}
)
end
end
context
'with size parameter'
do
let
(
:options
)
{
{
user:
user
,
size:
99
}
}
it
'uses provided size'
do
is_expected
.
to
eq
image_tag
(
avatar_icon
(
user
,
options
[
:size
]),
class:
"avatar has-tooltip s
#{
options
[
:size
]
}
"
,
alt:
"
#{
user
.
name
}
's avatar"
,
title:
user
.
name
,
data:
{
container:
'body'
}
)
end
end
context
'with url parameter'
do
let
(
:options
)
{
{
user:
user
,
url:
'/over/the/rainbow.png'
}
}
it
'uses provided url'
do
is_expected
.
to
eq
image_tag
(
options
[
:url
],
class:
'avatar has-tooltip s16 '
,
alt:
"
#{
user
.
name
}
's avatar"
,
title:
user
.
name
,
data:
{
container:
'body'
}
)
end
end
context
'with user_name parameter'
do
let
(
:options
)
{
{
user_name:
'Tinky Winky'
,
user_email:
'no@f.un'
}
}
context
'with user parameter'
do
let
(
:options
)
{
{
user:
user
,
user_name:
'Tinky Winky'
}
}
it
'prefers user parameter'
do
is_expected
.
to
eq
image_tag
(
avatar_icon
(
user
,
16
),
class:
'avatar has-tooltip s16 '
,
alt:
"
#{
user
.
name
}
's avatar"
,
title:
user
.
name
,
data:
{
container:
'body'
}
)
end
end
it
'uses user_name and user_email parameter if user is not present'
do
is_expected
.
to
eq
image_tag
(
avatar_icon
(
options
[
:user_email
],
16
),
class:
'avatar has-tooltip s16 '
,
alt:
"
#{
options
[
:user_name
]
}
's avatar"
,
title:
options
[
:user_name
],
data:
{
container:
'body'
}
)
end
end
end
end
end
spec/javascripts/droplab/plugins/ajax_filter_spec.js
0 → 100644
View file @
f2b34fb2
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
AjaxFilter
from
'
~/droplab/plugins/ajax_filter
'
;
describe
(
'
AjaxFilter
'
,
()
=>
{
let
dummyConfig
;
const
dummyData
=
'
dummy data
'
;
let
dummyList
;
beforeEach
(()
=>
{
dummyConfig
=
{
endpoint
:
'
dummy endpoint
'
,
searchKey
:
'
dummy search key
'
,
};
dummyList
=
{
data
:
[],
list
:
document
.
createElement
(
'
div
'
),
};
AjaxFilter
.
hook
=
{
config
:
{
AjaxFilter
:
dummyConfig
,
},
list
:
dummyList
,
};
});
describe
(
'
trigger
'
,
()
=>
{
let
ajaxSpy
;
beforeEach
(()
=>
{
spyOn
(
AjaxCache
,
'
retrieve
'
).
and
.
callFake
(
url
=>
ajaxSpy
(
url
));
spyOn
(
AjaxFilter
,
'
_loadData
'
);
dummyConfig
.
onLoadingFinished
=
jasmine
.
createSpy
(
'
spy
'
);
const
dynamicList
=
document
.
createElement
(
'
div
'
);
dynamicList
.
dataset
.
dynamic
=
true
;
dummyList
.
list
.
appendChild
(
dynamicList
);
});
it
(
'
calls onLoadingFinished after loading data
'
,
(
done
)
=>
{
ajaxSpy
=
(
url
)
=>
{
expect
(
url
).
toBe
(
'
dummy endpoint?dummy search key=
'
);
return
Promise
.
resolve
(
dummyData
);
};
AjaxFilter
.
trigger
()
.
then
(()
=>
{
expect
(
dummyConfig
.
onLoadingFinished
.
calls
.
count
()).
toBe
(
1
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
does not call onLoadingFinished if Ajax call fails
'
,
(
done
)
=>
{
const
dummyError
=
new
Error
(
'
My dummy is sick! :-(
'
);
ajaxSpy
=
(
url
)
=>
{
expect
(
url
).
toBe
(
'
dummy endpoint?dummy search key=
'
);
return
Promise
.
reject
(
dummyError
);
};
AjaxFilter
.
trigger
()
.
then
(
done
.
fail
)
.
catch
((
error
)
=>
{
expect
(
error
).
toBe
(
dummyError
);
expect
(
dummyConfig
.
onLoadingFinished
.
calls
.
count
()).
toBe
(
0
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
});
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