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
71b9d730
Commit
71b9d730
authored
3 years ago
by
Scott Stern
Committed by
Natalia Tepluhina
3 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add glfilteredsearch to group boards
parent
e9587bb3
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
152 additions
and
153 deletions
+152
-153
app/assets/javascripts/boards/components/filtered_search.vue
app/assets/javascripts/boards/components/filtered_search.vue
+0
-54
app/assets/javascripts/boards/filtered_search.js
app/assets/javascripts/boards/filtered_search.js
+0
-25
app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/author_token.vue
...ed/components/filtered_search_bar/tokens/author_token.vue
+8
-2
ee/app/assets/javascripts/boards/components/epic_filtered_search.vue
...ts/javascripts/boards/components/epic_filtered_search.vue
+53
-4
ee/app/assets/javascripts/boards/epic_filtered_search.js
ee/app/assets/javascripts/boards/epic_filtered_search.js
+2
-2
ee/app/assets/javascripts/boards/graphql/group_labels.query.graphql
...ets/javascripts/boards/graphql/group_labels.query.graphql
+17
-0
ee/app/assets/javascripts/boards/graphql/group_members.query.graphql
...ts/javascripts/boards/graphql/group_members.query.graphql
+14
-0
ee/app/assets/javascripts/epic_boards/index.js
ee/app/assets/javascripts/epic_boards/index.js
+1
-1
ee/spec/features/epic_boards/epic_boards_spec.rb
ee/spec/features/epic_boards/epic_boards_spec.rb
+27
-0
ee/spec/frontend/boards/components/epic_filtered_search_spec.js
...c/frontend/boards/components/epic_filtered_search_spec.js
+30
-0
spec/frontend/boards/components/filtered_search_spec.js
spec/frontend/boards/components/filtered_search_spec.js
+0
-65
No files found.
app/assets/javascripts/boards/components/filtered_search.vue
deleted
100644 → 0
View file @
e9587bb3
<
script
>
import
{
mapActions
}
from
'
vuex
'
;
import
{
historyPushState
}
from
'
~/lib/utils/common_utils
'
;
import
{
setUrlParams
}
from
'
~/lib/utils/url_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
FilteredSearch
from
'
~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
'
;
export
default
{
i18n
:
{
search
:
__
(
'
Search
'
),
},
components
:
{
FilteredSearch
},
props
:
{
search
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
computed
:
{
initialSearch
()
{
return
[{
type
:
'
filtered-search-term
'
,
value
:
{
data
:
this
.
search
}
}];
},
},
methods
:
{
...
mapActions
([
'
performSearch
'
]),
handleSearch
(
filters
)
{
let
itemValue
=
''
;
const
[
item
]
=
filters
;
if
(
filters
.
length
===
0
)
{
itemValue
=
''
;
}
else
{
itemValue
=
item
?.
value
?.
data
;
}
historyPushState
(
setUrlParams
({
search
:
itemValue
},
window
.
location
.
href
));
this
.
performSearch
();
},
},
};
</
script
>
<
template
>
<filtered-search
class=
"gl-w-full"
namespace=
""
:tokens=
"[]"
:search-input-placeholder=
"$options.i18n.search"
:initial-filter-value=
"initialSearch"
@
onFilter=
"handleSearch"
/>
</
template
>
This diff is collapsed.
Click to expand it.
app/assets/javascripts/boards/filtered_search.js
deleted
100644 → 0
View file @
e9587bb3
import
Vue
from
'
vue
'
;
import
store
from
'
~/boards/stores
'
;
import
{
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
FilteredSearch
from
'
./components/filtered_search.vue
'
;
export
default
()
=>
{
const
queryParams
=
queryToObject
(
window
.
location
.
search
);
const
el
=
document
.
getElementById
(
'
js-board-filtered-search
'
);
/*
When https://github.com/vuejs/vue-apollo/pull/1153 is merged and deployed
we can remove apolloProvider option from here. Currently without it its causing
an error
*/
return
new
Vue
({
el
,
store
,
apolloProvider
:
{},
render
:
(
createElement
)
=>
createElement
(
FilteredSearch
,
{
props
:
{
search
:
queryParams
.
search
},
}),
});
};
This diff is collapsed.
Click to expand it.
app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/author_token.vue
View file @
71b9d730
...
...
@@ -45,6 +45,9 @@ export default {
activeAuthor
()
{
return
this
.
authors
.
find
((
author
)
=>
author
.
username
.
toLowerCase
()
===
this
.
currentValue
);
},
activeAuthorAvatar
()
{
return
this
.
avatarUrl
(
this
.
activeAuthor
);
},
},
watch
:
{
active
:
{
...
...
@@ -74,6 +77,9 @@ export default {
this
.
loading
=
false
;
});
},
avatarUrl
(
author
)
{
return
author
.
avatarUrl
||
author
.
avatar_url
;
},
searchAuthors
:
debounce
(
function
debouncedSearch
({
data
})
{
this
.
fetchAuthorBySearchTerm
(
data
);
},
DEBOUNCE_DELAY
),
...
...
@@ -92,7 +98,7 @@ export default {
<gl-avatar
v-if=
"activeAuthor"
:size=
"16"
:src=
"activeAuthor
.avatar_url
"
:src=
"activeAuthor
Avatar
"
shape=
"circle"
class=
"gl-mr-2"
/>
...
...
@@ -115,7 +121,7 @@ export default {
:value=
"author.username"
>
<div
class=
"d-flex"
>
<gl-avatar
:size=
"32"
:src=
"a
uthor.avatar_url
"
/>
<gl-avatar
:size=
"32"
:src=
"a
vatarUrl(author)
"
/>
<div>
<div>
{{
author
.
name
}}
</div>
<div>
@
{{
author
.
username
}}
</div>
...
...
This diff is collapsed.
Click to expand it.
ee/app/assets/javascripts/boards/components/epic_filtered_search.vue
View file @
71b9d730
<
script
>
import
{
mapActions
}
from
'
vuex
'
;
import
{
mapActions
,
mapState
}
from
'
vuex
'
;
import
{
historyPushState
}
from
'
~/lib/utils/common_utils
'
;
import
{
setUrlParams
}
from
'
~/lib/utils/url_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
FilteredSearch
from
'
~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
'
;
import
AuthorToken
from
'
~/vue_shared/components/filtered_search_bar/tokens/author_token.vue
'
;
import
LabelToken
from
'
~/vue_shared/components/filtered_search_bar/tokens/label_token.vue
'
;
import
groupLabelsQuery
from
'
../graphql/group_labels.query.graphql
'
;
import
groupUsersQuery
from
'
../graphql/group_members.query.graphql
'
;
export
default
{
i18n
:
{
...
...
@@ -12,14 +16,58 @@ export default {
components
:
{
FilteredSearch
},
inject
:
[
'
search
'
],
computed
:
{
...
mapState
([
'
fullPath
'
]),
initialSearch
()
{
return
[{
type
:
'
filtered-search-term
'
,
value
:
{
data
:
this
.
search
}
}];
},
tokens
()
{
return
[
{
icon
:
'
labels
'
,
title
:
__
(
'
Label
'
),
type
:
'
labels
'
,
operators
:
[{
value
:
'
=
'
,
description
:
'
is
'
}],
token
:
LabelToken
,
unique
:
false
,
symbol
:
'
~
'
,
fetchLabels
:
this
.
fetchLabels
,
},
{
icon
:
'
pencil
'
,
title
:
__
(
'
Author
'
),
type
:
'
author
'
,
operators
:
[{
value
:
'
=
'
,
description
:
'
is
'
}],
symbol
:
'
@
'
,
token
:
AuthorToken
,
unique
:
true
,
fetchAuthors
:
this
.
fetchAuthors
,
},
];
},
},
methods
:
{
...
mapActions
([
'
performSearch
'
]),
tokens
()
{
return
[];
fetchAuthors
(
authorsSearchTerm
)
{
return
this
.
$apollo
.
query
({
query
:
groupUsersQuery
,
variables
:
{
fullPath
:
this
.
fullPath
,
search
:
authorsSearchTerm
,
},
})
.
then
(({
data
})
=>
data
.
group
?.
groupMembers
.
nodes
.
map
((
item
)
=>
item
.
user
));
},
fetchLabels
(
labelSearchTerm
)
{
return
this
.
$apollo
.
query
({
query
:
groupLabelsQuery
,
variables
:
{
fullPath
:
this
.
fullPath
,
search
:
labelSearchTerm
,
},
})
.
then
(({
data
})
=>
data
.
group
?.
labels
.
nodes
||
[]);
},
handleSearch
(
filters
=
[])
{
const
[
item
]
=
filters
;
...
...
@@ -35,9 +83,10 @@ export default {
<
template
>
<filtered-search
data-testid=
"epic-filtered-search"
class=
"gl-w-full"
namespace=
""
:tokens=
"tokens
()
"
:tokens=
"tokens"
:search-input-placeholder=
"$options.i18n.search"
:initial-filter-value=
"initialSearch"
@
onFilter=
"handleSearch"
...
...
This diff is collapsed.
Click to expand it.
ee/app/assets/javascripts/boards/epic_filtered_search.js
View file @
71b9d730
...
...
@@ -3,7 +3,7 @@ import EpicFilteredSearch from 'ee_component/boards/components/epic_filtered_sea
import
store
from
'
~/boards/stores
'
;
import
{
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
export
default
()
=>
{
export
default
(
apolloProvider
)
=>
{
const
queryParams
=
queryToObject
(
window
.
location
.
search
);
const
el
=
document
.
getElementById
(
'
js-board-filtered-search
'
);
...
...
@@ -17,7 +17,7 @@ export default () => {
search
:
queryParams
?.
search
||
''
,
},
store
,
// TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/324094
apolloProvider
:
{}
,
apolloProvider
,
render
:
(
createElement
)
=>
createElement
(
EpicFilteredSearch
),
});
};
This diff is collapsed.
Click to expand it.
ee/app/assets/javascripts/boards/graphql/group_labels.query.graphql
0 → 100644
View file @
71b9d730
query
EpicLabels
(
$fullPath
:
ID
!,
$search
:
String
)
{
group
(
fullPath
:
$fullPath
)
{
labels
(
includeAncestorGroups
:
true
includeDescendantGroups
:
true
first
:
20
searchTerm
:
$search
)
{
nodes
{
id
color
title
textColor
}
}
}
}
This diff is collapsed.
Click to expand it.
ee/app/assets/javascripts/boards/graphql/group_members.query.graphql
0 → 100644
View file @
71b9d730
query
EpicUsers
(
$fullPath
:
ID
!,
$search
:
String
)
{
group
(
fullPath
:
$fullPath
)
{
groupMembers
(
relations
:
[
DIRECT
,
DESCENDANTS
],
search
:
$search
)
{
nodes
{
user
{
id
name
username
avatarUrl
}
}
}
}
}
This diff is collapsed.
Click to expand it.
ee/app/assets/javascripts/epic_boards/index.js
View file @
71b9d730
...
...
@@ -44,7 +44,7 @@ export default () => {
if
(
gon
?.
features
?.
boardsFilteredSearch
)
{
import
(
'
ee/boards/epic_filtered_search
'
)
.
then
(({
default
:
initFilteredSearch
})
=>
{
initFilteredSearch
();
initFilteredSearch
(
apolloProvider
);
})
.
catch
(()
=>
{});
}
...
...
This diff is collapsed.
Click to expand it.
ee/spec/features/epic_boards/epic_boards_spec.rb
View file @
71b9d730
...
...
@@ -158,6 +158,33 @@ RSpec.describe 'epic boards', :js do
end
end
context
'filtered search'
do
before
do
stub_licensed_features
(
epics:
true
)
stub_feature_flags
(
boards_filtered_search:
true
)
group
.
add_guest
(
user
)
sign_in
(
user
)
visit_epic_boards_page
end
it
'can select an Author and Label'
do
page
.
find
(
'[data-testid="epic-filtered-search"]'
).
click
page
.
within
(
'[data-testid="epic-filtered-search"]'
)
do
click_link
'Author'
wait_for_requests
click_link
user
.
name
click_link
'Label'
wait_for_requests
click_link
label
.
title
expect
(
page
).
to
have_text
(
"Author =
#{
user
.
name
}
Label = ~
#{
label
.
title
}
"
)
end
end
end
def
visit_epic_boards_page
visit
group_epic_boards_path
(
group
)
wait_for_requests
...
...
This diff is collapsed.
Click to expand it.
ee/spec/frontend/boards/components/epic_filtered_search_spec.js
View file @
71b9d730
...
...
@@ -3,7 +3,10 @@ import Vuex from 'vuex';
import
EpicFilteredSearch
from
'
ee_component/boards/components/epic_filtered_search.vue
'
;
import
{
createStore
}
from
'
~/boards/stores
'
;
import
*
as
commonUtils
from
'
~/lib/utils/common_utils
'
;
import
{
__
}
from
'
~/locale
'
;
import
FilteredSearchBarRoot
from
'
~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
'
;
import
AuthorToken
from
'
~/vue_shared/components/filtered_search_bar/tokens/author_token.vue
'
;
import
LabelToken
from
'
~/vue_shared/components/filtered_search_bar/tokens/label_token.vue
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -44,6 +47,33 @@ describe('EpicFilteredSearch', () => {
expect
(
findFilteredSearch
().
exists
()).
toBe
(
true
);
});
it
(
'
passes the correct tokens to FilteredSearch
'
,
()
=>
{
const
tokens
=
[
{
icon
:
'
labels
'
,
title
:
__
(
'
Label
'
),
type
:
'
labels
'
,
operators
:
[{
value
:
'
=
'
,
description
:
'
is
'
}],
token
:
LabelToken
,
unique
:
false
,
symbol
:
'
~
'
,
fetchLabels
:
wrapper
.
vm
.
fetchLabels
,
},
{
icon
:
'
pencil
'
,
title
:
__
(
'
Author
'
),
type
:
'
author
'
,
operators
:
[{
value
:
'
=
'
,
description
:
'
is
'
}],
symbol
:
'
@
'
,
token
:
AuthorToken
,
unique
:
true
,
fetchAuthors
:
wrapper
.
vm
.
fetchAuthors
,
},
];
expect
(
findFilteredSearch
().
props
(
'
tokens
'
)).
toEqual
(
tokens
);
});
describe
(
'
when onFilter is emitted
'
,
()
=>
{
it
(
'
calls performSearch
'
,
()
=>
{
findFilteredSearch
().
vm
.
$emit
(
'
onFilter
'
,
[{
value
:
{
data
:
''
}
}]);
...
...
This diff is collapsed.
Click to expand it.
spec/frontend/boards/components/filtered_search_spec.js
deleted
100644 → 0
View file @
e9587bb3
import
{
createLocalVue
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
FilteredSearch
from
'
~/boards/components/filtered_search.vue
'
;
import
{
createStore
}
from
'
~/boards/stores
'
;
import
*
as
commonUtils
from
'
~/lib/utils/common_utils
'
;
import
FilteredSearchBarRoot
from
'
~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
describe
(
'
FilteredSearch
'
,
()
=>
{
let
wrapper
;
let
store
;
const
createComponent
=
()
=>
{
wrapper
=
shallowMount
(
FilteredSearch
,
{
localVue
,
propsData
:
{
search
:
''
},
store
,
attachTo
:
document
.
body
,
});
};
beforeEach
(()
=>
{
// this needed for actions call for performSearch
window
.
gon
=
{
features
:
{}
};
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
default
'
,
()
=>
{
beforeEach
(()
=>
{
store
=
createStore
();
jest
.
spyOn
(
store
,
'
dispatch
'
);
createComponent
();
});
it
(
'
finds FilteredSearch
'
,
()
=>
{
expect
(
wrapper
.
find
(
FilteredSearchBarRoot
).
exists
()).
toBe
(
true
);
});
describe
(
'
when onFilter is emitted
'
,
()
=>
{
it
(
'
calls performSearch
'
,
()
=>
{
wrapper
.
find
(
FilteredSearchBarRoot
).
vm
.
$emit
(
'
onFilter
'
,
[{
value
:
{
data
:
''
}
}]);
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
performSearch
'
);
});
it
(
'
calls historyPushState
'
,
()
=>
{
commonUtils
.
historyPushState
=
jest
.
fn
();
wrapper
.
find
(
FilteredSearchBarRoot
)
.
vm
.
$emit
(
'
onFilter
'
,
[{
value
:
{
data
:
'
searchQuery
'
}
}]);
expect
(
commonUtils
.
historyPushState
).
toHaveBeenCalledWith
(
'
http://test.host/?search=searchQuery
'
,
);
});
});
});
});
This diff is collapsed.
Click to expand it.
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