2020-05-24 23:13:21 +05:30
< script >
import {
2021-01-03 14:25:43 +05:30
GlAlert ,
2020-05-24 23:13:21 +05:30
GlLoadingIcon ,
GlTable ,
2020-11-24 15:15:51 +05:30
GlAvatarsInline ,
GlAvatarLink ,
GlAvatar ,
2020-05-24 23:13:21 +05:30
GlIcon ,
2020-07-28 23:09:34 +05:30
GlLink ,
GlSprintf ,
2020-11-24 15:15:51 +05:30
GlTooltipDirective ,
2020-05-24 23:13:21 +05:30
} from '@gitlab/ui' ;
2021-03-11 19:13:27 +05:30
import getAlertsQuery from '~/graphql_shared/queries/get_alerts.query.graphql' ;
2020-06-23 00:09:42 +05:30
import { fetchPolicies } from '~/lib/graphql' ;
2021-03-11 19:13:27 +05:30
import { convertToSnakeCase } from '~/lib/utils/text_utility' ;
2021-01-03 14:25:43 +05:30
import { joinPaths , visitUrl } from '~/lib/utils/url_utility' ;
2021-03-11 19:13:27 +05:30
import { s _ _ , _ _ } from '~/locale' ;
import AlertStatus from '~/vue_shared/alert_details/components/alert_status.vue' ;
2021-06-08 01:23:25 +05:30
import AlertsDeprecationWarning from '~/vue_shared/components/alerts_deprecation_warning.vue' ;
2021-01-03 14:25:43 +05:30
import {
tdClass ,
thClass ,
bodyTrClass ,
initialPaginationState ,
} from '~/vue_shared/components/paginated_table_with_search_and_tabs/constants' ;
2021-03-11 19:13:27 +05:30
import PaginatedTableWithSearchAndTabs from '~/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue' ;
2020-05-24 23:13:21 +05:30
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue' ;
2021-09-04 01:27:46 +05:30
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin' ;
2021-03-11 19:13:27 +05:30
import { ALERTS _STATUS _TABS , SEVERITY _LEVELS , trackAlertListViewsOptions } from '../constants' ;
2020-06-23 00:09:42 +05:30
import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query.graphql' ;
2020-05-24 23:13:21 +05:30
2020-11-24 15:15:51 +05:30
const TH _TEST _ID = { 'data-testid' : 'alert-management-severity-sort' } ;
2020-06-23 00:09:42 +05:30
2020-07-28 23:09:34 +05:30
const TWELVE _HOURS _IN _MS = 12 * 60 * 60 * 1000 ;
2020-05-24 23:13:21 +05:30
export default {
2021-01-03 14:25:43 +05:30
trackAlertListViewsOptions ,
2020-05-24 23:13:21 +05:30
i18n : {
noAlertsMsg : s _ _ (
2020-07-28 23:09:34 +05:30
'AlertManagement|No alerts available to display. See %{linkStart}enabling alert management%{linkEnd} for more information on adding alerts to the list.' ,
2020-05-24 23:13:21 +05:30
) ,
errorMsg : s _ _ (
"AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear." ,
) ,
2020-11-24 15:15:51 +05:30
unassigned : _ _ ( 'Unassigned' ) ,
2021-04-17 20:07:23 +05:30
closed : _ _ ( 'closed' ) ,
2020-05-24 23:13:21 +05:30
} ,
fields : [
{
key : 'severity' ,
label : s _ _ ( 'AlertManagement|Severity' ) ,
2020-07-28 23:09:34 +05:30
thClass : ` ${ thClass } gl-w-eighth ` ,
2020-11-24 15:15:51 +05:30
thAttr : TH _TEST _ID ,
2020-10-24 23:57:45 +05:30
tdClass : ` ${ tdClass } rounded-top text-capitalize sortable-cell ` ,
2020-06-23 00:09:42 +05:30
sortable : true ,
2020-05-24 23:13:21 +05:30
} ,
{
key : 'startedAt' ,
label : s _ _ ( 'AlertManagement|Start time' ) ,
2020-07-28 23:09:34 +05:30
thClass : ` ${ thClass } js-started-at w-15p ` ,
2020-10-24 23:57:45 +05:30
tdClass : ` ${ tdClass } sortable-cell ` ,
2020-06-23 00:09:42 +05:30
sortable : true ,
2020-05-24 23:13:21 +05:30
} ,
{
2020-11-24 15:15:51 +05:30
key : 'alertLabel' ,
2020-05-24 23:13:21 +05:30
label : s _ _ ( 'AlertManagement|Alert' ) ,
2020-07-28 23:09:34 +05:30
thClass : ` gl-pointer-events-none ` ,
2020-05-24 23:13:21 +05:30
tdClass ,
} ,
{
key : 'eventCount' ,
label : s _ _ ( 'AlertManagement|Events' ) ,
2020-07-28 23:09:34 +05:30
thClass : ` ${ thClass } text-right gl-w-12 ` ,
2020-10-24 23:57:45 +05:30
tdClass : ` ${ tdClass } text-md-right sortable-cell ` ,
2020-06-23 00:09:42 +05:30
sortable : true ,
} ,
2020-07-28 23:09:34 +05:30
{
key : 'issue' ,
2021-01-03 14:25:43 +05:30
label : s _ _ ( 'AlertManagement|Incident' ) ,
2021-04-17 20:07:23 +05:30
thClass : 'gl-w-15p gl-pointer-events-none' ,
2020-07-28 23:09:34 +05:30
tdClass ,
} ,
2020-06-23 00:09:42 +05:30
{
key : 'assignees' ,
label : s _ _ ( 'AlertManagement|Assignees' ) ,
2020-07-28 23:09:34 +05:30
thClass : 'gl-w-eighth gl-pointer-events-none' ,
2020-06-23 00:09:42 +05:30
tdClass ,
2020-05-24 23:13:21 +05:30
} ,
{
key : 'status' ,
label : s _ _ ( 'AlertManagement|Status' ) ,
2020-10-24 23:57:45 +05:30
thClass : ` ${ thClass } w-15p ` ,
tdClass : ` ${ tdClass } rounded-bottom sortable-cell ` ,
2020-06-23 00:09:42 +05:30
sortable : true ,
2020-05-24 23:13:21 +05:30
} ,
] ,
2021-03-11 19:13:27 +05:30
severityLabels : SEVERITY _LEVELS ,
2020-05-24 23:13:21 +05:30
statusTabs : ALERTS _STATUS _TABS ,
components : {
2021-06-08 01:23:25 +05:30
AlertsDeprecationWarning ,
2021-01-03 14:25:43 +05:30
GlAlert ,
2020-05-24 23:13:21 +05:30
GlLoadingIcon ,
GlTable ,
2020-11-24 15:15:51 +05:30
GlAvatarsInline ,
GlAvatarLink ,
GlAvatar ,
2020-05-24 23:13:21 +05:30
TimeAgo ,
GlIcon ,
2020-07-28 23:09:34 +05:30
GlLink ,
GlSprintf ,
AlertStatus ,
2021-01-03 14:25:43 +05:30
PaginatedTableWithSearchAndTabs ,
2020-05-24 23:13:21 +05:30
} ,
2020-11-24 15:15:51 +05:30
directives : {
GlTooltip : GlTooltipDirective ,
} ,
2021-09-04 01:27:46 +05:30
mixins : [ glFeatureFlagMixin ( ) ] ,
2021-01-03 14:25:43 +05:30
inject : [ 'projectPath' , 'textQuery' , 'assigneeUsernameQuery' , 'populatingAlertsHelpUrl' ] ,
2020-05-24 23:13:21 +05:30
apollo : {
alerts : {
2020-06-23 00:09:42 +05:30
fetchPolicy : fetchPolicies . CACHE _AND _NETWORK ,
2021-03-08 18:12:59 +05:30
query : getAlertsQuery ,
2020-05-24 23:13:21 +05:30
variables ( ) {
return {
2020-07-28 23:09:34 +05:30
searchTerm : this . searchTerm ,
2021-01-03 14:25:43 +05:30
assigneeUsername : this . assigneeUsername ,
2020-05-24 23:13:21 +05:30
projectPath : this . projectPath ,
statuses : this . statusFilter ,
2020-06-23 00:09:42 +05:30
sort : this . sort ,
firstPageSize : this . pagination . firstPageSize ,
lastPageSize : this . pagination . lastPageSize ,
prevPageCursor : this . pagination . prevPageCursor ,
nextPageCursor : this . pagination . nextPageCursor ,
2020-05-24 23:13:21 +05:30
} ;
} ,
update ( data ) {
2020-06-23 00:09:42 +05:30
const { alertManagementAlerts : { nodes : list = [ ] , pageInfo = { } } = { } } =
data . project || { } ;
2020-07-28 23:09:34 +05:30
const now = new Date ( ) ;
2021-03-08 18:12:59 +05:30
const listWithData = list . map ( ( alert ) => {
2020-07-28 23:09:34 +05:30
const then = new Date ( alert . startedAt ) ;
const diff = now - then ;
return {
... alert ,
isNew : diff < TWELVE _HOURS _IN _MS ,
} ;
} ) ;
2020-06-23 00:09:42 +05:30
return {
2020-07-28 23:09:34 +05:30
list : listWithData ,
2020-06-23 00:09:42 +05:30
pageInfo ,
} ;
2020-05-24 23:13:21 +05:30
} ,
error ( ) {
2021-01-03 14:25:43 +05:30
this . errored = true ;
2020-05-24 23:13:21 +05:30
} ,
} ,
2020-06-23 00:09:42 +05:30
alertsCount : {
2021-01-03 14:25:43 +05:30
fetchPolicy : fetchPolicies . CACHE _AND _NETWORK ,
2020-06-23 00:09:42 +05:30
query : getAlertsCountByStatus ,
variables ( ) {
return {
2020-07-28 23:09:34 +05:30
searchTerm : this . searchTerm ,
2021-01-03 14:25:43 +05:30
assigneeUsername : this . assigneeUsername ,
2020-06-23 00:09:42 +05:30
projectPath : this . projectPath ,
} ;
} ,
update ( data ) {
return data . project ? . alertManagementAlertStatusCounts ;
} ,
} ,
2020-05-24 23:13:21 +05:30
} ,
data ( ) {
return {
2021-01-03 14:25:43 +05:30
errored : false ,
serverErrorMessage : '' ,
isErrorAlertDismissed : false ,
2020-06-23 00:09:42 +05:30
sort : 'STARTED_AT_DESC' ,
statusFilter : [ ] ,
filteredByStatus : '' ,
2021-01-03 14:25:43 +05:30
alerts : { } ,
alertsCount : { } ,
2020-06-23 00:09:42 +05:30
sortBy : 'startedAt' ,
sortDesc : true ,
sortDirection : 'desc' ,
2021-01-03 14:25:43 +05:30
searchTerm : this . textQuery ,
assigneeUsername : this . assigneeUsernameQuery ,
pagination : initialPaginationState ,
2020-05-24 23:13:21 +05:30
} ;
} ,
computed : {
2021-01-03 14:25:43 +05:30
showErrorMsg ( ) {
return this . errored && ! this . isErrorAlertDismissed ;
} ,
2020-05-24 23:13:21 +05:30
showNoAlertsMsg ( ) {
2020-06-23 00:09:42 +05:30
return (
2021-01-03 14:25:43 +05:30
! this . errored &&
2020-07-28 23:09:34 +05:30
! this . loading &&
this . alertsCount ? . all === 0 &&
! this . searchTerm &&
2021-01-03 14:25:43 +05:30
! this . assigneeUsername &&
! this . isErrorAlertDismissed
2020-06-23 00:09:42 +05:30
) ;
2020-05-24 23:13:21 +05:30
} ,
loading ( ) {
return this . $apollo . queries . alerts . loading ;
} ,
2021-01-03 14:25:43 +05:30
isEmpty ( ) {
return ! this . alerts ? . list ? . length ;
2020-06-23 00:09:42 +05:30
} ,
} ,
2020-05-24 23:13:21 +05:30
methods : {
2020-06-23 00:09:42 +05:30
fetchSortedData ( { sortBy , sortDesc } ) {
const sortingDirection = sortDesc ? 'DESC' : 'ASC' ;
const sortingColumn = convertToSnakeCase ( sortBy ) . toUpperCase ( ) ;
2021-01-03 14:25:43 +05:30
this . pagination = initialPaginationState ;
2020-06-23 00:09:42 +05:30
this . sort = ` ${ sortingColumn } _ ${ sortingDirection } ` ;
2020-05-24 23:13:21 +05:30
} ,
2021-01-03 14:25:43 +05:30
navigateToAlertDetails ( { iid } , index , { metaKey } ) {
return visitUrl ( joinPaths ( window . location . pathname , iid , 'details' ) , metaKey ) ;
2020-06-23 00:09:42 +05:30
} ,
2020-11-24 15:15:51 +05:30
hasAssignees ( assignees ) {
return Boolean ( assignees . nodes ? . length ) ;
2020-06-23 00:09:42 +05:30
} ,
2021-04-17 20:07:23 +05:30
getIssueMeta ( { issue : { iid , state } } ) {
return {
state : state === 'closed' ? ` ( ${ this . $options . i18n . closed } ) ` : '' ,
link : joinPaths ( '/' , this . projectPath , '-' , 'issues/incident' , iid ) ,
} ;
2020-07-28 23:09:34 +05:30
} ,
tbodyTrClass ( item ) {
return {
2021-01-03 14:25:43 +05:30
[ bodyTrClass ] : ! this . loading && ! this . isEmpty ,
2020-07-28 23:09:34 +05:30
'new-alert' : item ? . isNew ,
} ;
} ,
handleAlertError ( errorMessage ) {
2021-01-03 14:25:43 +05:30
this . errored = true ;
this . serverErrorMessage = errorMessage ;
2020-07-28 23:09:34 +05:30
} ,
2021-01-03 14:25:43 +05:30
handleStatusUpdate ( ) {
this . $apollo . queries . alerts . refetch ( ) ;
this . $apollo . queries . alertsCount . refetch ( ) ;
} ,
pageChanged ( pagination ) {
this . pagination = pagination ;
} ,
statusChanged ( { filters , status } ) {
this . statusFilter = filters ;
this . filteredByStatus = status ;
} ,
filtersChanged ( { searchTerm , assigneeUsername } ) {
this . searchTerm = searchTerm ;
this . assigneeUsername = assigneeUsername ;
} ,
errorAlertDismissed ( ) {
this . errored = false ;
this . serverErrorMessage = '' ;
this . isErrorAlertDismissed = true ;
2020-07-28 23:09:34 +05:30
} ,
2020-05-24 23:13:21 +05:30
} ,
} ;
< / script >
< template >
< div >
2021-01-03 14:25:43 +05:30
< gl -alert v-if ="showNoAlertsMsg" @dismiss="errorAlertDismissed" >
< gl -sprintf :message ="$options.i18n.noAlertsMsg" >
< template # link = "{ content }" >
< gl -link class = "gl-display-inline-block" :href ="populatingAlertsHelpUrl" target = "_blank" >
{ { content } }
< / g l - l i n k >
< / template >
< / g l - s p r i n t f >
< / g l - a l e r t >
2020-05-24 23:13:21 +05:30
2021-09-04 01:27:46 +05:30
< alerts -deprecation -warning v -if = " ! glFeatures.managedAlertsDeprecation " / >
2021-06-08 01:23:25 +05:30
2021-01-03 14:25:43 +05:30
< paginated -table -with -search -and -tabs
: show - error - msg = "showErrorMsg"
: i18n = "$options.i18n"
: items = "alerts.list || []"
: page - info = "alerts.pageInfo"
: items - count = "alertsCount"
: status - tabs = "$options.statusTabs"
: track - views - options = "$options.trackAlertListViewsOptions"
: server - error - message = "serverErrorMessage"
: filter - search - tokens = "['assignee_username']"
filter - search - key = "alerts"
@ page - changed = "pageChanged"
@ tabs - changed = "statusChanged"
@ filters - changed = "filtersChanged"
@ error - alert - dismissed = "errorAlertDismissed"
>
< template # header -actions > < / template >
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
< template # title >
2020-05-24 23:13:21 +05:30
{ { s _ _ ( 'AlertManagement|Alerts' ) } }
2021-01-03 14:25:43 +05:30
< / template >
2020-05-24 23:13:21 +05:30
2021-01-03 14:25:43 +05:30
< template # table >
< gl -table
class = "alert-management-table"
: items = "alerts ? alerts.list : []"
: fields = "$options.fields"
: show - empty = "true"
: busy = "loading"
stacked = "md"
: tbody - tr - class = "tbodyTrClass"
: no - local - sorting = "true"
: sort - direction = "sortDirection"
: sort - desc . sync = "sortDesc"
: sort - by . sync = "sortBy"
sort - icon - left
fixed
@ row - clicked = "navigateToAlertDetails"
@ sort - changed = "fetchSortedData"
>
< 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-24 23:13:21 +05:30
2021-01-03 14:25:43 +05:30
< template # cell ( startedAt ) = " { item } " >
< time -ago v -if = " item.startedAt " :time ="item.startedAt" / >
< / template >
2020-06-23 00:09:42 +05:30
2021-01-03 14:25:43 +05:30
< template # cell ( eventCount ) = " { item } " >
{ { item . eventCount } }
< / template >
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
< template # cell ( alertLabel ) = " { item } " >
< div
class = "gl-max-w-full text-truncate"
: title = "`${item.iid} - ${item.title}`"
data - testid = "idField"
>
# { { item . iid } } { { item . title } }
< / div >
< / template >
2020-05-24 23:13:21 +05:30
2021-01-03 14:25:43 +05:30
< template # cell ( issue ) = " { item } " >
2021-04-17 20:07:23 +05:30
< gl -link
v - if = "item.issue"
v - gl - tooltip
: title = "item.issue.title"
data - testid = "issueField"
: href = "getIssueMeta(item).link"
>
# { { item . issue . iid } } { { getIssueMeta ( item ) . state } }
2021-01-03 14:25:43 +05:30
< / g l - l i n k >
< div v -else data -testid = " issueField " > { { s _ _ ( 'AlertManagement|None' ) } } < / div >
< / template >
2020-06-23 00:09:42 +05:30
2021-01-03 14:25:43 +05:30
< template # cell ( assignees ) = " { item } " >
< div data -testid = " assigneesField " >
< template v-if ="hasAssignees(item.assignees)" >
< gl -avatars -inline
: avatars = "item.assignees.nodes"
: collapsed = "true"
: max - visible = "4"
: avatar - size = "24"
badge - tooltip - prop = "name"
: badge - tooltip - max - chars = "100"
>
< template # avatar = "{ avatar }" >
< gl -avatar -link
: key = "avatar.username"
v - gl - tooltip
target = "_blank"
: href = "avatar.webUrl"
: title = "avatar.name"
>
< gl -avatar :src ="avatar.avatarUrl" :label ="avatar.name" :size ="24" / >
< / g l - a v a t a r - l i n k >
< / template >
< / g l - a v a t a r s - i n l i n e >
< / template >
< template v-else >
{ { $options . i18n . unassigned } }
< / template >
< / div >
< / template >
2020-05-24 23:13:21 +05:30
2021-01-03 14:25:43 +05:30
< template # cell ( status ) = " { item } " >
< alert -status
: alert = "item"
: project - path = "projectPath"
: is - sidebar = "false"
@ alert - error = "handleAlertError"
@ hide - dropdown = "handleStatusUpdate"
/ >
< / template >
2020-05-24 23:13:21 +05:30
2021-01-03 14:25:43 +05:30
< template # empty >
{ { s _ _ ( 'AlertManagement|No alerts to display.' ) } }
< / template >
2020-06-23 00:09:42 +05:30
2021-01-03 14:25:43 +05:30
< template # table -busy >
< gl -loading -icon size = "lg" color = "dark" class = "mt-3" / >
< / template >
< / g l - t a b l e >
< / template >
< / p a g i n a t e d - t a b l e - w i t h - s e a r c h - a n d - t a b s >
2020-05-24 23:13:21 +05:30
< / div >
< / template >