2020-06-23 00:09:42 +05:30
< script >
2020-07-28 23:09:34 +05:30
import { GlAlert , GlButton , GlEmptyState , GlLink , GlSprintf } from '@gitlab/ui' ;
import { isEmpty } from 'lodash' ;
2020-06-23 00:09:42 +05:30
import axios from '~/lib/utils/axios_utils' ;
import { _ _ } from '~/locale' ;
import DagGraph from './dag_graph.vue' ;
2020-07-28 23:09:34 +05:30
import DagAnnotations from './dag_annotations.vue' ;
import {
DEFAULT ,
PARSE _FAILURE ,
LOAD _FAILURE ,
UNSUPPORTED _DATA ,
ADD _NOTE ,
REMOVE _NOTE ,
REPLACE _NOTES ,
} from './constants' ;
2020-06-23 00:09:42 +05:30
import { parseData } from './parsing_utils' ;
export default {
// eslint-disable-next-line @gitlab/require-i18n-strings
name : 'Dag' ,
components : {
2020-07-28 23:09:34 +05:30
DagAnnotations ,
2020-06-23 00:09:42 +05:30
DagGraph ,
GlAlert ,
GlLink ,
GlSprintf ,
2020-07-28 23:09:34 +05:30
GlEmptyState ,
GlButton ,
2020-06-23 00:09:42 +05:30
} ,
props : {
graphUrl : {
type : String ,
required : false ,
default : '' ,
} ,
2020-07-28 23:09:34 +05:30
emptySvgPath : {
type : String ,
required : true ,
default : '' ,
} ,
dagDocPath : {
type : String ,
required : true ,
default : '' ,
} ,
2020-06-23 00:09:42 +05:30
} ,
data ( ) {
return {
2020-07-28 23:09:34 +05:30
annotationsMap : { } ,
2020-06-23 00:09:42 +05:30
failureType : null ,
graphData : null ,
2020-07-28 23:09:34 +05:30
showFailureAlert : false ,
showBetaInfo : true ,
hasNoDependentJobs : false ,
2020-06-23 00:09:42 +05:30
} ;
} ,
errorTexts : {
[ LOAD _FAILURE ] : _ _ ( 'We are currently unable to fetch data for this graph.' ) ,
[ PARSE _FAILURE ] : _ _ ( 'There was an error parsing the data for this graph.' ) ,
2020-07-28 23:09:34 +05:30
[ UNSUPPORTED _DATA ] : _ _ ( 'DAG visualization requires at least 3 dependent jobs.' ) ,
2020-06-23 00:09:42 +05:30
[ DEFAULT ] : _ _ ( 'An unknown error occurred while loading this graph.' ) ,
} ,
2020-07-28 23:09:34 +05:30
emptyStateTexts : {
title : _ _ ( 'Start using Directed Acyclic Graphs (DAG)' ) ,
firstDescription : _ _ (
"This pipeline does not use the %{codeStart}needs%{codeEnd} keyword and can't be represented as a directed acyclic graph." ,
) ,
secondDescription : _ _ (
'Using %{codeStart}needs%{codeEnd} allows jobs to run before their stage is reached, as soon as their individual dependencies are met, which speeds up your pipelines.' ,
) ,
button : _ _ ( 'Learn more about job dependencies' ) ,
} ,
2020-06-23 00:09:42 +05:30
computed : {
betaMessage ( ) {
return _ _ (
'This feature is currently in beta. We invite you to %{linkStart}give feedback%{linkEnd}.' ,
) ;
} ,
failure ( ) {
switch ( this . failureType ) {
case LOAD _FAILURE :
return {
text : this . $options . errorTexts [ LOAD _FAILURE ] ,
variant : 'danger' ,
} ;
case PARSE _FAILURE :
return {
text : this . $options . errorTexts [ PARSE _FAILURE ] ,
variant : 'danger' ,
} ;
case UNSUPPORTED _DATA :
return {
text : this . $options . errorTexts [ UNSUPPORTED _DATA ] ,
variant : 'info' ,
} ;
default :
return {
text : this . $options . errorTexts [ DEFAULT ] ,
vatiant : 'danger' ,
} ;
}
} ,
2020-07-28 23:09:34 +05:30
shouldDisplayAnnotations ( ) {
return ! isEmpty ( this . annotationsMap ) ;
} ,
2020-06-23 00:09:42 +05:30
shouldDisplayGraph ( ) {
return Boolean ( ! this . showFailureAlert && this . graphData ) ;
} ,
} ,
mounted ( ) {
const { processGraphData , reportFailure } = this ;
if ( ! this . graphUrl ) {
reportFailure ( ) ;
return ;
}
axios
. get ( this . graphUrl )
. then ( response => {
processGraphData ( response . data ) ;
} )
. catch ( ( ) => reportFailure ( LOAD _FAILURE ) ) ;
} ,
methods : {
2020-07-28 23:09:34 +05:30
addAnnotationToMap ( { uid , source , target } ) {
this . $set ( this . annotationsMap , uid , { source , target } ) ;
} ,
2020-06-23 00:09:42 +05:30
processGraphData ( data ) {
let parsed ;
try {
parsed = parseData ( data . stages ) ;
} catch {
this . reportFailure ( PARSE _FAILURE ) ;
return ;
}
2020-07-28 23:09:34 +05:30
if ( parsed . links . length === 1 ) {
2020-06-23 00:09:42 +05:30
this . reportFailure ( UNSUPPORTED _DATA ) ;
return ;
}
2020-07-28 23:09:34 +05:30
// If there are no links, we don't report failure
// as it simply means the user does not use job dependencies
if ( parsed . links . length === 0 ) {
this . hasNoDependentJobs = true ;
return ;
}
2020-06-23 00:09:42 +05:30
this . graphData = parsed ;
} ,
hideAlert ( ) {
this . showFailureAlert = false ;
} ,
hideBetaInfo ( ) {
this . showBetaInfo = false ;
} ,
2020-07-28 23:09:34 +05:30
removeAnnotationFromMap ( { uid } ) {
this . $delete ( this . annotationsMap , uid ) ;
} ,
2020-06-23 00:09:42 +05:30
reportFailure ( type ) {
this . showFailureAlert = true ;
this . failureType = type ;
} ,
2020-07-28 23:09:34 +05:30
updateAnnotation ( { type , data } ) {
switch ( type ) {
case ADD _NOTE :
this . addAnnotationToMap ( data ) ;
break ;
case REMOVE _NOTE :
this . removeAnnotationFromMap ( data ) ;
break ;
case REPLACE _NOTES :
this . annotationsMap = data ;
break ;
default :
break ;
}
} ,
2020-06-23 00:09:42 +05:30
} ,
} ;
< / script >
< template >
< div >
< gl-alert v-if = "showFailureAlert" :variant="failure.variant" @dismiss="hideAlert" >
{ { failure . text } }
< / gl-alert >
< gl-alert v-if = "showBetaInfo" @dismiss="hideBetaInfo" >
< gl-sprintf :message = "betaMessage" >
< template # link = "{ content }" >
< gl-link href = "https://gitlab.com/gitlab-org/gitlab/-/issues/220368" target = "_blank" >
{ { content } }
< / gl-link >
< / template >
< / gl-sprintf >
< / gl-alert >
2020-07-28 23:09:34 +05:30
< div class = "gl-relative" >
< dag-annotations v-if = "shouldDisplayAnnotations" :annotations="annotationsMap" / >
< dag-graph
v - if = "shouldDisplayGraph"
: graph - data = "graphData"
@ onFailure = "reportFailure"
@ update - annotation = "updateAnnotation"
/ >
< gl-empty-state
v - else - if = "hasNoDependentJobs"
: svg - path = "emptySvgPath"
: title = "$options.emptyStateTexts.title"
>
< template # description >
< div class = "gl-text-left" >
< p >
< gl-sprintf :message = "$options.emptyStateTexts.firstDescription" >
< template # code = "{ content }" >
< code > { { content } } < / code >
< / template >
< / gl-sprintf >
< / p >
< p >
< gl-sprintf :message = "$options.emptyStateTexts.secondDescription" >
< template # code = "{ content }" >
< code > { { content } } < / code >
< / template >
< / gl-sprintf >
< / p >
< / div >
< / template >
< template # actions >
< gl-button :href = "dagDocPath" target = "__blank" variant = "success" >
{ { $options . emptyStateTexts . button } }
< / gl-button >
< / template >
< / gl-empty-state >
< / div >
2020-06-23 00:09:42 +05:30
< / div >
< / template >