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
7cc6c10c
Commit
7cc6c10c
authored
Dec 13, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
630101f7
Changes
26
Show whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
398 additions
and
96 deletions
+398
-96
CHANGELOG-EE.md
CHANGELOG-EE.md
+7
-0
app/assets/javascripts/error_tracking/components/error_tracking_list.vue
...scripts/error_tracking/components/error_tracking_list.vue
+42
-26
app/assets/javascripts/error_tracking/services/index.js
app/assets/javascripts/error_tracking/services/index.js
+2
-2
app/assets/javascripts/error_tracking/store/list/actions.js
app/assets/javascripts/error_tracking/store/list/actions.js
+26
-4
app/assets/javascripts/error_tracking/store/list/mutation_types.js
...s/javascripts/error_tracking/store/list/mutation_types.js
+3
-1
app/assets/javascripts/error_tracking/store/list/mutations.js
...assets/javascripts/error_tracking/store/list/mutations.js
+9
-3
app/assets/javascripts/error_tracking/store/list/state.js
app/assets/javascripts/error_tracking/store/list/state.js
+3
-1
app/assets/javascripts/error_tracking/utils.js
app/assets/javascripts/error_tracking/utils.js
+1
-12
app/assets/javascripts/pages/snippets/show/index.js
app/assets/javascripts/pages/snippets/show/index.js
+3
-0
app/assets/javascripts/projects/project_new.js
app/assets/javascripts/projects/project_new.js
+9
-9
app/assets/javascripts/snippets/components/app.vue
app/assets/javascripts/snippets/components/app.vue
+31
-0
app/assets/javascripts/snippets/index.js
app/assets/javascripts/snippets/index.js
+34
-0
app/assets/javascripts/snippets/queries/getSnippet.query.graphql
...ets/javascripts/snippets/queries/getSnippet.query.graphql
+13
-0
app/assets/stylesheets/pages/error_tracking_list.scss
app/assets/stylesheets/pages/error_tracking_list.scss
+5
-0
app/assets/stylesheets/pages/groups.scss
app/assets/stylesheets/pages/groups.scss
+1
-0
app/views/admin/groups/_group.html.haml
app/views/admin/groups/_group.html.haml
+1
-1
app/views/shared/groups/_group.html.haml
app/views/shared/groups/_group.html.haml
+1
-1
app/views/shared/snippets/_snippet.html.haml
app/views/shared/snippets/_snippet.html.haml
+1
-1
app/views/snippets/show.html.haml
app/views/snippets/show.html.haml
+1
-1
changelogs/unreleased/34068-sort-error-list.yml
changelogs/unreleased/34068-sort-error-list.yml
+5
-0
doc/ci/merge_request_pipelines/index.md
doc/ci/merge_request_pipelines/index.md
+30
-0
locale/gitlab.pot
locale/gitlab.pot
+9
-3
spec/frontend/error_tracking/components/error_tracking_list_spec.js
...end/error_tracking/components/error_tracking_list_spec.js
+25
-12
spec/frontend/error_tracking/store/list/actions_spec.js
spec/frontend/error_tracking/store/list/actions_spec.js
+95
-8
spec/frontend/error_tracking/utils_spec.js
spec/frontend/error_tracking/utils_spec.js
+0
-11
spec/frontend/snippets/components/app_spec.js
spec/frontend/snippets/components/app_spec.js
+41
-0
No files found.
CHANGELOG-EE.md
View file @
7cc6c10c
...
...
@@ -835,6 +835,13 @@ Please view this file on the master branch, on stable branches it's out of date.
-
Don't send CI usage email notifications for self-hosted instances. !14809
## 12.0.12
### Fixed (1 change)
-
Backport the new reliable fetcher to 12.0.9. !20532
## 12.0.10
-
No changes.
...
...
app/assets/javascripts/error_tracking/components/error_tracking_list.vue
View file @
7cc6c10c
...
...
@@ -17,8 +17,6 @@ import AccessorUtils from '~/lib/utils/accessor';
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
TimeAgo
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
import
{
__
}
from
'
~/locale
'
;
import
TrackEventDirective
from
'
~/vue_shared/directives/track_event
'
;
import
{
trackViewInSentryOptions
}
from
'
../utils
'
;
export
default
{
fields
:
[
...
...
@@ -27,6 +25,11 @@ export default {
{
key
:
'
users
'
,
label
:
__
(
'
Users
'
)
},
{
key
:
'
lastSeen
'
,
label
:
__
(
'
Last seen
'
),
thClass
:
'
w-15p
'
},
],
sortFields
:
{
last_seen
:
__
(
'
Last Seen
'
),
first_seen
:
__
(
'
First Seen
'
),
frequency
:
__
(
'
Frequency
'
),
},
components
:
{
GlEmptyState
,
GlButton
,
...
...
@@ -43,7 +46,6 @@ export default {
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
TrackEvent
:
TrackEventDirective
,
},
props
:
{
indexPath
:
{
...
...
@@ -74,45 +76,47 @@ export default {
};
},
computed
:
{
...
mapState
(
'
list
'
,
[
'
errors
'
,
'
externalUrl
'
,
'
loading
'
,
'
recentSearches
'
]),
...
mapState
(
'
list
'
,
[
'
errors
'
,
'
loading
'
,
'
searchQuery
'
,
'
sortField
'
,
'
recentSearches
'
]),
},
created
()
{
if
(
this
.
errorTrackingEnabled
)
{
this
.
startPolling
(
this
.
indexPath
);
this
.
setEndpoint
(
this
.
indexPath
);
this
.
startPolling
();
}
},
methods
:
{
...
mapActions
(
'
list
'
,
[
'
startPolling
'
,
'
restartPolling
'
,
'
setEndpoint
'
,
'
searchByQuery
'
,
'
sortByField
'
,
'
addRecentSearch
'
,
'
clearRecentSearches
'
,
'
loadRecentSearches
'
,
'
setIndexPath
'
,
]),
filterErrors
()
{
const
searchTerm
=
this
.
errorSearchQuery
.
trim
();
this
.
addRecentSearch
(
searchTerm
);
this
.
startPolling
(
`
${
this
.
indexPath
}
?search_term=
${
searchTerm
}
`
);
},
setSearchText
(
text
)
{
this
.
errorSearchQuery
=
text
;
this
.
filterErrors
(
);
this
.
searchByQuery
(
text
);
},
trackViewInSentryOptions
,
getDetailsLink
(
errorId
)
{
return
`error_tracking/
${
errorId
}
/details`
;
},
isCurrentSortField
(
field
)
{
return
field
===
this
.
sortField
;
},
},
};
</
script
>
<
template
>
<div>
<div
class=
"error-list"
>
<div
v-if=
"errorTrackingEnabled"
>
<div
class=
"d-flex flex-row justify-content-around bg-secondary border p-3"
>
<div
class=
"filtered-search-box"
>
<div
class=
"d-flex flex-row justify-content-around align-items-center bg-secondary border mt-2"
>
<div
class=
"filtered-search-box flex-grow-1 my-3 ml-3 mr-2"
>
<gl-dropdown
:text=
"__('Recent searches')"
class=
"filtered-search-history-dropdown-wrapper d-none d-md-block"
...
...
@@ -143,7 +147,7 @@ export default {
:disabled=
"loading"
:placeholder=
"__('Search or filter results…')"
autofocus
@
keyup.enter.native=
"
filterErrors
"
@
keyup.enter.native=
"
searchByQuery(errorSearchQuery)
"
/>
</div>
<div
class=
"gl-search-box-by-type-right-icons"
>
...
...
@@ -160,16 +164,28 @@ export default {
</div>
</div>
<gl-
butto
n
v-track-event=
"trackViewInSentryOptions(externalUrl)
"
class=
"ml-3"
variant=
"primary
"
:href=
"externalUrl
"
target=
"_blank
"
<gl-
dropdow
n
:text=
"$options.sortFields[sortField]
"
left
:disabled=
"loading
"
class=
"mr-3
"
menu-class=
"sort-dropdown
"
>
{{ __('View in Sentry') }}
<icon
name=
"external-link"
class=
"flex-shrink-0"
/>
</gl-button>
<gl-dropdown-item
v-for=
"(label, field) in $options.sortFields"
:key=
"field"
@
click=
"sortByField(field)"
>
<span
class=
"d-flex"
>
<icon
class=
"flex-shrink-0 append-right-4"
:class=
"{ invisible: !isCurrentSortField(field) }"
name=
"mobile-issue-close"
/>
{{ label }}
</span>
</gl-dropdown-item>
</gl-dropdown>
</div>
<div
v-if=
"loading"
class=
"py-3"
>
...
...
app/assets/javascripts/error_tracking/services/index.js
View file @
7cc6c10c
import
axios
from
'
~/lib/utils/axios_utils
'
;
export
default
{
getSentryData
({
endpoint
})
{
return
axios
.
get
(
endpoint
);
getSentryData
({
endpoint
,
params
})
{
return
axios
.
get
(
endpoint
,
{
params
}
);
},
};
app/assets/javascripts/error_tracking/store/list/actions.js
View file @
7cc6c10c
...
...
@@ -6,19 +6,24 @@ import { __, sprintf } from '~/locale';
let
eTagPoll
;
export
function
startPolling
({
commit
,
dispatch
},
endpoint
)
{
export
function
startPolling
({
state
,
commit
,
dispatch
}
)
{
commit
(
types
.
SET_LOADING
,
true
);
eTagPoll
=
new
Poll
({
resource
:
Service
,
method
:
'
getSentryData
'
,
data
:
{
endpoint
},
data
:
{
endpoint
:
state
.
endpoint
,
params
:
{
search_term
:
state
.
searchQuery
,
sort
:
state
.
sortField
,
},
},
successCallback
:
({
data
})
=>
{
if
(
!
data
)
{
return
;
}
commit
(
types
.
SET_ERRORS
,
data
.
errors
);
commit
(
types
.
SET_EXTERNAL_URL
,
data
.
external_url
);
commit
(
types
.
SET_LOADING
,
false
);
dispatch
(
'
stopPolling
'
);
},
...
...
@@ -45,7 +50,6 @@ export const stopPolling = () => {
export
function
restartPolling
({
commit
})
{
commit
(
types
.
SET_ERRORS
,
[]);
commit
(
types
.
SET_EXTERNAL_URL
,
''
);
commit
(
types
.
SET_LOADING
,
true
);
if
(
eTagPoll
)
eTagPoll
.
restart
();
...
...
@@ -67,4 +71,22 @@ export function clearRecentSearches({ commit }) {
commit
(
types
.
CLEAR_RECENT_SEARCHES
);
}
export
const
searchByQuery
=
({
commit
,
dispatch
},
query
)
=>
{
const
searchQuery
=
query
.
trim
();
commit
(
types
.
SET_SEARCH_QUERY
,
searchQuery
);
commit
(
types
.
ADD_RECENT_SEARCH
,
searchQuery
);
dispatch
(
'
stopPolling
'
);
dispatch
(
'
startPolling
'
);
};
export
const
sortByField
=
({
commit
,
dispatch
},
field
)
=>
{
commit
(
types
.
SET_SORT_FIELD
,
field
);
dispatch
(
'
stopPolling
'
);
dispatch
(
'
startPolling
'
);
};
export
const
setEndpoint
=
({
commit
},
endpoint
)
=>
{
commit
(
types
.
SET_ENDPOINT
,
endpoint
);
};
export
default
()
=>
{};
app/assets/javascripts/error_tracking/store/list/mutation_types.js
View file @
7cc6c10c
export
const
SET_ERRORS
=
'
SET_ERRORS
'
;
export
const
SET_EXTERNAL_URL
=
'
SET_EXTERNAL_URL
'
;
export
const
SET_INDEX_PATH
=
'
SET_INDEX_PATH
'
;
export
const
SET_LOADING
=
'
SET_LOADING
'
;
export
const
ADD_RECENT_SEARCH
=
'
ADD_RECENT_SEARCH
'
;
export
const
CLEAR_RECENT_SEARCHES
=
'
CLEAR_RECENT_SEARCHES
'
;
export
const
LOAD_RECENT_SEARCHES
=
'
LOAD_RECENT_SEARCHES
'
;
export
const
SET_ENDPOINT
=
'
SET_ENDPOINT
'
;
export
const
SET_SORT_FIELD
=
'
SET_SORT_FIELD
'
;
export
const
SET_SEARCH_QUERY
=
'
SET_SEARCH_QUERY
'
;
app/assets/javascripts/error_tracking/store/list/mutations.js
View file @
7cc6c10c
...
...
@@ -6,9 +6,6 @@ export default {
[
types
.
SET_ERRORS
](
state
,
data
)
{
state
.
errors
=
convertObjectPropsToCamelCase
(
data
,
{
deep
:
true
});
},
[
types
.
SET_EXTERNAL_URL
](
state
,
url
)
{
state
.
externalUrl
=
url
;
},
[
types
.
SET_LOADING
](
state
,
loading
)
{
state
.
loading
=
loading
;
},
...
...
@@ -47,4 +44,13 @@ export default {
throw
e
;
}
},
[
types
.
SET_SORT_FIELD
](
state
,
field
)
{
state
.
sortField
=
field
;
},
[
types
.
SET_SEARCH_QUERY
](
state
,
query
)
{
state
.
searchQuery
=
query
;
},
[
types
.
SET_ENDPOINT
](
state
,
endpoint
)
{
state
.
endpoint
=
endpoint
;
},
};
app/assets/javascripts/error_tracking/store/list/state.js
View file @
7cc6c10c
export
default
()
=>
({
errors
:
[],
externalUrl
:
''
,
loading
:
true
,
endpoint
:
null
,
sortField
:
'
last_seen
'
,
searchQuery
:
null
,
indexPath
:
''
,
recentSearches
:
[],
});
app/assets/javascripts/error_tracking/utils.js
View file @
7cc6c10c
/* eslint-disable @gitlab/i18n/no-non-i18n-strings */
/**
* Tracks snowplow event when user clicks View in Sentry btn
* @param {String} externalUrl that will be send as a property for the event
*/
export
const
trackViewInSentryOptions
=
url
=>
({
category
:
'
Error Tracking
'
,
action
:
'
click_view_in_sentry
'
,
label
:
'
External Url
'
,
property
:
url
,
});
/* eslint-disable @gitlab/i18n/no-non-i18n-strings, import/prefer-default-export */
/**
* Tracks snowplow event when User clicks on error link to Sentry
...
...
app/assets/javascripts/pages/snippets/show/index.js
View file @
7cc6c10c
...
...
@@ -3,6 +3,7 @@ import BlobViewer from '~/blob/viewer';
import
ZenMode
from
'
~/zen_mode
'
;
import
initNotes
from
'
~/init_notes
'
;
import
snippetEmbed
from
'
~/snippet/snippet_embed
'
;
import
initSnippetsApp
from
'
~/snippets
'
;
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
{
if
(
!
gon
.
features
.
snippetsVue
)
{
...
...
@@ -11,5 +12,7 @@ document.addEventListener('DOMContentLoaded', () => {
initNotes
();
new
ZenMode
();
// eslint-disable-line no-new
snippetEmbed
();
}
else
{
initSnippetsApp
();
}
});
app/assets/javascripts/projects/project_new.js
View file @
7cc6c10c
...
...
@@ -128,15 +128,15 @@ const bindEvents = () => {
},
iosswift
:
{
text
:
s__
(
'
ProjectTemplates|iOS (Swift)
'
),
icon
:
'
.template-option
svg.icon-gitlab
'
,
icon
:
'
.template-option
.icon-iosswift
'
,
},
dotnetcore
:
{
text
:
s__
(
'
ProjectTemplates|.NET Core
'
),
icon
:
'
.template-option .icon-dotnet
'
,
icon
:
'
.template-option .icon-dotnet
core
'
,
},
android
:
{
text
:
s__
(
'
ProjectTemplates|Android
'
),
icon
:
'
.template-option
svg
.icon-android
'
,
icon
:
'
.template-option .icon-android
'
,
},
gomicro
:
{
text
:
s__
(
'
ProjectTemplates|Go Micro
'
),
...
...
@@ -164,27 +164,27 @@ const bindEvents = () => {
},
nfhugo
:
{
text
:
s__
(
'
ProjectTemplates|Netlify/Hugo
'
),
icon
:
'
.template-option .icon-n
etlify
'
,
icon
:
'
.template-option .icon-n
fhugo
'
,
},
nfjekyll
:
{
text
:
s__
(
'
ProjectTemplates|Netlify/Jekyll
'
),
icon
:
'
.template-option .icon-n
etlify
'
,
icon
:
'
.template-option .icon-n
fjekyll
'
,
},
nfplainhtml
:
{
text
:
s__
(
'
ProjectTemplates|Netlify/Plain HTML
'
),
icon
:
'
.template-option .icon-n
etlify
'
,
icon
:
'
.template-option .icon-n
fplainhtml
'
,
},
nfgitbook
:
{
text
:
s__
(
'
ProjectTemplates|Netlify/GitBook
'
),
icon
:
'
.template-option .icon-n
etlify
'
,
icon
:
'
.template-option .icon-n
fgitbook
'
,
},
nfhexo
:
{
text
:
s__
(
'
ProjectTemplates|Netlify/Hexo
'
),
icon
:
'
.template-option .icon-n
etlify
'
,
icon
:
'
.template-option .icon-n
fhexo
'
,
},
salesforcedx
:
{
text
:
s__
(
'
ProjectTemplates|SalesforceDX
'
),
icon
:
'
.template-option
svg.icon-gitlab
'
,
icon
:
'
.template-option
.icon-salesforcedx
'
,
},
serverless_framework
:
{
text
:
s__
(
'
ProjectTemplates|Serverless Framework/JS
'
),
...
...
app/assets/javascripts/snippets/components/app.vue
0 → 100644
View file @
7cc6c10c
<
script
>
import
getSnippet
from
'
../queries/getSnippet.query.graphql
'
;
export
default
{
apollo
:
{
snippetData
:
{
query
:
getSnippet
,
variables
()
{
return
{
ids
:
this
.
snippetGid
,
};
},
update
:
data
=>
data
.
snippets
.
edges
[
0
].
node
,
},
},
props
:
{
snippetGid
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
snippetData
:
{},
};
},
};
</
script
>
<
template
>
<div
class=
"js-snippet-view"
></div>
</
template
>
app/assets/javascripts/snippets/index.js
0 → 100644
View file @
7cc6c10c
import
Vue
from
'
vue
'
;
import
Translate
from
'
~/vue_shared/translate
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
createDefaultClient
from
'
~/lib/graphql
'
;
import
SnippetsApp
from
'
./components/app.vue
'
;
Vue
.
use
(
VueApollo
);
Vue
.
use
(
Translate
);
export
default
()
=>
{
const
el
=
document
.
getElementById
(
'
js-snippet-view
'
);
if
(
!
el
)
{
return
false
;
}
const
{
snippetGid
}
=
el
.
dataset
;
const
apolloProvider
=
new
VueApollo
({
defaultClient
:
createDefaultClient
(),
});
return
new
Vue
({
el
,
apolloProvider
,
render
(
createElement
)
{
return
createElement
(
SnippetsApp
,
{
props
:
{
snippetGid
,
},
});
},
});
};
app/assets/javascripts/snippets/queries/getSnippet.query.graphql
0 → 100644
View file @
7cc6c10c
query
getSnippet
(
$ids
:
[
ID
!])
{
snippets
(
ids
:
$ids
)
{
edges
{
node
{
title
description
createdAt
updatedAt
visibility
}
}
}
}
app/assets/stylesheets/pages/error_tracking_list.scss
0 → 100644
View file @
7cc6c10c
.error-list
{
.sort-dropdown
{
min-width
:
auto
;
}
}
app/assets/stylesheets/pages/groups.scss
View file @
7cc6c10c
...
...
@@ -25,6 +25,7 @@
.description
p
{
margin-bottom
:
0
;
color
:
$gl-text-color-secondary
;
}
}
...
...
app/views/admin/groups/_group.html.haml
View file @
7cc6c10c
-
group
=
local_assigns
.
fetch
(
:group
)
-
css_class
=
'no-description'
if
group
.
description
.
blank?
%li
.group-row
{
class:
css_class
}
%li
.group-row
.py-3
{
class:
css_class
}
.controls
=
link_to
_
(
'Edit'
),
admin_group_edit_path
(
group
),
id:
"edit_
#{
dom_id
(
group
)
}
"
,
class:
'btn'
=
link_to
_
(
'Delete'
),
[
:admin
,
group
],
data:
{
confirm:
_
(
"Are you sure you want to remove %{group_name}?"
)
%
{
group_name:
group
.
name
}
},
method: :delete
,
class:
'btn btn-remove'
...
...
app/views/shared/groups/_group.html.haml
View file @
7cc6c10c
-
user
=
local_assigns
.
fetch
(
:user
,
current_user
)
-
access
=
user
&
.
max_member_access_for_group
(
group
.
id
)
%li
.group-row
{
class:
(
'no-description'
if
group
.
description
.
blank?
)
}
%li
.group-row
.py-3
{
class:
(
'no-description'
if
group
.
description
.
blank?
)
}
.stats
%span
=
icon
(
'bookmark'
)
...
...
app/views/shared/snippets/_snippet.html.haml
View file @
7cc6c10c
-
link_project
=
local_assigns
.
fetch
(
:link_project
,
false
)
-
notes_count
=
@noteable_meta_data
[
snippet
.
id
].
user_notes_count
%li
.snippet-row
%li
.snippet-row
.py-3
=
image_tag
avatar_icon_for_user
(
snippet
.
author
),
class:
"avatar s40 d-none d-sm-block"
,
alt:
''
.title
...
...
app/views/snippets/show.html.haml
View file @
7cc6c10c
...
...
@@ -5,7 +5,7 @@
-
page_title
"
#{
@snippet
.
title
}
(
#{
@snippet
.
to_reference
}
)"
,
_
(
"Snippets"
)
-
if
Feature
.
enabled?
(
:snippets_vue
)
#js-snippet-view
{
'data-qa-selector'
:
'snippet_view'
}
#js-snippet-view
{
data:
{
'qa-selector'
:
'snippet_view'
,
'snippet-gid'
:
@snippet
.
to_global_id
}
}
-
else
=
render
'shared/snippets/header'
...
...
changelogs/unreleased/34068-sort-error-list.yml
0 → 100644
View file @
7cc6c10c
---
title
:
Sort Sentry error list by first seen, last seen or frequency
merge_request
:
21250
author
:
type
:
added
doc/ci/merge_request_pipelines/index.md
View file @
7cc6c10c
...
...
@@ -134,6 +134,36 @@ to add that `only:` rule to all of your jobs in order to make them always run. Y
can use this for scenarios like having only pipelines with merge requests get a
Review App set up, helping to save resources.
## Excluding certain branches
Pipelines for merge requests require special treatement when
using
[
`only`/`except`
](
../yaml/README.md#onlyexcept-basic
)
. Unlike ordinary
branch refs (for example
`refs/heads/my-feature-branch`
), merge request refs
use a special Git reference that looks like
`refs/merge-requests/:iid/head`
. Because
of this, the following configuration will
**not**
work as expected:
```
yaml
# Does not exclude a branch named "docs-my-fix"!
test
:
only
:
[
merge_requests
]
except
:
[
/^docs-/
]
```
Instead, you can use the
[
`$CI_COMMIT_REF_NAME` predefined environment
variable
](
../variables/predefined_variables.md#variables-reference
)
in
combination with
[
`only:variables`
](
../yaml/README.md#onlyvariablesexceptvariables
)
to
accomplish this behavior:
```
yaml
test
:
only
:
[
merge_requests
]
except
:
variables
:
$CI_COMMIT_REF_NAME =~ /^docs-/
```
## Important notes about merge requests from forked projects
Note that the current behavior is subject to change. In the usual contribution
...
...
locale/gitlab.pot
View file @
7cc6c10c
...
...
@@ -7735,6 +7735,9 @@ msgstr ""
msgid "Finished"
msgstr ""
msgid "First Seen"
msgstr ""
msgid "First day of the week"
msgstr ""
...
...
@@ -7861,6 +7864,9 @@ msgstr ""
msgid "Free Trial of GitLab.com Gold"
msgstr ""
msgid "Frequency"
msgstr ""
msgid "Friday"
msgstr ""
...
...
@@ -10201,6 +10207,9 @@ msgstr ""
msgid "Last Pipeline"
msgstr ""
msgid "Last Seen"
msgstr ""
msgid "Last accessed on"
msgstr ""
...
...
@@ -19762,9 +19771,6 @@ msgstr ""
msgid "View group labels"
msgstr ""
msgid "View in Sentry"
msgstr ""
msgid "View it on GitLab"
msgstr ""
...
...
spec/frontend/error_tracking/components/error_tracking_list_spec.js
View file @
7cc6c10c
import
{
createLocalVue
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
{
GlButton
,
GlEmptyState
,
GlLoadingIcon
,
GlTable
,
...
...
@@ -24,7 +23,9 @@ describe('ErrorTrackingList', () => {
const
findErrorListTable
=
()
=>
wrapper
.
find
(
'
table
'
);
const
findErrorListRows
=
()
=>
wrapper
.
findAll
(
'
tbody tr
'
);
const
findButton
=
()
=>
wrapper
.
find
(
GlButton
);
const
findSortDropdown
=
()
=>
wrapper
.
find
(
'
.sort-dropdown
'
);
const
findRecentSearchesDropdown
=
()
=>
wrapper
.
find
(
'
.filtered-search-history-dropdown-wrapper
'
);
const
findLoadingIcon
=
()
=>
wrapper
.
find
(
GlLoadingIcon
);
function
mountComponent
({
...
...
@@ -33,6 +34,8 @@ describe('ErrorTrackingList', () => {
stubs
=
{
'
gl-link
'
:
GlLink
,
'
gl-table
'
:
GlTable
,
'
gl-dropdown
'
:
GlDropdown
,
'
gl-dropdown-item
'
:
GlDropdownItem
,
},
}
=
{})
{
wrapper
=
shallowMount
(
ErrorTrackingList
,
{
...
...
@@ -46,6 +49,9 @@ describe('ErrorTrackingList', () => {
illustrationPath
:
'
illustration/path
'
,
},
stubs
,
data
()
{
return
{
errorSearchQuery
:
'
search
'
};
},
});
}
...
...
@@ -58,6 +64,9 @@ describe('ErrorTrackingList', () => {
loadRecentSearches
:
jest
.
fn
(),
setIndexPath
:
jest
.
fn
(),
clearRecentSearches
:
jest
.
fn
(),
setEndpoint
:
jest
.
fn
(),
searchByQuery
:
jest
.
fn
(),
sortByField
:
jest
.
fn
(),
};
const
state
=
createListState
();
...
...
@@ -101,7 +110,7 @@ describe('ErrorTrackingList', () => {
it
(
'
shows table
'
,
()
=>
{
expect
(
findLoadingIcon
().
exists
()).
toBe
(
false
);
expect
(
findErrorListTable
().
exists
()).
toBe
(
true
);
expect
(
find
Butto
n
().
exists
()).
toBe
(
true
);
expect
(
find
SortDropdow
n
().
exists
()).
toBe
(
true
);
});
it
(
'
shows list of errors in a table
'
,
()
=>
{
...
...
@@ -121,16 +130,20 @@ describe('ErrorTrackingList', () => {
describe
(
'
filtering
'
,
()
=>
{
const
findSearchBox
=
()
=>
wrapper
.
find
(
GlFormInput
);
it
(
'
shows search box
'
,
()
=>
{
it
(
'
shows search box
& sort dropdown
'
,
()
=>
{
expect
(
findSearchBox
().
exists
()).
toBe
(
true
);
expect
(
findSortDropdown
().
exists
()).
toBe
(
true
);
});
it
(
'
makes network request on submit
'
,
()
=>
{
expect
(
actions
.
startPolling
).
toHaveBeenCalledTimes
(
1
);
it
(
'
it searches by query
'
,
()
=>
{
findSearchBox
().
trigger
(
'
keyup.enter
'
);
expect
(
actions
.
searchByQuery
.
mock
.
calls
[
0
][
1
]).
toEqual
(
wrapper
.
vm
.
errorSearchQuery
);
});
expect
(
actions
.
startPolling
).
toHaveBeenCalledTimes
(
2
);
it
(
'
it sorts by fields
'
,
()
=>
{
const
findSortItem
=
()
=>
wrapper
.
find
(
'
.dropdown-item
'
);
findSortItem
().
trigger
(
'
click
'
);
expect
(
actions
.
sortByField
).
toHaveBeenCalled
();
});
});
});
...
...
@@ -148,7 +161,7 @@ describe('ErrorTrackingList', () => {
it
(
'
shows empty table
'
,
()
=>
{
expect
(
findLoadingIcon
().
exists
()).
toBe
(
false
);
expect
(
findErrorListRows
().
length
).
toEqual
(
1
);
expect
(
find
Butto
n
().
exists
()).
toBe
(
true
);
expect
(
find
SortDropdow
n
().
exists
()).
toBe
(
true
);
});
it
(
'
shows a message prompting to refresh
'
,
()
=>
{
...
...
@@ -170,7 +183,7 @@ describe('ErrorTrackingList', () => {
expect
(
wrapper
.
find
(
GlEmptyState
).
exists
()).
toBe
(
true
);
expect
(
findLoadingIcon
().
exists
()).
toBe
(
false
);
expect
(
findErrorListTable
().
exists
()).
toBe
(
false
);
expect
(
find
Butto
n
().
exists
()).
toBe
(
false
);
expect
(
find
SortDropdow
n
().
exists
()).
toBe
(
false
);
});
});
...
...
@@ -201,13 +214,13 @@ describe('ErrorTrackingList', () => {
it
(
'
shows empty message
'
,
()
=>
{
store
.
state
.
list
.
recentSearches
=
[];
expect
(
wrapper
.
find
(
GlDropdown
).
text
()).
toBe
(
"
You don't have any recent searches
"
);
expect
(
findRecentSearchesDropdown
().
text
()).
toContain
(
"
You don't have any recent searches
"
);
});
it
(
'
shows items
'
,
()
=>
{
store
.
state
.
list
.
recentSearches
=
[
'
great
'
,
'
search
'
];
const
dropdownItems
=
wrapper
.
findAll
(
GlDropdownItem
);
const
dropdownItems
=
wrapper
.
findAll
(
'
.filtered-search-box li
'
);
expect
(
dropdownItems
.
length
).
toBe
(
3
);
expect
(
dropdownItems
.
at
(
0
).
text
()).
toBe
(
'
great
'
);
...
...
spec/frontend/error_tracking/store/list/actions_spec.js
View file @
7cc6c10c
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
testAction
from
'
helpers/vuex_action_helper
'
;
import
httpStatusCodes
from
'
~/lib/utils/http_status
'
;
import
createFlash
from
'
~/flash
'
;
import
*
as
actions
from
'
~/error_tracking/store/list/actions
'
;
import
*
as
types
from
'
~/error_tracking/store/list/mutation_types
'
;
jest
.
mock
(
'
~/flash.js
'
);
describe
(
'
error tracking actions
'
,
()
=>
{
let
mock
;
...
...
@@ -15,15 +20,97 @@ describe('error tracking actions', () => {
});
describe
(
'
startPolling
'
,
()
=>
{
it
(
'
commits SET_LOADING
'
,
()
=>
{
mock
.
onGet
().
reply
(
200
);
const
endpoint
=
'
/errors
'
;
const
commit
=
jest
.
fn
();
const
state
=
{};
it
(
'
should start polling for data
'
,
done
=>
{
const
payload
=
{
errors
:
[{
id
:
1
},
{
id
:
2
}]
};
mock
.
onGet
().
reply
(
httpStatusCodes
.
OK
,
payload
);
testAction
(
actions
.
startPolling
,
{},
{},
[
{
type
:
types
.
SET_LOADING
,
payload
:
true
},
{
type
:
types
.
SET_ERRORS
,
payload
:
payload
.
errors
},
{
type
:
types
.
SET_LOADING
,
payload
:
false
},
],
[{
type
:
'
stopPolling
'
}],
()
=>
{
done
();
},
);
});
it
(
'
should show flash on API error
'
,
done
=>
{
mock
.
onGet
().
reply
(
httpStatusCodes
.
BAD_REQUEST
);
testAction
(
actions
.
startPolling
,
{},
{},
[{
type
:
types
.
SET_LOADING
,
payload
:
true
},
{
type
:
types
.
SET_LOADING
,
payload
:
false
}],
[],
()
=>
{
expect
(
createFlash
).
toHaveBeenCalledTimes
(
1
);
done
();
},
);
});
});
describe
(
'
restartPolling
'
,
()
=>
{
it
(
'
should restart polling
'
,
()
=>
{
testAction
(
actions
.
restartPolling
,
{},
{},
[{
type
:
types
.
SET_ERRORS
,
payload
:
[]
},
{
type
:
types
.
SET_LOADING
,
payload
:
true
}],
[],
);
});
});
describe
(
'
searchByQuery
'
,
()
=>
{
it
(
'
should search by query
'
,
()
=>
{
const
query
=
'
search
'
;
testAction
(
actions
.
searchByQuery
,
query
,
{},
[
{
type
:
types
.
SET_SEARCH_QUERY
,
payload
:
query
},
{
type
:
types
.
ADD_RECENT_SEARCH
,
payload
:
query
},
],
[{
type
:
'
stopPolling
'
},
{
type
:
'
startPolling
'
}],
);
});
});
describe
(
'
sortByField
'
,
()
=>
{
it
(
'
should search by query
'
,
()
=>
{
const
field
=
'
frequency
'
;
testAction
(
actions
.
sortByField
,
{
field
},
{},
[{
type
:
types
.
SET_SORT_FIELD
,
payload
:
{
field
}
}],
[{
type
:
'
stopPolling
'
},
{
type
:
'
startPolling
'
}],
);
});
});
actions
.
startPolling
({
commit
,
state
},
endpoint
);
describe
(
'
setEnpoint
'
,
()
=>
{
it
(
'
should set search endpoint
'
,
()
=>
{
const
endpoint
=
'
https://sentry.io
'
;
expect
(
commit
).
toHaveBeenCalledWith
(
types
.
SET_LOADING
,
true
);
testAction
(
actions
.
setEndpoint
,
{
endpoint
},
{},
[{
type
:
types
.
SET_ENDPOINT
,
payload
:
{
endpoint
}
}],
[],
);
});
});
});
spec/frontend/error_tracking/utils_spec.js
View file @
7cc6c10c
...
...
@@ -3,17 +3,6 @@ import * as errorTrackingUtils from '~/error_tracking/utils';
const
externalUrl
=
'
https://sentry.io/organizations/test-sentry-nk/issues/1/?project=1
'
;
describe
(
'
Error Tracking Events
'
,
()
=>
{
describe
(
'
trackViewInSentryOptions
'
,
()
=>
{
it
(
'
should return correct event options
'
,
()
=>
{
expect
(
errorTrackingUtils
.
trackViewInSentryOptions
(
externalUrl
)).
toEqual
({
category
:
'
Error Tracking
'
,
action
:
'
click_view_in_sentry
'
,
label
:
'
External Url
'
,
property
:
externalUrl
,
});
});
});
describe
(
'
trackClickErrorLinkToSentryOptions
'
,
()
=>
{
it
(
'
should return correct event options
'
,
()
=>
{
expect
(
errorTrackingUtils
.
trackClickErrorLinkToSentryOptions
(
externalUrl
)).
toEqual
({
...
...
spec/frontend/snippets/components/app_spec.js
0 → 100644
View file @
7cc6c10c
import
SnippetApp
from
'
~/snippets/components/app.vue
'
;
import
{
createLocalVue
,
shallowMount
}
from
'
@vue/test-utils
'
;
describe
(
'
Snippet view app
'
,
()
=>
{
let
wrapper
;
let
snippetDataMock
;
const
localVue
=
createLocalVue
();
const
defaultProps
=
{
snippetGid
:
'
gid://gitlab/PersonalSnippet/35
'
,
};
function
createComponent
({
props
=
defaultProps
,
snippetData
=
{}
}
=
{})
{
snippetDataMock
=
jest
.
fn
();
const
$apollo
=
{
queries
:
{
snippetData
:
snippetDataMock
,
},
};
wrapper
=
shallowMount
(
SnippetApp
,
{
sync
:
false
,
mocks
:
{
$apollo
},
localVue
,
propsData
:
{
...
props
,
},
});
wrapper
.
setData
({
snippetData
,
});
}
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
renders itself
'
,
()
=>
{
createComponent
();
expect
(
wrapper
.
find
(
'
.js-snippet-view
'
).
exists
()).
toBe
(
true
);
});
});
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