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
f1ec6510
Commit
f1ec6510
authored
Sep 28, 2020
by
Angelo Gulina
Committed by
Olena Horal-Koretska
Sep 28, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update Alert summary section
Add a slotted component for the summary Add a utility for VTU, findByTestId()
parent
af6e6aa7
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
217 additions
and
94 deletions
+217
-94
app/assets/javascripts/alert_management/components/alert_details.vue
...javascripts/alert_management/components/alert_details.vue
+68
-49
app/assets/javascripts/alert_management/components/alert_summary_row.vue
...scripts/alert_management/components/alert_summary_row.vue
+18
-0
app/assets/javascripts/vue_shared/components/alert_details_table.vue
...javascripts/vue_shared/components/alert_details_table.vue
+13
-5
locale/gitlab.pot
locale/gitlab.pot
+5
-0
spec/frontend/alert_management/components/alert_details_spec.js
...rontend/alert_management/components/alert_details_spec.js
+60
-38
spec/frontend/alert_management/components/alert_summary_row_spec.js
...end/alert_management/components/alert_summary_row_spec.js
+40
-0
spec/frontend/helpers/vue_test_utils_helper.js
spec/frontend/helpers/vue_test_utils_helper.js
+7
-0
spec/frontend/vue_shared/components/alert_details_table_spec.js
...rontend/vue_shared/components/alert_details_table_spec.js
+6
-2
No files found.
app/assets/javascripts/alert_management/components/alert_details.vue
View file @
f1ec6510
<
script
>
/* eslint-disable vue/no-v-html */
import
*
as
Sentry
from
'
@sentry/browser
'
;
import
{
GlAlert
,
GlBadge
,
GlIcon
,
GlLink
,
GlLoadingIcon
,
GlSprintf
,
GlTabs
,
GlTab
,
GlButton
,
GlSafeHtmlDirective
,
}
from
'
@gitlab/ui
'
;
import
{
s__
}
from
'
~/locale
'
;
import
alertQuery
from
'
../graphql/queries/details.query.graphql
'
;
...
...
@@ -28,6 +29,7 @@ import SystemNote from './system_notes/system_note.vue';
import
AlertSidebar
from
'
./alert_sidebar.vue
'
;
import
AlertMetrics
from
'
./alert_metrics.vue
'
;
import
AlertDetailsTable
from
'
~/vue_shared/components/alert_details_table.vue
'
;
import
AlertSummaryRow
from
'
./alert_summary_row.vue
'
;
const
containerEl
=
document
.
querySelector
(
'
.page-with-contextual-sidebar
'
);
...
...
@@ -39,6 +41,9 @@ export default {
reportedAt
:
s__
(
'
AlertManagement|Reported %{when}
'
),
reportedAtWithTool
:
s__
(
'
AlertManagement|Reported %{when} by %{tool}
'
),
},
directives
:
{
SafeHtml
:
GlSafeHtmlDirective
,
},
severityLabels
:
ALERTS_SEVERITY_LABELS
,
tabsConfig
:
[
{
...
...
@@ -56,9 +61,11 @@ export default {
],
components
:
{
AlertDetailsTable
,
AlertSummaryRow
,
GlBadge
,
GlAlert
,
GlIcon
,
GlLink
,
GlLoadingIcon
,
GlSprintf
,
GlTab
,
...
...
@@ -211,7 +218,7 @@ export default {
<
template
>
<div>
<gl-alert
v-if=
"showErrorMsg"
variant=
"danger"
@
dismiss=
"dismissError"
>
<p
v-html=
"sidebarErrorMessage || $options.i18n.errorMsg"
></p>
<p
v-
safe-
html=
"sidebarErrorMessage || $options.i18n.errorMsg"
></p>
</gl-alert>
<gl-alert
v-if=
"createIncidentError"
...
...
@@ -283,54 +290,66 @@ export default {
</div>
<gl-tabs
v-if=
"alert"
v-model=
"currentTabIndex"
data-testid=
"alertDetailsTabs"
>
<gl-tab
:data-testid=
"$options.tabsConfig[0].id"
:title=
"$options.tabsConfig[0].title"
>
<div
v-if=
"alert.severity"
class=
"gl-mt-3 gl-mb-5 gl-display-flex"
>
<div
class=
"gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3"
>
{{ s__('AlertManagement|Severity') }}:
</div>
<div
class=
"gl-pl-2"
data-testid=
"severity"
>
<span>
<alert-summary-row
v-if=
"alert.severity"
:label=
"`${s__('AlertManagement|Severity')}:`"
>
<span
data-testid=
"severity"
>
<gl-icon
class=
"gl-vertical-align-middle"
:size=
"12"
:name=
"`severity-${alert.severity.toLowerCase()}`"
:class=
"`icon-${alert.severity.toLowerCase()}`"
/>
</span>
{{ $options.severityLabels[alert.severity] }}
</div>
</div>
<div
v-if=
"alert.startedAt"
class=
"gl-my-5 gl-display-flex"
>
<div
class=
"gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3"
>
{{ s__('AlertManagement|Start time') }}:
</div>
<div
class=
"gl-pl-2"
>
</span>
</alert-summary-row>
<alert-summary-row
v-if=
"alert.environment"
:label=
"`${s__('AlertManagement|Environment')}:`"
>
<gl-link
v-if=
"alert.environmentUrl"
class=
"gl-display-inline-block"
data-testid=
"environmentUrl"
:href=
"alert.environmentUrl"
target=
"_blank"
>
{{ alert.environment }}
</gl-link>
<span
v-else
data-testid=
"environment"
>
{{ alert.environment }}
</span>
</alert-summary-row>
<alert-summary-row
v-if=
"alert.startedAt"
:label=
"`${s__('AlertManagement|Start time')}:`"
>
<time-ago-tooltip
data-testid=
"startTimeItem"
:time=
"alert.startedAt"
/>
</div>
</div>
<div
v-if=
"alert.eventCount"
class=
"gl-my-5 gl-display-flex"
>
<div
class=
"gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3"
>
{{ s__('AlertManagement|Events') }}:
</div>
<div
class=
"gl-pl-2"
data-testid=
"eventCount"
>
{{ alert.eventCount }}
</div>
</div>
<div
v-if=
"alert.monitoringTool"
class=
"gl-my-5 gl-display-flex"
>
<div
class=
"gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3"
>
{{ s__('AlertManagement|Tool') }}:
</div>
<div
class=
"gl-pl-2"
data-testid=
"monitoringTool"
>
{{ alert.monitoringTool }}
</div>
</div>
<div
v-if=
"alert.service"
class=
"gl-my-5 gl-display-flex"
>
<div
class=
"bold gl-w-13 gl-text-right gl-pr-3"
>
{{ s__('AlertManagement|Service') }}:
</div>
<div
class=
"gl-pl-2"
data-testid=
"service"
>
{{ alert.service }}
</div>
</div>
<div
v-if=
"alert.runbook"
class=
"gl-my-5 gl-display-flex"
>
<div
class=
"bold gl-w-13 gl-text-right gl-pr-3"
>
{{ s__('AlertManagement|Runbook') }}:
</div>
<div
class=
"gl-pl-2"
data-testid=
"runbook"
>
{{ alert.runbook }}
</div>
</div>
</alert-summary-row>
<alert-summary-row
v-if=
"alert.eventCount"
:label=
"`${s__('AlertManagement|Events')}:`"
data-testid=
"eventCount"
>
{{ alert.eventCount }}
</alert-summary-row>
<alert-summary-row
v-if=
"alert.monitoringTool"
:label=
"`${s__('AlertManagement|Tool')}:`"
data-testid=
"monitoringTool"
>
{{ alert.monitoringTool }}
</alert-summary-row>
<alert-summary-row
v-if=
"alert.service"
:label=
"`${s__('AlertManagement|Service')}:`"
data-testid=
"service"
>
{{ alert.service }}
</alert-summary-row>
<alert-summary-row
v-if=
"alert.runbook"
:label=
"`${s__('AlertManagement|Runbook')}:`"
data-testid=
"runbook"
>
{{ alert.runbook }}
</alert-summary-row>
<alert-details-table
:alert=
"alert"
:loading=
"loading"
/>
</gl-tab>
<gl-tab
:data-testid=
"$options.tabsConfig[1].id"
:title=
"$options.tabsConfig[1].title"
>
...
...
app/assets/javascripts/alert_management/components/alert_summary_row.vue
0 → 100644
View file @
f1ec6510
<
script
>
export
default
{
props
:
{
label
:
{
type
:
String
,
required
:
true
,
},
},
};
</
script
>
<
template
>
<div
class=
"gl-my-5 gl-display-flex"
>
<div
class=
"gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3"
>
{{
label
}}
</div>
<div
class=
"gl-pl-2"
>
<slot></slot>
</div>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/alert_details_table.vue
View file @
f1ec6510
<
script
>
import
{
GlLoadingIcon
,
GlTable
}
from
'
@gitlab/ui
'
;
import
{
reduce
}
from
'
lodash
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
capitalizeFirstCharacter
,
...
...
@@ -21,10 +22,10 @@ const allowedFields = [
'
description
'
,
'
endedAt
'
,
'
details
'
,
'
environment
'
,
];
const
filterAllowedFields
=
([
fieldName
])
=>
allowedFields
.
includes
(
fieldName
);
const
arrayToObject
=
([
fieldName
,
value
])
=>
({
fieldName
,
value
});
const
isAllowed
=
fieldName
=>
allowedFields
.
includes
(
fieldName
);
export
default
{
components
:
{
...
...
@@ -62,9 +63,16 @@ export default {
if
(
!
this
.
alert
)
{
return
[];
}
return
Object
.
entries
(
this
.
alert
)
.
filter
(
filterAllowedFields
)
.
map
(
arrayToObject
);
return
reduce
(
this
.
alert
,
(
allowedItems
,
value
,
fieldName
)
=>
{
if
(
isAllowed
(
fieldName
))
{
return
[...
allowedItems
,
{
fieldName
,
value
}];
}
return
allowedItems
;
},
[],
);
},
},
};
...
...
locale/gitlab.pot
View file @
f1ec6510
...
...
@@ -8,6 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-22 19:32+0200\n"
"PO-Revision-Date: 2020-09-22 19:32+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
...
...
@@ -2234,6 +2236,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
msgid "AlertManagement|Environment"
msgstr ""
msgid "AlertManagement|Events"
msgstr ""
...
...
spec/frontend/alert_management/components/alert_details_spec.js
View file @
f1ec6510
...
...
@@ -2,8 +2,10 @@ import { mount, shallowMount } from '@vue/test-utils';
import
{
GlAlert
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
axios
from
'
axios
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
AlertDetailsTable
from
'
~/vue_shared/components/alert_details_table.vue
'
;
import
AlertDetails
from
'
~/alert_management/components/alert_details.vue
'
;
import
AlertSummaryRow
from
'
~/alert_management/components/alert_summary_row.vue
'
;
import
createIssueMutation
from
'
~/alert_management/graphql/mutations/create_issue_from_alert.mutation.graphql
'
;
import
{
joinPaths
}
from
'
~/lib/utils/url_utility
'
;
import
{
...
...
@@ -24,7 +26,8 @@ describe('AlertDetails', () => {
const
$router
=
{
replace
:
jest
.
fn
()
};
function
mountComponent
({
data
,
loading
=
false
,
mountMethod
=
shallowMount
,
stubs
=
{}
}
=
{})
{
wrapper
=
mountMethod
(
AlertDetails
,
{
wrapper
=
extendedWrapper
(
mountMethod
(
AlertDetails
,
{
provide
:
{
alertId
:
'
alertId
'
,
projectPath
,
...
...
@@ -47,8 +50,12 @@ describe('AlertDetails', () => {
$router
,
$route
:
{
params
:
{}
},
},
stubs
,
});
stubs
:
{
...
stubs
,
AlertSummaryRow
,
},
}),
);
}
beforeEach
(()
=>
{
...
...
@@ -62,9 +69,10 @@ describe('AlertDetails', () => {
mock
.
restore
();
});
const
findCreateIncidentBtn
=
()
=>
wrapper
.
find
(
'
[data-testid="createIncidentBtn"]
'
);
const
findViewIncidentBtn
=
()
=>
wrapper
.
find
(
'
[data-testid="viewIncidentBtn"]
'
);
const
findIncidentCreationAlert
=
()
=>
wrapper
.
find
(
'
[data-testid="incidentCreationError"]
'
);
const
findCreateIncidentBtn
=
()
=>
wrapper
.
findByTestId
(
'
createIncidentBtn
'
);
const
findViewIncidentBtn
=
()
=>
wrapper
.
findByTestId
(
'
viewIncidentBtn
'
);
const
findIncidentCreationAlert
=
()
=>
wrapper
.
findByTestId
(
'
incidentCreationError
'
);
const
findEnvironmentLink
=
()
=>
wrapper
.
findByTestId
(
'
environmentUrl
'
);
const
findDetailsTable
=
()
=>
wrapper
.
find
(
AlertDetailsTable
);
describe
(
'
Alert details
'
,
()
=>
{
...
...
@@ -74,7 +82,7 @@ describe('AlertDetails', () => {
});
it
(
'
shows an empty state
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
[data-testid="alertDetailsTabs"]
'
).
exists
()).
toBe
(
false
);
expect
(
wrapper
.
find
ByTestId
(
'
alertDetailsTabs
'
).
exists
()).
toBe
(
false
);
});
});
...
...
@@ -84,28 +92,26 @@ describe('AlertDetails', () => {
});
it
(
'
renders a tab with overview information
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
[data-testid="overview"]
'
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
find
ByTestId
(
'
overview
'
).
exists
()).
toBe
(
true
);
});
it
(
'
renders a tab with an activity feed
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
[data-testid="activity"]
'
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
find
ByTestId
(
'
activity
'
).
exists
()).
toBe
(
true
);
});
it
(
'
renders severity
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
[data-testid="severity"]
'
).
text
()).
toBe
(
expect
(
wrapper
.
find
ByTestId
(
'
severity
'
).
text
()).
toBe
(
ALERTS_SEVERITY_LABELS
[
mockAlert
.
severity
],
);
});
it
(
'
renders a title
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
[data-testid="title"]
'
).
text
()).
toBe
(
mockAlert
.
title
);
expect
(
wrapper
.
find
ByTestId
(
'
title
'
).
text
()).
toBe
(
mockAlert
.
title
);
});
it
(
'
renders a start time
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
[data-testid="startTimeItem"]
'
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
find
(
'
[data-testid="startTimeItem"]
'
).
props
().
time
).
toBe
(
mockAlert
.
startedAt
,
);
expect
(
wrapper
.
findByTestId
(
'
startTimeItem
'
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
findByTestId
(
'
startTimeItem
'
).
props
(
'
time
'
)).
toBe
(
mockAlert
.
startedAt
);
});
});
...
...
@@ -114,6 +120,8 @@ describe('AlertDetails', () => {
field | data | isShown
${
'
eventCount
'
}
|
${
1
}
|
${
true
}
${
'
eventCount
'
}
|
${
undefined
}
|
${
false
}
${
'
environment
'
}
|
${
undefined
}
|
${
false
}
${
'
environment
'
}
|
${
'
Production
'
}
|
${
true
}
${
'
monitoringTool
'
}
|
${
'
New Relic
'
}
|
${
true
}
${
'
monitoringTool
'
}
|
${
undefined
}
|
${
false
}
${
'
service
'
}
|
${
'
Prometheus
'
}
|
${
true
}
...
...
@@ -126,15 +134,29 @@ describe('AlertDetails', () => {
});
it
(
`
${
field
}
is
${
isShown
?
'
displayed
'
:
'
hidden
'
}
correctly`
,
()
=>
{
const
element
=
wrapper
.
findByTestId
(
field
);
if
(
isShown
)
{
expect
(
wrapper
.
find
(
`[data-testid="
${
field
}
"]`
).
text
()).
toBe
(
data
.
toString
());
expect
(
element
.
text
()).
toContain
(
data
.
toString
());
}
else
{
expect
(
wrapper
.
find
(
`[data-testid="
${
field
}
"]`
).
exists
()).
toBe
(
false
);
expect
(
wrapper
.
find
ByTestId
(
field
).
exists
()).
toBe
(
false
);
}
});
});
});
describe
(
'
environment URL fields
'
,
()
=>
{
it
(
'
should show the environment URL when available
'
,
()
=>
{
const
environment
=
'
Production
'
;
const
environmentUrl
=
'
fake/url
'
;
mountComponent
({
data
:
{
alert
:
{
...
mockAlert
,
environment
,
environmentUrl
}
},
});
expect
(
findEnvironmentLink
().
text
()).
toBe
(
environment
);
expect
(
findEnvironmentLink
().
attributes
(
'
href
'
)).
toBe
(
environmentUrl
);
});
});
describe
(
'
Create incident from alert
'
,
()
=>
{
it
(
'
should display "View incident" button that links the incident page when incident exists
'
,
()
=>
{
const
issueIid
=
'
3
'
;
...
...
@@ -222,7 +244,7 @@ describe('AlertDetails', () => {
mountComponent
({
data
:
{
errored
:
true
,
sidebarErrorMessage
:
'
<span data-testid="htmlError" />
'
},
});
expect
(
wrapper
.
find
(
'
[data-testid="htmlError"]
'
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
find
ByTestId
(
'
htmlError
'
).
exists
()).
toBe
(
true
);
});
it
(
'
does not display an error when dismissed
'
,
()
=>
{
...
...
@@ -232,7 +254,7 @@ describe('AlertDetails', () => {
});
describe
(
'
header
'
,
()
=>
{
const
findHeader
=
()
=>
wrapper
.
find
(
'
[data-testid="alert-header"]
'
);
const
findHeader
=
()
=>
wrapper
.
find
ByTestId
(
'
alert-header
'
);
const
stubs
=
{
TimeAgoTooltip
:
{
template
:
'
<span>now</span>
'
}
};
describe
(
'
individual header fields
'
,
()
=>
{
...
...
spec/frontend/alert_management/components/alert_summary_row_spec.js
0 → 100644
View file @
f1ec6510
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
AlertSummaryRow
from
'
~/alert_management/components/alert_summary_row.vue
'
;
const
label
=
'
a label
'
;
const
value
=
'
a value
'
;
describe
(
'
AlertSummaryRow
'
,
()
=>
{
let
wrapper
;
function
mountComponent
({
mountMethod
=
shallowMount
,
props
,
defaultSlot
}
=
{})
{
wrapper
=
mountMethod
(
AlertSummaryRow
,
{
propsData
:
props
,
scopedSlots
:
{
default
:
defaultSlot
,
},
});
}
afterEach
(()
=>
{
if
(
wrapper
)
{
wrapper
.
destroy
();
wrapper
=
null
;
}
});
describe
(
'
Alert Summary Row
'
,
()
=>
{
beforeEach
(()
=>
{
mountComponent
({
props
:
{
label
,
},
defaultSlot
:
`<span class="value">
${
value
}
</span>`
,
});
});
it
(
'
should display a label and a value
'
,
()
=>
{
expect
(
wrapper
.
text
()).
toBe
(
`
${
label
}
${
value
}
`
);
});
});
});
spec/frontend/helpers/vue_test_utils_helper.js
View file @
f1ec6510
...
...
@@ -33,3 +33,10 @@ export const waitForMutation = (store, expectedMutationType) =>
}
});
});
export
const
extendedWrapper
=
wrapper
=>
Object
.
defineProperty
(
wrapper
,
'
findByTestId
'
,
{
value
(
id
)
{
return
this
.
find
(
`[data-testid="
${
id
}
"]`
);
},
});
spec/frontend/vue_shared/components/alert_detail_table_spec.js
→
spec/frontend/vue_shared/components/alert_detail
s
_table_spec.js
View file @
f1ec6510
import
{
GlLoadingIcon
,
GlTable
}
from
'
@gitlab/ui
'
;
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
GlTable
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
AlertDetailsTable
from
'
~/vue_shared/components/alert_details_table.vue
'
;
const
mockAlert
=
{
...
...
@@ -61,8 +61,10 @@ describe('AlertDetails', () => {
});
describe
(
'
with table data
'
,
()
=>
{
const
environment
=
'
myEnvironment
'
;
const
environmentUrl
=
'
fake/url
'
;
beforeEach
(()
=>
{
mountComponent
();
mountComponent
(
{
alert
:
{
...
mockAlert
,
environment
,
environmentUrl
}
}
);
});
it
(
'
renders a table
'
,
()
=>
{
...
...
@@ -80,6 +82,7 @@ describe('AlertDetails', () => {
expect
(
findTableField
(
fields
,
'
Title
'
).
exists
()).
toBe
(
true
);
expect
(
findTableField
(
fields
,
'
Severity
'
).
exists
()).
toBe
(
true
);
expect
(
findTableField
(
fields
,
'
Status
'
).
exists
()).
toBe
(
true
);
expect
(
findTableField
(
fields
,
'
Environment
'
).
exists
()).
toBe
(
true
);
});
it
(
'
should not show disallowed alert fields
'
,
()
=>
{
...
...
@@ -89,6 +92,7 @@ describe('AlertDetails', () => {
expect
(
findTableField
(
fields
,
'
Todos
'
).
exists
()).
toBe
(
false
);
expect
(
findTableField
(
fields
,
'
Notes
'
).
exists
()).
toBe
(
false
);
expect
(
findTableField
(
fields
,
'
Assignees
'
).
exists
()).
toBe
(
false
);
expect
(
findTableField
(
fields
,
'
EnvironmentUrl
'
).
exists
()).
toBe
(
false
);
});
});
});
...
...
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