Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
heptapod
heptapod
Commits
6e698a998797
Commit
974a0402
authored
Aug 02, 2017
by
Clement Ho
Committed by
Phil Hughes
Aug 02, 2017
Browse files
Add filtered search to group issue dashboard
parent
cf146ca79fff
Changes
19
Hide whitespace changes
Inline
Side-by-side
app/assets/javascripts/dispatcher.js
View file @
6e698a99
...
...
@@ -139,6 +139,8 @@ import GpgBadges from './gpg_badges';
.
init
();
}
const
filteredSearchEnabled
=
gl
.
FilteredSearchManager
&&
document
.
querySelector
(
'
.filtered-search
'
);
switch
(
page
)
{
case
'
profiles:preferences:show
'
:
initExperimentalFlags
();
...
...
@@ -155,7 +157,7 @@ import GpgBadges from './gpg_badges';
break
;
case
'
projects:merge_requests:index
'
:
case
'
projects:issues:index
'
:
if
(
gl
.
F
ilteredSearch
Manager
&&
document
.
querySelector
(
'
.filtered-search
'
)
)
{
if
(
f
ilteredSearch
Enabled
)
{
const
filteredSearchManager
=
new
gl
.
FilteredSearchManager
(
page
===
'
projects:issues:index
'
?
'
issues
'
:
'
merge_requests
'
);
filteredSearchManager
.
setup
();
}
...
...
@@ -183,11 +185,17 @@ import GpgBadges from './gpg_badges';
break
;
case
'
dashboard:issues
'
:
case
'
dashboard:merge_requests
'
:
case
'
groups:issues
'
:
case
'
groups:merge_requests
'
:
new
ProjectSelect
();
initLegacyFilters
();
break
;
case
'
groups:issues
'
:
if
(
filteredSearchEnabled
)
{
const
filteredSearchManager
=
new
gl
.
FilteredSearchManager
(
'
issues
'
);
filteredSearchManager
.
setup
();
}
new
ProjectSelect
();
break
;
case
'
dashboard:todos:index
'
:
new
Todos
();
break
;
...
...
app/assets/javascripts/droplab/plugins/ajax.js
View file @
6e698a99
...
...
@@ -11,6 +11,16 @@ const Ajax = {
if
(
!
self
.
destroyed
)
self
.
hook
.
list
[
config
.
method
].
call
(
self
.
hook
.
list
,
data
);
},
preprocessing
:
function
preprocessing
(
config
,
data
)
{
let
results
=
data
;
if
(
config
.
preprocessing
&&
!
data
.
preprocessed
)
{
results
=
config
.
preprocessing
(
data
);
AjaxCache
.
override
(
config
.
endpoint
,
results
);
}
return
results
;
},
init
:
function
init
(
hook
)
{
var
self
=
this
;
self
.
destroyed
=
false
;
...
...
@@ -31,7 +41,8 @@ const Ajax = {
dynamicList
.
outerHTML
=
loadingTemplate
.
outerHTML
;
}
AjaxCache
.
retrieve
(
config
.
endpoint
)
return
AjaxCache
.
retrieve
(
config
.
endpoint
)
.
then
(
self
.
preprocessing
.
bind
(
null
,
config
))
.
then
((
data
)
=>
self
.
_loadData
(
data
,
config
,
self
))
.
catch
(
config
.
onError
);
},
...
...
app/assets/javascripts/filtered_search/dropdown_non_user.js
View file @
6e698a99
...
...
@@ -6,7 +6,7 @@ import './filtered_search_dropdown';
class
DropdownNonUser
extends
gl
.
FilteredSearchDropdown
{
constructor
(
options
=
{})
{
const
{
input
,
endpoint
,
symbol
}
=
options
;
const
{
input
,
endpoint
,
symbol
,
preprocessing
}
=
options
;
super
(
options
);
this
.
symbol
=
symbol
;
this
.
config
=
{
...
...
@@ -14,6 +14,7 @@ class DropdownNonUser extends gl.FilteredSearchDropdown {
endpoint
,
method
:
'
setData
'
,
loadingTemplate
:
this
.
loadingTemplate
,
preprocessing
,
onError
()
{
/* eslint-disable no-new */
new
Flash
(
'
An error occured fetching the dropdown data.
'
);
...
...
app/assets/javascripts/filtered_search/dropdown_utils.js
View file @
6e698a99
...
...
@@ -50,6 +50,66 @@ class DropdownUtils {
return
updatedItem
;
}
static
mergeDuplicateLabels
(
dataMap
,
newLabel
)
{
const
updatedMap
=
dataMap
;
const
key
=
newLabel
.
title
;
const
hasKeyProperty
=
Object
.
prototype
.
hasOwnProperty
.
call
(
updatedMap
,
key
);
if
(
!
hasKeyProperty
)
{
updatedMap
[
key
]
=
newLabel
;
}
else
{
const
existing
=
updatedMap
[
key
];
if
(
!
existing
.
multipleColors
)
{
existing
.
multipleColors
=
[
existing
.
color
];
}
existing
.
multipleColors
.
push
(
newLabel
.
color
);
}
return
updatedMap
;
}
static
duplicateLabelColor
(
labelColors
)
{
const
colors
=
labelColors
;
const
spacing
=
100
/
colors
.
length
;
// Reduce the colors to 4
colors
.
length
=
Math
.
min
(
colors
.
length
,
4
);
const
color
=
colors
.
map
((
c
,
i
)
=>
{
const
percentFirst
=
Math
.
floor
(
spacing
*
i
);
const
percentSecond
=
Math
.
floor
(
spacing
*
(
i
+
1
));
return
`
${
c
}
${
percentFirst
}
%,
${
c
}
${
percentSecond
}
%`
;
}).
join
(
'
,
'
);
return
`linear-gradient(
${
color
}
)`
;
}
static
duplicateLabelPreprocessing
(
data
)
{
const
results
=
[];
const
dataMap
=
{};
data
.
forEach
(
DropdownUtils
.
mergeDuplicateLabels
.
bind
(
null
,
dataMap
));
Object
.
keys
(
dataMap
)
.
forEach
((
key
)
=>
{
const
label
=
dataMap
[
key
];
if
(
label
.
multipleColors
)
{
label
.
color
=
DropdownUtils
.
duplicateLabelColor
(
label
.
multipleColors
);
label
.
text_color
=
'
#000000
'
;
}
results
.
push
(
label
);
});
results
.
preprocessed
=
true
;
return
results
;
}
static
filterHint
(
config
,
item
)
{
const
{
input
,
allowedKeys
}
=
config
;
const
updatedItem
=
item
;
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
View file @
6e698a99
...
...
@@ -54,6 +54,7 @@ class FilteredSearchDropdownManager {
extraArguments
:
{
endpoint
:
`
${
this
.
baseEndpoint
}
/labels.json`
,
symbol
:
'
~
'
,
preprocessing
:
gl
.
DropdownUtils
.
duplicateLabelPreprocessing
,
},
element
:
this
.
container
.
querySelector
(
'
#js-dropdown-label
'
),
},
...
...
app/assets/javascripts/filtered_search/filtered_search_manager.js
View file @
6e698a99
...
...
@@ -20,13 +20,13 @@ class FilteredSearchManager {
allowedKeys
:
this
.
filteredSearchTokenKeys
.
getKeys
(),
});
this
.
searchHistoryDropdownElement
=
document
.
querySelector
(
'
.js-filtered-search-history-dropdown
'
);
const
project
Path
=
this
.
searchHistoryDropdownElement
?
this
.
searchHistoryDropdownElement
.
dataset
.
projectF
ullPath
:
'
project
'
;
const
full
Path
=
this
.
searchHistoryDropdownElement
?
this
.
searchHistoryDropdownElement
.
dataset
.
f
ullPath
:
'
project
'
;
let
recentSearchesPagePrefix
=
'
issue-recent-searches
'
;
if
(
this
.
page
===
'
merge_requests
'
)
{
recentSearchesPagePrefix
=
'
merge-request-recent-searches
'
;
}
const
recentSearchesKey
=
`
${
project
Path
}
-
${
recentSearchesPagePrefix
}
`
;
const
recentSearchesKey
=
`
${
full
Path
}
-
${
recentSearchesPagePrefix
}
`
;
this
.
recentSearchesService
=
new
RecentSearchesService
(
recentSearchesKey
);
}
...
...
app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js
View file @
6e698a99
...
...
@@ -58,29 +58,54 @@ class FilteredSearchVisualTokens {
`
;
}
static
setTokenStyle
(
tokenContainer
,
backgroundColor
,
textColor
)
{
const
token
=
tokenContainer
;
// Labels with linear gradient should not override default background color
if
(
backgroundColor
.
indexOf
(
'
linear-gradient
'
)
===
-
1
)
{
token
.
style
.
backgroundColor
=
backgroundColor
;
}
token
.
style
.
color
=
textColor
;
if
(
textColor
===
'
#FFFFFF
'
)
{
const
removeToken
=
token
.
querySelector
(
'
.remove-token
'
);
removeToken
.
classList
.
add
(
'
inverted
'
);
}
return
token
;
}
static
preprocessLabel
(
labelsEndpoint
,
labels
)
{
let
processed
=
labels
;
if
(
!
labels
.
preprocessed
)
{
processed
=
gl
.
DropdownUtils
.
duplicateLabelPreprocessing
(
labels
);
AjaxCache
.
override
(
labelsEndpoint
,
processed
);
processed
.
preprocessed
=
true
;
}
return
processed
;
}
static
updateLabelTokenColor
(
tokenValueContainer
,
tokenValue
)
{
const
filteredSearchInput
=
FilteredSearchContainer
.
container
.
querySelector
(
'
.filtered-search
'
);
const
baseEndpoint
=
filteredSearchInput
.
dataset
.
baseEndpoint
;
const
labelsEndpoint
=
`
${
baseEndpoint
}
/labels.json`
;
return
AjaxCache
.
retrieve
(
labelsEndpoint
)
.
then
((
labels
)
=>
{
const
matchingLabel
=
(
labels
||
[]).
find
(
label
=>
`~
${
gl
.
DropdownUtils
.
getEscapedText
(
label
.
title
)}
`
===
tokenValue
);
if
(
!
matchingLabel
)
{
return
;
}
.
then
(
FilteredSearchVisualTokens
.
preprocessLabel
.
bind
(
null
,
labelsEndpoint
))
.
then
((
labels
)
=>
{
const
matchingLabel
=
(
labels
||
[]).
find
(
label
=>
`~
${
gl
.
DropdownUtils
.
getEscapedText
(
label
.
title
)}
`
===
tokenValue
);
const
tokenValueStyle
=
tokenValueContainer
.
style
;
tokenValueStyle
.
backgroundColor
=
matchingLabel
.
color
;
tokenValueStyle
.
color
=
matchingLabel
.
text_color
;
if
(
!
matchingLabel
)
{
return
;
}
if
(
matchingLabel
.
text_color
===
'
#FFFFFF
'
)
{
const
removeToken
=
tokenValueContainer
.
querySelector
(
'
.remove-token
'
);
removeToken
.
classList
.
add
(
'
inverted
'
);
}
})
.
catch
(()
=>
new
Flash
(
'
An error occurred while fetching label colors.
'
));
FilteredSearchVisualTokens
.
setTokenStyle
(
tokenValueContainer
,
matchingLabel
.
color
,
matchingLabel
.
text_color
);
})
.
catch
(()
=>
new
Flash
(
'
An error occurred while fetching label colors.
'
));
}
static
updateUserTokenAppearance
(
tokenValueContainer
,
tokenValueElement
,
tokenValue
)
{
...
...
app/assets/javascripts/labels_select.js
View file @
6e698a99
...
...
@@ -3,6 +3,7 @@
/* global ListLabel */
import
IssuableBulkUpdateActions
from
'
./issuable_bulk_update_actions
'
;
import
DropdownUtils
from
'
./filtered_search/dropdown_utils
'
;
(
function
()
{
this
.
LabelsSelect
=
(
function
()
{
...
...
@@ -218,18 +219,7 @@ import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
}
}
if
(
label
.
duplicate
)
{
spacing
=
100
/
label
.
color
.
length
;
// Reduce the colors to 4
label
.
color
=
label
.
color
.
filter
(
function
(
color
,
i
)
{
return
i
<
4
;
});
color
=
_
.
map
(
label
.
color
,
function
(
color
,
i
)
{
var
percentFirst
,
percentSecond
;
percentFirst
=
Math
.
floor
(
spacing
*
i
);
percentSecond
=
Math
.
floor
(
spacing
*
(
i
+
1
));
return
color
+
"
"
+
percentFirst
+
"
%,
"
+
color
+
"
"
+
percentSecond
+
"
%
"
;
}).
join
(
'
,
'
);
color
=
"
linear-gradient(
"
+
color
+
"
)
"
;
color
=
gl
.
DropdownUtils
.
duplicateLabelColor
(
label
.
color
);
}
else
{
if
(
label
.
color
!=
null
)
{
...
...
app/assets/javascripts/lib/utils/ajax_cache.js
View file @
6e698a99
...
...
@@ -6,6 +6,10 @@ class AjaxCache extends Cache {
this
.
pendingRequests
=
{
};
}
override
(
endpoint
,
data
)
{
this
.
internalStorage
[
endpoint
]
=
data
;
}
retrieve
(
endpoint
,
forceRetrieve
)
{
if
(
this
.
hasData
(
endpoint
)
&&
!
forceRetrieve
)
{
return
Promise
.
resolve
(
this
.
get
(
endpoint
));
...
...
app/helpers/search_helper.rb
View file @
6e698a99
...
...
@@ -127,15 +127,23 @@ def search_filter_path(options = {})
end
def
search_filter_input_options
(
type
)
{
opts
=
{
id:
"filtered-search-
#{
type
}
"
,
placeholder:
'Search or filter results...'
,
data:
{
'project-id'
=>
@project
.
id
,
'username-params'
=>
@users
.
to_json
(
only:
[
:id
,
:username
]),
'base-endpoint'
=>
project_path
(
@project
)
'username-params'
=>
@users
.
to_json
(
only:
[
:id
,
:username
])
}
}
if
@project
.
present?
opts
[
:data
][
'project-id'
]
=
@project
.
id
opts
[
:data
][
'base-endpoint'
]
=
project_path
(
@project
)
else
# Group context
opts
[
:data
][
'base-endpoint'
]
=
group_canonical_path
(
@group
)
end
opts
end
# Sanitize a HTML field for search display. Most tags are stripped out and the
...
...
app/views/groups/issues.html.haml
View file @
6e698a99
...
...
@@ -4,6 +4,10 @@
=
content_for
:meta_tags
do
=
auto_discovery_link_tag
(
:atom
,
params
.
merge
(
rss_url_options
),
title:
"
#{
@group
.
name
}
issues"
)
-
content_for
:page_specific_javascripts
do
=
webpack_bundle_tag
'common_vue'
=
webpack_bundle_tag
'filtered_search'
-
if
show_new_nav?
&&
group_issues_exists
-
content_for
:breadcrumbs_extra
do
=
link_to
params
.
merge
(
rss_url_options
),
class:
'btn btn-default append-right-10'
do
...
...
@@ -20,7 +24,7 @@
Subscribe
=
render
'shared/new_project_item_select'
,
path:
'issues/new'
,
label:
"New issue"
=
render
'shared/issuable/
filte
r'
,
type: :issues
=
render
'shared/issuable/
search_ba
r'
,
type: :issues
.row-content-block.second-block
Only issues from the
...
...
app/views/shared/issuable/_search_bar.html.haml
View file @
6e698a99
-
type
=
local_assigns
.
fetch
(
:type
)
-
block_css_class
=
type
!=
:boards_modal
?
'row-content-block second-block'
:
''
-
full_path
=
@project
.
present?
?
@project
.
full_path
:
@group
.
full_path
.issues-filters
.issues-details-filters.filtered-search-block
{
class:
block_css_class
,
"v-pre"
=>
type
==
:boards_modal
}
...
...
@@ -18,7 +19,7 @@
dropdown_class:
"filtered-search-history-dropdown"
,
content_class:
"filtered-search-history-dropdown-content"
,
title:
"Recent searches"
})
do
.js-filtered-search-history-dropdown
{
data:
{
project_
full_path:
@project
.
full_path
}
}
.js-filtered-search-history-dropdown
{
data:
{
full_path:
full_path
}
}
.filtered-search-box-input-container.droplab-dropdown
.scroll-container
%ul
.tokens-container.list-unstyled
...
...
changelogs/unreleased/add-filtered-search-group-issues-ce.yml
0 → 100644
View file @
6e698a99
---
title
:
Add filtered search to group issue dashboard
merge_request
:
author
:
spec/features/groups/issues_spec.rb
View file @
6e698a99
require
'spec_helper'
feature
'Group issues page'
do
include
FilteredSearchHelpers
let
(
:path
)
{
issues_group_path
(
group
)
}
let
(
:issuable
)
{
create
(
:issue
,
project:
project
,
title:
"this is my created issuable"
)}
...
...
@@ -31,12 +33,10 @@
let
(
:path
)
{
issues_group_path
(
group
)
}
it
'filters by only group users'
do
click_button
(
'Assignee'
)
wait_for_requests
filtered_search
.
set
(
'assignee:'
)
expect
(
find
(
'
.
dropdown-
menu-
assignee'
)).
to
have_
link
(
user
.
name
)
expect
(
find
(
'
.
dropdown-
menu-
assignee'
)).
not_to
have_
link
(
user2
.
name
)
expect
(
find
(
'
#js-
dropdown-assignee
.filter-dropdown
'
)).
to
have_
content
(
user
.
name
)
expect
(
find
(
'
#js-
dropdown-assignee
.filter-dropdown
'
)).
not_to
have_
content
(
user2
.
name
)
end
end
end
spec/helpers/search_helper_spec.rb
View file @
6e698a99
...
...
@@ -68,4 +68,38 @@ def simple_sanitize(str)
end
end
end
describe
'search_filter_input_options'
do
context
'project'
do
before
do
@project
=
create
(
:project
,
:repository
)
end
it
'includes id with type'
do
expect
(
search_filter_input_options
(
'type'
)[
:id
]).
to
eq
(
'filtered-search-type'
)
end
it
'includes project-id'
do
expect
(
search_filter_input_options
(
''
)[
:data
][
'project-id'
]).
to
eq
(
@project
.
id
)
end
it
'includes project base-endpoint'
do
expect
(
search_filter_input_options
(
''
)[
:data
][
'base-endpoint'
]).
to
eq
(
project_path
(
@project
))
end
end
context
'group'
do
before
do
@group
=
create
(
:group
,
name:
'group'
)
end
it
'does not includes project-id'
do
expect
(
search_filter_input_options
(
''
)[
:data
][
'project-id'
]).
to
eq
(
nil
)
end
it
'includes group base-endpoint'
do
expect
(
search_filter_input_options
(
''
)[
:data
][
'base-endpoint'
]).
to
eq
(
"/groups
#{
group_path
(
@group
)
}
"
)
end
end
end
end
spec/javascripts/droplab/plugins/ajax_spec.js
0 → 100644
View file @
6e698a99
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
Ajax
from
'
~/droplab/plugins/ajax
'
;
describe
(
'
Ajax
'
,
()
=>
{
describe
(
'
preprocessing
'
,
()
=>
{
const
config
=
{};
describe
(
'
is not configured
'
,
()
=>
{
it
(
'
passes the data through
'
,
()
=>
{
const
data
=
[
'
data
'
];
expect
(
Ajax
.
preprocessing
(
config
,
data
)).
toEqual
(
data
);
});
});
describe
(
'
is configured
'
,
()
=>
{
const
processedArray
=
[
'
processed
'
];
beforeEach
(()
=>
{
config
.
preprocessing
=
()
=>
processedArray
;
spyOn
(
config
,
'
preprocessing
'
).
and
.
callFake
(()
=>
processedArray
);
});
it
(
'
calls preprocessing
'
,
()
=>
{
Ajax
.
preprocessing
(
config
,
[]);
expect
(
config
.
preprocessing
.
calls
.
count
()).
toBe
(
1
);
});
it
(
'
overrides AjaxCache
'
,
()
=>
{
spyOn
(
AjaxCache
,
'
override
'
).
and
.
callFake
((
endpoint
,
results
)
=>
expect
(
results
).
toEqual
(
processedArray
));
Ajax
.
preprocessing
(
config
,
[]);
expect
(
AjaxCache
.
override
.
calls
.
count
()).
toBe
(
1
);
});
});
});
});
spec/javascripts/filtered_search/dropdown_utils_spec.js
View file @
6e698a99
...
...
@@ -191,6 +191,102 @@ describe('Dropdown Utils', () => {
});
});
describe
(
'
mergeDuplicateLabels
'
,
()
=>
{
const
dataMap
=
{
label
:
{
title
:
'
label
'
,
color
:
'
#FFFFFF
'
,
},
};
it
(
'
should add label to dataMap if it is not a duplicate
'
,
()
=>
{
const
newLabel
=
{
title
:
'
new-label
'
,
color
:
'
#000000
'
,
};
const
updated
=
gl
.
DropdownUtils
.
mergeDuplicateLabels
(
dataMap
,
newLabel
);
expect
(
updated
[
newLabel
.
title
]).
toEqual
(
newLabel
);
});
it
(
'
should merge colors if label is a duplicate
'
,
()
=>
{
const
duplicate
=
{
title
:
'
label
'
,
color
:
'
#000000
'
,
};
const
updated
=
gl
.
DropdownUtils
.
mergeDuplicateLabels
(
dataMap
,
duplicate
);
expect
(
updated
.
label
.
multipleColors
).
toEqual
([
dataMap
.
label
.
color
,
duplicate
.
color
]);
});
});
describe
(
'
duplicateLabelColor
'
,
()
=>
{
it
(
'
should linear-gradient 2 colors
'
,
()
=>
{
const
gradient
=
gl
.
DropdownUtils
.
duplicateLabelColor
([
'
#FFFFFF
'
,
'
#000000
'
]);
expect
(
gradient
).
toEqual
(
'
linear-gradient(#FFFFFF 0%, #FFFFFF 50%, #000000 50%, #000000 100%)
'
);
});
it
(
'
should linear-gradient 3 colors
'
,
()
=>
{
const
gradient
=
gl
.
DropdownUtils
.
duplicateLabelColor
([
'
#FFFFFF
'
,
'
#000000
'
,
'
#333333
'
]);
expect
(
gradient
).
toEqual
(
'
linear-gradient(#FFFFFF 0%, #FFFFFF 33%, #000000 33%, #000000 66%, #333333 66%, #333333 100%)
'
);
});
it
(
'
should linear-gradient 4 colors
'
,
()
=>
{
const
gradient
=
gl
.
DropdownUtils
.
duplicateLabelColor
([
'
#FFFFFF
'
,
'
#000000
'
,
'
#333333
'
,
'
#DDDDDD
'
]);
expect
(
gradient
).
toEqual
(
'
linear-gradient(#FFFFFF 0%, #FFFFFF 25%, #000000 25%, #000000 50%, #333333 50%, #333333 75%, #DDDDDD 75%, #DDDDDD 100%)
'
);
});
it
(
'
should not linear-gradient more than 4 colors
'
,
()
=>
{
const
gradient
=
gl
.
DropdownUtils
.
duplicateLabelColor
([
'
#FFFFFF
'
,
'
#000000
'
,
'
#333333
'
,
'
#DDDDDD
'
,
'
#EEEEEE
'
]);
expect
(
gradient
.
indexOf
(
'
#EEEEEE
'
)
===
-
1
).
toEqual
(
true
);
});
});
describe
(
'
duplicateLabelPreprocessing
'
,
()
=>
{
it
(
'
should set preprocessed to true
'
,
()
=>
{
const
results
=
gl
.
DropdownUtils
.
duplicateLabelPreprocessing
([]);
expect
(
results
.
preprocessed
).
toEqual
(
true
);
});
it
(
'
should not mutate existing data if there are no duplicates
'
,
()
=>
{
const
data
=
[{
title
:
'
label1
'
,
color
:
'
#FFFFFF
'
,
},
{
title
:
'
label2
'
,
color
:
'
#000000
'
,
}];
const
results
=
gl
.
DropdownUtils
.
duplicateLabelPreprocessing
(
data
);
expect
(
results
.
length
).
toEqual
(
2
);
expect
(
results
[
0
]).
toEqual
(
data
[
0
]);
expect
(
results
[
1
]).
toEqual
(
data
[
1
]);
});
describe
(
'
duplicate labels
'
,
()
=>
{
const
data
=
[{
title
:
'
label
'
,
color
:
'
#FFFFFF
'
,
},
{
title
:
'
label
'
,
color
:
'
#000000
'
,
}];
const
results
=
gl
.
DropdownUtils
.
duplicateLabelPreprocessing
(
data
);
it
(
'
should merge duplicate labels
'
,
()
=>
{
expect
(
results
.
length
).
toEqual
(
1
);
});
it
(
'
should convert multiple colored labels into linear-gradient
'
,
()
=>
{
expect
(
results
[
0
].
color
).
toEqual
(
gl
.
DropdownUtils
.
duplicateLabelColor
([
'
#FFFFFF
'
,
'
#000000
'
]));
});
it
(
'
should set multiple colored label text color to black
'
,
()
=>
{
expect
(
results
[
0
].
text_color
).
toEqual
(
'
#000000
'
);
});
});
});
describe
(
'
setDataValueIfSelected
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
gl
.
FilteredSearchDropdownManager
,
'
addWordToInput
'
)
...
...
spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
View file @
6e698a99
...
...
@@ -797,6 +797,69 @@ describe('Filtered Search Visual Tokens', () => {
});
});
describe
(
'
setTokenStyle
'
,
()
=>
{
let
originalTextColor
;
beforeEach
(()
=>
{
originalTextColor
=
bugLabelToken
.
style
.
color
;
});
it
(
'
should set backgroundColor
'
,
()
=>
{
const
originalBackgroundColor
=
bugLabelToken
.
style
.
backgroundColor
;
const
token
=
subject
.
setTokenStyle
(
bugLabelToken
,
'
blue
'
,
'
white
'
);
expect
(
token
.
style
.
backgroundColor
).
toEqual
(
'
blue
'
);