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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
3157a8cc
Commit
3157a8cc
authored
Jun 02, 2021
by
Zack Cuddy
Committed by
Enrique Alcántara
Jun 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Global Search - Refactor Group/Project Filters
parent
631c7c83
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
125 additions
and
57 deletions
+125
-57
app/assets/javascripts/search/topbar/components/group_filter.vue
...ets/javascripts/search/topbar/components/group_filter.vue
+2
-2
app/assets/javascripts/search/topbar/components/project_filter.vue
...s/javascripts/search/topbar/components/project_filter.vue
+2
-2
app/assets/javascripts/search/topbar/components/searchable_dropdown.vue
...ascripts/search/topbar/components/searchable_dropdown.vue
+36
-6
app/assets/javascripts/search/topbar/constants.js
app/assets/javascripts/search/topbar/constants.js
+4
-4
app/assets/stylesheets/pages/search.scss
app/assets/stylesheets/pages/search.scss
+10
-0
spec/features/search/user_searches_for_code_spec.rb
spec/features/search/user_searches_for_code_spec.rb
+1
-1
spec/features/search/user_searches_for_issues_spec.rb
spec/features/search/user_searches_for_issues_spec.rb
+1
-1
spec/features/search/user_searches_for_merge_requests_spec.rb
.../features/search/user_searches_for_merge_requests_spec.rb
+1
-1
spec/features/search/user_searches_for_milestones_spec.rb
spec/features/search/user_searches_for_milestones_spec.rb
+1
-1
spec/features/search/user_searches_for_wiki_pages_spec.rb
spec/features/search/user_searches_for_wiki_pages_spec.rb
+1
-1
spec/features/search/user_uses_search_filters_spec.rb
spec/features/search/user_uses_search_filters_spec.rb
+4
-4
spec/frontend/search/mock_data.js
spec/frontend/search/mock_data.js
+15
-13
spec/frontend/search/topbar/components/searchable_dropdown_spec.js
...tend/search/topbar/components/searchable_dropdown_spec.js
+47
-21
No files found.
app/assets/javascripts/search/topbar/components/group_filter.vue
View file @
3157a8cc
...
...
@@ -39,8 +39,8 @@ export default {
<searchable-dropdown
data-testid=
"group-filter"
:header-text=
"$options.GROUP_DATA.headerText"
:
selected-display-value=
"$options.GROUP_DATA.selectedDisplayValu
e"
:
items-display-value=
"$options.GROUP_DATA.itemsDisplayValu
e"
:
name=
"$options.GROUP_DATA.nam
e"
:
full-name=
"$options.GROUP_DATA.fullNam
e"
:loading=
"fetchingGroups"
:selected-item=
"selectedGroup"
:items=
"groups"
...
...
app/assets/javascripts/search/topbar/components/project_filter.vue
View file @
3157a8cc
...
...
@@ -42,8 +42,8 @@ export default {
<searchable-dropdown
data-testid=
"project-filter"
:header-text=
"$options.PROJECT_DATA.headerText"
:
selected-display-value=
"$options.PROJECT_DATA.selectedDisplayValu
e"
:
items-display-value=
"$options.PROJECT_DATA.itemsDisplayValu
e"
:
name=
"$options.PROJECT_DATA.nam
e"
:
full-name=
"$options.PROJECT_DATA.fullNam
e"
:loading=
"fetchingProjects"
:selected-item=
"selectedProject"
:items=
"projects"
...
...
app/assets/javascripts/search/topbar/components/searchable_dropdown.vue
View file @
3157a8cc
...
...
@@ -8,7 +8,10 @@ import {
GlButton
,
GlSkeletonLoader
,
GlTooltipDirective
,
GlAvatar
,
}
from
'
@gitlab/ui
'
;
import
highlight
from
'
~/lib/utils/highlight
'
;
import
{
truncateNamespace
}
from
'
~/lib/utils/text_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
ANY_OPTION
}
from
'
../constants
'
;
...
...
@@ -25,6 +28,7 @@ export default {
GlIcon
,
GlButton
,
GlSkeletonLoader
,
GlAvatar
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
...
...
@@ -35,12 +39,12 @@ export default {
required
:
false
,
default
:
"
__('Filter')
"
,
},
selectedDisplayValu
e
:
{
nam
e
:
{
type
:
String
,
required
:
false
,
default
:
'
name
'
,
},
itemsDisplayValu
e
:
{
fullNam
e
:
{
type
:
String
,
required
:
false
,
default
:
'
name
'
,
...
...
@@ -75,6 +79,12 @@ export default {
resetDropdown
()
{
this
.
$emit
(
'
change
'
,
ANY_OPTION
);
},
truncateNamespace
(
namespace
)
{
return
truncateNamespace
(
namespace
);
},
highlightedItemName
(
name
)
{
return
highlight
(
name
,
this
.
searchText
);
},
},
ANY_OPTION
,
};
...
...
@@ -83,15 +93,16 @@ export default {
<
template
>
<gl-dropdown
class=
"gl-w-full"
menu-class=
"gl
-w-full!
"
menu-class=
"gl
obal-search-dropdown-menu
"
toggle-class=
"gl-text-truncate"
:header-text=
"headerText"
:right=
"true"
@
show=
"$emit('search', searchText)"
@
shown=
"$refs.searchBox.focusInput()"
>
<template
#button-content
>
<span
class=
"dropdown-toggle-text gl-flex-grow-1 gl-text-truncate"
>
{{
selectedItem
[
selectedDisplayValu
e
]
}}
{{
selectedItem
[
nam
e
]
}}
</span>
<gl-loading-icon
v-if=
"loading"
inline
class=
"gl-mr-3"
/>
<gl-button
...
...
@@ -121,9 +132,10 @@ export default {
class=
"gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2"
:is-check-item=
"true"
:is-checked=
"isSelected($options.ANY_OPTION)"
:is-check-centered=
"true"
@
click=
"resetDropdown"
>
{{ $options.ANY_OPTION.name }}
<span
data-testid=
"item-title"
>
{{ $options.ANY_OPTION.name }}
</span>
</gl-dropdown-item>
</div>
<div
v-if=
"!loading"
>
...
...
@@ -132,9 +144,27 @@ export default {
:key=
"item.id"
:is-check-item=
"true"
:is-checked=
"isSelected(item)"
:is-check-centered=
"true"
@
click=
"$emit('change', item)"
>
{{ item[itemsDisplayValue] }}
<div
class=
"gl-display-flex gl-align-items-center"
>
<gl-avatar
:src=
"item.avatar_url"
:entity-id=
"item.id"
:entity-name=
"item[name]"
shape=
"rect"
:size=
"32"
/>
<div
class=
"gl-display-flex gl-flex-direction-column"
>
<!-- eslint-disable-next-line vue/no-v-html -->
<span
data-testid=
"item-title"
v-html=
"highlightedItemName(item[name])"
>
{{
item[name]
}}
</span>
<span
class=
"gl-font-sm gl-text-gray-700"
data-testid=
"item-namespace"
>
{{
truncateNamespace(item[fullName])
}}
</span>
</div>
</div>
</gl-dropdown-item>
</div>
<div
v-if=
"loading"
class=
"gl-mx-4 gl-mt-3"
>
...
...
app/assets/javascripts/search/topbar/constants.js
View file @
3157a8cc
...
...
@@ -9,13 +9,13 @@ export const ANY_OPTION = Object.freeze({
export
const
GROUP_DATA
=
{
headerText
:
__
(
'
Filter results by group
'
),
queryParam
:
'
group_id
'
,
selectedDisplayValu
e
:
'
name
'
,
itemsDisplayValu
e
:
'
full_name
'
,
nam
e
:
'
name
'
,
fullNam
e
:
'
full_name
'
,
};
export
const
PROJECT_DATA
=
{
headerText
:
__
(
'
Filter results by project
'
),
queryParam
:
'
project_id
'
,
selectedDisplayValue
:
'
name_with_namespac
e
'
,
itemsDisplayValu
e
:
'
name_with_namespace
'
,
name
:
'
nam
e
'
,
fullNam
e
:
'
name_with_namespace
'
,
};
app/assets/stylesheets/pages/search.scss
View file @
3157a8cc
...
...
@@ -295,6 +295,16 @@ input[type='checkbox']:hover {
@include
str-truncated
(
10em
);
}
.global-search-dropdown-menu
{
width
:
100%
!
important
;
max-width
:
400px
;
@include
media-breakpoint-up
(
md
)
{
// This is larger than the container so width: 100% doesn't work.
width
:
400px
!
important
;
}
}
// Disable webkit input icons, link to solution: https://stackoverflow.com/questions/9421551/how-do-i-remove-all-default-webkit-search-field-styling
/* stylelint-disable property-no-vendor-prefix */
input
[
type
=
'search'
]
::-webkit-search-decoration
,
...
...
spec/features/search/user_searches_for_code_spec.rb
View file @
3157a8cc
...
...
@@ -32,7 +32,7 @@ RSpec.describe 'User searches for code' do
wait_for_requests
page
.
within
(
'[data-testid="project-filter"]'
)
do
click_on
(
project
.
full_
name
)
click_on
(
project
.
name
)
end
end
...
...
spec/features/search/user_searches_for_issues_spec.rb
View file @
3157a8cc
...
...
@@ -90,7 +90,7 @@ RSpec.describe 'User searches for issues', :js do
wait_for_requests
page
.
within
(
'[data-testid="project-filter"]'
)
do
click_on
(
project
.
full_
name
)
click_on
(
project
.
name
)
end
search_for_issue
(
issue1
.
title
)
...
...
spec/features/search/user_searches_for_merge_requests_spec.rb
View file @
3157a8cc
...
...
@@ -55,7 +55,7 @@ RSpec.describe 'User searches for merge requests', :js do
wait_for_requests
page
.
within
(
'[data-testid="project-filter"]'
)
do
click_on
(
project
.
full_
name
)
click_on
(
project
.
name
)
end
search_for_mr
(
merge_request1
.
title
)
...
...
spec/features/search/user_searches_for_milestones_spec.rb
View file @
3157a8cc
...
...
@@ -35,7 +35,7 @@ RSpec.describe 'User searches for milestones', :js do
wait_for_requests
page
.
within
(
'[data-testid="project-filter"]'
)
do
click_on
(
project
.
full_
name
)
click_on
(
project
.
name
)
end
fill_in
(
'dashboard_search'
,
with:
milestone1
.
title
)
...
...
spec/features/search/user_searches_for_wiki_pages_spec.rb
View file @
3157a8cc
...
...
@@ -23,7 +23,7 @@ RSpec.describe 'User searches for wiki pages', :js do
wait_for_requests
page
.
within
(
'[data-testid="project-filter"]'
)
do
click_on
(
project
.
full_
name
)
click_on
(
project
.
name
)
end
fill_in
(
'dashboard_search'
,
with:
search_term
)
...
...
spec/features/search/user_uses_search_filters_spec.rb
View file @
3157a8cc
...
...
@@ -33,10 +33,10 @@ RSpec.describe 'User uses search filters', :js do
wait_for_requests
page
.
within
(
'[data-testid="project-filter"]'
)
do
click_on
(
group_project
.
full_
name
)
click_on
(
group_project
.
name
)
end
expect
(
find
(
'[data-testid="project-filter"]'
)).
to
have_content
(
group_project
.
full_
name
)
expect
(
find
(
'[data-testid="project-filter"]'
)).
to
have_content
(
group_project
.
name
)
end
context
'when the group filter is set'
do
...
...
@@ -65,10 +65,10 @@ RSpec.describe 'User uses search filters', :js do
wait_for_requests
page
.
within
(
'[data-testid="project-filter"]'
)
do
click_on
(
project
.
full_
name
)
click_on
(
project
.
name
)
end
expect
(
find
(
'[data-testid="project-filter"]'
)).
to
have_content
(
project
.
full_
name
)
expect
(
find
(
'[data-testid="project-filter"]'
)).
to
have_content
(
project
.
name
)
end
context
'when the project filter is set'
do
...
...
spec/frontend/search/mock_data.js
View file @
3157a8cc
...
...
@@ -2,47 +2,49 @@ export const MOCK_QUERY = {
scope
:
'
issues
'
,
state
:
'
all
'
,
confidential
:
null
,
group_id
:
'
test_1
'
,
group_id
:
1
,
};
export
const
MOCK_GROUP
=
{
name
:
'
test group
'
,
full_name
:
'
full name test group
'
,
id
:
'
test_1
'
,
full_name
:
'
full name
/
test group
'
,
id
:
1
,
};
export
const
MOCK_GROUPS
=
[
{
avatar_url
:
null
,
name
:
'
test group
'
,
full_name
:
'
full name test group
'
,
id
:
'
test_1
'
,
full_name
:
'
full name
/
test group
'
,
id
:
1
,
},
{
avatar_url
:
'
https://avatar.com
'
,
name
:
'
test group 2
'
,
full_name
:
'
full name test group 2
'
,
id
:
'
test_2
'
,
full_name
:
'
full name
/
test group 2
'
,
id
:
2
,
},
];
export
const
MOCK_PROJECT
=
{
name
:
'
test project
'
,
namespace
:
MOCK_GROUP
,
nameWithNamespace
:
'
test group test project
'
,
id
:
'
test_1
'
,
nameWithNamespace
:
'
test group
/
test project
'
,
id
:
1
,
};
export
const
MOCK_PROJECTS
=
[
{
name
:
'
test project
'
,
namespace
:
MOCK_GROUP
,
name_with_namespace
:
'
test group test project
'
,
id
:
'
test_1
'
,
name_with_namespace
:
'
test group
/
test project
'
,
id
:
1
,
},
{
name
:
'
test project 2
'
,
namespace
:
MOCK_GROUP
,
name_with_namespace
:
'
test group test project 2
'
,
id
:
'
test_2
'
,
name_with_namespace
:
'
test group
/
test project 2
'
,
id
:
2
,
},
];
...
...
spec/frontend/search/topbar/components/searchable_dropdown_spec.js
View file @
3157a8cc
import
{
GlDropdown
,
GlDropdownItem
,
GlSearchBoxByType
,
GlSkeletonLoader
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
,
shallowMount
,
mount
}
from
'
@vue/test-utils
'
;
import
{
GlDropdown
,
GlDropdownItem
,
GlSearchBoxByType
,
GlSkeletonLoader
,
GlAvatar
,
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
mount
}
from
'
@vue/test-utils
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
MOCK_GROUPS
,
MOCK_GROUP
,
MOCK_QUERY
}
from
'
jest/search/mock_data
'
;
import
{
truncateNamespace
}
from
'
~/lib/utils/text_utility
'
;
import
SearchableDropdown
from
'
~/search/topbar/components/searchable_dropdown.vue
'
;
import
{
ANY_OPTION
,
GROUP_DATA
}
from
'
~/search/topbar/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
Vue
.
use
(
Vuex
);
describe
(
'
Global Search Searchable Dropdown
'
,
()
=>
{
let
wrapper
;
const
defaultProps
=
{
headerText
:
GROUP_DATA
.
headerText
,
selectedDisplayValue
:
GROUP_DATA
.
selectedDisplayValu
e
,
itemsDisplayValue
:
GROUP_DATA
.
itemsDisplayValu
e
,
name
:
GROUP_DATA
.
nam
e
,
fullName
:
GROUP_DATA
.
fullNam
e
,
loading
:
false
,
selectedItem
:
ANY_OPTION
,
items
:
[],
...
...
@@ -28,14 +36,15 @@ describe('Global Search Searchable Dropdown', () => {
},
});
wrapper
=
mountFn
(
SearchableDropdown
,
{
localVue
,
store
,
propsData
:
{
...
defaultProps
,
...
props
,
},
});
wrapper
=
extendedWrapper
(
mountFn
(
SearchableDropdown
,
{
store
,
propsData
:
{
...
defaultProps
,
...
props
,
},
}),
);
};
afterEach
(()
=>
{
...
...
@@ -47,11 +56,18 @@ describe('Global Search Searchable Dropdown', () => {
const
findGlDropdownSearch
=
()
=>
findGlDropdown
().
find
(
GlSearchBoxByType
);
const
findDropdownText
=
()
=>
findGlDropdown
().
find
(
'
.dropdown-toggle-text
'
);
const
findDropdownItems
=
()
=>
findGlDropdown
().
findAll
(
GlDropdownItem
);
const
findDropdownItemsText
=
()
=>
findDropdownItems
().
wrappers
.
map
((
w
)
=>
w
.
text
());
const
findDropdownItemTitles
=
()
=>
wrapper
.
findAllByTestId
(
'
item-title
'
);
const
findDropdownItemNamespaces
=
()
=>
wrapper
.
findAllByTestId
(
'
item-namespace
'
);
const
findDropdownAvatars
=
()
=>
wrapper
.
findAllComponents
(
GlAvatar
);
const
findAnyDropdownItem
=
()
=>
findDropdownItems
().
at
(
0
);
const
findFirstGroupDropdownItem
=
()
=>
findDropdownItems
().
at
(
1
);
const
findLoader
=
()
=>
wrapper
.
find
(
GlSkeletonLoader
);
const
findDropdownItemTitlesText
=
()
=>
findDropdownItemTitles
().
wrappers
.
map
((
w
)
=>
w
.
text
());
const
findDropdownItemNamespacesText
=
()
=>
findDropdownItemNamespaces
().
wrappers
.
map
((
w
)
=>
w
.
text
());
const
findDropdownAvatarUrls
=
()
=>
findDropdownAvatars
().
wrappers
.
map
((
w
)
=>
w
.
props
(
'
src
'
));
describe
(
'
template
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
...
...
@@ -93,9 +109,19 @@ describe('Global Search Searchable Dropdown', () => {
expect
(
findLoader
().
exists
()).
toBe
(
false
);
});
it
(
'
renders an instance for each namespace
'
,
()
=>
{
const
resultsIncludeAny
=
[
'
Any
'
].
concat
(
MOCK_GROUPS
.
map
((
n
)
=>
n
.
full_name
));
expect
(
findDropdownItemsText
()).
toStrictEqual
(
resultsIncludeAny
);
it
(
'
renders titles correctly including Any
'
,
()
=>
{
const
resultsIncludeAny
=
[
'
Any
'
].
concat
(
MOCK_GROUPS
.
map
((
n
)
=>
n
[
GROUP_DATA
.
name
]));
expect
(
findDropdownItemTitlesText
()).
toStrictEqual
(
resultsIncludeAny
);
});
it
(
'
renders namespaces truncated correctly
'
,
()
=>
{
const
namespaces
=
MOCK_GROUPS
.
map
((
n
)
=>
truncateNamespace
(
n
[
GROUP_DATA
.
fullName
]));
expect
(
findDropdownItemNamespacesText
()).
toStrictEqual
(
namespaces
);
});
it
(
'
renders GlAvatar for each item
'
,
()
=>
{
const
avatars
=
MOCK_GROUPS
.
map
((
n
)
=>
n
.
avatar_url
);
expect
(
findDropdownAvatarUrls
()).
toStrictEqual
(
avatars
);
});
});
...
...
@@ -109,7 +135,7 @@ describe('Global Search Searchable Dropdown', () => {
});
it
(
'
renders only Any in dropdown
'
,
()
=>
{
expect
(
findDropdownItemsText
()).
toStrictEqual
([
'
Any
'
]);
expect
(
findDropdownItem
Title
sText
()).
toStrictEqual
([
'
Any
'
]);
});
});
...
...
@@ -140,8 +166,8 @@ describe('Global Search Searchable Dropdown', () => {
createComponent
({},
{
selectedItem
:
MOCK_GROUP
},
mount
);
});
it
(
'
sets dropdown text to the selectedItem
selectedDisplayValu
e
'
,
()
=>
{
expect
(
findDropdownText
().
text
()).
toBe
(
MOCK_GROUP
[
GROUP_DATA
.
selectedDisplayValu
e
]);
it
(
'
sets dropdown text to the selectedItem
nam
e
'
,
()
=>
{
expect
(
findDropdownText
().
text
()).
toBe
(
MOCK_GROUP
[
GROUP_DATA
.
nam
e
]);
});
});
});
...
...
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