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
0
Merge Requests
0
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
Léo-Paul Géneau
gitlab-ce
Commits
5a521254
Commit
5a521254
authored
Jan 11, 2019
by
Simon Knox
Committed by
Clement Ho
Jan 11, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
List Sentry Errors in GitLab - Frontend
parent
6d6c2e95
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
483 additions
and
0 deletions
+483
-0
app/assets/javascripts/error_tracking/components/error_tracking_list.vue
...scripts/error_tracking/components/error_tracking_list.vue
+118
-0
app/assets/javascripts/error_tracking/index.js
app/assets/javascripts/error_tracking/index.js
+35
-0
app/assets/javascripts/error_tracking/services/index.js
app/assets/javascripts/error_tracking/services/index.js
+7
-0
app/assets/javascripts/error_tracking/store/actions.js
app/assets/javascripts/error_tracking/store/actions.js
+31
-0
app/assets/javascripts/error_tracking/store/index.js
app/assets/javascripts/error_tracking/store/index.js
+19
-0
app/assets/javascripts/error_tracking/store/mutation_types.js
...assets/javascripts/error_tracking/store/mutation_types.js
+3
-0
app/assets/javascripts/error_tracking/store/mutations.js
app/assets/javascripts/error_tracking/store/mutations.js
+14
-0
app/assets/javascripts/pages/projects/error_tracking/index.js
...assets/javascripts/pages/projects/error_tracking/index.js
+5
-0
app/helpers/projects/error_tracking_helper.rb
app/helpers/projects/error_tracking_helper.rb
+15
-0
app/helpers/projects_helper.rb
app/helpers/projects_helper.rb
+2
-0
app/views/layouts/nav/sidebar/_project.html.haml
app/views/layouts/nav/sidebar/_project.html.haml
+6
-0
app/views/projects/error_tracking/index.html.haml
app/views/projects/error_tracking/index.html.haml
+2
-0
changelogs/unreleased/error_tracking_feature_flag_fe.yml
changelogs/unreleased/error_tracking_feature_flag_fe.yml
+5
-0
locale/gitlab.pot
locale/gitlab.pot
+27
-0
spec/helpers/projects/error_tracking_helper_spec.rb
spec/helpers/projects/error_tracking_helper_spec.rb
+58
-0
spec/javascripts/error_tracking/components/error_tracking_list_spec.js
...pts/error_tracking/components/error_tracking_list_spec.js
+100
-0
spec/javascripts/error_tracking/store/mutation_spec.js
spec/javascripts/error_tracking/store/mutation_spec.js
+36
-0
No files found.
app/assets/javascripts/error_tracking/components/error_tracking_list.vue
0 → 100644
View file @
5a521254
<
script
>
import
{
mapActions
,
mapState
}
from
'
vuex
'
;
import
{
GlEmptyState
,
GlButton
,
GlLink
,
GlLoadingIcon
,
GlTable
}
from
'
@gitlab/ui
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
TimeAgo
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
import
{
__
}
from
'
~/locale
'
;
export
default
{
fields
:
[
{
key
:
'
error
'
,
label
:
__
(
'
Open errors
'
)
},
{
key
:
'
events
'
,
label
:
__
(
'
Events
'
)
},
{
key
:
'
users
'
,
label
:
__
(
'
Users
'
)
},
{
key
:
'
lastSeen
'
,
label
:
__
(
'
Last seen
'
)
},
],
components
:
{
GlEmptyState
,
GlButton
,
GlLink
,
GlLoadingIcon
,
GlTable
,
Icon
,
TimeAgo
,
},
props
:
{
indexPath
:
{
type
:
String
,
required
:
true
,
},
enableErrorTrackingLink
:
{
type
:
String
,
required
:
true
,
},
errorTrackingEnabled
:
{
type
:
Boolean
,
required
:
true
,
},
illustrationPath
:
{
type
:
String
,
required
:
true
,
},
},
computed
:
{
...
mapState
([
'
errors
'
,
'
externalUrl
'
,
'
loading
'
]),
},
created
()
{
if
(
this
.
errorTrackingEnabled
)
{
this
.
startPolling
(
this
.
indexPath
);
}
},
methods
:
{
...
mapActions
([
'
startPolling
'
]),
},
};
</
script
>
<
template
>
<div>
<div
v-if=
"errorTrackingEnabled"
>
<div
v-if=
"loading"
class=
"py-3"
><gl-loading-icon
:size=
"3"
/></div>
<div
v-else
>
<div
class=
"d-flex justify-content-end"
>
<gl-button
class=
"my-3 ml-auto"
variant=
"primary"
:href=
"externalUrl"
target=
"_blank"
>
View in Sentry
<icon
name=
"external-link"
/>
</gl-button>
</div>
<gl-table
:items=
"errors"
:fields=
"$options.fields"
:show-empty=
"true"
:empty-text=
"__('No errors to display')"
>
<template
slot=
"HEAD_events"
slot-scope=
"data"
>
<div
class=
"text-right"
>
{{
data
.
label
}}
</div>
</
template
>
<
template
slot=
"HEAD_users"
slot-scope=
"data"
>
<div
class=
"text-right"
>
{{
data
.
label
}}
</div>
</
template
>
<
template
slot=
"error"
slot-scope=
"errors"
>
<div
class=
"d-flex flex-column"
>
<div
class=
"d-flex"
>
<gl-link
:href=
"errors.item.externalUrl"
class=
"d-flex text-dark"
target=
"_blank"
>
<strong>
{{
errors
.
item
.
title
.
trim
()
}}
</strong>
<icon
name=
"external-link"
class=
"ml-1"
/>
</gl-link>
<span
class=
"text-secondary ml-2"
>
{{
errors
.
item
.
culprit
}}
</span>
</div>
{{
errors
.
item
.
message
||
__
(
'
No details available
'
)
}}
</div>
</
template
>
<
template
slot=
"events"
slot-scope=
"errors"
>
<div
class=
"text-right"
>
{{
errors
.
item
.
count
}}
</div>
</
template
>
<
template
slot=
"users"
slot-scope=
"errors"
>
<div
class=
"text-right"
>
{{
errors
.
item
.
userCount
}}
</div>
</
template
>
<
template
slot=
"lastSeen"
slot-scope=
"errors"
>
<div
class=
"d-flex align-items-center"
>
<icon
name=
"calendar"
css-classes=
"text-secondary mr-1"
/>
<time-ago
:time=
"errors.item.lastSeen"
class=
"text-secondary"
/>
</div>
</
template
>
</gl-table>
</div>
</div>
<div
v-else
>
<gl-empty-state
:title=
"__('Get started with error tracking')"
:description=
"__('Monitor your errors by integrating with Sentry')"
:primary-button-text=
"__('Enable error tracking')"
:primary-button-link=
"enableErrorTrackingLink"
:svg-path=
"illustrationPath"
/>
</div>
</div>
</template>
app/assets/javascripts/error_tracking/index.js
0 → 100644
View file @
5a521254
import
Vue
from
'
vue
'
;
import
{
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
store
from
'
./store
'
;
import
ErrorTrackingList
from
'
./components/error_tracking_list.vue
'
;
export
default
()
=>
{
if
(
!
gon
.
features
.
errorTracking
)
{
return
;
}
// eslint-disable-next-line no-new
new
Vue
({
el
:
'
#js-error_tracking
'
,
components
:
{
ErrorTrackingList
,
},
store
,
render
(
createElement
)
{
const
domEl
=
document
.
querySelector
(
this
.
$options
.
el
);
const
{
indexPath
,
enableErrorTrackingLink
,
illustrationPath
}
=
domEl
.
dataset
;
let
{
errorTrackingEnabled
}
=
domEl
.
dataset
;
errorTrackingEnabled
=
parseBoolean
(
errorTrackingEnabled
);
return
createElement
(
'
error-tracking-list
'
,
{
props
:
{
indexPath
,
enableErrorTrackingLink
,
errorTrackingEnabled
,
illustrationPath
,
},
});
},
});
};
app/assets/javascripts/error_tracking/services/index.js
0 → 100644
View file @
5a521254
import
axios
from
'
~/lib/utils/axios_utils
'
;
export
default
{
getErrorList
({
endpoint
})
{
return
axios
.
get
(
endpoint
);
},
};
app/assets/javascripts/error_tracking/store/actions.js
0 → 100644
View file @
5a521254
import
Service
from
'
../services
'
;
import
*
as
types
from
'
./mutation_types
'
;
import
createFlash
from
'
~/flash
'
;
import
Poll
from
'
~/lib/utils/poll
'
;
import
{
__
}
from
'
~/locale
'
;
let
eTagPoll
;
export
function
startPolling
({
commit
},
endpoint
)
{
eTagPoll
=
new
Poll
({
resource
:
Service
,
method
:
'
getErrorList
'
,
data
:
{
endpoint
},
successCallback
:
({
data
})
=>
{
if
(
!
data
)
{
return
;
}
commit
(
types
.
SET_ERRORS
,
data
.
errors
);
commit
(
types
.
SET_EXTERNAL_URL
,
data
.
external_url
);
commit
(
types
.
SET_LOADING
,
false
);
},
errorCallback
:
()
=>
{
commit
(
types
.
SET_LOADING
,
false
);
createFlash
(
__
(
'
Failed to load errors from Sentry
'
));
},
});
eTagPoll
.
makeRequest
();
}
export
default
()
=>
{};
app/assets/javascripts/error_tracking/store/index.js
0 → 100644
View file @
5a521254
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
*
as
actions
from
'
./actions
'
;
import
mutations
from
'
./mutations
'
;
Vue
.
use
(
Vuex
);
export
const
createStore
=
()
=>
new
Vuex
.
Store
({
state
:
{
errors
:
[],
externalUrl
:
''
,
loading
:
true
,
},
actions
,
mutations
,
});
export
default
createStore
();
app/assets/javascripts/error_tracking/store/mutation_types.js
0 → 100644
View file @
5a521254
export
const
SET_ERRORS
=
'
SET_ERRORS
'
;
export
const
SET_EXTERNAL_URL
=
'
SET_EXTERNAL_URL
'
;
export
const
SET_LOADING
=
'
SET_LOADING
'
;
app/assets/javascripts/error_tracking/store/mutations.js
0 → 100644
View file @
5a521254
import
*
as
types
from
'
./mutation_types
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
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
;
},
};
app/assets/javascripts/pages/projects/error_tracking/index.js
0 → 100644
View file @
5a521254
import
ErrorTracking
from
'
~/error_tracking
'
;
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
{
ErrorTracking
();
});
app/helpers/projects/error_tracking_helper.rb
0 → 100644
View file @
5a521254
# frozen_string_literal: true
module
Projects::ErrorTrackingHelper
def
error_tracking_data
(
project
)
error_tracking_enabled
=
!!
project
.
error_tracking_setting
&
.
enabled?
{
'index-path'
=>
project_error_tracking_index_path
(
project
,
format: :json
),
'enable-error-tracking-link'
=>
project_settings_operations_path
(
project
),
'error-tracking-enabled'
=>
error_tracking_enabled
.
to_s
,
'illustration-path'
=>
image_path
(
'illustrations/cluster_popover.svg'
)
}
end
end
app/helpers/projects_helper.rb
View file @
5a521254
...
@@ -335,6 +335,7 @@ module ProjectsHelper
...
@@ -335,6 +335,7 @@ module ProjectsHelper
builds: :read_build
,
builds: :read_build
,
clusters: :read_cluster
,
clusters: :read_cluster
,
serverless: :read_cluster
,
serverless: :read_cluster
,
error_tracking: :read_sentry_issue
,
labels: :read_label
,
labels: :read_label
,
issues: :read_issue
,
issues: :read_issue
,
project_members: :read_project_member
,
project_members: :read_project_member
,
...
@@ -579,6 +580,7 @@ module ProjectsHelper
...
@@ -579,6 +580,7 @@ module ProjectsHelper
environments
environments
clusters
clusters
functions
functions
error_tracking
user
user
gcp
gcp
]
]
...
...
app/views/layouts/nav/sidebar/_project.html.haml
View file @
5a521254
...
@@ -227,6 +227,12 @@
...
@@ -227,6 +227,12 @@
%span
%span
=
_
(
'Environments'
)
=
_
(
'Environments'
)
-
if
project_nav_tab?
(
:error_tracking
)
&&
Feature
.
enabled?
(
:error_tracking
,
@project
)
=
nav_link
(
controller: :error_tracking
)
do
=
link_to
project_error_tracking_index_path
(
@project
),
title:
_
(
'Error Tracking'
),
class:
'shortcuts-tracking qa-operations-tracking-link'
do
%span
=
_
(
'Error Tracking'
)
-
if
project_nav_tab?
:serverless
-
if
project_nav_tab?
:serverless
=
nav_link
(
controller: :functions
)
do
=
nav_link
(
controller: :functions
)
do
=
link_to
project_serverless_functions_path
(
@project
),
title:
_
(
'Serverless'
)
do
=
link_to
project_serverless_functions_path
(
@project
),
title:
_
(
'Serverless'
)
do
...
...
app/views/projects/error_tracking/index.html.haml
View file @
5a521254
-
page_title
_
(
'Errors'
)
-
page_title
_
(
'Errors'
)
#js-error_tracking
{
data:
error_tracking_data
(
@project
)
}
changelogs/unreleased/error_tracking_feature_flag_fe.yml
0 → 100644
View file @
5a521254
---
title
:
Display a list of Sentry Issues in GitLab
merge_request
:
23770
author
:
type
:
added
locale/gitlab.pot
View file @
5a521254
...
@@ -2749,6 +2749,9 @@ msgstr ""
...
@@ -2749,6 +2749,9 @@ msgstr ""
msgid "Enable and configure Prometheus metrics."
msgid "Enable and configure Prometheus metrics."
msgstr ""
msgstr ""
msgid "Enable error tracking"
msgstr ""
msgid "Enable for this project"
msgid "Enable for this project"
msgstr ""
msgstr ""
...
@@ -2980,6 +2983,9 @@ msgstr ""
...
@@ -2980,6 +2983,9 @@ msgstr ""
msgid "EventFilterBy|Filter by team"
msgid "EventFilterBy|Filter by team"
msgstr ""
msgstr ""
msgid "Events"
msgstr ""
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
msgstr ""
...
@@ -3067,6 +3073,9 @@ msgstr ""
...
@@ -3067,6 +3073,9 @@ msgstr ""
msgid "Failed to load emoji list."
msgid "Failed to load emoji list."
msgstr ""
msgstr ""
msgid "Failed to load errors from Sentry"
msgstr ""
msgid "Failed to remove issue from board, please try again."
msgid "Failed to remove issue from board, please try again."
msgstr ""
msgstr ""
...
@@ -3250,6 +3259,9 @@ msgstr ""
...
@@ -3250,6 +3259,9 @@ msgstr ""
msgid "Geo"
msgid "Geo"
msgstr ""
msgstr ""
msgid "Get started with error tracking"
msgstr ""
msgid "Getting started with releases"
msgid "Getting started with releases"
msgstr ""
msgstr ""
...
@@ -3956,6 +3968,9 @@ msgstr ""
...
@@ -3956,6 +3968,9 @@ msgstr ""
msgid "Last reply by"
msgid "Last reply by"
msgstr ""
msgstr ""
msgid "Last seen"
msgstr ""
msgid "Last update"
msgid "Last update"
msgstr ""
msgstr ""
...
@@ -4345,6 +4360,9 @@ msgstr ""
...
@@ -4345,6 +4360,9 @@ msgstr ""
msgid "Modal|Close"
msgid "Modal|Close"
msgstr ""
msgstr ""
msgid "Monitor your errors by integrating with Sentry"
msgstr ""
msgid "Monitoring"
msgid "Monitoring"
msgstr ""
msgstr ""
...
@@ -4509,9 +4527,15 @@ msgstr ""
...
@@ -4509,9 +4527,15 @@ msgstr ""
msgid "No contributions were found"
msgid "No contributions were found"
msgstr ""
msgstr ""
msgid "No details available"
msgstr ""
msgid "No due date"
msgid "No due date"
msgstr ""
msgstr ""
msgid "No errors to display"
msgstr ""
msgid "No estimate or time spent"
msgid "No estimate or time spent"
msgstr ""
msgstr ""
...
@@ -4730,6 +4754,9 @@ msgstr ""
...
@@ -4730,6 +4754,9 @@ msgstr ""
msgid "Open comment type dropdown"
msgid "Open comment type dropdown"
msgstr ""
msgstr ""
msgid "Open errors"
msgstr ""
msgid "Open in Xcode"
msgid "Open in Xcode"
msgstr ""
msgstr ""
...
...
spec/helpers/projects/error_tracking_helper_spec.rb
0 → 100644
View file @
5a521254
# frozen_string_literal: true
require
'spec_helper'
describe
Projects
::
ErrorTrackingHelper
do
include
Gitlab
::
Routing
.
url_helpers
set
(
:project
)
{
create
(
:project
)
}
describe
'#error_tracking_data'
do
let
(
:setting_path
)
{
project_settings_operations_path
(
project
)
}
let
(
:index_path
)
do
project_error_tracking_index_path
(
project
,
format: :json
)
end
context
'without error_tracking_setting'
do
it
'returns frontend configuration'
do
expect
(
error_tracking_data
(
project
)).
to
eq
(
'index-path'
=>
index_path
,
'enable-error-tracking-link'
=>
setting_path
,
'error-tracking-enabled'
=>
'false'
,
"illustration-path"
=>
"/images/illustrations/cluster_popover.svg"
)
end
end
context
'with error_tracking_setting'
do
let
(
:error_tracking_setting
)
do
create
(
:project_error_tracking_setting
,
project:
project
)
end
context
'when enabled'
do
before
do
error_tracking_setting
.
update!
(
enabled:
true
)
end
it
'show error tracking enabled'
do
expect
(
error_tracking_data
(
project
)).
to
include
(
'error-tracking-enabled'
=>
'true'
)
end
end
context
'when disabled'
do
before
do
error_tracking_setting
.
update!
(
enabled:
false
)
end
it
'show error tracking not enabled'
do
expect
(
error_tracking_data
(
project
)).
to
include
(
'error-tracking-enabled'
=>
'false'
)
end
end
end
end
end
spec/javascripts/error_tracking/components/error_tracking_list_spec.js
0 → 100644
View file @
5a521254
import
{
createLocalVue
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
ErrorTrackingList
from
'
~/error_tracking/components/error_tracking_list.vue
'
;
import
{
GlButton
,
GlEmptyState
,
GlLoadingIcon
,
GlTable
}
from
'
@gitlab/ui
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
describe
(
'
ErrorTrackingList
'
,
()
=>
{
let
store
;
let
wrapper
;
function
mountComponent
({
errorTrackingEnabled
=
true
}
=
{})
{
wrapper
=
shallowMount
(
ErrorTrackingList
,
{
localVue
,
store
,
propsData
:
{
indexPath
:
'
/path
'
,
enableErrorTrackingLink
:
'
/link
'
,
errorTrackingEnabled
,
illustrationPath
:
'
illustration/path
'
,
},
});
}
beforeEach
(()
=>
{
const
actions
=
{
getErrorList
:
()
=>
{},
};
const
state
=
{
errors
:
[],
loading
:
true
,
};
store
=
new
Vuex
.
Store
({
actions
,
state
,
});
});
afterEach
(()
=>
{
if
(
wrapper
)
{
wrapper
.
destroy
();
}
});
describe
(
'
loading
'
,
()
=>
{
beforeEach
(()
=>
{
mountComponent
();
});
it
(
'
shows spinner
'
,
()
=>
{
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBeTruthy
();
expect
(
wrapper
.
find
(
GlTable
).
exists
()).
toBeFalsy
();
expect
(
wrapper
.
find
(
GlButton
).
exists
()).
toBeFalsy
();
});
});
describe
(
'
results
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
state
.
loading
=
false
;
mountComponent
();
});
it
(
'
shows table
'
,
()
=>
{
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBeFalsy
();
expect
(
wrapper
.
find
(
GlTable
).
exists
()).
toBeTruthy
();
expect
(
wrapper
.
find
(
GlButton
).
exists
()).
toBeTruthy
();
});
});
describe
(
'
no results
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
state
.
loading
=
false
;
mountComponent
();
});
it
(
'
shows empty table
'
,
()
=>
{
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBeFalsy
();
expect
(
wrapper
.
find
(
GlTable
).
exists
()).
toBeTruthy
();
expect
(
wrapper
.
find
(
GlButton
).
exists
()).
toBeTruthy
();
});
});
describe
(
'
error tracking feature disabled
'
,
()
=>
{
beforeEach
(()
=>
{
mountComponent
({
errorTrackingEnabled
:
false
});
});
it
(
'
shows empty state
'
,
()
=>
{
expect
(
wrapper
.
find
(
GlEmptyState
).
exists
()).
toBeTruthy
();
expect
(
wrapper
.
find
(
GlLoadingIcon
).
exists
()).
toBeFalsy
();
expect
(
wrapper
.
find
(
GlTable
).
exists
()).
toBeFalsy
();
expect
(
wrapper
.
find
(
GlButton
).
exists
()).
toBeFalsy
();
});
});
});
spec/javascripts/error_tracking/store/mutation_spec.js
0 → 100644
View file @
5a521254
import
mutations
from
'
~/error_tracking/store/mutations
'
;
import
*
as
types
from
'
~/error_tracking/store/mutation_types
'
;
describe
(
'
Error tracking mutations
'
,
()
=>
{
describe
(
'
SET_ERRORS
'
,
()
=>
{
let
state
;
beforeEach
(()
=>
{
state
=
{
errors
:
[]
};
});
it
(
'
camelizes response
'
,
()
=>
{
const
errors
=
[
{
title
:
'
the title
'
,
external_url
:
'
localhost:3456
'
,
count
:
100
,
userCount
:
10
,
},
];
mutations
[
types
.
SET_ERRORS
](
state
,
errors
);
expect
(
state
).
toEqual
({
errors
:
[
{
title
:
'
the title
'
,
externalUrl
:
'
localhost:3456
'
,
count
:
100
,
userCount
:
10
,
},
],
});
});
});
});
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