Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
李少辉-开发者
gitlab-foss
提交
e7bb9b95
G
gitlab-foss
项目概览
李少辉-开发者
/
gitlab-foss
通知
15
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
gitlab-foss
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
e7bb9b95
编写于
2月 01, 2019
作者:
A
Adriel Santiago
提交者:
Phil Hughes
2月 01, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Remove d3 metrics graph
上级
c1286332
变更
24
隐藏空白更改
内联
并排
Showing
24 changed file
with
2 addition
and
1868 deletion
+2
-1868
app/assets/javascripts/monitoring/components/dashboard.vue
app/assets/javascripts/monitoring/components/dashboard.vue
+2
-34
app/assets/javascripts/monitoring/components/graph.vue
app/assets/javascripts/monitoring/components/graph.vue
+0
-329
app/assets/javascripts/monitoring/components/graph/axis.vue
app/assets/javascripts/monitoring/components/graph/axis.vue
+0
-118
app/assets/javascripts/monitoring/components/graph/deployment.vue
...ts/javascripts/monitoring/components/graph/deployment.vue
+0
-48
app/assets/javascripts/monitoring/components/graph/flag.vue
app/assets/javascripts/monitoring/components/graph/flag.vue
+0
-151
app/assets/javascripts/monitoring/components/graph/legend.vue
...assets/javascripts/monitoring/components/graph/legend.vue
+0
-62
app/assets/javascripts/monitoring/components/graph/path.vue
app/assets/javascripts/monitoring/components/graph/path.vue
+0
-65
app/assets/javascripts/monitoring/components/graph/track_info.vue
...ts/javascripts/monitoring/components/graph/track_info.vue
+0
-28
app/assets/javascripts/monitoring/components/graph/track_line.vue
...ts/javascripts/monitoring/components/graph/track_line.vue
+0
-33
app/assets/javascripts/monitoring/event_hub.js
app/assets/javascripts/monitoring/event_hub.js
+0
-3
app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
...assets/javascripts/monitoring/mixins/monitoring_mixins.js
+0
-86
app/assets/javascripts/monitoring/utils/date_time_formatters.js
...sets/javascripts/monitoring/utils/date_time_formatters.js
+0
-42
app/assets/javascripts/monitoring/utils/measurements.js
app/assets/javascripts/monitoring/utils/measurements.js
+0
-44
app/assets/javascripts/monitoring/utils/multiple_time_series.js
...sets/javascripts/monitoring/utils/multiple_time_series.js
+0
-223
locale/gitlab.pot
locale/gitlab.pot
+0
-6
spec/javascripts/monitoring/graph/axis_spec.js
spec/javascripts/monitoring/graph/axis_spec.js
+0
-65
spec/javascripts/monitoring/graph/deployment_spec.js
spec/javascripts/monitoring/graph/deployment_spec.js
+0
-53
spec/javascripts/monitoring/graph/flag_spec.js
spec/javascripts/monitoring/graph/flag_spec.js
+0
-133
spec/javascripts/monitoring/graph/legend_spec.js
spec/javascripts/monitoring/graph/legend_spec.js
+0
-44
spec/javascripts/monitoring/graph/track_info_spec.js
spec/javascripts/monitoring/graph/track_info_spec.js
+0
-44
spec/javascripts/monitoring/graph/track_line_spec.js
spec/javascripts/monitoring/graph/track_line_spec.js
+0
-52
spec/javascripts/monitoring/graph_path_spec.js
spec/javascripts/monitoring/graph_path_spec.js
+0
-56
spec/javascripts/monitoring/graph_spec.js
spec/javascripts/monitoring/graph_spec.js
+0
-127
spec/javascripts/monitoring/utils/multiple_time_series_spec.js
...javascripts/monitoring/utils/multiple_time_series_spec.js
+0
-22
未找到文件。
app/assets/javascripts/monitoring/components/dashboard.vue
浏览文件 @
e7bb9b95
...
...
@@ -6,15 +6,12 @@ import Flash from '../../flash';
import
MonitoringService
from
'
../services/monitoring_service
'
;
import
MonitorAreaChart
from
'
./charts/area.vue
'
;
import
GraphGroup
from
'
./graph_group.vue
'
;
import
Graph
from
'
./graph.vue
'
;
import
EmptyState
from
'
./empty_state.vue
'
;
import
MonitoringStore
from
'
../stores/monitoring_store
'
;
import
eventHub
from
'
../event_hub
'
;
export
default
{
components
:
{
MonitorAreaChart
,
Graph
,
GraphGroup
,
EmptyState
,
Icon
,
...
...
@@ -25,21 +22,11 @@ export default {
required
:
false
,
default
:
true
,
},
showLegend
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
showPanels
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
forceSmallGraph
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
documentationPath
:
{
type
:
String
,
required
:
true
,
...
...
@@ -99,14 +86,10 @@ export default {
store
:
new
MonitoringStore
(),
state
:
'
gettingStarted
'
,
showEmptyState
:
true
,
hoverData
:
{},
elWidth
:
0
,
};
},
computed
:
{
graphComponent
()
{
return
gon
.
features
&&
gon
.
features
.
areaChart
?
MonitorAreaChart
:
Graph
;
},
forceRedraw
()
{
return
this
.
elWidth
;
},
...
...
@@ -122,10 +105,8 @@ export default {
childList
:
false
,
subtree
:
false
,
};
eventHub
.
$on
(
'
hoverChanged
'
,
this
.
hoverChanged
);
},
beforeDestroy
()
{
eventHub
.
$off
(
'
hoverChanged
'
,
this
.
hoverChanged
);
window
.
removeEventListener
(
'
resize
'
,
this
.
resizeThrottled
,
false
);
this
.
sidebarMutationObserver
.
disconnect
();
},
...
...
@@ -176,9 +157,6 @@ export default {
resize
()
{
this
.
elWidth
=
this
.
$el
.
clientWidth
;
},
hoverChanged
(
data
)
{
this
.
hoverData
=
data
;
},
},
};
</
script
>
...
...
@@ -215,23 +193,13 @@ export default {
:name=
"groupData.group"
:show-panels=
"showPanels"
>
<component
:is=
"graphComponent"
<monitor-area-chart
v-for=
"(graphData, graphIndex) in groupData.metrics"
:key=
"graphIndex"
:graph-data=
"graphData"
:hover-data=
"hoverData"
:deployment-data=
"store.deploymentData"
:project-path=
"projectPath"
:tags-path=
"tagsPath"
:show-legend=
"showLegend"
:small-graph=
"forceSmallGraph"
:alert-data=
"getGraphAlerts(graphData.id)"
group-id=
"monitor-area-chart"
>
<!-- EE content -->
{{
null
}}
</component>
/>
</graph-group>
</div>
<empty-state
...
...
app/assets/javascripts/monitoring/components/graph.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
import
{
scaleLinear
,
scaleTime
}
from
'
d3-scale
'
;
import
{
axisLeft
,
axisBottom
}
from
'
d3-axis
'
;
import
_
from
'
underscore
'
;
import
{
max
,
extent
}
from
'
d3-array
'
;
import
{
select
}
from
'
d3-selection
'
;
import
GraphAxis
from
'
./graph/axis.vue
'
;
import
GraphLegend
from
'
./graph/legend.vue
'
;
import
GraphFlag
from
'
./graph/flag.vue
'
;
import
GraphDeployment
from
'
./graph/deployment.vue
'
;
import
GraphPath
from
'
./graph/path.vue
'
;
import
MonitoringMixin
from
'
../mixins/monitoring_mixins
'
;
import
eventHub
from
'
../event_hub
'
;
import
measurements
from
'
../utils/measurements
'
;
import
{
bisectDate
,
timeScaleFormat
}
from
'
../utils/date_time_formatters
'
;
import
createTimeSeries
from
'
../utils/multiple_time_series
'
;
import
bp
from
'
../../breakpoints
'
;
const
d3
=
{
scaleLinear
,
scaleTime
,
axisLeft
,
axisBottom
,
max
,
extent
,
select
};
export
default
{
components
:
{
GraphAxis
,
GraphFlag
,
GraphDeployment
,
GraphPath
,
GraphLegend
,
},
mixins
:
[
MonitoringMixin
],
props
:
{
graphData
:
{
type
:
Object
,
required
:
true
,
},
deploymentData
:
{
type
:
Array
,
required
:
true
,
},
hoverData
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({}),
},
projectPath
:
{
type
:
String
,
required
:
true
,
},
tagsPath
:
{
type
:
String
,
required
:
true
,
},
showLegend
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
smallGraph
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
baseGraphHeight
:
450
,
baseGraphWidth
:
600
,
graphHeight
:
450
,
graphWidth
:
600
,
graphHeightOffset
:
120
,
margin
:
{},
unitOfDisplay
:
''
,
yAxisLabel
:
''
,
legendTitle
:
''
,
reducedDeploymentData
:
[],
measurements
:
measurements
.
large
,
currentData
:
{
time
:
new
Date
(),
value
:
0
,
},
currentXCoordinate
:
0
,
currentCoordinates
:
{},
showFlag
:
false
,
showFlagContent
:
false
,
timeSeries
:
[],
graphDrawData
:
{},
realPixelRatio
:
1
,
seriesUnderMouse
:
[],
};
},
computed
:
{
outerViewBox
()
{
return
`0 0
${
this
.
baseGraphWidth
}
${
this
.
baseGraphHeight
}
`
;
},
innerViewBox
()
{
return
`0 0
${
this
.
baseGraphWidth
-
150
}
${
this
.
baseGraphHeight
}
`
;
},
axisTransform
()
{
return
`translate(70,
${
this
.
graphHeight
-
100
}
)`
;
},
paddingBottomRootSvg
()
{
return
{
paddingBottom
:
`
${
Math
.
ceil
(
this
.
baseGraphHeight
*
100
)
/
this
.
baseGraphWidth
||
0
}
%`
,
};
},
deploymentFlagData
()
{
return
this
.
reducedDeploymentData
.
find
(
deployment
=>
deployment
.
showDeploymentFlag
);
},
shouldRenderData
()
{
return
this
.
graphData
.
queries
.
filter
(
s
=>
s
.
result
.
length
>
0
).
length
>
0
;
},
},
watch
:
{
hoverData
()
{
this
.
positionFlag
();
},
},
mounted
()
{
this
.
draw
();
},
methods
:
{
showDot
(
path
)
{
return
this
.
showFlagContent
&&
this
.
seriesUnderMouse
.
includes
(
path
);
},
draw
()
{
const
breakpointSize
=
bp
.
getBreakpointSize
();
const
svgWidth
=
this
.
$refs
.
baseSvg
.
getBoundingClientRect
().
width
;
this
.
margin
=
measurements
.
large
.
margin
;
if
(
this
.
smallGraph
||
breakpointSize
===
'
xs
'
||
breakpointSize
===
'
sm
'
)
{
this
.
graphHeight
=
300
;
this
.
margin
=
measurements
.
small
.
margin
;
this
.
measurements
=
measurements
.
small
;
}
this
.
yAxisLabel
=
this
.
graphData
.
y_label
||
'
Values
'
;
this
.
graphWidth
=
svgWidth
-
this
.
margin
.
left
-
this
.
margin
.
right
;
this
.
graphHeight
=
this
.
graphHeight
-
this
.
margin
.
top
-
this
.
margin
.
bottom
;
this
.
baseGraphHeight
=
this
.
graphHeight
-
50
;
this
.
baseGraphWidth
=
this
.
graphWidth
;
// pixel offsets inside the svg and outside are not 1:1
this
.
realPixelRatio
=
svgWidth
/
this
.
baseGraphWidth
;
// set the legends on the axes
const
[
query
]
=
this
.
graphData
.
queries
;
this
.
legendTitle
=
query
?
query
.
label
:
'
Average
'
;
this
.
unitOfDisplay
=
query
?
query
.
unit
:
''
;
if
(
this
.
shouldRenderData
)
{
this
.
renderAxesPaths
();
this
.
formatDeployments
();
}
},
handleMouseOverGraph
(
e
)
{
let
point
=
this
.
$refs
.
graphData
.
createSVGPoint
();
point
.
x
=
e
.
clientX
;
point
.
y
=
e
.
clientY
;
point
=
point
.
matrixTransform
(
this
.
$refs
.
graphData
.
getScreenCTM
().
inverse
());
point
.
x
+=
7
;
this
.
seriesUnderMouse
=
this
.
timeSeries
.
filter
(
series
=>
{
const
mouseX
=
series
.
timeSeriesScaleX
.
invert
(
point
.
x
);
let
minDistance
=
Infinity
;
const
closestTickMark
=
Object
.
keys
(
this
.
allXAxisValues
).
reduce
((
closest
,
x
)
=>
{
const
distance
=
Math
.
abs
(
Number
(
new
Date
(
x
))
-
Number
(
mouseX
));
if
(
distance
<
minDistance
)
{
minDistance
=
distance
;
return
x
;
}
return
closest
;
});
return
series
.
values
.
find
(
v
=>
v
.
time
.
toString
()
===
closestTickMark
);
});
const
firstTimeSeries
=
this
.
seriesUnderMouse
[
0
];
const
timeValueOverlay
=
firstTimeSeries
.
timeSeriesScaleX
.
invert
(
point
.
x
);
const
overlayIndex
=
bisectDate
(
firstTimeSeries
.
values
,
timeValueOverlay
,
1
);
const
d0
=
firstTimeSeries
.
values
[
overlayIndex
-
1
];
const
d1
=
firstTimeSeries
.
values
[
overlayIndex
];
if
(
d0
===
undefined
||
d1
===
undefined
)
return
;
const
evalTime
=
timeValueOverlay
-
d0
[
0
]
>
d1
[
0
]
-
timeValueOverlay
;
const
hoveredDataIndex
=
evalTime
?
overlayIndex
:
overlayIndex
-
1
;
const
hoveredDate
=
firstTimeSeries
.
values
[
hoveredDataIndex
].
time
;
const
currentDeployXPos
=
this
.
mouseOverDeployInfo
(
point
.
x
);
eventHub
.
$emit
(
'
hoverChanged
'
,
{
hoveredDate
,
currentDeployXPos
,
});
},
renderAxesPaths
()
{
({
timeSeries
:
this
.
timeSeries
,
graphDrawData
:
this
.
graphDrawData
}
=
createTimeSeries
(
this
.
graphData
.
queries
,
this
.
graphWidth
,
this
.
graphHeight
,
this
.
graphHeightOffset
,
));
if
(
_
.
findWhere
(
this
.
timeSeries
,
{
renderCanary
:
true
}))
{
this
.
timeSeries
=
this
.
timeSeries
.
map
(
series
=>
({
...
series
,
renderCanary
:
true
}));
}
const
axisXScale
=
d3
.
scaleTime
().
range
([
0
,
this
.
graphWidth
-
70
]);
const
axisYScale
=
d3
.
scaleLinear
().
range
([
this
.
graphHeight
-
this
.
graphHeightOffset
,
0
]);
const
allValues
=
this
.
timeSeries
.
reduce
((
all
,
{
values
})
=>
all
.
concat
(
values
),
[]);
axisXScale
.
domain
(
d3
.
extent
(
allValues
,
d
=>
d
.
time
));
axisYScale
.
domain
([
0
,
d3
.
max
(
allValues
.
map
(
d
=>
d
.
value
))]);
this
.
allXAxisValues
=
this
.
timeSeries
.
reduce
((
obj
,
series
)
=>
{
const
seriesKeys
=
{};
series
.
values
.
forEach
(
v
=>
{
seriesKeys
[
v
.
time
]
=
true
;
});
return
{
...
obj
,
...
seriesKeys
,
};
},
{});
const
xAxis
=
d3
.
axisBottom
()
.
scale
(
axisXScale
)
.
ticks
(
this
.
graphWidth
/
120
)
.
tickFormat
(
timeScaleFormat
);
const
yAxis
=
d3
.
axisLeft
()
.
scale
(
axisYScale
)
.
ticks
(
measurements
.
yTicks
);
d3
.
select
(
this
.
$refs
.
baseSvg
)
.
select
(
'
.x-axis
'
)
.
call
(
xAxis
);
const
width
=
this
.
graphWidth
;
d3
.
select
(
this
.
$refs
.
baseSvg
)
.
select
(
'
.y-axis
'
)
.
call
(
yAxis
)
.
selectAll
(
'
.tick
'
)
.
each
(
function
createTickLines
(
d
,
i
)
{
if
(
i
>
0
)
{
d3
.
select
(
this
)
.
select
(
'
line
'
)
.
attr
(
'
x2
'
,
width
)
.
attr
(
'
class
'
,
'
axis-tick
'
);
}
// Avoid adding the class to the first tick, to prevent coloring
});
// This will select all of the ticks once they're rendered
},
},
};
</
script
>
<
template
>
<div
class=
"prometheus-graph"
@
mouseover=
"showFlagContent = true"
@
mouseleave=
"showFlagContent = false"
>
<div
class=
"prometheus-graph-header"
>
<h5
class=
"prometheus-graph-title"
>
{{
graphData
.
title
}}
</h5>
<div
class=
"prometheus-graph-widgets"
><slot></slot></div>
</div>
<div
:style=
"paddingBottomRootSvg"
class=
"prometheus-svg-container"
>
<svg
ref=
"baseSvg"
:viewBox=
"outerViewBox"
>
<g
:transform=
"axisTransform"
class=
"x-axis"
/>
<g
class=
"y-axis"
transform=
"translate(70, 20)"
/>
<graph-axis
:graph-width=
"graphWidth"
:graph-height=
"graphHeight"
:margin=
"margin"
:measurements=
"measurements"
:y-axis-label=
"yAxisLabel"
:unit-of-display=
"unitOfDisplay"
/>
<svg
v-if=
"shouldRenderData"
ref=
"graphData"
:viewBox=
"innerViewBox"
class=
"graph-data"
>
<slot
name=
"additionalSvgContent"
:graphDrawData=
"graphDrawData"
/>
<graph-path
v-for=
"(path, index) in timeSeries"
:key=
"index"
:generated-line-path=
"path.linePath"
:generated-area-path=
"path.areaPath"
:line-style=
"path.lineStyle"
:line-color=
"path.lineColor"
:area-color=
"path.areaColor"
:current-coordinates=
"currentCoordinates[path.metricTag]"
:show-dot=
"showDot(path)"
/>
<graph-deployment
:deployment-data=
"reducedDeploymentData"
:graph-height=
"graphHeight"
:graph-height-offset=
"graphHeightOffset"
/>
<rect
ref=
"graphOverlay"
:width=
"graphWidth - 70"
:height=
"graphHeight - 100"
class=
"prometheus-graph-overlay"
transform=
"translate(-5, 20)"
@
mousemove=
"handleMouseOverGraph($event)"
/>
</svg>
<svg
v-else
:viewBox=
"innerViewBox"
class=
"js-no-data-to-display"
>
<text
x=
"50%"
y=
"50%"
alignment-baseline=
"middle"
text-anchor=
"middle"
>
{{
s__
(
'
Metrics|No data to display
'
)
}}
</text>
</svg>
</svg>
<graph-flag
v-if=
"shouldRenderData"
:real-pixel-ratio=
"realPixelRatio"
:current-x-coordinate=
"currentXCoordinate"
:current-data=
"currentData"
:graph-height=
"graphHeight"
:graph-height-offset=
"graphHeightOffset"
:show-flag-content=
"showFlagContent"
:time-series=
"seriesUnderMouse"
:unit-of-display=
"unitOfDisplay"
:legend-title=
"legendTitle"
:deployment-flag-data=
"deploymentFlagData"
:current-coordinates=
"currentCoordinates"
/>
</div>
<graph-legend
v-if=
"showLegend"
:legend-title=
"legendTitle"
:time-series=
"timeSeries"
/>
</div>
</
template
>
app/assets/javascripts/monitoring/components/graph/axis.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
import
{
convertToSentenceCase
}
from
'
~/lib/utils/text_utility
'
;
import
{
s__
}
from
'
~/locale
'
;
export
default
{
props
:
{
graphWidth
:
{
type
:
Number
,
required
:
true
,
},
graphHeight
:
{
type
:
Number
,
required
:
true
,
},
margin
:
{
type
:
Object
,
required
:
true
,
},
measurements
:
{
type
:
Object
,
required
:
true
,
},
yAxisLabel
:
{
type
:
String
,
required
:
true
,
},
unitOfDisplay
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
yLabelWidth
:
0
,
yLabelHeight
:
0
,
};
},
computed
:
{
textTransform
()
{
const
yCoordinate
=
(
this
.
graphHeight
-
this
.
margin
.
top
+
this
.
measurements
.
axisLabelLineOffset
)
/
2
||
0
;
return
`translate(15,
${
yCoordinate
}
) rotate(-90)`
;
},
rectTransform
()
{
const
yCoordinate
=
(
this
.
graphHeight
-
this
.
margin
.
top
+
this
.
measurements
.
axisLabelLineOffset
)
/
2
+
this
.
yLabelWidth
/
2
||
0
;
return
`translate(0,
${
yCoordinate
}
) rotate(-90)`
;
},
xPosition
()
{
return
(
this
.
graphWidth
+
this
.
measurements
.
axisLabelLineOffset
)
/
2
-
this
.
margin
.
right
||
0
;
},
yPosition
()
{
return
this
.
graphHeight
-
this
.
margin
.
top
+
this
.
measurements
.
axisLabelLineOffset
||
0
;
},
yAxisLabelSentenceCase
()
{
return
`
${
convertToSentenceCase
(
this
.
yAxisLabel
)}
(
${
this
.
unitOfDisplay
}
)`
;
},
timeString
()
{
return
s__
(
'
PrometheusDashboard|Time
'
);
},
},
mounted
()
{
this
.
$nextTick
(()
=>
{
const
bbox
=
this
.
$refs
.
ylabel
.
getBBox
();
this
.
yLabelWidth
=
bbox
.
width
+
10
;
// Added some padding
this
.
yLabelHeight
=
bbox
.
height
+
5
;
});
},
};
</
script
>
<
template
>
<g
class=
"axis-label-container"
>
<line
:y1=
"yPosition"
:x2=
"graphWidth + 20"
:y2=
"yPosition"
class=
"label-x-axis-line"
stroke=
"#000000"
stroke-width=
"1"
x1=
"10"
/>
<line
:x2=
"10"
:y2=
"yPosition"
class=
"label-y-axis-line"
stroke=
"#000000"
stroke-width=
"1"
x1=
"10"
y1=
"0"
/>
<rect
:transform=
"rectTransform"
:width=
"yLabelWidth"
:height=
"yLabelHeight"
class=
"rect-axis-text"
/>
<text
ref=
"ylabel"
:transform=
"textTransform"
class=
"label-axis-text y-label-text"
text-anchor=
"middle"
>
{{
yAxisLabelSentenceCase
}}
</text>
<rect
:x=
"xPosition + 60"
:y=
"graphHeight - 80"
class=
"rect-axis-text"
width=
"35"
height=
"50"
/>
<text
:x=
"xPosition + 60"
:y=
"yPosition"
class=
"label-axis-text x-label-text"
dy=
".35em"
>
{{
timeString
}}
</text>
</g>
</
template
>
app/assets/javascripts/monitoring/components/graph/deployment.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
export
default
{
props
:
{
deploymentData
:
{
type
:
Array
,
required
:
true
,
},
graphHeight
:
{
type
:
Number
,
required
:
true
,
},
graphHeightOffset
:
{
type
:
Number
,
required
:
true
,
},
},
computed
:
{
calculatedHeight
()
{
return
this
.
graphHeight
-
this
.
graphHeightOffset
;
},
},
methods
:
{
transformDeploymentGroup
(
deployment
)
{
return
`translate(
${
Math
.
floor
(
deployment
.
xPos
)
-
5
}
, 20)`
;
},
},
};
</
script
>
<
template
>
<g
class=
"deploy-info"
>
<g
v-for=
"(deployment, index) in deploymentData"
:key=
"index"
:transform=
"transformDeploymentGroup(deployment)"
>
<rect
:height=
"calculatedHeight"
x=
"0"
y=
"0"
width=
"3"
fill=
"url(#shadow-gradient)"
/>
<line
:y2=
"calculatedHeight"
class=
"deployment-line"
x1=
"0"
y1=
"0"
x2=
"0"
stroke=
"#000"
/>
</g>
<svg
height=
"0"
width=
"0"
>
<defs>
<linearGradient
id=
"shadow-gradient"
>
<stop
offset=
"0%"
stop-color=
"#000"
stop-opacity=
"0.4"
/>
<stop
offset=
"100%"
stop-color=
"#000"
stop-opacity=
"0"
/>
</linearGradient>
</defs>
</svg>
</g>
</
template
>
app/assets/javascripts/monitoring/components/graph/flag.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
import
{
dateFormat
,
timeFormat
}
from
'
../../utils/date_time_formatters
'
;
import
{
formatRelevantDigits
}
from
'
../../../lib/utils/number_utils
'
;
import
Icon
from
'
../../../vue_shared/components/icon.vue
'
;
import
TrackLine
from
'
./track_line.vue
'
;
export
default
{
components
:
{
Icon
,
TrackLine
,
},
props
:
{
currentXCoordinate
:
{
type
:
Number
,
required
:
true
,
},
currentData
:
{
type
:
Object
,
required
:
true
,
},
deploymentFlagData
:
{
type
:
Object
,
required
:
false
,
default
:
null
,
},
graphHeight
:
{
type
:
Number
,
required
:
true
,
},
graphHeightOffset
:
{
type
:
Number
,
required
:
true
,
},
realPixelRatio
:
{
type
:
Number
,
required
:
true
,
},
showFlagContent
:
{
type
:
Boolean
,
required
:
true
,
},
timeSeries
:
{
type
:
Array
,
required
:
true
,
},
unitOfDisplay
:
{
type
:
String
,
required
:
true
,
},
legendTitle
:
{
type
:
String
,
required
:
true
,
},
currentCoordinates
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
formatTime
()
{
return
this
.
deploymentFlagData
?
timeFormat
(
this
.
deploymentFlagData
.
time
)
:
timeFormat
(
this
.
currentData
.
time
);
},
formatDate
()
{
return
this
.
deploymentFlagData
?
dateFormat
(
this
.
deploymentFlagData
.
time
)
:
dateFormat
(
this
.
currentData
.
time
);
},
cursorStyle
()
{
const
xCoordinate
=
this
.
deploymentFlagData
?
this
.
deploymentFlagData
.
xPos
:
this
.
currentXCoordinate
;
const
offsetTop
=
20
*
this
.
realPixelRatio
;
const
offsetLeft
=
(
70
+
xCoordinate
)
*
this
.
realPixelRatio
;
const
height
=
(
this
.
graphHeight
-
this
.
graphHeightOffset
)
*
this
.
realPixelRatio
;
return
{
top
:
`
${
offsetTop
}
px`
,
left
:
`
${
offsetLeft
}
px`
,
height
:
`
${
height
}
px`
,
};
},
flagOrientation
()
{
if
(
this
.
currentXCoordinate
*
this
.
realPixelRatio
>
120
)
{
return
'
left
'
;
}
return
'
right
'
;
},
},
methods
:
{
seriesMetricValue
(
seriesIndex
,
series
)
{
const
indexFromCoordinates
=
this
.
currentCoordinates
[
series
.
metricTag
]
?
this
.
currentCoordinates
[
series
.
metricTag
].
currentDataIndex
:
0
;
const
index
=
this
.
deploymentFlagData
?
this
.
deploymentFlagData
.
seriesIndex
:
indexFromCoordinates
;
const
value
=
series
.
values
[
index
]
&&
series
.
values
[
index
].
value
;
if
(
Number
.
isNaN
(
value
))
{
return
'
-
'
;
}
return
`
${
formatRelevantDigits
(
value
)}${
this
.
unitOfDisplay
}
`
;
},
seriesMetricLabel
(
index
,
series
)
{
if
(
this
.
timeSeries
.
length
<
2
)
{
return
this
.
legendTitle
;
}
if
(
series
.
metricTag
)
{
return
series
.
metricTag
;
}
return
`series
${
index
+
1
}
`
;
},
},
};
</
script
>
<
template
>
<div
:style=
"cursorStyle"
class=
"prometheus-graph-cursor"
>
<div
v-if=
"showFlagContent"
:class=
"flagOrientation"
class=
"prometheus-graph-flag popover"
>
<div
class=
"arrow-shadow"
></div>
<div
class=
"arrow"
></div>
<div
class=
"popover-title"
>
<h5
v-if=
"deploymentFlagData"
>
Deployed
</h5>
{{
formatDate
}}
<strong>
{{
formatTime
}}
</strong>
</div>
<div
v-if=
"deploymentFlagData"
class=
"popover-content deploy-meta-content"
>
<div>
<icon
:size=
"12"
name=
"commit"
/>
<a
:href=
"deploymentFlagData.commitUrl"
>
{{
deploymentFlagData
.
sha
.
slice
(
0
,
8
)
}}
</a>
</div>
<div
v-if=
"deploymentFlagData.tag"
>
<icon
:size=
"12"
name=
"label"
/>
<a
:href=
"deploymentFlagData.tagUrl"
>
{{
deploymentFlagData
.
ref
}}
</a>
</div>
</div>
<div
class=
"popover-content"
>
<table
class=
"prometheus-table"
>
<tr
v-for=
"(series, index) in timeSeries"
:key=
"index"
>
<track-line
:track=
"series"
/>
<td>
{{
series
.
track
}}
{{
seriesMetricLabel
(
index
,
series
)
}}
</td>
<td>
<strong>
{{
seriesMetricValue
(
index
,
series
)
}}
</strong>
</td>
</tr>
</table>
</div>
</div>
</div>
</
template
>
app/assets/javascripts/monitoring/components/graph/legend.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
import
TrackLine
from
'
./track_line.vue
'
;
import
TrackInfo
from
'
./track_info.vue
'
;
export
default
{
components
:
{
TrackLine
,
TrackInfo
,
},
props
:
{
legendTitle
:
{
type
:
String
,
required
:
true
,
},
timeSeries
:
{
type
:
Array
,
required
:
true
,
},
},
methods
:
{
isStable
(
track
)
{
return
{
'
prometheus-table-row-highlight
'
:
track
.
trackName
!==
'
Canary
'
&&
track
.
renderCanary
,
};
},
},
};
</
script
>
<
template
>
<div
class=
"prometheus-graph-legends prepend-left-10"
>
<table
class=
"prometheus-table"
>
<tr
v-for=
"(series, index) in timeSeries"
v-if=
"series.shouldRenderLegend"
:key=
"index"
:class=
"isStable(series)"
>
<td>
<strong
v-if=
"series.renderCanary"
>
{{
series
.
trackName
}}
</strong>
</td>
<track-line
:track=
"series"
/>
<td
v-if=
"timeSeries.length > 1"
class=
"legend-metric-title"
>
<track-info
v-if=
"series.metricTag"
:track=
"series"
/>
<track-info
v-else
:track=
"series"
>
<strong>
{{
legendTitle
}}
</strong>
series
{{
index
+
1
}}
</track-info>
</td>
<td
v-else
>
<track-info
:track=
"series"
>
<strong>
{{
legendTitle
}}
</strong>
</track-info>
</td>
<template
v-for=
"(track, trackIndex) in series.tracksLegend"
>
<track-line
:key=
"`track-line-$
{trackIndex}`" :track="track" />
<td
:key=
"`track-info-$
{trackIndex}`">
<track-info
:track=
"track"
class=
"legend-metric-title"
/>
</td>
</
template
>
</tr>
</table>
</div>
</template>
app/assets/javascripts/monitoring/components/graph/path.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
export
default
{
props
:
{
generatedLinePath
:
{
type
:
String
,
required
:
true
,
},
generatedAreaPath
:
{
type
:
String
,
required
:
true
,
},
lineStyle
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
lineColor
:
{
type
:
String
,
required
:
true
,
},
areaColor
:
{
type
:
String
,
required
:
true
,
},
currentCoordinates
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({
currentX
:
0
,
currentY
:
0
}),
},
showDot
:
{
type
:
Boolean
,
required
:
true
,
},
},
computed
:
{
strokeDashArray
()
{
if
(
this
.
lineStyle
===
'
dashed
'
)
return
'
3, 1
'
;
if
(
this
.
lineStyle
===
'
dotted
'
)
return
'
1, 1
'
;
return
null
;
},
},
};
</
script
>
<
template
>
<g
transform=
"translate(-5, 20)"
>
<circle
v-if=
"showDot"
:cx=
"currentCoordinates.currentX"
:cy=
"currentCoordinates.currentY"
:fill=
"lineColor"
:stroke=
"lineColor"
class=
"circle-path"
r=
"3"
/>
<path
:d=
"generatedAreaPath"
:fill=
"areaColor"
class=
"metric-area"
/>
<path
:d=
"generatedLinePath"
:stroke=
"lineColor"
:stroke-dasharray=
"strokeDashArray"
class=
"metric-line"
fill=
"none"
stroke-width=
"1"
/>
</g>
</
template
>
app/assets/javascripts/monitoring/components/graph/track_info.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
import
{
formatRelevantDigits
}
from
'
~/lib/utils/number_utils
'
;
export
default
{
name
:
'
TrackInfo
'
,
props
:
{
track
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
summaryMetrics
()
{
return
`Avg:
${
formatRelevantDigits
(
this
.
track
.
average
)}
· Max:
${
formatRelevantDigits
(
this
.
track
.
max
,
)}
`
;
},
},
};
</
script
>
<
template
>
<span>
<slot>
<strong>
{{
track
.
metricTag
}}
</strong>
</slot>
{{
summaryMetrics
}}
</span>
</
template
>
app/assets/javascripts/monitoring/components/graph/track_line.vue
已删除
100644 → 0
浏览文件 @
c1286332
<
script
>
export
default
{
name
:
'
TrackLine
'
,
props
:
{
track
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
stylizedLine
()
{
if
(
this
.
track
.
lineStyle
===
'
dashed
'
)
return
'
6, 3
'
;
if
(
this
.
track
.
lineStyle
===
'
dotted
'
)
return
'
3, 3
'
;
return
null
;
},
},
};
</
script
>
<
template
>
<td>
<svg
width=
"16"
height=
"8"
>
<line
:stroke-dasharray=
"stylizedLine"
:stroke=
"track.lineColor"
:x1=
"0"
:x2=
"16"
:y1=
"4"
:y2=
"4"
stroke-width=
"4"
/>
</svg>
</td>
</
template
>
app/assets/javascripts/monitoring/event_hub.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
export
default
new
Vue
();
app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
已删除
100644 → 0
浏览文件 @
c1286332
import
{
bisectDate
}
from
'
../utils/date_time_formatters
'
;
const
mixins
=
{
methods
:
{
mouseOverDeployInfo
(
mouseXPos
)
{
if
(
!
this
.
reducedDeploymentData
)
return
false
;
let
dataFound
=
false
;
this
.
reducedDeploymentData
=
this
.
reducedDeploymentData
.
map
(
d
=>
{
const
deployment
=
d
;
if
(
d
.
xPos
>=
mouseXPos
-
10
&&
d
.
xPos
<=
mouseXPos
+
10
&&
!
dataFound
)
{
dataFound
=
d
.
xPos
+
1
;
deployment
.
showDeploymentFlag
=
true
;
}
else
{
deployment
.
showDeploymentFlag
=
false
;
}
return
deployment
;
});
return
dataFound
;
},
formatDeployments
()
{
this
.
reducedDeploymentData
=
this
.
deploymentData
.
reduce
((
deploymentDataArray
,
deployment
)
=>
{
const
time
=
new
Date
(
deployment
.
created_at
);
const
xPos
=
Math
.
floor
(
this
.
timeSeries
[
0
].
timeSeriesScaleX
(
time
));
time
.
setSeconds
(
this
.
timeSeries
[
0
].
values
[
0
].
time
.
getSeconds
());
if
(
xPos
>=
0
)
{
const
seriesIndex
=
bisectDate
(
this
.
timeSeries
[
0
].
values
,
time
,
1
);
deploymentDataArray
.
push
({
id
:
deployment
.
id
,
time
,
sha
:
deployment
.
sha
,
commitUrl
:
`
${
this
.
projectPath
}
/commit/
${
deployment
.
sha
}
`
,
tag
:
deployment
.
tag
,
tagUrl
:
deployment
.
tag
?
`
${
this
.
tagsPath
}
/
${
deployment
.
ref
.
name
}
`
:
null
,
ref
:
deployment
.
ref
.
name
,
xPos
,
seriesIndex
,
showDeploymentFlag
:
false
,
});
}
return
deploymentDataArray
;
},
[]);
},
positionFlag
()
{
const
timeSeries
=
this
.
seriesUnderMouse
[
0
];
if
(
!
timeSeries
)
{
return
;
}
const
hoveredDataIndex
=
bisectDate
(
timeSeries
.
values
,
this
.
hoverData
.
hoveredDate
);
this
.
currentData
=
timeSeries
.
values
[
hoveredDataIndex
];
this
.
currentXCoordinate
=
Math
.
floor
(
timeSeries
.
timeSeriesScaleX
(
this
.
currentData
.
time
));
this
.
currentCoordinates
=
{};
this
.
seriesUnderMouse
.
forEach
(
series
=>
{
const
currentDataIndex
=
bisectDate
(
series
.
values
,
this
.
hoverData
.
hoveredDate
);
const
currentData
=
series
.
values
[
currentDataIndex
];
const
currentX
=
Math
.
floor
(
series
.
timeSeriesScaleX
(
currentData
.
time
));
const
currentY
=
Math
.
floor
(
series
.
timeSeriesScaleY
(
currentData
.
value
));
this
.
currentCoordinates
[
series
.
metricTag
]
=
{
currentX
,
currentY
,
currentDataIndex
,
};
});
if
(
this
.
hoverData
.
currentDeployXPos
)
{
this
.
showFlag
=
false
;
}
else
{
this
.
showFlag
=
true
;
}
},
},
};
export
default
mixins
;
app/assets/javascripts/monitoring/utils/date_time_formatters.js
已删除
100644 → 0
浏览文件 @
c1286332
import
{
timeFormat
as
time
}
from
'
d3-time-format
'
;
import
{
timeSecond
,
timeMinute
,
timeHour
,
timeDay
,
timeWeek
,
timeMonth
,
timeYear
}
from
'
d3-time
'
;
import
{
bisector
}
from
'
d3-array
'
;
const
d3
=
{
time
,
bisector
,
timeSecond
,
timeMinute
,
timeHour
,
timeDay
,
timeWeek
,
timeMonth
,
timeYear
,
};
export
const
dateFormat
=
d3
.
time
(
'
%d %b %Y,
'
);
export
const
timeFormat
=
d3
.
time
(
'
%-I:%M%p
'
);
export
const
dateFormatWithName
=
d3
.
time
(
'
%a, %b %-d
'
);
export
const
bisectDate
=
d3
.
bisector
(
d
=>
d
.
time
).
left
;
export
function
timeScaleFormat
(
date
)
{
let
formatFunction
;
if
(
d3
.
timeSecond
(
date
)
<
date
)
{
formatFunction
=
d3
.
time
(
'
.%L
'
);
}
else
if
(
d3
.
timeMinute
(
date
)
<
date
)
{
formatFunction
=
d3
.
time
(
'
:%S
'
);
}
else
if
(
d3
.
timeHour
(
date
)
<
date
)
{
formatFunction
=
d3
.
time
(
'
%-I:%M
'
);
}
else
if
(
d3
.
timeDay
(
date
)
<
date
)
{
formatFunction
=
d3
.
time
(
'
%-I %p
'
);
}
else
if
(
d3
.
timeWeek
(
date
)
<
date
)
{
formatFunction
=
d3
.
time
(
'
%a %d
'
);
}
else
if
(
d3
.
timeMonth
(
date
)
<
date
)
{
formatFunction
=
d3
.
time
(
'
%b %d
'
);
}
else
if
(
d3
.
timeYear
(
date
)
<
date
)
{
formatFunction
=
d3
.
time
(
'
%B
'
);
}
else
{
formatFunction
=
d3
.
time
(
'
%Y
'
);
}
return
formatFunction
(
date
);
}
app/assets/javascripts/monitoring/utils/measurements.js
已删除
100644 → 0
浏览文件 @
c1286332
export
default
{
small
:
{
// Covers both xs and sm screen sizes
margin
:
{
top
:
40
,
right
:
40
,
bottom
:
50
,
left
:
40
,
},
legends
:
{
width
:
15
,
height
:
3
,
offsetX
:
20
,
offsetY
:
32
,
},
backgroundLegend
:
{
width
:
30
,
height
:
50
,
},
axisLabelLineOffset
:
-
20
,
},
large
:
{
// This covers both md and lg screen sizes
margin
:
{
top
:
80
,
right
:
80
,
bottom
:
100
,
left
:
80
,
},
legends
:
{
width
:
15
,
height
:
3
,
offsetX
:
20
,
offsetY
:
34
,
},
backgroundLegend
:
{
width
:
30
,
height
:
150
,
},
axisLabelLineOffset
:
20
,
},
xTicks
:
8
,
yTicks
:
3
,
};
app/assets/javascripts/monitoring/utils/multiple_time_series.js
已删除
100644 → 0
浏览文件 @
c1286332
import
_
from
'
underscore
'
;
import
{
scaleLinear
,
scaleTime
}
from
'
d3-scale
'
;
import
{
line
,
area
,
curveLinear
}
from
'
d3-shape
'
;
import
{
extent
,
max
,
sum
}
from
'
d3-array
'
;
import
{
timeMinute
,
timeSecond
}
from
'
d3-time
'
;
import
{
capitalizeFirstCharacter
}
from
'
~/lib/utils/text_utility
'
;
const
d3
=
{
scaleLinear
,
scaleTime
,
line
,
area
,
curveLinear
,
extent
,
max
,
timeMinute
,
timeSecond
,
sum
,
};
const
defaultColorPalette
=
{
blue
:
[
'
#1f78d1
'
,
'
#8fbce8
'
],
orange
:
[
'
#fc9403
'
,
'
#feca81
'
],
red
:
[
'
#db3b21
'
,
'
#ed9d90
'
],
green
:
[
'
#1aaa55
'
,
'
#8dd5aa
'
],
purple
:
[
'
#6666c4
'
,
'
#d1d1f0
'
],
};
const
defaultColorOrder
=
[
'
blue
'
,
'
orange
'
,
'
red
'
,
'
green
'
,
'
purple
'
];
const
defaultStyleOrder
=
[
'
solid
'
,
'
dashed
'
,
'
dotted
'
];
function
queryTimeSeries
(
query
,
graphDrawData
,
lineStyle
)
{
let
usedColors
=
[];
let
renderCanary
=
false
;
const
timeSeriesParsed
=
[];
function
pickColor
(
name
)
{
let
pick
;
if
(
name
&&
defaultColorPalette
[
name
])
{
pick
=
name
;
}
else
{
const
unusedColors
=
_
.
difference
(
defaultColorOrder
,
usedColors
);
if
(
unusedColors
.
length
>
0
)
{
[
pick
]
=
unusedColors
;
}
else
{
usedColors
=
[];
[
pick
]
=
defaultColorOrder
;
}
}
usedColors
.
push
(
pick
);
return
defaultColorPalette
[
pick
];
}
function
findByDate
(
series
,
time
)
{
const
val
=
series
.
find
(
v
=>
Math
.
abs
(
d3
.
timeSecond
.
count
(
time
,
v
.
time
))
<
60
);
if
(
val
)
{
return
val
.
value
;
}
return
NaN
;
}
// The timeseries data may have gaps in it
// but we need a regularly-spaced set of time/value pairs
// this gives us a complete range of one minute intervals
// offset the same amount as the original data
const
[
minX
,
maxX
]
=
graphDrawData
.
xDom
;
const
offset
=
d3
.
timeMinute
(
minX
)
-
Number
(
minX
);
const
datesWithoutGaps
=
d3
.
timeSecond
.
every
(
60
)
.
range
(
d3
.
timeMinute
.
offset
(
minX
,
-
1
),
maxX
)
.
map
(
d
=>
d
-
offset
);
query
.
result
.
forEach
((
timeSeries
,
timeSeriesNumber
)
=>
{
let
metricTag
=
''
;
let
lineColor
=
''
;
let
areaColor
=
''
;
let
shouldRenderLegend
=
true
;
const
timeSeriesValues
=
timeSeries
.
values
.
map
(
d
=>
d
.
value
);
const
maximumValue
=
d3
.
max
(
timeSeriesValues
);
const
accum
=
d3
.
sum
(
timeSeriesValues
);
const
trackName
=
capitalizeFirstCharacter
(
query
.
track
?
query
.
track
:
'
Stable
'
);
if
(
trackName
===
'
Canary
'
)
{
renderCanary
=
true
;
}
const
timeSeriesMetricLabel
=
timeSeries
.
metric
[
Object
.
keys
(
timeSeries
.
metric
)[
0
]];
const
seriesCustomizationData
=
query
.
series
!=
null
&&
_
.
findWhere
(
query
.
series
[
0
].
when
,
{
value
:
timeSeriesMetricLabel
});
if
(
seriesCustomizationData
)
{
metricTag
=
seriesCustomizationData
.
value
||
timeSeriesMetricLabel
;
[
lineColor
,
areaColor
]
=
pickColor
(
seriesCustomizationData
.
color
);
if
(
timeSeriesParsed
.
length
>
0
)
{
shouldRenderLegend
=
false
;
}
else
{
shouldRenderLegend
=
true
;
}
}
else
{
metricTag
=
timeSeriesMetricLabel
||
query
.
label
||
`series
${
timeSeriesNumber
+
1
}
`
;
[
lineColor
,
areaColor
]
=
pickColor
();
if
(
timeSeriesParsed
.
length
>
1
)
{
shouldRenderLegend
=
false
;
}
}
const
values
=
datesWithoutGaps
.
map
(
time
=>
({
time
,
value
:
findByDate
(
timeSeries
.
values
,
time
),
}));
timeSeriesParsed
.
push
({
linePath
:
graphDrawData
.
lineFunction
(
values
),
areaPath
:
graphDrawData
.
areaBelowLine
(
values
),
timeSeriesScaleX
:
graphDrawData
.
timeSeriesScaleX
,
timeSeriesScaleY
:
graphDrawData
.
timeSeriesScaleY
,
values
:
timeSeries
.
values
,
max
:
maximumValue
,
average
:
accum
/
timeSeries
.
values
.
length
,
lineStyle
,
lineColor
,
areaColor
,
metricTag
,
trackName
,
shouldRenderLegend
,
renderCanary
,
});
if
(
!
shouldRenderLegend
)
{
if
(
!
timeSeriesParsed
[
0
].
tracksLegend
)
{
timeSeriesParsed
[
0
].
tracksLegend
=
[];
}
timeSeriesParsed
[
0
].
tracksLegend
.
push
({
max
:
maximumValue
,
average
:
accum
/
timeSeries
.
values
.
length
,
lineStyle
,
lineColor
,
metricTag
,
});
}
});
return
timeSeriesParsed
;
}
function
xyDomain
(
queries
)
{
const
allValues
=
queries
.
reduce
(
(
allQueryResults
,
query
)
=>
allQueryResults
.
concat
(
query
.
result
.
reduce
((
allResults
,
result
)
=>
allResults
.
concat
(
result
.
values
),
[]),
),
[],
);
const
xDom
=
d3
.
extent
(
allValues
,
d
=>
d
.
time
);
const
yDom
=
[
0
,
d3
.
max
(
allValues
.
map
(
d
=>
d
.
value
))];
return
{
xDom
,
yDom
,
};
}
export
function
generateGraphDrawData
(
queries
,
graphWidth
,
graphHeight
,
graphHeightOffset
)
{
const
{
xDom
,
yDom
}
=
xyDomain
(
queries
);
const
timeSeriesScaleX
=
d3
.
scaleTime
().
range
([
0
,
graphWidth
-
70
]);
const
timeSeriesScaleY
=
d3
.
scaleLinear
().
range
([
graphHeight
-
graphHeightOffset
,
0
]);
timeSeriesScaleX
.
domain
(
xDom
);
timeSeriesScaleX
.
ticks
(
d3
.
timeMinute
,
60
);
timeSeriesScaleY
.
domain
(
yDom
);
const
defined
=
d
=>
!
Number
.
isNaN
(
d
.
value
)
&&
d
.
value
!=
null
;
const
lineFunction
=
d3
.
line
()
.
defined
(
defined
)
.
curve
(
d3
.
curveLinear
)
// d3 v4 uses curbe instead of interpolate
.
x
(
d
=>
timeSeriesScaleX
(
d
.
time
))
.
y
(
d
=>
timeSeriesScaleY
(
d
.
value
));
const
areaBelowLine
=
d3
.
area
()
.
defined
(
defined
)
.
curve
(
d3
.
curveLinear
)
.
x
(
d
=>
timeSeriesScaleX
(
d
.
time
))
.
y0
(
graphHeight
-
graphHeightOffset
)
.
y1
(
d
=>
timeSeriesScaleY
(
d
.
value
));
const
areaAboveLine
=
d3
.
area
()
.
defined
(
defined
)
.
curve
(
d3
.
curveLinear
)
.
x
(
d
=>
timeSeriesScaleX
(
d
.
time
))
.
y0
(
0
)
.
y1
(
d
=>
timeSeriesScaleY
(
d
.
value
));
return
{
lineFunction
,
areaBelowLine
,
areaAboveLine
,
xDom
,
yDom
,
timeSeriesScaleX
,
timeSeriesScaleY
,
};
}
export
default
function
createTimeSeries
(
queries
,
graphWidth
,
graphHeight
,
graphHeightOffset
)
{
const
graphDrawData
=
generateGraphDrawData
(
queries
,
graphWidth
,
graphHeight
,
graphHeightOffset
);
const
timeSeries
=
queries
.
reduce
((
series
,
query
,
index
)
=>
{
const
lineStyle
=
defaultStyleOrder
[
index
%
defaultStyleOrder
.
length
];
return
series
.
concat
(
queryTimeSeries
(
query
,
graphDrawData
,
lineStyle
));
},
[]);
return
{
timeSeries
,
graphDrawData
,
};
}
locale/gitlab.pot
浏览文件 @
e7bb9b95
...
...
@@ -4447,9 +4447,6 @@ msgstr ""
msgid "Metrics|Learn about environments"
msgstr ""
msgid "Metrics|No data to display"
msgstr ""
msgid "Metrics|No deployed environments"
msgstr ""
...
...
@@ -5711,9 +5708,6 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
msgid "PrometheusDashboard|Time"
msgstr ""
msgid "PrometheusService|%{exporters} with %{metrics} were found"
msgstr ""
...
...
spec/javascripts/monitoring/graph/axis_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
GraphAxis
from
'
~/monitoring/components/graph/axis.vue
'
;
import
measurements
from
'
~/monitoring/utils/measurements
'
;
const
createComponent
=
propsData
=>
{
const
Component
=
Vue
.
extend
(
GraphAxis
);
return
new
Component
({
propsData
,
}).
$mount
();
};
const
defaultValuesComponent
=
{
graphWidth
:
500
,
graphHeight
:
300
,
graphHeightOffset
:
120
,
margin
:
measurements
.
large
.
margin
,
measurements
:
measurements
.
large
,
yAxisLabel
:
'
Values
'
,
unitOfDisplay
:
'
MB
'
,
};
function
getTextFromNode
(
component
,
selector
)
{
return
component
.
$el
.
querySelector
(
selector
).
firstChild
.
nodeValue
.
trim
();
}
describe
(
'
Axis
'
,
()
=>
{
describe
(
'
Computed props
'
,
()
=>
{
it
(
'
textTransform
'
,
()
=>
{
const
component
=
createComponent
(
defaultValuesComponent
);
expect
(
component
.
textTransform
).
toContain
(
'
translate(15, 120) rotate(-90)
'
);
});
it
(
'
xPosition
'
,
()
=>
{
const
component
=
createComponent
(
defaultValuesComponent
);
expect
(
component
.
xPosition
).
toEqual
(
180
);
});
it
(
'
yPosition
'
,
()
=>
{
const
component
=
createComponent
(
defaultValuesComponent
);
expect
(
component
.
yPosition
).
toEqual
(
240
);
});
it
(
'
rectTransform
'
,
()
=>
{
const
component
=
createComponent
(
defaultValuesComponent
);
expect
(
component
.
rectTransform
).
toContain
(
'
translate(0, 120) rotate(-90)
'
);
});
});
it
(
'
has 2 rect-axis-text rect svg elements
'
,
()
=>
{
const
component
=
createComponent
(
defaultValuesComponent
);
expect
(
component
.
$el
.
querySelectorAll
(
'
.rect-axis-text
'
).
length
).
toEqual
(
2
);
});
it
(
'
contains text to signal the usage, title and time with multiple time series
'
,
()
=>
{
const
component
=
createComponent
(
defaultValuesComponent
);
expect
(
getTextFromNode
(
component
,
'
.y-label-text
'
)).
toEqual
(
'
Values (MB)
'
);
});
});
spec/javascripts/monitoring/graph/deployment_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
GraphDeployment
from
'
~/monitoring/components/graph/deployment.vue
'
;
import
{
deploymentData
}
from
'
../mock_data
'
;
const
createComponent
=
propsData
=>
{
const
Component
=
Vue
.
extend
(
GraphDeployment
);
return
new
Component
({
propsData
,
}).
$mount
();
};
describe
(
'
MonitoringDeployment
'
,
()
=>
{
describe
(
'
Methods
'
,
()
=>
{
it
(
'
should contain a hidden gradient
'
,
()
=>
{
const
component
=
createComponent
({
showDeployInfo
:
true
,
deploymentData
,
graphHeight
:
300
,
graphWidth
:
440
,
graphHeightOffset
:
120
,
});
expect
(
component
.
$el
.
querySelector
(
'
#shadow-gradient
'
)).
not
.
toBeNull
();
});
it
(
'
transformDeploymentGroup translates an available deployment
'
,
()
=>
{
const
component
=
createComponent
({
showDeployInfo
:
false
,
deploymentData
,
graphHeight
:
300
,
graphWidth
:
440
,
graphHeightOffset
:
120
,
});
expect
(
component
.
transformDeploymentGroup
({
xPos
:
16
})).
toContain
(
'
translate(11, 20)
'
);
});
describe
(
'
Computed props
'
,
()
=>
{
it
(
'
calculatedHeight
'
,
()
=>
{
const
component
=
createComponent
({
showDeployInfo
:
true
,
deploymentData
,
graphHeight
:
300
,
graphWidth
:
440
,
graphHeightOffset
:
120
,
});
expect
(
component
.
calculatedHeight
).
toEqual
(
180
);
});
});
});
});
spec/javascripts/monitoring/graph/flag_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
GraphFlag
from
'
~/monitoring/components/graph/flag.vue
'
;
import
{
deploymentData
}
from
'
../mock_data
'
;
const
createComponent
=
propsData
=>
{
const
Component
=
Vue
.
extend
(
GraphFlag
);
return
new
Component
({
propsData
,
}).
$mount
();
};
const
defaultValuesComponent
=
{
currentXCoordinate
:
200
,
currentYCoordinate
:
100
,
currentFlagPosition
:
100
,
currentData
:
{
time
:
new
Date
(
'
2017-06-04T18:17:33.501Z
'
),
value
:
'
1.49609375
'
,
},
graphHeight
:
300
,
graphHeightOffset
:
120
,
showFlagContent
:
true
,
realPixelRatio
:
1
,
timeSeries
:
[
{
values
:
[
{
time
:
new
Date
(
'
2017-06-04T18:17:33.501Z
'
),
value
:
'
1.49609375
'
,
},
],
},
],
unitOfDisplay
:
'
ms
'
,
currentDataIndex
:
0
,
legendTitle
:
'
Average
'
,
currentCoordinates
:
{},
};
const
deploymentFlagData
=
{
...
deploymentData
[
0
],
ref
:
deploymentData
[
0
].
ref
.
name
,
xPos
:
10
,
time
:
new
Date
(
deploymentData
[
0
].
created_at
),
};
describe
(
'
GraphFlag
'
,
()
=>
{
let
component
;
it
(
'
has a line at the currentXCoordinate
'
,
()
=>
{
component
=
createComponent
(
defaultValuesComponent
);
expect
(
component
.
$el
.
style
.
left
).
toEqual
(
`
${
70
+
component
.
currentXCoordinate
}
px`
);
});
describe
(
'
Deployment flag
'
,
()
=>
{
it
(
'
shows a deployment flag when deployment data provided
'
,
()
=>
{
const
deploymentFlagComponent
=
createComponent
({
...
defaultValuesComponent
,
deploymentFlagData
,
});
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.popover-title
'
)).
toContainText
(
'
Deployed
'
);
});
it
(
'
contains the ref when a tag is available
'
,
()
=>
{
const
deploymentFlagComponent
=
createComponent
({
...
defaultValuesComponent
,
deploymentFlagData
:
{
...
deploymentFlagData
,
sha
:
'
f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187
'
,
tag
:
true
,
ref
:
'
1.0
'
,
},
});
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
toContainText
(
'
f5bcd1d9
'
,
);
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
toContainText
(
'
1.0
'
,
);
});
it
(
'
does not contain the ref when a tag is unavailable
'
,
()
=>
{
const
deploymentFlagComponent
=
createComponent
({
...
defaultValuesComponent
,
deploymentFlagData
:
{
...
deploymentFlagData
,
sha
:
'
f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187
'
,
tag
:
false
,
ref
:
'
1.0
'
,
},
});
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
toContainText
(
'
f5bcd1d9
'
,
);
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
not
.
toContainText
(
'
1.0
'
,
);
});
});
describe
(
'
Computed props
'
,
()
=>
{
beforeEach
(()
=>
{
component
=
createComponent
(
defaultValuesComponent
);
});
it
(
'
formatTime
'
,
()
=>
{
expect
(
component
.
formatTime
).
toMatch
(
/
\d
:17PM/
);
});
it
(
'
formatDate
'
,
()
=>
{
expect
(
component
.
formatDate
).
toEqual
(
'
04 Jun 2017,
'
);
});
it
(
'
cursorStyle
'
,
()
=>
{
expect
(
component
.
cursorStyle
).
toEqual
({
top
:
'
20px
'
,
left
:
'
270px
'
,
height
:
'
180px
'
,
});
});
it
(
'
flagOrientation
'
,
()
=>
{
expect
(
component
.
flagOrientation
).
toEqual
(
'
left
'
);
});
});
});
spec/javascripts/monitoring/graph/legend_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
GraphLegend
from
'
~/monitoring/components/graph/legend.vue
'
;
import
createTimeSeries
from
'
~/monitoring/utils/multiple_time_series
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
singleRowMetricsMultipleSeries
,
convertDatesMultipleSeries
}
from
'
../mock_data
'
;
const
convertedMetrics
=
convertDatesMultipleSeries
(
singleRowMetricsMultipleSeries
);
const
defaultValuesComponent
=
{};
const
{
timeSeries
}
=
createTimeSeries
(
convertedMetrics
[
0
].
queries
,
500
,
300
,
120
);
defaultValuesComponent
.
timeSeries
=
timeSeries
;
describe
(
'
Legend Component
'
,
()
=>
{
let
vm
;
let
Legend
;
beforeEach
(()
=>
{
Legend
=
Vue
.
extend
(
GraphLegend
);
});
describe
(
'
View
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Legend
,
{
legendTitle
:
'
legend
'
,
timeSeries
,
currentDataIndex
:
0
,
unitOfDisplay
:
'
Req/Sec
'
,
});
});
it
(
'
should render the usage, title and time with multiple time series
'
,
()
=>
{
const
titles
=
vm
.
$el
.
querySelectorAll
(
'
.legend-metric-title
'
);
expect
(
titles
[
0
].
textContent
.
indexOf
(
'
1xx
'
)).
not
.
toEqual
(
-
1
);
expect
(
titles
[
1
].
textContent
.
indexOf
(
'
2xx
'
)).
not
.
toEqual
(
-
1
);
});
it
(
'
should container the same number of rows in the table as time series
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.prometheus-table tr
'
).
length
).
toEqual
(
vm
.
timeSeries
.
length
);
});
});
});
spec/javascripts/monitoring/graph/track_info_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
TrackInfo
from
'
~/monitoring/components/graph/track_info.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
createTimeSeries
from
'
~/monitoring/utils/multiple_time_series
'
;
import
{
singleRowMetricsMultipleSeries
,
convertDatesMultipleSeries
}
from
'
../mock_data
'
;
const
convertedMetrics
=
convertDatesMultipleSeries
(
singleRowMetricsMultipleSeries
);
const
{
timeSeries
}
=
createTimeSeries
(
convertedMetrics
[
0
].
queries
,
500
,
300
,
120
);
describe
(
'
TrackInfo component
'
,
()
=>
{
let
vm
;
let
Component
;
beforeEach
(()
=>
{
Component
=
Vue
.
extend
(
TrackInfo
);
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
describe
(
'
Computed props
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
track
:
timeSeries
[
0
]
});
});
it
(
'
summaryMetrics
'
,
()
=>
{
expect
(
vm
.
summaryMetrics
).
toEqual
(
'
Avg: 0.000 · Max: 0.000
'
);
});
});
describe
(
'
Rendered output
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
track
:
timeSeries
[
0
]
});
});
it
(
'
contains metric tag and the summary metrics
'
,
()
=>
{
const
metricTag
=
vm
.
$el
.
querySelector
(
'
strong
'
);
expect
(
metricTag
.
textContent
.
trim
()).
toEqual
(
vm
.
track
.
metricTag
);
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
Avg: 0.000 · Max: 0.000
'
);
});
});
});
spec/javascripts/monitoring/graph/track_line_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
TrackLine
from
'
~/monitoring/components/graph/track_line.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
createTimeSeries
from
'
~/monitoring/utils/multiple_time_series
'
;
import
{
singleRowMetricsMultipleSeries
,
convertDatesMultipleSeries
}
from
'
../mock_data
'
;
const
convertedMetrics
=
convertDatesMultipleSeries
(
singleRowMetricsMultipleSeries
);
const
{
timeSeries
}
=
createTimeSeries
(
convertedMetrics
[
0
].
queries
,
500
,
300
,
120
);
describe
(
'
TrackLine component
'
,
()
=>
{
let
vm
;
let
Component
;
beforeEach
(()
=>
{
Component
=
Vue
.
extend
(
TrackLine
);
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
describe
(
'
Computed props
'
,
()
=>
{
it
(
'
stylizedLine for dashed lineStyles
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
track
:
{
...
timeSeries
[
0
],
lineStyle
:
'
dashed
'
}
});
expect
(
vm
.
stylizedLine
).
toEqual
(
'
6, 3
'
);
});
it
(
'
stylizedLine for dotted lineStyles
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
track
:
{
...
timeSeries
[
0
],
lineStyle
:
'
dotted
'
}
});
expect
(
vm
.
stylizedLine
).
toEqual
(
'
3, 3
'
);
});
});
describe
(
'
Rendered output
'
,
()
=>
{
it
(
'
has an svg with a line
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
track
:
{
...
timeSeries
[
0
]
}
});
const
svgEl
=
vm
.
$el
.
querySelector
(
'
svg
'
);
const
lineEl
=
vm
.
$el
.
querySelector
(
'
svg line
'
);
expect
(
svgEl
.
getAttribute
(
'
width
'
)).
toEqual
(
'
16
'
);
expect
(
svgEl
.
getAttribute
(
'
height
'
)).
toEqual
(
'
8
'
);
expect
(
lineEl
.
getAttribute
(
'
stroke-width
'
)).
toEqual
(
'
4
'
);
expect
(
lineEl
.
getAttribute
(
'
x1
'
)).
toEqual
(
'
0
'
);
expect
(
lineEl
.
getAttribute
(
'
x2
'
)).
toEqual
(
'
16
'
);
expect
(
lineEl
.
getAttribute
(
'
y1
'
)).
toEqual
(
'
4
'
);
expect
(
lineEl
.
getAttribute
(
'
y2
'
)).
toEqual
(
'
4
'
);
});
});
});
spec/javascripts/monitoring/graph_path_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
GraphPath
from
'
~/monitoring/components/graph/path.vue
'
;
import
createTimeSeries
from
'
~/monitoring/utils/multiple_time_series
'
;
import
{
singleRowMetricsMultipleSeries
,
convertDatesMultipleSeries
}
from
'
./mock_data
'
;
const
createComponent
=
propsData
=>
{
const
Component
=
Vue
.
extend
(
GraphPath
);
return
new
Component
({
propsData
,
}).
$mount
();
};
const
convertedMetrics
=
convertDatesMultipleSeries
(
singleRowMetricsMultipleSeries
);
const
{
timeSeries
}
=
createTimeSeries
(
convertedMetrics
[
0
].
queries
,
428
,
272
,
120
);
const
firstTimeSeries
=
timeSeries
[
0
];
describe
(
'
Monitoring Paths
'
,
()
=>
{
it
(
'
renders two paths to represent a line and the area underneath it
'
,
()
=>
{
const
component
=
createComponent
({
generatedLinePath
:
firstTimeSeries
.
linePath
,
generatedAreaPath
:
firstTimeSeries
.
areaPath
,
lineColor
:
firstTimeSeries
.
lineColor
,
areaColor
:
firstTimeSeries
.
areaColor
,
showDot
:
false
,
});
const
metricArea
=
component
.
$el
.
querySelector
(
'
.metric-area
'
);
const
metricLine
=
component
.
$el
.
querySelector
(
'
.metric-line
'
);
expect
(
metricArea
.
getAttribute
(
'
fill
'
)).
toBe
(
'
#8fbce8
'
);
expect
(
metricArea
.
getAttribute
(
'
d
'
)).
toBe
(
firstTimeSeries
.
areaPath
);
expect
(
metricLine
.
getAttribute
(
'
stroke
'
)).
toBe
(
'
#1f78d1
'
);
expect
(
metricLine
.
getAttribute
(
'
d
'
)).
toBe
(
firstTimeSeries
.
linePath
);
});
describe
(
'
Computed properties
'
,
()
=>
{
it
(
'
strokeDashArray
'
,
()
=>
{
const
component
=
createComponent
({
generatedLinePath
:
firstTimeSeries
.
linePath
,
generatedAreaPath
:
firstTimeSeries
.
areaPath
,
lineColor
:
firstTimeSeries
.
lineColor
,
areaColor
:
firstTimeSeries
.
areaColor
,
showDot
:
false
,
});
component
.
lineStyle
=
'
dashed
'
;
expect
(
component
.
strokeDashArray
).
toBe
(
'
3, 1
'
);
component
.
lineStyle
=
'
dotted
'
;
expect
(
component
.
strokeDashArray
).
toBe
(
'
1, 1
'
);
});
});
});
spec/javascripts/monitoring/graph_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
Vue
from
'
vue
'
;
import
Graph
from
'
~/monitoring/components/graph.vue
'
;
import
MonitoringMixins
from
'
~/monitoring/mixins/monitoring_mixins
'
;
import
{
deploymentData
,
convertDatesMultipleSeries
,
singleRowMetricsMultipleSeries
,
queryWithoutData
,
}
from
'
./mock_data
'
;
const
tagsPath
=
'
http://test.host/frontend-fixtures/environments-project/tags
'
;
const
projectPath
=
'
http://test.host/frontend-fixtures/environments-project
'
;
const
createComponent
=
propsData
=>
{
const
Component
=
Vue
.
extend
(
Graph
);
return
new
Component
({
propsData
,
}).
$mount
();
};
const
convertedMetrics
=
convertDatesMultipleSeries
(
singleRowMetricsMultipleSeries
);
describe
(
'
Graph
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
MonitoringMixins
.
methods
,
'
formatDeployments
'
).
and
.
returnValue
({});
});
it
(
'
has a title
'
,
()
=>
{
const
component
=
createComponent
({
graphData
:
convertedMetrics
[
1
],
updateAspectRatio
:
false
,
deploymentData
,
tagsPath
,
projectPath
,
});
expect
(
component
.
$el
.
querySelector
(
'
.prometheus-graph-title
'
).
innerText
.
trim
()).
toBe
(
component
.
graphData
.
title
,
);
});
describe
(
'
Computed props
'
,
()
=>
{
it
(
'
axisTransform translates an element Y position depending of its height
'
,
()
=>
{
const
component
=
createComponent
({
graphData
:
convertedMetrics
[
1
],
updateAspectRatio
:
false
,
deploymentData
,
tagsPath
,
projectPath
,
});
const
transformedHeight
=
`
${
component
.
graphHeight
-
100
}
`
;
expect
(
component
.
axisTransform
.
indexOf
(
transformedHeight
)).
not
.
toEqual
(
-
1
);
});
it
(
'
outerViewBox gets a width and height property based on the DOM size of the element
'
,
()
=>
{
const
component
=
createComponent
({
graphData
:
convertedMetrics
[
1
],
updateAspectRatio
:
false
,
deploymentData
,
tagsPath
,
projectPath
,
});
const
viewBoxArray
=
component
.
outerViewBox
.
split
(
'
'
);
expect
(
typeof
component
.
outerViewBox
).
toEqual
(
'
string
'
);
expect
(
viewBoxArray
[
2
]).
toEqual
(
component
.
graphWidth
.
toString
());
expect
(
viewBoxArray
[
3
]).
toEqual
((
component
.
graphHeight
-
50
).
toString
());
});
});
it
(
'
has a title for the y-axis and the chart legend that comes from the backend
'
,
()
=>
{
const
component
=
createComponent
({
graphData
:
convertedMetrics
[
1
],
updateAspectRatio
:
false
,
deploymentData
,
tagsPath
,
projectPath
,
});
expect
(
component
.
yAxisLabel
).
toEqual
(
component
.
graphData
.
y_label
);
expect
(
component
.
legendTitle
).
toEqual
(
component
.
graphData
.
queries
[
0
].
label
);
});
it
(
'
sets the currentData object based on the hovered data index
'
,
()
=>
{
const
component
=
createComponent
({
graphData
:
convertedMetrics
[
1
],
updateAspectRatio
:
false
,
deploymentData
,
graphIdentifier
:
0
,
hoverData
:
{
hoveredDate
:
new
Date
(
'
Sun Aug 27 2017 06:11:51 GMT-0500 (CDT)
'
),
currentDeployXPos
:
null
,
},
tagsPath
,
projectPath
,
});
// simulate moving mouse over data series
component
.
seriesUnderMouse
=
component
.
timeSeries
;
component
.
positionFlag
();
expect
(
component
.
currentData
).
toBe
(
component
.
timeSeries
[
0
].
values
[
10
]);
});
describe
(
'
Without data to display
'
,
()
=>
{
it
(
'
shows a "no data to display" empty state on a graph
'
,
done
=>
{
const
component
=
createComponent
({
graphData
:
queryWithoutData
,
deploymentData
,
tagsPath
,
projectPath
,
});
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-no-data-to-display text
'
).
textContent
.
trim
(),
).
toEqual
(
'
No data to display
'
);
done
();
});
});
});
});
spec/javascripts/monitoring/utils/multiple_time_series_spec.js
已删除
100644 → 0
浏览文件 @
c1286332
import
createTimeSeries
from
'
~/monitoring/utils/multiple_time_series
'
;
import
{
convertDatesMultipleSeries
,
singleRowMetricsMultipleSeries
}
from
'
../mock_data
'
;
const
convertedMetrics
=
convertDatesMultipleSeries
(
singleRowMetricsMultipleSeries
);
const
{
timeSeries
}
=
createTimeSeries
(
convertedMetrics
[
0
].
queries
,
428
,
272
,
120
);
const
firstTimeSeries
=
timeSeries
[
0
];
describe
(
'
Multiple time series
'
,
()
=>
{
it
(
'
createTimeSeries returned array contains an object for each element
'
,
()
=>
{
expect
(
typeof
firstTimeSeries
.
linePath
).
toEqual
(
'
string
'
);
expect
(
typeof
firstTimeSeries
.
areaPath
).
toEqual
(
'
string
'
);
expect
(
typeof
firstTimeSeries
.
timeSeriesScaleX
).
toEqual
(
'
function
'
);
expect
(
typeof
firstTimeSeries
.
areaColor
).
toEqual
(
'
string
'
);
expect
(
typeof
firstTimeSeries
.
lineColor
).
toEqual
(
'
string
'
);
expect
(
firstTimeSeries
.
values
instanceof
Array
).
toEqual
(
true
);
});
it
(
'
createTimeSeries returns an array
'
,
()
=>
{
expect
(
timeSeries
instanceof
Array
).
toEqual
(
true
);
expect
(
timeSeries
.
length
).
toEqual
(
2
);
});
});
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录