Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
gitlab-ce
Commits
798b17a3
Commit
798b17a3
authored
Sep 15, 2016
by
Fatih Acet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement Cycle Analytics frontend.
parent
74626106
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
255 additions
and
52 deletions
+255
-52
app/assets/javascripts/cycle-analytics.js.es6
app/assets/javascripts/cycle-analytics.js.es6
+70
-0
app/assets/javascripts/dispatcher.js
app/assets/javascripts/dispatcher.js
+3
-0
app/assets/stylesheets/pages/cycle_analytics.scss
app/assets/stylesheets/pages/cycle_analytics.scss
+115
-0
app/helpers/gitlab_routing_helper.rb
app/helpers/gitlab_routing_helper.rb
+4
-0
app/views/layouts/nav/_project.html.haml
app/views/layouts/nav/_project.html.haml
+1
-1
app/views/projects/cycle_analytics/show.html.haml
app/views/projects/cycle_analytics/show.html.haml
+56
-51
app/views/projects/pipelines/_head.html.haml
app/views/projects/pipelines/_head.html.haml
+5
-0
app/views/shared/icons/_icon_cycle_analytics_splash.svg
app/views/shared/icons/_icon_cycle_analytics_splash.svg
+1
-0
No files found.
app/assets/javascripts/cycle-analytics.js.es6
0 → 100644
View file @
798b17a3
((global) => {
gl.CycleAnalytics = class CycleAnalytics {
constructor() {
this.vue = new Vue({
el: '#cycle-analytics',
name: 'CycleAnalytics',
created: this.fetchData(),
data: this.getData({ isLoading: true })
});
}
fetchData() {
$.get('cycle_analytics.json')
.done((data) => {
this.vue.$data = this.getData(data);
this.initDropdown();
})
.error((data) => {
this.handleError(data);
})
.always(() => {
this.vue.isLoading = false;
})
}
getData(data) {
return {
notAvailable: data.notAvailable || false,
isLoading: data.isLoading || false,
analytics: {
summary: [
{ desc: 'New Issues', value: data.issues || '-' },
{ desc: 'Commits', value: data.commits || '-' },
{ desc: 'Deploys', value: data.deploys || '-' }
],
data: [
{ title: 'Issue', desc: 'Time before an issue get scheduled', value: data.issue || '-' },
{ title: 'Plan', desc: 'Time before an issue starts implementation', value: data.plan || '-' },
{ title: 'Code', desc: 'Time until first merge request', value: data.code || '-' },
{ title: 'Test', desc: 'CI test time of the default branch', value: data.test || '-' },
{ title: 'Review', desc: 'Time between MR creation and merge/close', value: data.review || '-' },
{ title: 'Deploy', desc: 'Time for a new commit to land in one of the environments', value: data.deploy || '-' }
]
}
}
}
handleError(data) {
// TODO: Make sure that this is the proper error handling
new Flash('There was an error while fetching cycyle analytics data.', 'alert');
}
initDropdown() {
const $dropdown = $('.js-ca-dropdown');
const $label = $dropdown.find('.dropdown-label');
$dropdown.find('li a').on('click', (e) => {
e.preventDefault();
const $target = $(e.currentTarget);
$label.text($target.text().trim());
value = $target.data('value');
this.vue.isLoading = true;
})
}
}
})(window.gl || (window.gl = {}));
app/assets/javascripts/dispatcher.js
View file @
798b17a3
...
@@ -186,6 +186,9 @@
...
@@ -186,6 +186,9 @@
new
gl
.
ProtectedBranchCreate
();
new
gl
.
ProtectedBranchCreate
();
new
gl
.
ProtectedBranchEditList
();
new
gl
.
ProtectedBranchEditList
();
break
;
break
;
case
'
projects:cycle_analytics:show
'
:
window
.
ca
=
new
gl
.
CycleAnalytics
();
break
;
}
}
switch
(
path
.
first
())
{
switch
(
path
.
first
())
{
case
'
admin
'
:
case
'
admin
'
:
...
...
app/assets/stylesheets/pages/cycle_analytics.scss
0 → 100644
View file @
798b17a3
#cycle-analytics
{
margin-top
:
24px
;
.panel
{
.content-block
{
padding
:
24px
0
;
border-bottom
:
none
;
position
:
relative
;
}
.column
{
text-align
:
center
;
.header
{
font-size
:
30px
;
line-height
:
38px
;
font-weight
:
normal
;
margin
:
0
;
}
.text
{
color
:
$layout-link-gray
;
}
}
.dropdown
{
position
:
relative
;
top
:
10px
;
}
}
.bordered-box
{
border
:
1px
solid
$border-color
;
@include
border-radius
(
$border-radius-default
);
position
:
relative
;
}
.content-list
{
li
{
padding
:
18px
$gl-padding
$gl-padding
;
}
.col-md-10
{
span
{
&
:first-child
{
line-height
:
19px
;
font-size
:
15px
;
font-weight
:
600
;
}
&
:last-child
{
color
:
#8C8C8C
;
}
}
}
.col-md-2
span
{
line-height
:
42px
;
}
}
.inner-content
{
width
:
450px
;
text-align
:
center
;
margin
:
0
auto
;
padding
:
62px
0
;
.btn-block
{
max-width
:
130px
;
margin
:
0
auto
;
}
h4
{
color
:
$gl-text-color
;
font-size
:
17px
;
}
p
{
color
:
#8C8C8C
;
margin-bottom
:
$gl-padding
;
}
}
&
.waiting
{
.panel
.header
{
width
:
35px
;
height
:
35px
;
margin-bottom
:
3px
;
}
span
{
background-color
:
#F8F8F8
;
color
:
#F8F8F8
!
important
;
display
:
inline-block
;
line-height
:
13px
!
important
;
}
.dropdown
{
opacity
:
.33
;
}
.col-md-2
span
{
position
:
relative
;
top
:
11px
;
}
.fa-spinner
{
font-size
:
32px
;
position
:
absolute
;
left
:
50%
;
top
:
50%
;
margin
:
-16px
0
0
-16px
;
}
}
}
app/helpers/gitlab_routing_helper.rb
View file @
798b17a3
...
@@ -46,6 +46,10 @@ module GitlabRoutingHelper
...
@@ -46,6 +46,10 @@ module GitlabRoutingHelper
namespace_project_environments_path
(
project
.
namespace
,
project
,
*
args
)
namespace_project_environments_path
(
project
.
namespace
,
project
,
*
args
)
end
end
def
project_cycle_analytics_path
(
project
,
*
args
)
namespace_project_cycle_analytics_path
(
project
.
namespace
,
project
,
*
args
)
end
def
project_builds_path
(
project
,
*
args
)
def
project_builds_path
(
project
,
*
args
)
namespace_project_builds_path
(
project
.
namespace
,
project
,
*
args
)
namespace_project_builds_path
(
project
.
namespace
,
project
,
*
args
)
end
end
...
...
app/views/layouts/nav/_project.html.haml
View file @
798b17a3
...
@@ -47,7 +47,7 @@
...
@@ -47,7 +47,7 @@
Repository
Repository
-
if
project_nav_tab?
:pipelines
-
if
project_nav_tab?
:pipelines
=
nav_link
(
controller:
[
:pipelines
,
:builds
,
:environments
])
do
=
nav_link
(
controller:
[
:pipelines
,
:builds
,
:environments
,
:cycle_analytics
])
do
=
link_to
project_pipelines_path
(
@project
),
title:
'Pipelines'
,
class:
'shortcuts-pipelines'
do
=
link_to
project_pipelines_path
(
@project
),
title:
'Pipelines'
,
class:
'shortcuts-pipelines'
do
%span
%span
Pipelines
Pipelines
...
...
app/views/projects/cycle_analytics/show.html.haml
View file @
798b17a3
%h2
Cycle Analytics from
#{
@cycle_analytics
.
from
}
to Today
=
render
'projects/pipelines/head'
%ul
.list-group
#cycle-analytics
{
"v-cloak"
=>
"true"
,
":class"
=>
"{ 'waiting': isLoading }"
}
%li
.list-group-item
.panel.panel-default
Issue:
.panel-heading
-
if
issue
=
@cycle_analytics
.
issue
Pipeline Health
=
distance_of_time_in_words
issue
-
else
.content-block
=
"<Not enough data>"
=
icon
(
"spinner spin"
,
"v-if"
=>
"isLoading"
)
%li
.list-group-item
.row
Plan:
%template
{
"v-for"
=>
"info in analytics.summary"
}
-
if
plan
=
@cycle_analytics
.
plan
.col-md-3.column
=
distance_of_time_in_words
plan
%span
.header
{{info.value}}
-
else
%br
=
"<Not enough data>"
%span
.text
{{info.desc}}
%li
.list-group-item
.col-md-3.column
Code:
.dropdown.inline.js-ca-dropdown
-
if
code
=
@cycle_analytics
.
code
.
presence
%button
.dropdown-menu-toggle
{
"aria-expanded"
=>
"false"
,
"data-toggle"
=>
"dropdown"
,
:type
=>
"button"
}
=
distance_of_time_in_words
code
%span
.dropdown-label
Last 30 days
-
else
%i
.fa.fa-chevron-down
=
"<Not enough data>"
%ul
.dropdown-menu.dropdown-menu-align-right
%li
%li
.list-group-item
%a
{
'href'
=>
"#"
,
'data-value'
=>
'30days'
}
Test:
Last 30 days
-
if
test
=
@cycle_analytics
.
test
.
presence
%li
=
distance_of_time_in_words
test
%a
{
'href'
=>
"#"
,
'data-value'
=>
'90days'
}
-
else
Last 90 days
=
"<Not enough data>"
.bordered-box
%li
.list-group-item
=
icon
(
"spinner spin"
,
"v-if"
=>
"isLoading"
)
Review:
-
if
review
=
@cycle_analytics
.
review
.
presence
%ul
.content-list
{{
"v-if"
=>
"!notAvailable"
}}
=
distance_of_time_in_words
review
%li
{
"v-for"
=>
"info in analytics.data"
}
-
else
.row
=
"<Not enough data>"
.col-md-10
%span
%li
.list-group-item
{{info.title}}
Staging:
%br
-
if
staging
=
@cycle_analytics
.
staging
.
presence
%span
=
distance_of_time_in_words
staging
{{info.desc}}
-
else
.col-md-2
=
"<Not enough data>"
%span
{{info.value}}
%li
.list-group-item
Production:
-
if
production
=
@cycle_analytics
.
production
.
presence
.content-block
{{
"v-if"
=>
"notAvailable"
}}
=
distance_of_time_in_words
production
.inner-content
-
else
=
custom_icon
(
'icon_cycle_analytics_splash'
)
=
"<Not enough data>"
%h4
Set up your deploys to environment!
%p
Cycle Analytics will give an overview on how much time it takes to go from an idea to production in your project.
=
button_tag
'Set up'
,
class:
'btn btn-create btn-block'
app/views/projects/pipelines/_head.html.haml
View file @
798b17a3
...
@@ -19,3 +19,8 @@
...
@@ -19,3 +19,8 @@
=
link_to
project_environments_path
(
@project
),
title:
'Environments'
,
class:
'shortcuts-environments'
do
=
link_to
project_environments_path
(
@project
),
title:
'Environments'
,
class:
'shortcuts-environments'
do
%span
%span
Environments
Environments
=
nav_link
(
controller:
%w(cycle_analytics)
)
do
=
link_to
project_cycle_analytics_path
(
@project
),
title:
'Cycle Analytics'
do
%span
Cycle Analytics
app/views/shared/icons/_icon_cycle_analytics_splash.svg
0 → 100644
View file @
798b17a3
<svg
width=
"167"
height=
"166"
viewBox=
"261 77 167 166"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
><defs><path
id=
"a"
d=
"M18 84h34v9H18z"
/><mask
id=
"h"
x=
"0"
y=
"0"
width=
"34"
height=
"9"
fill=
"#fff"
><use
xlink:href=
"#a"
/></mask><path
d=
"M26 95c0 4.97 4.03 9 9 9s9-4.03 9-9"
id=
"b"
/><mask
id=
"i"
x=
"0"
y=
"0"
width=
"18"
height=
"9"
fill=
"#fff"
><use
xlink:href=
"#b"
/></mask><path
d=
"M42 48l25.564 18.26C68.91 67.22 70 69.34 70 70.994v22.004c0 2.21-1.456 2.962-3.253 1.678L42 77V48z"
id=
"c"
/><mask
id=
"j"
x=
"0"
y=
"0"
width=
"28"
height=
"47.303"
fill=
"#fff"
><use
xlink:href=
"#c"
/></mask><path
d=
"M0 48l25.564 18.26C26.91 67.22 28 69.34 28 70.994v22.004c0 2.21-1.456 2.962-3.253 1.678L0 77V48z"
id=
"d"
/><mask
id=
"k"
x=
"0"
y=
"0"
width=
"28"
height=
"47.303"
fill=
"#fff"
><use
xlink:href=
"#d"
/></mask><path
d=
"M52.994 86C59.156 79.382 62 67.656 62 49.725 62 19.235 38.032 1.18 38.032 1.18c-1.675-1.434-4.408-1.466-6.064 0C31.968 1.18 8 19.234 8 49.724 8 67.655 10.844 79.382 17.006 86h35.988z"
id=
"e"
/><mask
id=
"l"
x=
"0"
y=
"0"
width=
"54"
height=
"85.908"
fill=
"#fff"
><use
xlink:href=
"#e"
/></mask><circle
id=
"f"
cx=
"35"
cy=
"43"
r=
"13"
/><mask
id=
"m"
x=
"0"
y=
"0"
width=
"26"
height=
"26"
fill=
"#fff"
><use
xlink:href=
"#f"
/></mask><circle
id=
"g"
cx=
"35"
cy=
"43"
r=
"8"
/><mask
id=
"n"
x=
"0"
y=
"0"
width=
"16"
height=
"16"
fill=
"#fff"
><use
xlink:href=
"#g"
/></mask></defs><g
fill=
"none"
fill-rule=
"evenodd"
transform=
"translate(262 77)"
><g
transform=
"translate(47 6)"
><path
d=
"M51 132c0 2.21 1.79 4 4 4s4-1.79 4-4M11 122c0 2.21 1.79 4 4 4s4-1.79 4-4"
stroke=
"#E5E5E5"
stroke-width=
"2"
stroke-linecap=
"round"
/><rect
fill=
"#E5E5E5"
x=
"50"
y=
"107"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"50"
y=
"117"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"34"
y=
"107"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"42"
y=
"107"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"34"
y=
"117"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"34"
y=
"127"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"42"
y=
"117"
width=
"2"
height=
"30"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"26"
y=
"107"
width=
"2"
height=
"27"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"50"
y=
"127"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"18"
y=
"107"
width=
"2"
height=
"6"
rx=
"1"
/><rect
fill=
"#E5E5E5"
x=
"18"
y=
"117"
width=
"2"
height=
"6"
rx=
"1"
/><use
stroke=
"#E5E5E5"
mask=
"url(#h)"
stroke-width=
"4"
xlink:href=
"#a"
/><use
stroke=
"#E5E5E5"
mask=
"url(#i)"
stroke-width=
"4"
xlink:href=
"#b"
/><use
stroke=
"#E5E5E5"
mask=
"url(#j)"
stroke-width=
"4"
xlink:href=
"#c"
/><use
stroke=
"#E5E5E5"
mask=
"url(#k)"
stroke-width=
"4"
transform=
"matrix(-1 0 0 1 28 0)"
xlink:href=
"#d"
/><use
stroke=
"#E5E5E5"
mask=
"url(#l)"
stroke-width=
"4"
fill=
"#FFF"
xlink:href=
"#e"
/><use
stroke=
"#E5E5E5"
mask=
"url(#m)"
stroke-width=
"4"
xlink:href=
"#f"
/><use
stroke=
"#E5E5E5"
mask=
"url(#n)"
stroke-width=
"4"
xlink:href=
"#g"
/><path
d=
"M43 146c0 3.59 2.91 6.5 6.5 6.5s6.5-2.91 6.5-6.5M14 133c0 3.59 2.91 6.5 6.5 6.5s6.5-2.91 6.5-6.5"
stroke=
"#E5E5E5"
stroke-width=
"2"
stroke-linecap=
"round"
/></g><circle
stroke=
"#E5E5E5"
stroke-width=
"2"
cx=
"138.5"
cy=
"115.5"
r=
"6.5"
/><circle
stroke=
"#E5E5E5"
stroke-width=
"2"
cx=
"33.5"
cy=
"28.5"
r=
"6.5"
/><circle
stroke=
"#E5E5E5"
stroke-width=
"2"
cx=
"142"
cy=
"52"
r=
"4"
/><circle
stroke=
"#E5E5E5"
stroke-width=
"2"
cx=
"4"
cy=
"83"
r=
"4"
/></g></svg>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment