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
4241fb40
Commit
4241fb40
authored
Oct 21, 2021
by
Zack Cuddy
Committed by
Natalia Tepluhina
Oct 21, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Global Search - Update Apply Button
parent
b0267c1c
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
121 additions
and
27 deletions
+121
-27
app/assets/javascripts/search/sidebar/components/app.vue
app/assets/javascripts/search/sidebar/components/app.vue
+2
-2
app/assets/javascripts/search/sidebar/constants/state_filter_data.js
...javascripts/search/sidebar/constants/state_filter_data.js
+1
-1
app/assets/javascripts/search/store/actions.js
app/assets/javascripts/search/store/actions.js
+7
-3
app/assets/javascripts/search/store/constants.js
app/assets/javascripts/search/store/constants.js
+5
-0
app/assets/javascripts/search/store/mutation_types.js
app/assets/javascripts/search/store/mutation_types.js
+1
-0
app/assets/javascripts/search/store/mutations.js
app/assets/javascripts/search/store/mutations.js
+3
-0
app/assets/javascripts/search/store/state.js
app/assets/javascripts/search/store/state.js
+3
-0
app/assets/javascripts/search/store/utils.js
app/assets/javascripts/search/store/utils.js
+11
-1
spec/frontend/search/sidebar/components/app_spec.js
spec/frontend/search/sidebar/components/app_spec.js
+29
-9
spec/frontend/search/store/actions_spec.js
spec/frontend/search/store/actions_spec.js
+22
-9
spec/frontend/search/store/mutations_spec.js
spec/frontend/search/store/mutations_spec.js
+10
-0
spec/frontend/search/store/utils_spec.js
spec/frontend/search/store/utils_spec.js
+27
-2
No files found.
app/assets/javascripts/search/sidebar/components/app.vue
View file @
4241fb40
...
...
@@ -13,7 +13,7 @@ export default {
ConfidentialityFilter
,
},
computed
:
{
...
mapState
([
'
query
'
]),
...
mapState
([
'
query
'
,
'
sidebarDirty
'
]),
showReset
()
{
return
this
.
query
.
state
||
this
.
query
.
confidential
;
},
...
...
@@ -32,7 +32,7 @@ export default {
<status-filter
/>
<confidentiality-filter
/>
<div
class=
"gl-display-flex gl-align-items-center gl-mt-3"
>
<gl-button
category=
"primary"
variant=
"confirm"
size=
"small"
type=
"submit
"
>
<gl-button
category=
"primary"
variant=
"confirm"
type=
"submit"
:disabled=
"!sidebarDirty
"
>
{{
__
(
'
Apply
'
)
}}
</gl-button>
<gl-link
v-if=
"showReset"
class=
"gl-ml-auto"
@
click=
"resetQuery"
>
{{
...
...
app/assets/javascripts/search/sidebar/constants/state_filter_data.js
View file @
4241fb40
...
...
@@ -5,7 +5,7 @@ const header = __('Status');
const
filters
=
{
ANY
:
{
label
:
__
(
'
Any
'
),
value
:
'
all
'
,
value
:
null
,
},
OPEN
:
{
label
:
__
(
'
Open
'
),
...
...
app/assets/javascripts/search/store/actions.js
View file @
4241fb40
...
...
@@ -2,9 +2,9 @@ import Api from '~/api';
import
createFlash
from
'
~/flash
'
;
import
{
visitUrl
,
setUrlParams
}
from
'
~/lib/utils/url_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
GROUPS_LOCAL_STORAGE_KEY
,
PROJECTS_LOCAL_STORAGE_KEY
}
from
'
./constants
'
;
import
{
GROUPS_LOCAL_STORAGE_KEY
,
PROJECTS_LOCAL_STORAGE_KEY
,
SIDEBAR_PARAMS
}
from
'
./constants
'
;
import
*
as
types
from
'
./mutation_types
'
;
import
{
loadDataFromLS
,
setFrequentItemToLS
,
mergeById
}
from
'
./utils
'
;
import
{
loadDataFromLS
,
setFrequentItemToLS
,
mergeById
,
isSidebarDirty
}
from
'
./utils
'
;
export
const
fetchGroups
=
({
commit
},
search
)
=>
{
commit
(
types
.
REQUEST_GROUPS
);
...
...
@@ -86,8 +86,12 @@ export const setFrequentProject = ({ state, commit }, item) => {
commit
(
types
.
LOAD_FREQUENT_ITEMS
,
{
key
:
PROJECTS_LOCAL_STORAGE_KEY
,
data
:
frequentItems
});
};
export
const
setQuery
=
({
commit
},
{
key
,
value
})
=>
{
export
const
setQuery
=
({
state
,
commit
},
{
key
,
value
})
=>
{
commit
(
types
.
SET_QUERY
,
{
key
,
value
});
if
(
SIDEBAR_PARAMS
.
includes
(
key
))
{
commit
(
types
.
SET_SIDEBAR_DIRTY
,
isSidebarDirty
(
state
.
query
,
state
.
urlQuery
));
}
};
export
const
applyQuery
=
({
state
})
=>
{
...
...
app/assets/javascripts/search/store/constants.js
View file @
4241fb40
import
{
stateFilterData
}
from
'
~/search/sidebar/constants/state_filter_data
'
;
import
{
confidentialFilterData
}
from
'
~/search/sidebar/constants/confidential_filter_data
'
;
export
const
MAX_FREQUENT_ITEMS
=
5
;
export
const
MAX_FREQUENCY
=
5
;
...
...
@@ -5,3 +8,5 @@ export const MAX_FREQUENCY = 5;
export
const
GROUPS_LOCAL_STORAGE_KEY
=
'
global-search-frequent-groups
'
;
export
const
PROJECTS_LOCAL_STORAGE_KEY
=
'
global-search-frequent-projects
'
;
export
const
SIDEBAR_PARAMS
=
[
stateFilterData
.
filterParam
,
confidentialFilterData
.
filterParam
];
app/assets/javascripts/search/store/mutation_types.js
View file @
4241fb40
...
...
@@ -7,5 +7,6 @@ export const RECEIVE_PROJECTS_SUCCESS = 'RECEIVE_PROJECTS_SUCCESS';
export
const
RECEIVE_PROJECTS_ERROR
=
'
RECEIVE_PROJECTS_ERROR
'
;
export
const
SET_QUERY
=
'
SET_QUERY
'
;
export
const
SET_SIDEBAR_DIRTY
=
'
SET_SIDEBAR_DIRTY
'
;
export
const
LOAD_FREQUENT_ITEMS
=
'
LOAD_FREQUENT_ITEMS
'
;
app/assets/javascripts/search/store/mutations.js
View file @
4241fb40
...
...
@@ -26,6 +26,9 @@ export default {
[
types
.
SET_QUERY
](
state
,
{
key
,
value
})
{
state
.
query
[
key
]
=
value
;
},
[
types
.
SET_SIDEBAR_DIRTY
](
state
,
value
)
{
state
.
sidebarDirty
=
value
;
},
[
types
.
LOAD_FREQUENT_ITEMS
](
state
,
{
key
,
data
})
{
state
.
frequentItems
[
key
]
=
data
;
},
...
...
app/assets/javascripts/search/store/state.js
View file @
4241fb40
import
{
cloneDeep
}
from
'
lodash
'
;
import
{
GROUPS_LOCAL_STORAGE_KEY
,
PROJECTS_LOCAL_STORAGE_KEY
}
from
'
./constants
'
;
const
createState
=
({
query
})
=>
({
urlQuery
:
cloneDeep
(
query
),
query
,
groups
:
[],
fetchingGroups
:
false
,
...
...
@@ -10,5 +12,6 @@ const createState = ({ query }) => ({
[
GROUPS_LOCAL_STORAGE_KEY
]:
[],
[
PROJECTS_LOCAL_STORAGE_KEY
]:
[],
},
sidebarDirty
:
false
,
});
export
default
createState
;
app/assets/javascripts/search/store/utils.js
View file @
4241fb40
import
AccessorUtilities
from
'
../../lib/utils/accessor
'
;
import
{
MAX_FREQUENT_ITEMS
,
MAX_FREQUENCY
}
from
'
./constants
'
;
import
{
MAX_FREQUENT_ITEMS
,
MAX_FREQUENCY
,
SIDEBAR_PARAMS
}
from
'
./constants
'
;
function
extractKeys
(
object
,
keyList
)
{
return
Object
.
fromEntries
(
keyList
.
map
((
key
)
=>
[
key
,
object
[
key
]]));
...
...
@@ -80,3 +80,13 @@ export const mergeById = (inflatedData, storedData) => {
return
{
...
stored
,
...
data
};
});
};
export
const
isSidebarDirty
=
(
currentQuery
,
urlQuery
)
=>
{
return
SIDEBAR_PARAMS
.
some
((
param
)
=>
{
// userAddParam ensures we don't get a false dirty from null !== undefined
const
userAddedParam
=
!
urlQuery
[
param
]
&&
currentQuery
[
param
];
const
userChangedExistingParam
=
urlQuery
[
param
]
&&
urlQuery
[
param
]
!==
currentQuery
[
param
];
return
userAddedParam
||
userChangedExistingParam
;
});
};
spec/frontend/search/sidebar/components/app_spec.js
View file @
4241fb40
import
{
GlButton
,
GlLink
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
{
MOCK_QUERY
}
from
'
jest/search/mock_data
'
;
import
GlobalSearchSidebar
from
'
~/search/sidebar/components/app.vue
'
;
import
ConfidentialityFilter
from
'
~/search/sidebar/components/confidentiality_filter.vue
'
;
import
StatusFilter
from
'
~/search/sidebar/components/status_filter.vue
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
Vue
.
use
(
Vuex
);
describe
(
'
GlobalSearchSidebar
'
,
()
=>
{
let
wrapper
;
...
...
@@ -27,21 +27,19 @@ describe('GlobalSearchSidebar', () => {
});
wrapper
=
shallowMount
(
GlobalSearchSidebar
,
{
localVue
,
store
,
});
};
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
=
null
;
});
const
findSidebarForm
=
()
=>
wrapper
.
find
(
'
form
'
);
const
findStatusFilter
=
()
=>
wrapper
.
find
(
StatusFilter
);
const
findConfidentialityFilter
=
()
=>
wrapper
.
find
(
ConfidentialityFilter
);
const
findApplyButton
=
()
=>
wrapper
.
find
(
GlButton
);
const
findResetLinkButton
=
()
=>
wrapper
.
find
(
GlLink
);
const
findStatusFilter
=
()
=>
wrapper
.
find
Component
(
StatusFilter
);
const
findConfidentialityFilter
=
()
=>
wrapper
.
find
Component
(
ConfidentialityFilter
);
const
findApplyButton
=
()
=>
wrapper
.
find
Component
(
GlButton
);
const
findResetLinkButton
=
()
=>
wrapper
.
find
Component
(
GlLink
);
describe
(
'
template
'
,
()
=>
{
beforeEach
(()
=>
{
...
...
@@ -61,6 +59,28 @@ describe('GlobalSearchSidebar', () => {
});
});
describe
(
'
ApplyButton
'
,
()
=>
{
describe
(
'
when sidebarDirty is false
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
sidebarDirty
:
false
});
});
it
(
'
disables the button
'
,
()
=>
{
expect
(
findApplyButton
().
attributes
(
'
disabled
'
)).
toBe
(
'
true
'
);
});
});
describe
(
'
when sidebarDirty is true
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
sidebarDirty
:
true
});
});
it
(
'
enables the button
'
,
()
=>
{
expect
(
findApplyButton
().
attributes
(
'
disabled
'
)).
toBe
(
undefined
);
});
});
});
describe
(
'
ResetLinkButton
'
,
()
=>
{
describe
(
'
with no filter selected
'
,
()
=>
{
beforeEach
(()
=>
{
...
...
spec/frontend/search/store/actions_spec.js
View file @
4241fb40
...
...
@@ -5,7 +5,11 @@ import createFlash from '~/flash';
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
*
as
actions
from
'
~/search/store/actions
'
;
import
{
GROUPS_LOCAL_STORAGE_KEY
,
PROJECTS_LOCAL_STORAGE_KEY
}
from
'
~/search/store/constants
'
;
import
{
GROUPS_LOCAL_STORAGE_KEY
,
PROJECTS_LOCAL_STORAGE_KEY
,
SIDEBAR_PARAMS
,
}
from
'
~/search/store/constants
'
;
import
*
as
types
from
'
~/search/store/mutation_types
'
;
import
createState
from
'
~/search/store/state
'
;
import
*
as
storeUtils
from
'
~/search/store/utils
'
;
...
...
@@ -153,15 +157,24 @@ describe('Global Search Store Actions', () => {
});
});
describe
(
'
setQuery
'
,
()
=>
{
const
payload
=
{
key
:
'
key1
'
,
value
:
'
value1
'
};
describe
.
each
`
payload | isDirty | isDirtyMutation
${{
key
:
SIDEBAR_PARAMS
[
0
],
value
:
'
test
'
}
} |
${
false
}
|
${[{
type
:
types
.
SET_SIDEBAR_DIRTY
,
payload
:
false
}]}
${{
key
:
SIDEBAR_PARAMS
[
0
],
value
:
'
test
'
}
} |
${
true
}
|
${[{
type
:
types
.
SET_SIDEBAR_DIRTY
,
payload
:
true
}]}
${{
key
:
SIDEBAR_PARAMS
[
1
],
value
:
'
test
'
}
} |
${
false
}
|
${[{
type
:
types
.
SET_SIDEBAR_DIRTY
,
payload
:
false
}]}
${{
key
:
SIDEBAR_PARAMS
[
1
],
value
:
'
test
'
}
} |
${
true
}
|
${[{
type
:
types
.
SET_SIDEBAR_DIRTY
,
payload
:
true
}]}
${{
key
:
'
non-sidebar
'
,
value
:
'
test
'
}
} |
${
false
}
|
${[]}
${{
key
:
'
non-sidebar
'
,
value
:
'
test
'
}
} |
${
true
}
|
${[]}
`
(
'
setQuery
'
,
({
payload
,
isDirty
,
isDirtyMutation
})
=>
{
describe
(
`when filter param is
${
payload
.
key
}
and utils.isSidebarDirty returns
${
isDirty
}
`
,
()
=>
{
const
expectedMutations
=
[{
type
:
types
.
SET_QUERY
,
payload
}].
concat
(
isDirtyMutation
);
it
(
'
calls the SET_QUERY mutation
'
,
()
=>
{
return
testAction
({
action
:
actions
.
setQuery
,
payload
,
state
,
expectedMutations
:
[{
type
:
types
.
SET_QUERY
,
payload
}],
beforeEach
(
()
=>
{
storeUtils
.
isSidebarDirty
=
jest
.
fn
().
mockReturnValue
(
isDirty
);
});
it
(
`should dispatch the correct mutations`
,
()
=>
{
return
testAction
({
action
:
actions
.
setQuery
,
payload
,
state
,
expectedMutations
});
});
});
});
...
...
spec/frontend/search/store/mutations_spec.js
View file @
4241fb40
...
...
@@ -72,6 +72,16 @@ describe('Global Search Store Mutations', () => {
});
});
describe
(
'
SET_SIDEBAR_DIRTY
'
,
()
=>
{
const
value
=
true
;
it
(
'
sets sidebarDirty to the value
'
,
()
=>
{
mutations
[
types
.
SET_SIDEBAR_DIRTY
](
state
,
value
);
expect
(
state
.
sidebarDirty
).
toBe
(
value
);
});
});
describe
(
'
LOAD_FREQUENT_ITEMS
'
,
()
=>
{
it
(
'
sets frequentItems[key] to data
'
,
()
=>
{
const
payload
=
{
key
:
'
test-key
'
,
data
:
[
1
,
2
,
3
]
};
...
...
spec/frontend/search/store/utils_spec.js
View file @
4241fb40
import
{
useLocalStorageSpy
}
from
'
helpers/local_storage_helper
'
;
import
{
MAX_FREQUENCY
}
from
'
~/search/store/constants
'
;
import
{
loadDataFromLS
,
setFrequentItemToLS
,
mergeById
}
from
'
~/search/store/utils
'
;
import
{
MAX_FREQUENCY
,
SIDEBAR_PARAMS
}
from
'
~/search/store/constants
'
;
import
{
loadDataFromLS
,
setFrequentItemToLS
,
mergeById
,
isSidebarDirty
,
}
from
'
~/search/store/utils
'
;
import
{
MOCK_LS_KEY
,
MOCK_GROUPS
,
...
...
@@ -216,4 +221,24 @@ describe('Global Search Store Utils', () => {
});
});
});
describe
.
each
`
description | currentQuery | urlQuery | isDirty
${
'
identical
'
}
|
${{
[
SIDEBAR_PARAMS
[
0
]]:
'
default
'
,
[
SIDEBAR_PARAMS
[
1
]]:
'
default
'
}
} |
${{
[
SIDEBAR_PARAMS
[
0
]]:
'
default
'
,
[
SIDEBAR_PARAMS
[
1
]]:
'
default
'
}
} |
${
false
}
${
'
different
'
}
|
${{
[
SIDEBAR_PARAMS
[
0
]]:
'
default
'
,
[
SIDEBAR_PARAMS
[
1
]]:
'
new
'
}
} |
${{
[
SIDEBAR_PARAMS
[
0
]]:
'
default
'
,
[
SIDEBAR_PARAMS
[
1
]]:
'
default
'
}
} |
${
true
}
${
'
null/undefined
'
}
|
${{
[
SIDEBAR_PARAMS
[
0
]]:
null
,
[
SIDEBAR_PARAMS
[
1
]]:
null
}
} |
${{
[
SIDEBAR_PARAMS
[
0
]]:
undefined
,
[
SIDEBAR_PARAMS
[
1
]]:
undefined
}
} |
${
false
}
${
'
updated/undefined
'
}
|
${{
[
SIDEBAR_PARAMS
[
0
]]:
'
new
'
,
[
SIDEBAR_PARAMS
[
1
]]:
'
new
'
}
} |
${{
[
SIDEBAR_PARAMS
[
0
]]:
undefined
,
[
SIDEBAR_PARAMS
[
1
]]:
undefined
}
} |
${
true
}
`
(
'
isSidebarDirty
'
,
({
description
,
currentQuery
,
urlQuery
,
isDirty
})
=>
{
describe
(
`with
${
description
}
sidebar query data`
,
()
=>
{
let
res
;
beforeEach
(()
=>
{
res
=
isSidebarDirty
(
currentQuery
,
urlQuery
);
});
it
(
`returns
${
isDirty
}
`
,
()
=>
{
expect
(
res
).
toStrictEqual
(
isDirty
);
});
});
});
});
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