2020-04-21 15:21:10 +00:00
< script >
2020-05-04 06:10:10 +00:00
import {
GlEmptyState ,
GlDeprecatedButton ,
GlLoadingIcon ,
GlTable ,
GlAlert ,
2020-05-13 18:08:47 +00:00
GlIcon ,
GlDropdown ,
GlDropdownItem ,
2020-05-07 15:09:29 +00:00
GlTabs ,
GlTab ,
2020-05-26 21:07:45 +00:00
GlDeprecatedBadge as GlBadge ,
2020-05-04 06:10:10 +00:00
} from '@gitlab/ui' ;
2020-05-13 18:08:47 +00:00
import createFlash from '~/flash' ;
2020-04-24 18:09:46 +00:00
import { s _ _ } from '~/locale' ;
2020-05-18 21:08:42 +00:00
import { joinPaths , visitUrl } from '~/lib/utils/url_utility' ;
2020-05-21 15:08:18 +00:00
import { fetchPolicies } from '~/lib/graphql' ;
2020-04-30 12:09:45 +00:00
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue' ;
2020-05-21 15:08:18 +00:00
import getAlerts from '../graphql/queries/get_alerts.query.graphql' ;
import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query.graphql' ;
2020-05-26 15:08:17 +00:00
import {
ALERTS _STATUS ,
ALERTS _STATUS _TABS ,
ALERTS _SEVERITY _LABELS ,
trackAlertListViewsOptions ,
trackAlertStatusUpdateOptions ,
} from '../constants' ;
2020-05-13 18:08:47 +00:00
import updateAlertStatus from '../graphql/mutations/update_alert_status.graphql' ;
2020-05-25 15:07:58 +00:00
import { capitalizeFirstCharacter , convertToSnakeCase } from '~/lib/utils/text_utility' ;
2020-05-26 15:08:17 +00:00
import Tracking from '~/tracking' ;
2020-04-24 09:09:44 +00:00
2020-05-07 06:09:38 +00:00
const tdClass = 'table-col d-flex d-md-table-cell align-items-center' ;
2020-05-15 18:07:52 +00:00
const bodyTrClass =
2020-05-26 15:08:17 +00:00
'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-bg-blue-50 gl-hover-cursor-pointer gl-hover-border-b-solid gl-hover-border-blue-200' ;
2020-05-25 15:07:58 +00:00
const findDefaultSortColumn = ( ) => document . querySelector ( '.js-started-at' ) ;
2020-05-07 06:09:38 +00:00
2020-04-21 15:21:10 +00:00
export default {
2020-04-24 18:09:46 +00:00
i18n : {
noAlertsMsg : s _ _ (
"AlertManagement|No alerts available to display. If you think you're seeing this message in error, refresh the page." ,
) ,
errorMsg : s _ _ (
"AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear." ,
) ,
} ,
2020-04-24 09:09:44 +00:00
fields : [
2020-05-14 00:07:47 +00:00
{
key : 'severity' ,
label : s _ _ ( 'AlertManagement|Severity' ) ,
tdClass : ` ${ tdClass } rounded-top text-capitalize ` ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-05-14 00:07:47 +00:00
} ,
2020-04-24 09:09:44 +00:00
{
2020-05-25 15:07:58 +00:00
key : 'startTime' ,
2020-04-30 12:09:45 +00:00
label : s _ _ ( 'AlertManagement|Start time' ) ,
2020-05-25 15:07:58 +00:00
thClass : 'js-started-at' ,
2020-05-07 06:09:38 +00:00
tdClass ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-04-24 09:09:44 +00:00
} ,
{
2020-05-25 15:07:58 +00:00
key : 'endTime' ,
2020-04-30 12:09:45 +00:00
label : s _ _ ( 'AlertManagement|End time' ) ,
2020-05-07 06:09:38 +00:00
tdClass ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-04-24 09:09:44 +00:00
} ,
{
2020-04-30 12:09:45 +00:00
key : 'title' ,
2020-04-24 18:09:46 +00:00
label : s _ _ ( 'AlertManagement|Alert' ) ,
2020-05-25 15:07:58 +00:00
thClass : 'w-30p alert-title' ,
2020-05-07 06:09:38 +00:00
tdClass ,
2020-05-25 15:07:58 +00:00
sortable : false ,
2020-04-24 09:09:44 +00:00
} ,
{
2020-05-25 15:07:58 +00:00
key : 'eventsCount' ,
2020-04-24 18:09:46 +00:00
label : s _ _ ( 'AlertManagement|Events' ) ,
2020-05-25 15:07:58 +00:00
thClass : 'text-right gl-pr-9 w-3rem' ,
2020-05-20 12:07:52 +00:00
tdClass : ` ${ tdClass } text-md-right ` ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-04-24 09:09:44 +00:00
} ,
{
key : 'status' ,
2020-05-13 18:08:47 +00:00
thClass : 'w-15p' ,
2020-04-24 18:09:46 +00:00
label : s _ _ ( 'AlertManagement|Status' ) ,
2020-05-15 18:07:52 +00:00
tdClass : ` ${ tdClass } rounded-bottom ` ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-04-24 09:09:44 +00:00
} ,
] ,
2020-05-04 06:10:10 +00:00
statuses : {
2020-05-07 15:09:29 +00:00
[ ALERTS _STATUS . TRIGGERED ] : s _ _ ( 'AlertManagement|Triggered' ) ,
[ ALERTS _STATUS . ACKNOWLEDGED ] : s _ _ ( 'AlertManagement|Acknowledged' ) ,
[ ALERTS _STATUS . RESOLVED ] : s _ _ ( 'AlertManagement|Resolved' ) ,
2020-05-04 06:10:10 +00:00
} ,
2020-05-14 00:07:47 +00:00
severityLabels : ALERTS _SEVERITY _LABELS ,
2020-05-07 15:09:29 +00:00
statusTabs : ALERTS _STATUS _TABS ,
2020-04-21 15:21:10 +00:00
components : {
GlEmptyState ,
GlLoadingIcon ,
2020-04-24 09:09:44 +00:00
GlTable ,
GlAlert ,
2020-04-27 18:09:41 +00:00
GlDeprecatedButton ,
2020-04-30 12:09:45 +00:00
TimeAgo ,
2020-05-13 18:08:47 +00:00
GlDropdown ,
GlDropdownItem ,
GlIcon ,
2020-05-07 15:09:29 +00:00
GlTabs ,
GlTab ,
2020-05-21 15:08:18 +00:00
GlBadge ,
2020-04-21 15:21:10 +00:00
} ,
props : {
2020-04-30 12:09:45 +00:00
projectPath : {
2020-04-21 15:21:10 +00:00
type : String ,
required : true ,
} ,
2020-04-24 09:09:44 +00:00
alertManagementEnabled : {
type : Boolean ,
2020-04-27 18:09:41 +00:00
required : true ,
2020-04-24 09:09:44 +00:00
} ,
2020-04-21 15:21:10 +00:00
enableAlertManagementPath : {
type : String ,
required : true ,
} ,
2020-04-27 18:09:41 +00:00
userCanEnableAlertManagement : {
type : Boolean ,
required : true ,
} ,
2020-04-21 15:21:10 +00:00
emptyAlertSvgPath : {
type : String ,
required : true ,
} ,
} ,
2020-04-24 18:09:46 +00:00
apollo : {
alerts : {
2020-05-21 15:08:18 +00:00
fetchPolicy : fetchPolicies . CACHE _AND _NETWORK ,
2020-04-24 18:09:46 +00:00
query : getAlerts ,
variables ( ) {
return {
2020-04-30 12:09:45 +00:00
projectPath : this . projectPath ,
2020-05-15 09:07:59 +00:00
statuses : this . statusFilter ,
2020-05-25 15:07:58 +00:00
sort : this . sort ,
2020-04-24 18:09:46 +00:00
} ;
} ,
2020-04-30 12:09:45 +00:00
update ( data ) {
2020-05-21 15:08:18 +00:00
return data . project ? . alertManagementAlerts ? . nodes ;
2020-04-30 12:09:45 +00:00
} ,
2020-04-24 18:09:46 +00:00
error ( ) {
this . errored = true ;
} ,
} ,
2020-05-21 15:08:18 +00:00
alertsCount : {
query : getAlertsCountByStatus ,
variables ( ) {
return {
projectPath : this . projectPath ,
} ;
} ,
update ( data ) {
return data . project ? . alertManagementAlertStatusCounts ;
} ,
} ,
2020-04-24 18:09:46 +00:00
} ,
2020-04-21 15:21:10 +00:00
data ( ) {
return {
2020-04-24 18:09:46 +00:00
errored : false ,
2020-04-24 09:09:44 +00:00
isAlertDismissed : false ,
2020-04-24 18:09:46 +00:00
isErrorAlertDismissed : false ,
2020-05-25 15:07:58 +00:00
sort : 'START_TIME_ASC' ,
2020-05-15 09:07:59 +00:00
statusFilter : this . $options . statusTabs [ 4 ] . filters ,
2020-04-21 15:21:10 +00:00
} ;
} ,
2020-04-24 09:09:44 +00:00
computed : {
showNoAlertsMsg ( ) {
2020-05-21 15:08:18 +00:00
return (
! this . errored && ! this . loading && this . alertsCount ? . all === 0 && ! this . isAlertDismissed
) ;
2020-04-24 18:09:46 +00:00
} ,
showErrorMsg ( ) {
return this . errored && ! this . isErrorAlertDismissed ;
} ,
loading ( ) {
return this . $apollo . queries . alerts . loading ;
2020-04-24 09:09:44 +00:00
} ,
2020-05-20 15:08:20 +00:00
hasAlerts ( ) {
return this . alerts ? . length ;
} ,
tbodyTrClass ( ) {
return ! this . loading && this . hasAlerts ? bodyTrClass : '' ;
} ,
2020-04-24 09:09:44 +00:00
} ,
2020-05-25 15:07:58 +00:00
mounted ( ) {
findDefaultSortColumn ( ) . ariaSort = 'ascending' ;
2020-05-26 15:08:17 +00:00
this . trackPageViews ( ) ;
2020-05-25 15:07:58 +00:00
} ,
2020-05-07 15:09:29 +00:00
methods : {
2020-05-15 12:08:28 +00:00
filterAlertsByStatus ( tabIndex ) {
2020-05-15 09:07:59 +00:00
this . statusFilter = this . $options . statusTabs [ tabIndex ] . filters ;
2020-05-07 15:09:29 +00:00
} ,
2020-05-25 15:07:58 +00:00
fetchSortedData ( { sortBy , sortDesc } ) {
const sortDirection = sortDesc ? 'DESC' : 'ASC' ;
const sortColumn = convertToSnakeCase ( sortBy ) . toUpperCase ( ) ;
if ( sortBy !== 'startTime' ) {
findDefaultSortColumn ( ) . ariaSort = 'none' ;
}
this . sort = ` ${ sortColumn } _ ${ sortDirection } ` ;
} ,
2020-05-13 18:08:47 +00:00
capitalizeFirstCharacter ,
updateAlertStatus ( status , iid ) {
this . $apollo
. mutate ( {
mutation : updateAlertStatus ,
variables : {
iid ,
status : status . toUpperCase ( ) ,
projectPath : this . projectPath ,
} ,
} )
2020-05-18 21:08:42 +00:00
. then ( ( ) => {
2020-05-26 15:08:17 +00:00
this . trackStatusUpdate ( status ) ;
2020-05-18 21:08:42 +00:00
this . $apollo . queries . alerts . refetch ( ) ;
2020-05-21 15:08:18 +00:00
this . $apollo . queries . alertsCount . refetch ( ) ;
2020-05-18 21:08:42 +00:00
} )
2020-05-13 18:08:47 +00:00
. catch ( ( ) => {
createFlash (
s _ _ (
'AlertManagement|There was an error while updating the status of the alert. Please try again.' ,
) ,
) ;
} ) ;
} ,
2020-05-18 21:08:42 +00:00
navigateToAlertDetails ( { iid } ) {
return visitUrl ( joinPaths ( window . location . pathname , iid , 'details' ) ) ;
2020-05-15 18:07:52 +00:00
} ,
2020-05-26 15:08:17 +00:00
trackPageViews ( ) {
const { category , action } = trackAlertListViewsOptions ;
Tracking . event ( category , action ) ;
} ,
trackStatusUpdate ( status ) {
const { category , action , label } = trackAlertStatusUpdateOptions ;
Tracking . event ( category , action , { label , property : status } ) ;
} ,
2020-05-07 15:09:29 +00:00
} ,
2020-04-21 15:21:10 +00:00
} ;
< / script >
< template >
< div >
2020-04-24 09:09:44 +00:00
< div v-if ="alertManagementEnabled" class="alert-management-list" >
< gl -alert v-if ="showNoAlertsMsg" @dismiss="isAlertDismissed = true" >
2020-04-24 18:09:46 +00:00
{ { $options . i18n . noAlertsMsg } }
< / g l - a l e r t >
< gl -alert v-if ="showErrorMsg" variant="danger" @dismiss="isErrorAlertDismissed = true" >
{ { $options . i18n . errorMsg } }
2020-04-24 09:09:44 +00:00
< / g l - a l e r t >
2020-05-21 15:08:18 +00:00
< gl -tabs @input ="filterAlertsByStatus" >
2020-05-07 15:09:29 +00:00
< gl -tab v-for ="tab in $options.statusTabs" :key="tab.status" >
< template slot = "title" >
< span > { { tab . title } } < / span >
2020-05-21 15:08:18 +00:00
< gl -badge v-if ="alertsCount" pill size="sm" class="gl-tab-counter-badge" >
{ { alertsCount [ tab . status . toLowerCase ( ) ] } }
< / g l - b a d g e >
2020-05-07 15:09:29 +00:00
< / template >
< / g l - t a b >
< / g l - t a b s >
2020-05-07 06:09:38 +00:00
< h4 class = "d-block d-md-none my-3" >
{ { s _ _ ( 'AlertManagement|Alerts' ) } }
< / h4 >
2020-04-24 09:09:44 +00:00
< gl -table
2020-05-07 06:09:38 +00:00
class = "alert-management-table mt-3"
2020-04-24 09:09:44 +00:00
: items = "alerts"
: fields = "$options.fields"
: show - empty = "true"
2020-04-24 18:09:46 +00:00
: busy = "loading"
2020-04-30 12:09:45 +00:00
stacked = "md"
2020-05-20 15:08:20 +00:00
: tbody - tr - class = "tbodyTrClass"
2020-05-25 15:07:58 +00:00
: no - local - sorting = "true"
sort - icon - left
2020-05-18 21:08:42 +00:00
@ row - clicked = "navigateToAlertDetails"
2020-05-25 15:07:58 +00:00
@ sort - changed = "fetchSortedData"
2020-04-24 09:09:44 +00:00
>
2020-05-14 00:07:47 +00:00
< template # cell ( severity ) = " { item } " >
< div
class = "d-inline-flex align-items-center justify-content-between"
data - testid = "severityField"
>
< gl -icon
class = "mr-2"
: size = "12"
: name = "`severity-${item.severity.toLowerCase()}`"
: class = "`icon-${item.severity.toLowerCase()}`"
/ >
{ { $options . severityLabels [ item . severity ] } }
< / div >
< / template >
2020-05-25 15:07:58 +00:00
< template # cell ( startTime ) = " { item } " >
2020-05-11 09:09:45 +00:00
< time -ago v -if = " item.startedAt " :time ="item.startedAt" / >
2020-04-30 12:09:45 +00:00
< / template >
2020-05-25 15:07:58 +00:00
< template # cell ( endTime ) = " { item } " >
2020-05-11 09:09:45 +00:00
< time -ago v -if = " item.endedAt " :time ="item.endedAt" / >
2020-04-30 12:09:45 +00:00
< / template >
2020-05-25 15:07:58 +00:00
<!-- TODO : Remove after : https : //gitlab.com/gitlab-org/gitlab/-/issues/218467 -->
< template # cell ( eventsCount ) = " { item } " >
{ { item . eventCount } }
< / template >
2020-04-30 12:09:45 +00:00
< template # cell ( title ) = " { item } " >
< div class = "gl-max-w-full text-truncate" > { { item . title } } < / div >
< / template >
2020-05-07 06:09:38 +00:00
2020-05-04 06:10:10 +00:00
< template # cell ( status ) = " { item } " >
2020-05-13 18:08:47 +00:00
< gl -dropdown
: text = "capitalizeFirstCharacter(item.status.toLowerCase())"
class = "w-100"
right
>
< gl -dropdown -item
v - for = "(label, field) in $options.statuses"
: key = "field"
@ click = "updateAlertStatus(label, item.iid)"
>
< span class = "d-flex" >
< gl -icon
class = "flex-shrink-0 append-right-4"
: class = "{ invisible: label.toUpperCase() !== item.status }"
name = "mobile-issue-close"
/ >
{ { label } }
< / span >
< / g l - d r o p d o w n - i t e m >
< / g l - d r o p d o w n >
2020-05-04 06:10:10 +00:00
< / template >
2020-04-30 12:09:45 +00:00
2020-04-24 09:09:44 +00:00
< template # empty >
2020-04-24 18:09:46 +00:00
{ { s _ _ ( 'AlertManagement|No alerts to display.' ) } }
< / template >
2020-04-30 12:09:45 +00:00
2020-04-24 18:09:46 +00:00
< template # table -busy >
< gl -loading -icon size = "lg" color = "dark" class = "mt-3" / >
2020-04-24 09:09:44 +00:00
< / template >
< / g l - t a b l e >
2020-04-21 15:21:10 +00:00
< / div >
2020-04-30 12:09:45 +00:00
< gl -empty -state
v - else
2020-05-07 12:09:46 +00:00
: title = "s__('AlertManagement|Surface alerts in GitLab')"
2020-04-30 12:09:45 +00:00
: svg - path = "emptyAlertSvgPath"
>
2020-04-27 18:09:41 +00:00
< template # description >
< div class = "d-block" >
< span > { {
s _ _ (
'AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents.' ,
)
} } < / span >
< a href = "/help/user/project/operations/alert_management.html" target = "_blank" >
{ { s _ _ ( 'AlertManagement|More information' ) } }
< / a >
< / div >
< div v-if ="userCanEnableAlertManagement" class="d-block center pt-4" >
< gl -deprecated -button
category = "primary"
variant = "success"
: href = "enableAlertManagementPath"
>
{ { s _ _ ( 'AlertManagement|Authorize external service' ) } }
< / g l - d e p r e c a t e d - b u t t o n >
< / div >
< / template >
< / g l - e m p t y - s t a t e >
2020-04-21 15:21:10 +00:00
< / div >
< / template >