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
355f2c6b
Commit
355f2c6b
authored
Jun 18, 2020
by
Jiaan Louw
Committed by
Paul Slaughter
Jun 18, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove form logic from audit event components
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33741
parent
d3c5b084
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
285 additions
and
330 deletions
+285
-330
ee/app/assets/javascripts/audit_events/components/audit_events_app.vue
.../javascripts/audit_events/components/audit_events_app.vue
+25
-24
ee/app/assets/javascripts/audit_events/components/audit_events_filter.vue
...vascripts/audit_events/components/audit_events_filter.vue
+15
-34
ee/app/assets/javascripts/audit_events/components/date_range_field.vue
.../javascripts/audit_events/components/date_range_field.vue
+18
-50
ee/app/assets/javascripts/audit_events/components/sorting_field.vue
...ets/javascripts/audit_events/components/sorting_field.vue
+13
-21
ee/app/assets/javascripts/audit_events/init_audit_events.js
ee/app/assets/javascripts/audit_events/init_audit_events.js
+6
-9
ee/app/assets/javascripts/audit_events/store/actions.js
ee/app/assets/javascripts/audit_events/store/actions.js
+2
-3
ee/app/assets/javascripts/audit_events/store/mutations.js
ee/app/assets/javascripts/audit_events/store/mutations.js
+3
-3
ee/app/assets/javascripts/audit_events/store/state.js
ee/app/assets/javascripts/audit_events/store/state.js
+1
-4
ee/app/assets/javascripts/audit_events/utils.js
ee/app/assets/javascripts/audit_events/utils.js
+14
-7
ee/spec/features/admin/admin_audit_logs_spec.rb
ee/spec/features/admin/admin_audit_logs_spec.rb
+3
-2
ee/spec/frontend/audit_events/components/__snapshots__/audit_events_app_spec.js.snap
...ts/components/__snapshots__/audit_events_app_spec.js.snap
+9
-18
ee/spec/frontend/audit_events/components/audit_events_app_spec.js
...frontend/audit_events/components/audit_events_app_spec.js
+57
-12
ee/spec/frontend/audit_events/components/audit_events_filter_spec.js
...ntend/audit_events/components/audit_events_filter_spec.js
+34
-53
ee/spec/frontend/audit_events/components/date_range_field_spec.js
...frontend/audit_events/components/date_range_field_spec.js
+28
-48
ee/spec/frontend/audit_events/components/sorting_field_spec.js
...ec/frontend/audit_events/components/sorting_field_spec.js
+38
-27
ee/spec/frontend/audit_events/store/actions_spec.js
ee/spec/frontend/audit_events/store/actions_spec.js
+8
-4
ee/spec/frontend/audit_events/store/mutations_spec.js
ee/spec/frontend/audit_events/store/mutations_spec.js
+6
-6
ee/spec/frontend/audit_events/utils_spec.js
ee/spec/frontend/audit_events/utils_spec.js
+5
-5
No files found.
ee/app/assets/javascripts/audit_events/components/audit_events_app.vue
View file @
355f2c6b
<
script
>
<
script
>
import
{
mapActions
,
mapState
}
from
'
vuex
'
;
import
AuditEventsFilter
from
'
./audit_events_filter.vue
'
;
import
AuditEventsFilter
from
'
./audit_events_filter.vue
'
;
import
DateRangeField
from
'
./date_range_field.vue
'
;
import
DateRangeField
from
'
./date_range_field.vue
'
;
import
SortingField
from
'
./sorting_field.vue
'
;
import
SortingField
from
'
./sorting_field.vue
'
;
...
@@ -12,10 +13,6 @@ export default {
...
@@ -12,10 +13,6 @@ export default {
AuditEventsTable
,
AuditEventsTable
,
},
},
props
:
{
props
:
{
formPath
:
{
type
:
String
,
required
:
true
,
},
events
:
{
events
:
{
type
:
Array
,
type
:
Array
,
required
:
false
,
required
:
false
,
...
@@ -41,16 +38,11 @@ export default {
...
@@ -41,16 +38,11 @@ export default {
default
:
undefined
,
default
:
undefined
,
},
},
},
},
data
()
{
computed
:
{
return
{
...
mapState
([
'
filterValue
'
,
'
startDate
'
,
'
endDate
'
,
'
sortBy
'
]),
formElement
:
null
,
};
},
},
mounted
()
{
methods
:
{
// Passing the form to child components is only temporary
...
mapActions
([
'
setDateRange
'
,
'
setFilterValue
'
,
'
setSortBy
'
,
'
searchForAuditEvents
'
]),
// and should be changed when this issue is completed:
// https://gitlab.com/gitlab-org/gitlab/-/issues/217759
this
.
formElement
=
this
.
$refs
.
form
;
},
},
};
};
</
script
>
</
script
>
...
@@ -58,25 +50,34 @@ export default {
...
@@ -58,25 +50,34 @@ export default {
<
template
>
<
template
>
<div>
<div>
<div
class=
"row-content-block second-block pb-0"
>
<div
class=
"row-content-block second-block pb-0"
>
<form
<div
class=
"d-flex justify-content-between audit-controls row"
>
ref=
"form"
method=
"GET"
:path=
"formPath"
class=
"filter-form d-flex justify-content-between audit-controls row"
>
<div
class=
"col-lg-auto flex-fill form-group align-items-lg-center pr-lg-8"
>
<div
class=
"col-lg-auto flex-fill form-group align-items-lg-center pr-lg-8"
>
<audit-events-filter
v-bind=
"
{ enabledTokenTypes, qaSelector: filterQaSelector }" />
<audit-events-filter
:enabled-token-types=
"enabledTokenTypes"
:qa-selector=
"filterQaSelector"
:value=
"filterValue"
@
selected=
"setFilterValue"
@
submit=
"searchForAuditEvents"
/>
</div>
</div>
<div
class=
"d-flex col-lg-auto flex-wrap pl-lg-0"
>
<div
class=
"d-flex col-lg-auto flex-wrap pl-lg-0"
>
<div
<div
class=
"audit-controls d-flex align-items-lg-center flex-column flex-lg-row col-lg-auto px-0"
class=
"audit-controls d-flex align-items-lg-center flex-column flex-lg-row col-lg-auto px-0"
>
>
<date-range-field
v-if=
"formElement"
:form-element=
"formElement"
/>
<date-range-field
<sorting-field
/>
:start-date=
"startDate"
:end-date=
"endDate"
@
selected=
"setDateRange"
/>
<sorting-field
:sort-by=
"sortBy"
@
selected=
"setSortBy"
/>
</div>
</div>
</div>
</div>
</
form
>
</
div
>
</div>
</div>
<audit-events-table
v-bind=
"
{ events, isLastPage, qaSelector: tableQaSelector }" />
<audit-events-table
:events=
"events"
:is-last-page=
"isLastPage"
:qa-selector=
"tableQaSelector"
/>
</div>
</div>
</
template
>
</
template
>
ee/app/assets/javascripts/audit_events/components/audit_events_filter.vue
View file @
355f2c6b
<
script
>
<
script
>
import
{
GlFilteredSearch
}
from
'
@gitlab/ui
'
;
import
{
GlFilteredSearch
}
from
'
@gitlab/ui
'
;
import
{
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
{
FILTER_TOKENS
,
AVAILABLE_TOKEN_TYPES
}
from
'
../constants
'
;
import
{
FILTER_TOKENS
,
AVAILABLE_TOKEN_TYPES
}
from
'
../constants
'
;
import
{
availableTokensValidator
}
from
'
../validators
'
;
import
{
availableTokensValidator
}
from
'
../validators
'
;
...
@@ -9,6 +8,11 @@ export default {
...
@@ -9,6 +8,11 @@ export default {
GlFilteredSearch
,
GlFilteredSearch
,
},
},
props
:
{
props
:
{
value
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
enabledTokenTypes
:
{
enabledTokenTypes
:
{
type
:
Array
,
type
:
Array
,
required
:
false
,
required
:
false
,
...
@@ -21,14 +25,9 @@ export default {
...
@@ -21,14 +25,9 @@ export default {
default
:
undefined
,
default
:
undefined
,
},
},
},
},
data
()
{
return
{
searchTerms
:
[],
};
},
computed
:
{
computed
:
{
searchTerm
()
{
searchTerm
()
{
return
this
.
searchTerms
.
find
(
term
=>
AVAILABLE_TOKEN_TYPES
.
includes
(
term
.
type
));
return
this
.
value
.
find
(
term
=>
AVAILABLE_TOKEN_TYPES
.
includes
(
term
.
type
));
},
},
enabledTokens
()
{
enabledTokens
()
{
return
FILTER_TOKENS
.
filter
(
token
=>
this
.
enabledTokenTypes
.
includes
(
token
.
type
));
return
FILTER_TOKENS
.
filter
(
token
=>
this
.
enabledTokenTypes
.
includes
(
token
.
type
));
...
@@ -36,39 +35,23 @@ export default {
...
@@ -36,39 +35,23 @@ export default {
filterTokens
()
{
filterTokens
()
{
// This limits the user to search by only one of the available tokens
// This limits the user to search by only one of the available tokens
const
{
enabledTokens
,
searchTerm
}
=
this
;
const
{
enabledTokens
,
searchTerm
}
=
this
;
if
(
searchTerm
?.
type
)
{
if
(
searchTerm
?.
type
)
{
return
enabledTokens
.
map
(
token
=>
({
return
enabledTokens
.
map
(
token
=>
({
...
token
,
...
token
,
disabled
:
searchTerm
.
type
!==
token
.
type
,
disabled
:
searchTerm
.
type
!==
token
.
type
,
}));
}));
}
}
return
enabledTokens
;
return
enabledTokens
;
},
},
id
()
{
return
this
.
searchTerm
?.
value
?.
data
;
},
type
()
{
return
this
.
searchTerm
?.
type
;
},
},
created
()
{
this
.
setSearchTermsFromQuery
();
},
},
methods
:
{
methods
:
{
// The form logic here will be removed once all the audit
onSubmit
()
{
// components are migrated into a single Vue application.
this
.
$emit
(
'
submit
'
);
// https://gitlab.com/gitlab-org/gitlab/-/issues/215363
getFormElement
()
{
return
this
.
$refs
.
input
.
form
;
},
},
setSearchTermsFromQuery
()
{
onInput
(
val
)
{
const
{
entity_type
:
type
,
entity_id
:
value
}
=
queryToObject
(
window
.
location
.
search
);
this
.
$emit
(
'
selected
'
,
val
);
if
(
type
&&
value
)
{
this
.
searchTerms
=
[{
type
,
value
:
{
data
:
value
,
operator
:
'
=
'
}
}];
}
},
filteredSearchSubmit
()
{
this
.
getFormElement
().
submit
();
},
},
},
},
};
};
...
@@ -81,16 +64,14 @@ export default {
...
@@ -81,16 +64,14 @@ export default {
:data-qa-selector=
"qaSelector"
:data-qa-selector=
"qaSelector"
>
>
<gl-filtered-search
<gl-filtered-search
v-model=
"searchTerms
"
:value=
"value
"
:placeholder=
"__('Search')"
:placeholder=
"__('Search')"
:clear-button-title=
"__('Clear')"
:clear-button-title=
"__('Clear')"
:close-button-title=
"__('Close')"
:close-button-title=
"__('Close')"
:available-tokens=
"filterTokens"
:available-tokens=
"filterTokens"
class=
"gl-h-32 w-100"
class=
"gl-h-32 w-100"
@
submit=
"filteredSearchSubmit"
@
submit=
"onSubmit"
@
input=
"onInput"
/>
/>
<input
ref=
"input"
v-model=
"type"
type=
"hidden"
name=
"entity_type"
/>
<input
v-model=
"id"
type=
"hidden"
name=
"entity_id"
/>
</div>
</div>
</
template
>
</
template
>
ee/app/assets/javascripts/audit_events/components/date_range_field.vue
View file @
355f2c6b
<
script
>
<
script
>
import
{
GlDaterangePicker
}
from
'
@gitlab/ui
'
;
import
{
GlDaterangePicker
}
from
'
@gitlab/ui
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
export
default
{
export
default
{
components
:
{
components
:
{
GlDaterangePicker
,
GlDaterangePicker
,
},
},
props
:
{
props
:
{
formElement
:
{
startDate
:
{
type
:
HTMLFormElement
,
type
:
Date
,
required
:
true
,
required
:
false
,
default
:
null
,
},
},
},
endDate
:
{
data
()
{
type
:
Date
,
const
data
=
{
required
:
false
,
startDate
:
null
,
default
:
null
,
endDate
:
null
,
};
const
{
created_after
:
initialStartDate
,
created_before
:
initialEndDate
}
=
queryToObject
(
window
.
location
.
search
,
);
if
(
initialStartDate
)
{
data
.
startDate
=
parsePikadayDate
(
initialStartDate
);
}
if
(
initialEndDate
)
{
data
.
endDate
=
parsePikadayDate
(
initialEndDate
);
}
return
data
;
},
computed
:
{
createdAfter
()
{
return
this
.
startDate
?
pikadayToString
(
this
.
startDate
)
:
''
;
},
createdBefore
()
{
return
this
.
endDate
?
pikadayToString
(
this
.
endDate
)
:
''
;
},
},
},
},
methods
:
{
methods
:
{
handleInput
(
dates
)
{
onInput
(
dates
)
{
this
.
startDate
=
dates
.
startDate
;
this
.
$emit
(
'
selected
'
,
dates
);
this
.
endDate
=
dates
.
endDate
;
this
.
$nextTick
(()
=>
this
.
formElement
.
submit
());
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div>
<gl-daterange-picker
<gl-daterange-picker
class=
"d-flex flex-wrap flex-sm-nowrap"
class=
"d-flex flex-wrap flex-sm-nowrap"
:default-start-date=
"startDate"
:default-start-date=
"startDate"
:default-end-date=
"endDate"
:default-end-date=
"endDate"
start-picker-class=
"form-group align-items-lg-center mr-0 mr-sm-1 d-flex flex-column flex-lg-row"
start-picker-class=
"form-group align-items-lg-center mr-0 mr-sm-1 d-flex flex-column flex-lg-row"
end-picker-class=
"form-group align-items-lg-center mr-0 mr-sm-2 d-flex flex-column flex-lg-row"
end-picker-class=
"form-group align-items-lg-center mr-0 mr-sm-2 d-flex flex-column flex-lg-row"
@
input=
"onInput"
@
input=
"handleInput"
/>
/>
<input
type=
"hidden"
name=
"created_after"
:value=
"createdAfter"
/>
<input
type=
"hidden"
name=
"created_before"
:value=
"createdBefore"
/>
</div>
</
template
>
</
template
>
ee/app/assets/javascripts/audit_events/components/sorting_field.vue
View file @
355f2c6b
<
script
>
<
script
>
import
{
GlNewDropdown
,
GlNewDropdownHeader
,
GlNewDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
GlNewDropdown
,
GlNewDropdownHeader
,
GlNewDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
setUrlParams
,
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
s__
}
from
'
~/locale
'
;
const
SORTING_TITLE
=
s__
(
'
SortOptions|Sort by:
'
);
const
SORTING_TITLE
=
s__
(
'
SortOptions|Sort by:
'
);
...
@@ -22,24 +20,24 @@ export default {
...
@@ -22,24 +20,24 @@ export default {
GlNewDropdownHeader
,
GlNewDropdownHeader
,
GlNewDropdownItem
,
GlNewDropdownItem
,
},
},
data
()
{
props
:
{
const
{
sort
:
selectedOption
}
=
queryToObject
(
window
.
location
.
search
);
sortBy
:
{
type
:
String
,
return
{
required
:
false
,
selectedOption
:
selectedOption
||
SORTING_OPTIONS
[
0
].
key
,
default
:
null
,
}
;
}
,
},
},
computed
:
{
computed
:
{
selectedOption
Text
()
{
selectedOption
()
{
return
SORTING_OPTIONS
.
find
(
option
=>
option
.
key
===
this
.
s
electedOption
).
text
;
return
SORTING_OPTIONS
.
find
(
option
=>
option
.
key
===
this
.
s
ortBy
)
||
SORTING_OPTIONS
[
0
]
;
},
},
},
},
methods
:
{
methods
:
{
getItemLink
(
key
)
{
onItemClick
(
option
)
{
return
setUrlParams
({
sort
:
key
}
);
this
.
$emit
(
'
selected
'
,
option
);
},
},
isChecked
(
key
)
{
isChecked
(
key
)
{
return
key
===
this
.
selectedOption
;
return
key
===
this
.
selectedOption
.
key
;
},
},
},
},
SORTING_TITLE
,
SORTING_TITLE
,
...
@@ -49,23 +47,17 @@ export default {
...
@@ -49,23 +47,17 @@ export default {
<
template
>
<
template
>
<div>
<div>
<gl-new-dropdown
<gl-new-dropdown
:text=
"selectedOption.text"
class=
"w-100 flex-column flex-lg-row form-group"
>
v-model=
"selectedOption"
:text=
"selectedOptionText"
class=
"w-100 flex-column flex-lg-row form-group"
>
<gl-new-dropdown-header>
{{
$options
.
SORTING_TITLE
}}
</gl-new-dropdown-header>
<gl-new-dropdown-header>
{{
$options
.
SORTING_TITLE
}}
</gl-new-dropdown-header>
<gl-new-dropdown-item
<gl-new-dropdown-item
v-for=
"option in $options.SORTING_OPTIONS"
v-for=
"option in $options.SORTING_OPTIONS"
:key=
"option.key"
:key=
"option.key"
:is-check-item=
"true"
:is-check-item=
"true"
:is-checked=
"isChecked(option.key)"
:is-checked=
"isChecked(option.key)"
:href=
"getItemLin
k(option.key)"
@
click=
"onItemClic
k(option.key)"
>
>
{{
option
.
text
}}
{{
option
.
text
}}
</gl-new-dropdown-item>
</gl-new-dropdown-item>
</gl-new-dropdown>
</gl-new-dropdown>
<input
type=
"hidden"
name=
"sort"
:value=
"selectedOption"
/>
</div>
</div>
</
template
>
</
template
>
ee/app/assets/javascripts/audit_events/init_audit_events.js
View file @
355f2c6b
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
{
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
{
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
AuditEventsApp
from
'
./components/audit_events_app.vue
'
;
import
AuditEventsApp
from
'
./components/audit_events_app.vue
'
;
import
createStore
from
'
./store
'
;
export
default
selector
=>
{
export
default
selector
=>
{
const
el
=
document
.
querySelector
(
selector
);
const
el
=
document
.
querySelector
(
selector
);
const
{
const
{
events
,
isLastPage
,
enabledTokenTypes
,
filterQaSelector
,
tableQaSelector
}
=
el
.
dataset
;
events
,
isLastPage
,
const
store
=
createStore
();
formPath
,
store
.
dispatch
(
'
initializeAuditEvents
'
);
enabledTokenTypes
,
filterQaSelector
,
tableQaSelector
,
}
=
el
.
dataset
;
return
new
Vue
({
return
new
Vue
({
el
,
el
,
store
,
render
:
createElement
=>
render
:
createElement
=>
createElement
(
AuditEventsApp
,
{
createElement
(
AuditEventsApp
,
{
props
:
{
props
:
{
events
:
JSON
.
parse
(
events
),
events
:
JSON
.
parse
(
events
),
isLastPage
:
parseBoolean
(
isLastPage
),
isLastPage
:
parseBoolean
(
isLastPage
),
enabledTokenTypes
:
JSON
.
parse
(
enabledTokenTypes
),
enabledTokenTypes
:
JSON
.
parse
(
enabledTokenTypes
),
formPath
,
filterQaSelector
,
filterQaSelector
,
tableQaSelector
,
tableQaSelector
,
},
},
...
...
ee/app/assets/javascripts/audit_events/store/actions.js
View file @
355f2c6b
...
@@ -18,9 +18,8 @@ export const setDateRange = ({ commit, dispatch }, { startDate, endDate }) => {
...
@@ -18,9 +18,8 @@ export const setDateRange = ({ commit, dispatch }, { startDate, endDate }) => {
dispatch
(
'
searchForAuditEvents
'
);
dispatch
(
'
searchForAuditEvents
'
);
};
};
export
const
setFilterValue
=
({
commit
,
dispatch
},
{
id
,
type
})
=>
{
export
const
setFilterValue
=
({
commit
},
filterValue
)
=>
{
commit
(
types
.
SET_FILTER_VALUE
,
{
id
,
type
});
commit
(
types
.
SET_FILTER_VALUE
,
filterValue
);
dispatch
(
'
searchForAuditEvents
'
);
};
};
export
const
setSortBy
=
({
commit
,
dispatch
},
sortBy
)
=>
{
export
const
setSortBy
=
({
commit
,
dispatch
},
sortBy
)
=>
{
...
...
ee/app/assets/javascripts/audit_events/store/mutations.js
View file @
355f2c6b
...
@@ -11,14 +11,14 @@ export default {
...
@@ -11,14 +11,14 @@ export default {
sort
:
sortBy
=
null
,
sort
:
sortBy
=
null
,
}
=
{},
}
=
{},
)
{
)
{
state
.
filterValue
=
{
id
,
type
}
;
state
.
filterValue
=
type
&&
id
?
[{
type
,
value
:
{
data
:
id
,
operator
:
'
=
'
}
}]
:
[]
;
state
.
startDate
=
startDate
;
state
.
startDate
=
startDate
;
state
.
endDate
=
endDate
;
state
.
endDate
=
endDate
;
state
.
sortBy
=
sortBy
;
state
.
sortBy
=
sortBy
;
},
},
[
types
.
SET_FILTER_VALUE
](
state
,
{
id
,
type
}
)
{
[
types
.
SET_FILTER_VALUE
](
state
,
filterValue
)
{
state
.
filterValue
=
{
id
,
type
}
;
state
.
filterValue
=
filterValue
;
},
},
[
types
.
SET_DATE_RANGE
](
state
,
{
startDate
,
endDate
})
{
[
types
.
SET_DATE_RANGE
](
state
,
{
startDate
,
endDate
})
{
...
...
ee/app/assets/javascripts/audit_events/store/state.js
View file @
355f2c6b
export
default
()
=>
({
export
default
()
=>
({
filterValue
:
{
filterValue
:
[],
id
:
null
,
type
:
null
,
},
startDate
:
null
,
startDate
:
null
,
endDate
:
null
,
endDate
:
null
,
...
...
ee/app/assets/javascripts/audit_events/utils.js
View file @
355f2c6b
import
{
parsePikadayDate
,
pikadayToString
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
AVAILABLE_TOKEN_TYPES
}
from
'
./constants
'
;
export
const
isNumeric
=
str
=>
{
export
const
isNumeric
=
str
=>
{
return
!
Number
.
isNaN
(
parseInt
(
str
,
10
),
10
);
return
!
Number
.
isNaN
(
parseInt
(
str
,
10
),
10
);
...
@@ -14,10 +15,16 @@ export const parseAuditEventSearchQuery = ({
...
@@ -14,10 +15,16 @@ export const parseAuditEventSearchQuery = ({
created_before
:
createdBefore
?
parsePikadayDate
(
createdBefore
)
:
null
,
created_before
:
createdBefore
?
parsePikadayDate
(
createdBefore
)
:
null
,
});
});
export
const
createAuditEventSearchQuery
=
({
filterValue
,
startDate
,
endDate
,
sortBy
})
=>
({
export
const
createAuditEventSearchQuery
=
({
filterValue
,
startDate
,
endDate
,
sortBy
})
=>
{
entity_id
:
filterValue
.
id
,
const
entityValue
=
filterValue
.
find
(
value
=>
AVAILABLE_TOKEN_TYPES
.
includes
(
value
.
type
));
entity_type
:
filterValue
.
type
,
created_after
:
startDate
?
pikadayToString
(
startDate
)
:
null
,
return
{
created_before
:
endDate
?
pikadayToString
(
endDate
)
:
null
,
created_after
:
startDate
?
pikadayToString
(
startDate
)
:
null
,
sort
:
sortBy
,
created_before
:
endDate
?
pikadayToString
(
endDate
)
:
null
,
});
sort
:
sortBy
,
entity_id
:
entityValue
?.
value
.
data
,
entity_type
:
entityValue
?.
type
,
// When changing the search parameters, we should be resetting to the first page
page
:
null
,
};
};
ee/spec/features/admin/admin_audit_logs_spec.rb
View file @
355f2c6b
...
@@ -162,9 +162,10 @@ RSpec.describe 'Admin::AuditLogs', :js do
...
@@ -162,9 +162,10 @@ RSpec.describe 'Admin::AuditLogs', :js do
end
end
def
filter_for
(
type
,
name
)
def
filter_for
(
type
,
name
)
within
'[data-qa-selector="admin_audit_log_filter"]'
do
filter_container
=
'[data-testid="audit-events-filter"]'
find
(
'input'
).
click
find
(
filter_container
).
click
within
filter_container
do
click_link
type
click_link
type
click_link
name
click_link
name
...
...
ee/spec/frontend/audit_events/components/__snapshots__/audit_events_app_spec.js.snap
View file @
355f2c6b
...
@@ -5,10 +5,8 @@ exports[`AuditEventsApp when initialized matches the snapshot 1`] = `
...
@@ -5,10 +5,8 @@ exports[`AuditEventsApp when initialized matches the snapshot 1`] = `
<div
<div
class="row-content-block second-block pb-0"
class="row-content-block second-block pb-0"
>
>
<form
<div
class="filter-form d-flex justify-content-between audit-controls row"
class="d-flex justify-content-between audit-controls row"
method="GET"
path="form/path"
>
>
<div
<div
class="col-lg-auto flex-fill form-group align-items-lg-center pr-lg-8"
class="col-lg-auto flex-fill form-group align-items-lg-center pr-lg-8"
...
@@ -24,17 +22,7 @@ exports[`AuditEventsApp when initialized matches the snapshot 1`] = `
...
@@ -24,17 +22,7 @@ exports[`AuditEventsApp when initialized matches the snapshot 1`] = `
clearbuttontitle="Clear"
clearbuttontitle="Clear"
close-button-title="Close"
close-button-title="Close"
placeholder="Search"
placeholder="Search"
value=""
value="[object Object]"
/>
<input
name="entity_type"
type="hidden"
/>
<input
name="entity_id"
type="hidden"
/>
/>
</div>
</div>
</div>
</div>
...
@@ -46,13 +34,16 @@ exports[`AuditEventsApp when initialized matches the snapshot 1`] = `
...
@@ -46,13 +34,16 @@ exports[`AuditEventsApp when initialized matches the snapshot 1`] = `
class="audit-controls d-flex align-items-lg-center flex-column flex-lg-row col-lg-auto px-0"
class="audit-controls d-flex align-items-lg-center flex-column flex-lg-row col-lg-auto px-0"
>
>
<date-range-field-stub
<date-range-field-stub
formelement="[object HTMLFormElement]"
enddate="Sun Feb 02 2020 00:00:00 GMT+0000 (Greenwich Mean Time)"
startdate="Wed Jan 01 2020 00:00:00 GMT+0000 (Greenwich Mean Time)"
/>
/>
<sorting-field-stub />
<sorting-field-stub
sortby="created_asc"
/>
</div>
</div>
</div>
</div>
</
form
>
</
div
>
</div>
</div>
<audit-events-table-stub
<audit-events-table-stub
...
...
ee/spec/frontend/audit_events/components/audit_events_app_spec.js
View file @
355f2c6b
...
@@ -2,12 +2,20 @@ import { shallowMount } from '@vue/test-utils';
...
@@ -2,12 +2,20 @@ import { shallowMount } from '@vue/test-utils';
import
AuditEventsApp
from
'
ee/audit_events/components/audit_events_app.vue
'
;
import
AuditEventsApp
from
'
ee/audit_events/components/audit_events_app.vue
'
;
import
DateRangeField
from
'
ee/audit_events/components/date_range_field.vue
'
;
import
DateRangeField
from
'
ee/audit_events/components/date_range_field.vue
'
;
import
SortingField
from
'
ee/audit_events/components/sorting_field.vue
'
;
import
AuditEventsTable
from
'
ee/audit_events/components/audit_events_table.vue
'
;
import
AuditEventsTable
from
'
ee/audit_events/components/audit_events_table.vue
'
;
import
AuditEventsFilter
from
'
ee/audit_events/components/audit_events_filter.vue
'
;
import
AuditEventsFilter
from
'
ee/audit_events/components/audit_events_filter.vue
'
;
import
{
AVAILABLE_TOKEN_TYPES
}
from
'
ee/audit_events/constants
'
;
import
{
AVAILABLE_TOKEN_TYPES
}
from
'
ee/audit_events/constants
'
;
import
createStore
from
'
ee/audit_events/store
'
;
const
TEST_SORT_BY
=
'
created_asc
'
;
const
TEST_START_DATE
=
new
Date
(
'
2020-01-01
'
);
const
TEST_END_DATE
=
new
Date
(
'
2020-02-02
'
);
const
TEST_FILTER_VALUE
=
[{
id
:
50
,
type
:
'
User
'
}];
describe
(
'
AuditEventsApp
'
,
()
=>
{
describe
(
'
AuditEventsApp
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
let
store
;
const
events
=
[{
foo
:
'
bar
'
}];
const
events
=
[{
foo
:
'
bar
'
}];
const
enabledTokenTypes
=
AVAILABLE_TOKEN_TYPES
;
const
enabledTokenTypes
=
AVAILABLE_TOKEN_TYPES
;
...
@@ -16,8 +24,8 @@ describe('AuditEventsApp', () => {
...
@@ -16,8 +24,8 @@ describe('AuditEventsApp', () => {
const
initComponent
=
(
props
=
{})
=>
{
const
initComponent
=
(
props
=
{})
=>
{
wrapper
=
shallowMount
(
AuditEventsApp
,
{
wrapper
=
shallowMount
(
AuditEventsApp
,
{
store
,
propsData
:
{
propsData
:
{
formPath
:
'
form/path
'
,
isLastPage
:
true
,
isLastPage
:
true
,
filterQaSelector
,
filterQaSelector
,
tableQaSelector
,
tableQaSelector
,
...
@@ -31,9 +39,20 @@ describe('AuditEventsApp', () => {
...
@@ -31,9 +39,20 @@ describe('AuditEventsApp', () => {
});
});
};
};
beforeEach
(()
=>
{
store
=
createStore
();
Object
.
assign
(
store
.
state
,
{
startDate
:
TEST_START_DATE
,
endDate
:
TEST_END_DATE
,
sortBy
:
TEST_SORT_BY
,
filterValue
:
TEST_FILTER_VALUE
,
});
});
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
wrapper
=
null
;
wrapper
=
null
;
store
=
null
;
});
});
describe
(
'
when initialized
'
,
()
=>
{
describe
(
'
when initialized
'
,
()
=>
{
...
@@ -45,25 +64,51 @@ describe('AuditEventsApp', () => {
...
@@ -45,25 +64,51 @@ describe('AuditEventsApp', () => {
expect
(
wrapper
.
element
).
toMatchSnapshot
();
expect
(
wrapper
.
element
).
toMatchSnapshot
();
});
});
it
(
'
sets the form element on the date range field
'
,
()
=>
{
it
(
'
renders audit events table
'
,
()
=>
{
const
{
element
}
=
wrapper
.
find
(
'
form
'
);
expect
(
wrapper
.
find
(
AuditEventsTable
).
props
()).
toEqual
({
expect
(
wrapper
.
find
(
DateRangeField
).
props
(
'
formElement
'
)).
toEqual
(
element
);
events
,
qaSelector
:
tableQaSelector
,
isLastPage
:
true
,
});
});
it
(
'
renders audit events filter
'
,
()
=>
{
expect
(
wrapper
.
find
(
AuditEventsFilter
).
props
()).
toEqual
({
enabledTokenTypes
,
qaSelector
:
filterQaSelector
,
value
:
TEST_FILTER_VALUE
,
});
});
});
it
(
'
passes its events property to the logs table
'
,
()
=>
{
it
(
'
renders date range field
'
,
()
=>
{
expect
(
wrapper
.
find
(
AuditEventsTable
).
props
(
'
events
'
)).
toEqual
(
events
);
expect
(
wrapper
.
find
(
DateRangeField
).
props
()).
toEqual
({
startDate
:
TEST_START_DATE
,
endDate
:
TEST_END_DATE
,
});
});
});
it
(
'
passes the tables QA selector to the logs table
'
,
()
=>
{
it
(
'
renders sorting field
'
,
()
=>
{
expect
(
wrapper
.
find
(
AuditEventsTable
).
props
(
'
qaSelector
'
)).
toEqual
(
tableQaSelector
);
expect
(
wrapper
.
find
(
SortingField
).
props
()).
toEqual
({
sortBy
:
TEST_SORT_BY
}
);
});
});
});
it
(
'
passes its available token types to the logs filter
'
,
()
=>
{
describe
(
'
when a field is selected
'
,
()
=>
{
expect
(
wrapper
.
find
(
AuditEventsFilter
).
props
(
'
enabledTokenTypes
'
)).
toEqual
(
enabledTokenTypes
);
beforeEach
(()
=>
{
jest
.
spyOn
(
store
,
'
dispatch
'
).
mockImplementation
();
initComponent
();
});
});
it
(
'
passes the filters QA selector to the logs filter
'
,
()
=>
{
it
.
each
`
expect
(
wrapper
.
find
(
AuditEventsFilter
).
props
(
'
qaSelector
'
)).
toEqual
(
filterQaSelector
);
name | field | action | payload
${
'
date range
'
}
|
${
DateRangeField
}
|
${
'
setDateRange
'
}
|
${
'
test
'
}
${
'
sort by
'
}
|
${
SortingField
}
|
${
'
setSortBy
'
}
|
${
'
test
'
}
${
'
events filter
'
}
|
${
AuditEventsFilter
}
|
${
'
setFilterValue
'
}
|
${
'
test
'
}
`
(
'
for $name, it calls $handler
'
,
({
field
,
action
,
payload
})
=>
{
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalled
();
wrapper
.
find
(
field
).
vm
.
$emit
(
'
selected
'
,
payload
);
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
action
,
payload
);
});
});
});
});
});
});
ee/spec/frontend/audit_events/components/audit_events_filter_spec.js
View file @
355f2c6b
...
@@ -6,9 +6,8 @@ import { AVAILABLE_TOKEN_TYPES } from 'ee/audit_events/constants';
...
@@ -6,9 +6,8 @@ import { AVAILABLE_TOKEN_TYPES } from 'ee/audit_events/constants';
describe
(
'
AuditEventsFilter
'
,
()
=>
{
describe
(
'
AuditEventsFilter
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
const
formElement
=
document
.
createElement
(
'
form
'
);
formElement
.
submit
=
jest
.
fn
();
const
value
=
[{
type
:
'
Project
'
,
value
:
{
data
:
1
,
operator
:
'
=
'
}
}];
const
findFilteredSearch
=
()
=>
wrapper
.
find
(
GlFilteredSearch
);
const
findFilteredSearch
=
()
=>
wrapper
.
find
(
GlFilteredSearch
);
const
getAvailableTokens
=
()
=>
findFilteredSearch
().
props
(
'
availableTokens
'
);
const
getAvailableTokens
=
()
=>
findFilteredSearch
().
props
(
'
availableTokens
'
);
const
getAvailableTokenProps
=
type
=>
const
getAvailableTokenProps
=
type
=>
...
@@ -19,9 +18,6 @@ describe('AuditEventsFilter', () => {
...
@@ -19,9 +18,6 @@ describe('AuditEventsFilter', () => {
propsData
:
{
propsData
:
{
...
props
,
...
props
,
},
},
methods
:
{
getFormElement
:
()
=>
formElement
,
},
});
});
};
};
...
@@ -46,74 +42,59 @@ describe('AuditEventsFilter', () => {
...
@@ -46,74 +42,59 @@ describe('AuditEventsFilter', () => {
});
});
});
});
describe
(
'
when the URL query has a search term
'
,
()
=>
{
describe
(
'
when the default token value is set
'
,
()
=>
{
const
type
=
'
User
'
;
const
id
=
'
1
'
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
delete
window
.
location
;
initComponent
({
value
});
window
.
location
=
{
search
:
`entity_type=
${
type
}
&entity_id=
${
id
}
`
};
initComponent
();
});
});
it
(
'
sets the filtered searched token
'
,
()
=>
{
it
(
'
sets the filtered searched token
'
,
()
=>
{
expect
(
findFilteredSearch
().
props
(
'
value
'
)).
toMatchObject
([
expect
(
findFilteredSearch
().
props
(
'
value
'
)).
toEqual
(
value
);
{
type
,
value
:
{
data
:
id
,
},
},
]);
});
});
});
describe
(
'
when the URL query is empty
'
,
()
=>
{
it
(
'
only one token matching the selected token type is enabled
'
,
()
=>
{
beforeEach
(()
=>
{
expect
(
getAvailableTokenProps
(
'
Project
'
).
disabled
).
toEqual
(
false
);
delete
window
.
location
;
expect
(
getAvailableTokenProps
(
'
Group
'
).
disabled
).
toEqual
(
true
);
window
.
location
=
{
search
:
''
};
expect
(
getAvailableTokenProps
(
'
User
'
).
disabled
).
toEqual
(
true
);
initComponent
();
});
});
it
(
'
has an empty search value
'
,
()
=>
{
describe
(
'
and the user submits the search field
'
,
()
=>
{
expect
(
findFilteredSearch
().
vm
.
value
).
toEqual
([]);
beforeEach
(()
=>
{
findFilteredSearch
().
vm
.
$emit
(
'
submit
'
);
});
it
(
'
should emit the "submit" event
'
,
()
=>
{
expect
(
wrapper
.
emitted
().
submit
).
toHaveLength
(
1
);
});
});
});
});
});
describe
(
'
when
submitting the filtered search
'
,
()
=>
{
describe
(
'
when
the default token value is not set
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
initComponent
();
initComponent
();
findFilteredSearch
().
vm
.
$emit
(
'
submit
'
);
});
});
it
(
"
calls submit on this component's FORM element
"
,
()
=>
{
it
(
'
has an empty search value
'
,
()
=>
{
expect
(
f
ormElement
.
submit
).
toHaveBeenCalledWith
(
);
expect
(
f
indFilteredSearch
().
vm
.
value
).
toEqual
([]
);
});
});
});
describe
(
'
when a search token has been selected
'
,
()
=>
{
describe
(
'
and the user inputs nothing into the search field
'
,
()
=>
{
const
searchTerm
=
{
beforeEach
(()
=>
{
value
:
{
data
:
'
1
'
},
findFilteredSearch
().
vm
.
$emit
(
'
input
'
,
[]);
type
:
'
Project
'
,
};
beforeEach
(()
=>
{
initComponent
();
wrapper
.
setData
({
searchTerms
:
[
searchTerm
],
});
});
});
it
(
'
only one token matching the selected type is available
'
,
()
=>
{
it
(
'
should emit the "selected" event with empty values
'
,
()
=>
{
expect
(
getAvailableTokenProps
(
'
Project
'
).
disabled
).
toEqual
(
false
);
expect
(
wrapper
.
emitted
().
selected
[
0
]).
toEqual
([[]]);
expect
(
getAvailableTokenProps
(
'
Group
'
).
disabled
).
toEqual
(
true
);
});
expect
(
getAvailableTokenProps
(
'
User
'
).
disabled
).
toEqual
(
true
);
});
describe
(
'
and the user submits the search field
'
,
()
=>
{
beforeEach
(()
=>
{
findFilteredSearch
().
vm
.
$emit
(
'
submit
'
);
});
it
(
'
sets the input values according to the search term
'
,
()
=>
{
it
(
'
should emit the "submit" event
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
input[name="entity_type"]
'
).
attributes
().
value
).
toEqual
(
searchTerm
.
type
);
expect
(
wrapper
.
emitted
().
submit
).
toHaveLength
(
1
);
expect
(
wrapper
.
find
(
'
input[name="entity_id"]
'
).
attributes
().
value
).
toEqual
(
});
searchTerm
.
value
.
data
,
});
);
});
});
});
});
...
...
ee/spec/frontend/audit_events/components/date_range_field_spec.js
View file @
355f2c6b
...
@@ -5,81 +5,61 @@ import DateRangeField from 'ee/audit_events/components/date_range_field.vue';
...
@@ -5,81 +5,61 @@ import DateRangeField from 'ee/audit_events/components/date_range_field.vue';
import
{
parsePikadayDate
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
parsePikadayDate
}
from
'
~/lib/utils/datetime_utility
'
;
describe
(
'
DateRangeField component
'
,
()
=>
{
describe
(
'
DateRangeField component
'
,
()
=>
{
const
DATE
=
'
1970-01-01
'
;
let
wrapper
;
let
wrapper
;
const
createComponent
=
(
props
=
{})
=>
{
const
startDate
=
parsePikadayDate
(
'
2020-03-13
'
);
const
formElement
=
document
.
createElement
(
'
form
'
);
const
endDate
=
parsePikadayDate
(
'
2020-03-14
'
);
document
.
body
.
appendChild
(
formElement
);
return
shallowMount
(
DateRangeField
,
{
const
createComponent
=
(
props
=
{})
=>
{
propsData
:
{
formElement
,
...
props
},
wrapper
=
shallowMount
(
DateRangeField
,
{
propsData
:
{
...
props
},
});
});
};
};
beforeEach
(()
=>
{
delete
window
.
location
;
window
.
location
=
{
search
:
''
};
});
afterEach
(()
=>
{
afterEach
(()
=>
{
document
.
querySelector
(
'
form
'
).
remove
();
wrapper
.
destroy
();
wrapper
.
destroy
();
wrapper
=
null
;
});
});
it
(
'
should populate the initial start date if passed in the query string
'
,
()
=>
{
it
(
'
passes the startDate to the date picker as defaultStartDate
'
,
()
=>
{
window
.
location
.
search
=
`?created_after=
${
DATE
}
`
;
createComponent
({
startDate
});
wrapper
=
createComponent
();
expect
(
wrapper
.
find
(
GlDaterangePicker
).
props
()).
toMatchObject
({
expect
(
wrapper
.
find
(
GlDaterangePicker
).
props
()).
toMatchObject
({
defaultStartDate
:
parsePikadayDate
(
DATE
)
,
defaultStartDate
:
startDate
,
defaultEndDate
:
null
,
defaultEndDate
:
null
,
});
});
});
});
it
(
'
should populate the initial end date if passed in the query string
'
,
()
=>
{
it
(
'
passes the endDate to the date picker as defaultEndDate
'
,
()
=>
{
window
.
location
.
search
=
`?created_before=
${
DATE
}
`
;
createComponent
({
endDate
});
wrapper
=
createComponent
();
expect
(
wrapper
.
find
(
GlDaterangePicker
).
props
()).
toMatchObject
({
expect
(
wrapper
.
find
(
GlDaterangePicker
).
props
()).
toMatchObject
({
defaultStartDate
:
null
,
defaultStartDate
:
null
,
defaultEndDate
:
parsePikadayDate
(
DATE
)
,
defaultEndDate
:
endDate
,
});
});
});
});
it
(
'
should populate both the initial start and end dates if passed in the query string
'
,
()
=>
{
it
(
'
passes both startDate and endDate to the date picker as default dates
'
,
()
=>
{
window
.
location
.
search
=
`?created_after=
${
DATE
}
&created_before=
${
DATE
}
`
;
createComponent
({
startDate
,
endDate
});
wrapper
=
createComponent
();
expect
(
wrapper
.
find
(
GlDaterangePicker
).
props
()).
toMatchObject
({
expect
(
wrapper
.
find
(
GlDaterangePicker
).
props
()).
toMatchObject
({
defaultStartDate
:
parsePikadayDate
(
DATE
)
,
defaultStartDate
:
startDate
,
defaultEndDate
:
parsePikadayDate
(
DATE
)
,
defaultEndDate
:
endDate
,
});
});
});
});
it
(
'
should populate the date hidden fields on input
'
,
()
=>
{
it
(
'
should emit the "selected" event with startDate and endDate on input change
'
,
()
=>
{
wrapper
=
createComponent
();
createComponent
();
wrapper
.
find
(
GlDaterangePicker
).
vm
.
$emit
(
'
input
'
,
{
startDate
,
endDate
});
wrapper
.
find
(
GlDaterangePicker
)
return
wrapper
.
vm
.
$nextTick
(()
=>
{
.
vm
.
$emit
(
'
input
'
,
{
startDate
:
parsePikadayDate
(
DATE
),
endDate
:
parsePikadayDate
(
DATE
)
});
expect
(
wrapper
.
emitted
().
selected
).
toBeTruthy
();
expect
(
wrapper
.
emitted
().
selected
[
0
]).
toEqual
([
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
{
expect
(
wrapper
.
find
(
'
input[name="created_after"]
'
).
attributes
().
value
).
toEqual
(
DATE
);
startDate
,
expect
(
wrapper
.
find
(
'
input[name="created_before"]
'
).
attributes
().
value
).
toEqual
(
DATE
);
endDate
,
});
},
});
]);
it
(
'
should submit the form on input change
'
,
()
=>
{
wrapper
=
createComponent
();
const
spy
=
jest
.
spyOn
(
wrapper
.
props
().
formElement
,
'
submit
'
);
wrapper
.
find
(
GlDaterangePicker
)
.
vm
.
$emit
(
'
input
'
,
{
startDate
:
parsePikadayDate
(
DATE
),
endDate
:
parsePikadayDate
(
DATE
)
});
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
spy
).
toHaveBeenCalledTimes
(
1
);
});
});
});
});
});
});
ee/spec/frontend/audit_events/components/sorting_field_spec.js
View file @
355f2c6b
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
GlNewDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
GlNewDropdownItem
}
from
'
@gitlab/ui
'
;
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
SortingField
from
'
ee/audit_events/components/sorting_field.vue
'
;
import
SortingField
from
'
ee/audit_events/components/sorting_field.vue
'
;
describe
(
'
SortingField component
'
,
()
=>
{
describe
(
'
SortingField component
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
const
DUMMY_URL
=
'
https://localhost
'
;
const
initComponent
=
(
props
=
{})
=>
{
const
createComponent
=
()
=>
wrapper
=
shallowMount
(
SortingField
,
{
shallowMount
(
SortingField
,
{
stubs
:
{
GlNewDropdown
:
true
,
GlNewDropdownItem
:
true
}
});
propsData
:
{
...
props
},
stubs
:
{
GlNewDropdown
:
true
,
GlNewDropdownItem
:
true
,
},
});
};
const
getCheckedOptions
=
()
=>
const
getCheckedOptions
=
()
=>
wrapper
.
findAll
(
GlNewDropdownItem
).
filter
(
item
=>
item
.
props
().
isChecked
);
wrapper
.
findAll
(
GlNewDropdownItem
).
filter
(
item
=>
item
.
props
().
isChecked
);
const
getCheckedOptionHref
=
()
=>
{
return
getCheckedOptions
()
.
at
(
0
)
.
attributes
().
href
;
};
beforeEach
(()
=>
{
beforeEach
(()
=>
{
urlUtils
.
setUrlParams
=
jest
.
fn
(({
sort
})
=>
`
${
DUMMY_URL
}
/?sort=
${
sort
}
`
);
initComponent
();
wrapper
=
createComponent
();
});
});
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
wrapper
=
null
;
});
});
describe
(
'
Sorting behaviour
'
,
()
=>
{
describe
(
'
when initialized
'
,
()
=>
{
it
(
'
should have sorting options
'
,
()
=>
{
it
(
'
should have sorting options
'
,
()
=>
{
expect
(
wrapper
.
findAll
(
GlNewDropdownItem
)).
toHaveLength
(
2
);
expect
(
wrapper
.
findAll
(
GlNewDropdownItem
)).
toHaveLength
(
2
);
});
});
it
(
'
should set the sorting option to `created_desc` by default
'
,
()
=>
{
it
(
'
should set the sorting option to `created_desc` by default
'
,
()
=>
{
expect
(
getCheckedOptions
()).
toHaveLength
(
1
);
expect
(
getCheckedOptions
()).
toHaveLength
(
1
);
expect
(
getCheckedOptionHref
()).
toBe
(
`
${
DUMMY_URL
}
/?sort=created_desc`
);
});
});
it
(
'
should get the sorting option from the URL
'
,
()
=>
{
describe
(
'
with a sortBy value
'
,
()
=>
{
urlUtils
.
queryToObject
=
jest
.
fn
(()
=>
({
sort
:
'
created_asc
'
}));
beforeEach
(()
=>
{
wrapper
=
createComponent
();
initComponent
({
sortBy
:
'
created_asc
'
,
});
});
expect
(
getCheckedOptions
()).
toHaveLength
(
1
);
it
(
'
should set the sorting option accordingly
'
,
()
=>
{
expect
(
getCheckedOptionHref
()).
toBe
(
`
${
DUMMY_URL
}
/?sort=created_asc`
);
expect
(
getCheckedOptions
()).
toHaveLength
(
1
);
expect
(
getCheckedOptions
()
.
at
(
0
)
.
text
(),
).
toEqual
(
'
Oldest created
'
);
});
});
});
});
it
(
'
should retain other params when creating the option URL
'
,
()
=>
{
describe
(
'
when the user clicks on a option
'
,
()
=>
{
urlUtils
.
setUrlParams
=
jest
.
fn
(({
sort
})
=>
`
${
DUMMY_URL
}
/?abc=defg&sort=
${
sort
}
`
);
beforeEach
(()
=>
{
urlUtils
.
queryToObject
=
jest
.
fn
(()
=>
({
sort
:
'
created_desc
'
,
abc
:
'
defg
'
}));
initComponent
();
wrapper
wrapper
=
createComponent
();
.
findAll
(
GlNewDropdownItem
)
.
at
(
1
)
.
vm
.
$emit
(
'
click
'
);
});
expect
(
getCheckedOptionHref
()).
toBe
(
`
${
DUMMY_URL
}
/?abc=defg&sort=created_desc`
);
it
(
'
should emit the "selected" event with clicked option
'
,
()
=>
{
expect
(
wrapper
.
emitted
().
selected
).
toBeTruthy
();
expect
(
wrapper
.
emitted
().
selected
[
0
]).
toEqual
([
'
created_asc
'
]);
});
});
});
});
});
});
ee/spec/frontend/audit_events/store/actions_spec.js
View file @
355f2c6b
...
@@ -18,10 +18,9 @@ describe('Audit Event actions', () => {
...
@@ -18,10 +18,9 @@ describe('Audit Event actions', () => {
});
});
it
.
each
`
it
.
each
`
action | type | payload
action | type | payload
${
'
setDateRange
'
}
|
${
types
.
SET_DATE_RANGE
}
|
${{
startDate
,
endDate
}
}
${
'
setDateRange
'
}
|
${
types
.
SET_DATE_RANGE
}
|
${{
startDate
,
endDate
}
}
${
'
setFilterValue
'
}
|
${
types
.
SET_FILTER_VALUE
}
|
${{
id
:
'
1
'
,
type
:
'
user
'
}
}
${
'
setSortBy
'
}
|
${
types
.
SET_SORT_BY
}
|
${
'
created_asc
'
}
${
'
setSortBy
'
}
|
${
types
.
SET_SORT_BY
}
|
${
'
created_asc
'
}
`
(
`
(
'
$action should commit $type with $payload and dispatches "searchForAuditEvents"
'
,
'
$action should commit $type with $payload and dispatches "searchForAuditEvents"
'
,
({
action
,
type
,
payload
})
=>
{
({
action
,
type
,
payload
})
=>
{
...
@@ -40,6 +39,11 @@ describe('Audit Event actions', () => {
...
@@ -40,6 +39,11 @@ describe('Audit Event actions', () => {
},
},
);
);
it
(
'
setFilterValue action should commit to the store
'
,
()
=>
{
const
payload
=
[{
type
:
'
User
'
,
value
:
{
data
:
1
,
operator
:
'
=
'
}
}];
testAction
(
actions
.
setFilterValue
,
payload
,
state
,
[{
type
:
types
.
SET_FILTER_VALUE
,
payload
}]);
});
describe
(
'
searchForAuditEvents
'
,
()
=>
{
describe
(
'
searchForAuditEvents
'
,
()
=>
{
let
spy
;
let
spy
;
...
...
ee/spec/frontend/audit_events/store/mutations_spec.js
View file @
355f2c6b
...
@@ -15,10 +15,10 @@ describe('Audit Event mutations', () => {
...
@@ -15,10 +15,10 @@ describe('Audit Event mutations', () => {
});
});
it
.
each
`
it
.
each
`
mutation | payload | expectedState
mutation | payload
| expectedState
${
types
.
SET_FILTER_VALUE
}
|
${
{
id
:
'
1
'
,
type
:
'
user
'
}
} |
${{
filterValue
:
{
id
:
'
1
'
,
type
:
'
user
'
}
}}
${
types
.
SET_FILTER_VALUE
}
|
${
[{
type
:
'
User
'
,
value
:
{
data
:
1
,
operator
:
'
=
'
}
}]}
|
$
{{
filterValue
:
[{
type
:
'
User
'
,
value
:
{
data
:
1
,
operator
:
'
=
'
}
}]
}}
${
types
.
SET_DATE_RANGE
}
|
${{
startDate
,
endDate
}
} |
${{
startDate
,
endDate
}
}
$
{
types
.
SET_DATE_RANGE
}
|
${{
startDate
,
endDate
}
}
|
${{
startDate
,
endDate
}
}
${
types
.
SET_SORT_BY
}
|
${
'
created_asc
'
}
|
${{
sortBy
:
'
created_asc
'
}
}
${
types
.
SET_SORT_BY
}
|
${
'
created_asc
'
}
|
${{
sortBy
:
'
created_asc
'
}
}
`
(
`
(
'
$mutation with payload $payload will update state with $expectedState
'
,
'
$mutation with payload $payload will update state with $expectedState
'
,
({
mutation
,
payload
,
expectedState
})
=>
{
({
mutation
,
payload
,
expectedState
})
=>
{
...
@@ -32,7 +32,7 @@ describe('Audit Event mutations', () => {
...
@@ -32,7 +32,7 @@ describe('Audit Event mutations', () => {
describe
(
`
${
types
.
INITIALIZE_AUDIT_EVENTS
}
`
,
()
=>
{
describe
(
`
${
types
.
INITIALIZE_AUDIT_EVENTS
}
`
,
()
=>
{
const
payload
=
{
const
payload
=
{
entity_id
:
'
1
'
,
entity_id
:
'
1
'
,
entity_type
:
'
u
ser
'
,
entity_type
:
'
U
ser
'
,
created_after
:
startDate
,
created_after
:
startDate
,
created_before
:
endDate
,
created_before
:
endDate
,
sort
:
'
created_asc
'
,
sort
:
'
created_asc
'
,
...
@@ -40,7 +40,7 @@ describe('Audit Event mutations', () => {
...
@@ -40,7 +40,7 @@ describe('Audit Event mutations', () => {
it
.
each
`
it
.
each
`
stateKey | expectedState
stateKey | expectedState
${
'
filterValue
'
}
|
${
{
id
:
payload
.
entity_id
,
type
:
payload
.
entity_type
}
}
${
'
filterValue
'
}
|
${
[{
type
:
payload
.
entity_type
,
value
:
{
data
:
payload
.
entity_id
,
operator
:
'
=
'
}
}]
}
$
{
'
startDate
'
}
|
${
payload
.
created_after
}
$
{
'
startDate
'
}
|
${
payload
.
created_after
}
${
'
endDate
'
}
|
${
payload
.
created_before
}
${
'
endDate
'
}
|
${
payload
.
created_before
}
${
'
sortBy
'
}
|
${
payload
.
sort
}
${
'
sortBy
'
}
|
${
payload
.
sort
}
...
...
ee/spec/frontend/audit_events/utils_spec.js
View file @
355f2c6b
...
@@ -8,6 +8,7 @@ describe('Audit Event Utils', () => {
...
@@ -8,6 +8,7 @@ describe('Audit Event Utils', () => {
created_before
:
'
2020-04-13
'
,
created_before
:
'
2020-04-13
'
,
sortBy
:
'
created_asc
'
,
sortBy
:
'
created_asc
'
,
};
};
expect
(
parseAuditEventSearchQuery
(
input
)).
toEqual
({
expect
(
parseAuditEventSearchQuery
(
input
)).
toEqual
({
created_after
:
new
Date
(
'
2020-03-13
'
),
created_after
:
new
Date
(
'
2020-03-13
'
),
created_before
:
new
Date
(
'
2020-04-13
'
),
created_before
:
new
Date
(
'
2020-04-13
'
),
...
@@ -19,20 +20,19 @@ describe('Audit Event Utils', () => {
...
@@ -19,20 +20,19 @@ describe('Audit Event Utils', () => {
describe
(
'
createAuditEventSearchQuery
'
,
()
=>
{
describe
(
'
createAuditEventSearchQuery
'
,
()
=>
{
it
(
'
returns a query object with remapped keys and stringified dates
'
,
()
=>
{
it
(
'
returns a query object with remapped keys and stringified dates
'
,
()
=>
{
const
input
=
{
const
input
=
{
filterValue
:
{
filterValue
:
[{
type
:
'
User
'
,
value
:
{
data
:
'
1
'
,
operator
:
'
=
'
}
}],
id
:
'
1
'
,
type
:
'
user
'
,
},
startDate
:
new
Date
(
'
2020-03-13
'
),
startDate
:
new
Date
(
'
2020-03-13
'
),
endDate
:
new
Date
(
'
2020-04-13
'
),
endDate
:
new
Date
(
'
2020-04-13
'
),
sortBy
:
'
bar
'
,
sortBy
:
'
bar
'
,
};
};
expect
(
createAuditEventSearchQuery
(
input
)).
toEqual
({
expect
(
createAuditEventSearchQuery
(
input
)).
toEqual
({
entity_id
:
'
1
'
,
entity_id
:
'
1
'
,
entity_type
:
'
u
ser
'
,
entity_type
:
'
U
ser
'
,
created_after
:
'
2020-03-13
'
,
created_after
:
'
2020-03-13
'
,
created_before
:
'
2020-04-13
'
,
created_before
:
'
2020-04-13
'
,
sort
:
'
bar
'
,
sort
:
'
bar
'
,
page
:
null
,
});
});
});
});
});
});
...
...
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