2020-04-21 15:21:10 +00:00
< script >
2020-05-04 06:10:10 +00:00
import {
2020-10-15 18:08:43 +00:00
GlAlert ,
2020-05-04 06:10:10 +00:00
GlLoadingIcon ,
GlTable ,
2020-08-27 09:10:18 +00:00
GlAvatarsInline ,
GlAvatarLink ,
GlAvatar ,
2020-05-13 18:08:47 +00:00
GlIcon ,
2020-06-18 00:08:35 +00:00
GlLink ,
GlSprintf ,
2020-08-27 09:10:18 +00:00
GlTooltipDirective ,
2020-05-04 06:10:10 +00:00
} from '@gitlab/ui' ;
2021-02-14 18:09:20 +00:00
import getAlertsQuery from '~/graphql_shared/queries/get_alerts.query.graphql' ;
2022-03-09 21:07:04 +00:00
import { sortObjectToString } from '~/lib/utils/table_utility' ;
2020-05-21 15:08:18 +00:00
import { fetchPolicies } from '~/lib/graphql' ;
2020-10-15 18:08:43 +00:00
import { joinPaths , visitUrl } from '~/lib/utils/url_utility' ;
2022-02-01 15:18:50 +00:00
import { s _ _ , _ _ , n _ _ } from '~/locale' ;
2021-02-14 18:09:20 +00:00
import AlertStatus from '~/vue_shared/alert_details/components/alert_status.vue' ;
2020-10-15 18:08:43 +00:00
import {
tdClass ,
thClass ,
bodyTrClass ,
initialPaginationState ,
} from '~/vue_shared/components/paginated_table_with_search_and_tabs/constants' ;
2021-02-14 18:09:20 +00:00
import PaginatedTableWithSearchAndTabs from '~/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue' ;
2020-04-30 12:09:45 +00:00
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue' ;
2021-02-04 18:09:22 +00:00
import { ALERTS _STATUS _TABS , SEVERITY _LEVELS , trackAlertListViewsOptions } from '../constants' ;
2021-02-14 18:09:20 +00:00
import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query.graphql' ;
2020-04-24 09:09:44 +00:00
2020-08-24 15:10:11 +00:00
const TH _TEST _ID = { 'data-testid' : 'alert-management-severity-sort' } ;
2020-05-07 06:09:38 +00:00
2020-07-13 18:09:16 +00:00
const TWELVE _HOURS _IN _MS = 12 * 60 * 60 * 1000 ;
2022-02-01 15:18:50 +00:00
const MAX _VISIBLE _ASSIGNEES = 4 ;
2020-04-21 15:21:10 +00:00
export default {
2020-10-15 18:08:43 +00:00
trackAlertListViewsOptions ,
2022-02-01 15:18:50 +00:00
MAX _VISIBLE _ASSIGNEES ,
2020-04-24 18:09:46 +00:00
i18n : {
noAlertsMsg : s _ _ (
2020-06-18 00:08:35 +00:00
'AlertManagement|No alerts available to display. See %{linkStart}enabling alert management%{linkEnd} for more information on adding alerts to the list.' ,
2020-04-24 18:09:46 +00:00
) ,
errorMsg : s _ _ (
"AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear." ,
) ,
2020-08-27 09:10:18 +00:00
unassigned : _ _ ( 'Unassigned' ) ,
2021-03-04 15:11:19 +00:00
closed : _ _ ( 'closed' ) ,
2020-04-24 18:09:46 +00:00
} ,
2020-04-24 09:09:44 +00:00
fields : [
2020-05-14 00:07:47 +00:00
{
key : 'severity' ,
label : s _ _ ( 'AlertManagement|Severity' ) ,
2020-06-29 12:09:20 +00:00
thClass : ` ${ thClass } gl-w-eighth ` ,
2020-08-24 15:10:11 +00:00
thAttr : TH _TEST _ID ,
2020-07-21 06:09:45 +00:00
tdClass : ` ${ tdClass } rounded-top text-capitalize sortable-cell ` ,
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-27 00:08:11 +00:00
key : 'startedAt' ,
2020-04-30 12:09:45 +00:00
label : s _ _ ( 'AlertManagement|Start time' ) ,
2020-06-29 12:09:20 +00:00
thClass : ` ${ thClass } js-started-at w-15p ` ,
2020-07-21 06:09:45 +00:00
tdClass : ` ${ tdClass } sortable-cell ` ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-04-24 09:09:44 +00:00
} ,
{
2020-08-24 15:10:11 +00:00
key : 'alertLabel' ,
2020-04-24 18:09:46 +00:00
label : s _ _ ( 'AlertManagement|Alert' ) ,
2020-07-01 15:08:45 +00:00
thClass : ` gl-pointer-events-none ` ,
2020-05-07 06:09:38 +00:00
tdClass ,
2020-04-24 09:09:44 +00:00
} ,
{
2020-05-27 00:08:11 +00:00
key : 'eventCount' ,
2020-04-24 18:09:46 +00:00
label : s _ _ ( 'AlertManagement|Events' ) ,
2020-06-29 12:09:20 +00:00
thClass : ` ${ thClass } text-right gl-w-12 ` ,
2020-07-21 06:09:45 +00:00
tdClass : ` ${ tdClass } text-md-right sortable-cell ` ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-04-24 09:09:44 +00:00
} ,
2020-07-03 09:08:53 +00:00
{
key : 'issue' ,
2020-10-14 21:08:38 +00:00
label : s _ _ ( 'AlertManagement|Incident' ) ,
2021-03-04 15:11:19 +00:00
thClass : 'gl-w-15p gl-pointer-events-none' ,
2020-07-03 09:08:53 +00:00
tdClass ,
} ,
2020-05-29 21:08:35 +00:00
{
key : 'assignees' ,
label : s _ _ ( 'AlertManagement|Assignees' ) ,
2020-07-01 15:08:45 +00:00
thClass : 'gl-w-eighth gl-pointer-events-none' ,
2020-05-29 21:08:35 +00:00
tdClass ,
} ,
2020-04-24 09:09:44 +00:00
{
key : 'status' ,
2020-04-24 18:09:46 +00:00
label : s _ _ ( 'AlertManagement|Status' ) ,
2020-07-21 06:09:45 +00:00
thClass : ` ${ thClass } w-15p ` ,
tdClass : ` ${ tdClass } rounded-bottom sortable-cell ` ,
2020-05-25 15:07:58 +00:00
sortable : true ,
2020-04-24 09:09:44 +00:00
} ,
] ,
2021-02-04 18:09:22 +00:00
severityLabels : SEVERITY _LEVELS ,
2020-05-07 15:09:29 +00:00
statusTabs : ALERTS _STATUS _TABS ,
2020-04-21 15:21:10 +00:00
components : {
2020-10-15 18:08:43 +00:00
GlAlert ,
2020-04-21 15:21:10 +00:00
GlLoadingIcon ,
2020-04-24 09:09:44 +00:00
GlTable ,
2020-08-27 09:10:18 +00:00
GlAvatarsInline ,
GlAvatarLink ,
GlAvatar ,
2020-04-30 12:09:45 +00:00
TimeAgo ,
2020-05-13 18:08:47 +00:00
GlIcon ,
2020-06-18 00:08:35 +00:00
GlLink ,
GlSprintf ,
2020-06-24 15:08:50 +00:00
AlertStatus ,
2020-10-15 18:08:43 +00:00
PaginatedTableWithSearchAndTabs ,
2020-04-21 15:21:10 +00:00
} ,
2020-08-27 09:10:18 +00:00
directives : {
GlTooltip : GlTooltipDirective ,
} ,
2020-10-15 18:08:43 +00:00
inject : [ 'projectPath' , 'textQuery' , 'assigneeUsernameQuery' , 'populatingAlertsHelpUrl' ] ,
2020-04-24 18:09:46 +00:00
apollo : {
alerts : {
2020-05-21 15:08:18 +00:00
fetchPolicy : fetchPolicies . CACHE _AND _NETWORK ,
2021-01-08 12:10:35 +00:00
query : getAlertsQuery ,
2020-04-24 18:09:46 +00:00
variables ( ) {
return {
2020-06-18 09:08:41 +00:00
searchTerm : this . searchTerm ,
2020-10-15 18:08:43 +00:00
assigneeUsername : this . assigneeUsername ,
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-06-01 15:08:16 +00:00
firstPageSize : this . pagination . firstPageSize ,
lastPageSize : this . pagination . lastPageSize ,
prevPageCursor : this . pagination . prevPageCursor ,
nextPageCursor : this . pagination . nextPageCursor ,
2020-04-24 18:09:46 +00:00
} ;
} ,
2020-04-30 12:09:45 +00:00
update ( data ) {
2020-06-01 15:08:16 +00:00
const { alertManagementAlerts : { nodes : list = [ ] , pageInfo = { } } = { } } =
data . project || { } ;
2020-07-13 18:09:16 +00:00
const now = new Date ( ) ;
2020-12-23 21:10:24 +00:00
const listWithData = list . map ( ( alert ) => {
2020-07-13 18:09:16 +00:00
const then = new Date ( alert . startedAt ) ;
const diff = now - then ;
return {
... alert ,
isNew : diff < TWELVE _HOURS _IN _MS ,
} ;
} ) ;
2020-06-01 15:08:16 +00:00
return {
2020-07-13 18:09:16 +00:00
list : listWithData ,
2020-06-01 15:08:16 +00:00
pageInfo ,
} ;
2020-04-30 12:09:45 +00:00
} ,
2020-04-24 18:09:46 +00:00
error ( ) {
2020-10-15 18:08:43 +00:00
this . errored = true ;
2020-04-24 18:09:46 +00:00
} ,
} ,
2020-05-21 15:08:18 +00:00
alertsCount : {
2020-10-15 18:08:43 +00:00
fetchPolicy : fetchPolicies . CACHE _AND _NETWORK ,
2020-05-21 15:08:18 +00:00
query : getAlertsCountByStatus ,
variables ( ) {
return {
2020-06-18 09:08:41 +00:00
searchTerm : this . searchTerm ,
2020-10-15 18:08:43 +00:00
assigneeUsername : this . assigneeUsername ,
2020-05-21 15:08:18 +00:00
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-10-15 18:08:43 +00:00
errored : false ,
serverErrorMessage : '' ,
isErrorAlertDismissed : false ,
2020-06-06 03:08:19 +00:00
sort : 'STARTED_AT_DESC' ,
2022-05-03 21:08:54 +00:00
statusFilter : ALERTS _STATUS _TABS [ 0 ] . filters ,
filteredByStatus : ALERTS _STATUS _TABS [ 0 ] . status ,
2020-10-15 18:08:43 +00:00
alerts : { } ,
alertsCount : { } ,
2020-06-06 03:08:19 +00:00
sortBy : 'startedAt' ,
sortDesc : true ,
2020-06-15 18:08:43 +00:00
sortDirection : 'desc' ,
2020-10-15 18:08:43 +00:00
searchTerm : this . textQuery ,
assigneeUsername : this . assigneeUsernameQuery ,
pagination : initialPaginationState ,
2020-04-21 15:21:10 +00:00
} ;
} ,
2020-04-24 09:09:44 +00:00
computed : {
2020-10-15 18:08:43 +00:00
showErrorMsg ( ) {
return this . errored && ! this . isErrorAlertDismissed ;
} ,
2020-04-24 09:09:44 +00:00
showNoAlertsMsg ( ) {
2020-05-21 15:08:18 +00:00
return (
2020-10-15 18:08:43 +00:00
! this . errored &&
2020-06-18 09:08:41 +00:00
! this . loading &&
this . alertsCount ? . all === 0 &&
! this . searchTerm &&
2020-10-15 18:08:43 +00:00
! this . assigneeUsername &&
! this . isErrorAlertDismissed
2020-05-21 15:08:18 +00:00
) ;
2020-04-24 18:09:46 +00:00
} ,
loading ( ) {
return this . $apollo . queries . alerts . loading ;
2020-04-24 09:09:44 +00:00
} ,
2020-10-15 18:08:43 +00:00
isEmpty ( ) {
return ! this . alerts ? . list ? . length ;
2020-06-01 15:08:16 +00:00
} ,
2020-04-24 09:09:44 +00:00
} ,
2020-05-07 15:09:29 +00:00
methods : {
2020-05-25 15:07:58 +00:00
fetchSortedData ( { sortBy , sortDesc } ) {
2020-10-15 18:08:43 +00:00
this . pagination = initialPaginationState ;
2022-03-09 21:07:04 +00:00
this . sort = sortObjectToString ( { sortBy , sortDesc } ) ;
2020-05-25 15:07:58 +00:00
} ,
2022-10-06 21:09:01 +00:00
showAlertLink ( { iid } ) {
return joinPaths ( window . location . pathname , iid , 'details' ) ;
} ,
2020-09-21 06:09:41 +00:00
navigateToAlertDetails ( { iid } , index , { metaKey } ) {
2022-10-06 21:09:01 +00:00
return visitUrl ( this . showAlertLink ( { iid } ) , metaKey ) ;
2020-05-15 18:07:52 +00:00
} ,
2020-08-27 09:10:18 +00:00
hasAssignees ( assignees ) {
return Boolean ( assignees . nodes ? . length ) ;
2020-05-29 21:08:35 +00:00
} ,
2021-03-04 15:11:19 +00:00
getIssueMeta ( { issue : { iid , state } } ) {
return {
state : state === 'closed' ? ` ( ${ this . $options . i18n . closed } ) ` : '' ,
2021-03-05 00:09:24 +00:00
link : joinPaths ( '/' , this . projectPath , '-' , 'issues/incident' , iid ) ,
2021-03-04 15:11:19 +00:00
} ;
2020-07-03 09:08:53 +00:00
} ,
2020-07-13 18:09:16 +00:00
tbodyTrClass ( item ) {
return {
2020-10-15 18:08:43 +00:00
[ bodyTrClass ] : ! this . loading && ! this . isEmpty ,
2020-07-13 18:09:16 +00:00
'new-alert' : item ? . isNew ,
} ;
} ,
2020-06-24 15:08:50 +00:00
handleAlertError ( errorMessage ) {
2020-10-15 18:08:43 +00:00
this . errored = true ;
this . serverErrorMessage = errorMessage ;
2020-06-24 15:08:50 +00:00
} ,
2020-10-15 18:08:43 +00:00
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-06-24 15:08:50 +00:00
} ,
2022-02-01 15:18:50 +00:00
assigneesBadgeSrOnlyText ( item ) {
return n _ _ (
'%d additional assignee' ,
'%d additional assignees' ,
item . assignees . nodes . length - MAX _VISIBLE _ASSIGNEES ,
) ;
} ,
2020-05-07 15:09:29 +00:00
} ,
2020-04-21 15:21:10 +00:00
} ;
< / script >
< template >
< div >
2020-10-15 18:08:43 +00:00
< 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-07 15:09:29 +00:00
2020-10-15 18:08:43 +00:00
< paginated -table -with -search -and -tabs
: show - error - msg = "showErrorMsg"
: i18n = "$options.i18n"
2022-05-03 18:07:53 +00:00
: items = "
alerts . list || [ ] /* eslint-disable-line @gitlab/vue-no-new-non-primitive-in-template */
"
2020-10-15 18:08:43 +00:00
: page - info = "alerts.pageInfo"
: items - count = "alertsCount"
: status - tabs = "$options.statusTabs"
: track - views - options = "$options.trackAlertListViewsOptions"
: server - error - message = "serverErrorMessage"
2022-05-03 18:07:53 +00:00
: filter - search - tokens = " /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
'assignee_username' ,
] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */ "
2020-10-15 18:08:43 +00:00
filter - search - key = "alerts"
@ page - changed = "pageChanged"
@ tabs - changed = "statusChanged"
@ filters - changed = "filtersChanged"
@ error - alert - dismissed = "errorAlertDismissed"
>
< template # header -actions > < / template >
2020-06-18 09:08:41 +00:00
2020-10-15 18:08:43 +00:00
< template # title >
2020-05-07 06:09:38 +00:00
{ { s _ _ ( 'AlertManagement|Alerts' ) } }
2020-10-15 18:08:43 +00:00
< / template >
2020-05-14 00:07:47 +00:00
2020-10-15 18:08:43 +00:00
< template # table >
< gl -table
class = "alert-management-table"
2022-05-03 18:07:53 +00:00
: items = "
alerts
? alerts . list
: [ ] /* eslint-disable-line @gitlab/vue-no-new-non-primitive-in-template */
"
2020-10-15 18:08:43 +00:00
: 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-04-30 12:09:45 +00:00
2020-10-15 18:08:43 +00:00
< template # cell ( startedAt ) = " { item } " >
< time -ago v -if = " item.startedAt " :time ="item.startedAt" / >
< / template >
2020-04-30 12:09:45 +00:00
2020-10-15 18:08:43 +00:00
< template # cell ( eventCount ) = " { item } " >
{ { item . eventCount } }
< / template >
2020-07-03 09:08:53 +00:00
2020-10-15 18:08:43 +00:00
< template # cell ( alertLabel ) = " { item } " >
< div
class = "gl-max-w-full text-truncate"
: title = "`${item.iid} - ${item.title}`"
data - testid = "idField"
>
2022-10-06 21:09:01 +00:00
< gl -link :href ="showAlertLink(item)" > # { { item . iid } } { { item . title } } < / g l - l i n k >
2020-10-15 18:08:43 +00:00
< / div >
< / template >
2020-05-07 06:09:38 +00:00
2020-10-15 18:08:43 +00:00
< template # cell ( issue ) = " { item } " >
2021-03-04 15:11:19 +00:00
< 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 } }
2020-10-15 18:08:43 +00:00
< / g l - l i n k >
< div v -else data -testid = " issueField " > { { s _ _ ( 'AlertManagement|None' ) } } < / div >
< / template >
2020-05-29 21:08:35 +00:00
2020-10-15 18:08:43 +00:00
< template # cell ( assignees ) = " { item } " >
< div data -testid = " assigneesField " >
< template v-if ="hasAssignees(item.assignees)" >
< gl -avatars -inline
: avatars = "item.assignees.nodes"
: collapsed = "true"
2022-02-01 15:18:50 +00:00
: max - visible = "$options.MAX_VISIBLE_ASSIGNEES"
2020-10-15 18:08:43 +00:00
: avatar - size = "24"
badge - tooltip - prop = "name"
: badge - tooltip - max - chars = "100"
2022-02-01 15:18:50 +00:00
: badge - sr - only - text = "assigneesBadgeSrOnlyText(item)"
2020-10-15 18:08:43 +00:00
>
< 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-04-30 12:09:45 +00:00
2020-10-15 18:08:43 +00:00
< template # cell ( status ) = " { item } " >
< alert -status
: alert = "item"
: project - path = "projectPath"
: is - sidebar = "false"
@ alert - error = "handleAlertError"
@ hide - dropdown = "handleStatusUpdate"
/ >
< / template >
2020-04-30 12:09:45 +00:00
2020-10-15 18:08:43 +00:00
< template # empty >
{ { s _ _ ( 'AlertManagement|No alerts to display.' ) } }
< / template >
2020-06-01 15:08:16 +00:00
2020-10-15 18:08:43 +00:00
< 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-04-21 15:21:10 +00:00
< / div >
< / template >