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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
88d762ca
Commit
88d762ca
authored
Sep 14, 2020
by
Simon Knox
Committed by
Miguel Rincon
Sep 14, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use burnup graphQL endpoint for milestone charts
Requires padding data as endpoint only returns changes
parent
ffea1ee9
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
370 additions
and
58 deletions
+370
-58
app/assets/javascripts/lib/utils/datetime_utility.js
app/assets/javascripts/lib/utils/datetime_utility.js
+10
-0
ee/app/assets/javascripts/burndown_chart/components/burn_charts.vue
...ets/javascripts/burndown_chart/components/burn_charts.vue
+109
-5
ee/app/assets/javascripts/burndown_chart/components/burndown_chart.vue
.../javascripts/burndown_chart/components/burndown_chart.vue
+6
-4
ee/app/assets/javascripts/burndown_chart/components/burnup_chart.vue
...ts/javascripts/burndown_chart/components/burnup_chart.vue
+49
-9
ee/app/assets/javascripts/burndown_chart/index.js
ee/app/assets/javascripts/burndown_chart/index.js
+13
-17
ee/app/assets/javascripts/burndown_chart/queries/burnup.query.graphql
...s/javascripts/burndown_chart/queries/burnup.query.graphql
+13
-0
ee/app/views/shared/milestones/_burndown.html.haml
ee/app/views/shared/milestones/_burndown.html.haml
+1
-1
ee/spec/frontend/burndown_chart/components/burn_charts_spec.js
...ec/frontend/burndown_chart/components/burn_charts_spec.js
+96
-12
ee/spec/frontend/burndown_chart/components/burnup_chart_spec.js
...c/frontend/burndown_chart/components/burnup_chart_spec.js
+21
-7
ee/spec/frontend/burndown_chart/mock_data.js
ee/spec/frontend/burndown_chart/mock_data.js
+31
-0
locale/gitlab.pot
locale/gitlab.pot
+21
-3
No files found.
app/assets/javascripts/lib/utils/datetime_utility.js
View file @
88d762ca
...
...
@@ -642,6 +642,16 @@ export const secondsToMilliseconds = seconds => seconds * 1000;
*/
export
const
secondsToDays
=
seconds
=>
Math
.
round
(
seconds
/
86400
);
/**
* Returns the date n days after the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfDays number of days after
* @return {Date} the date following the date provided
*/
export
const
nDaysAfter
=
(
date
,
numberOfDays
)
=>
new
Date
(
newDate
(
date
)).
setDate
(
date
.
getDate
()
+
numberOfDays
);
/**
* Returns the date after the date provided
*
...
...
ee/app/assets/javascripts/burndown_chart/components/burn_charts.vue
View file @
88d762ca
<
script
>
import
{
GlButton
,
GlButtonGroup
}
from
'
@gitlab/ui
'
;
import
{
GlAlert
,
GlButton
,
GlButtonGroup
}
from
'
@gitlab/ui
'
;
import
dateFormat
from
'
dateformat
'
;
import
glFeatureFlagsMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
getDayDifference
,
nDaysAfter
,
newDateAsLocaleTime
}
from
'
~/lib/utils/datetime_utility
'
;
import
BurndownChart
from
'
./burndown_chart.vue
'
;
import
BurnupChart
from
'
./burnup_chart.vue
'
;
import
BurnupQuery
from
'
../queries/burnup.query.graphql
'
;
export
default
{
components
:
{
GlAlert
,
GlButton
,
GlButtonGroup
,
BurndownChart
,
...
...
@@ -32,15 +36,38 @@ export default {
required
:
false
,
default
:
()
=>
[],
},
burnupScope
:
{
type
:
Array
,
milestoneId
:
{
type
:
String
,
required
:
false
,
default
:
()
=>
[],
default
:
''
,
},
},
apollo
:
{
burnupData
:
{
skip
()
{
return
!
this
.
glFeatures
.
burnupCharts
||
!
this
.
milestoneId
;
},
query
:
BurnupQuery
,
variables
()
{
return
{
milestoneId
:
this
.
milestoneId
,
};
},
update
(
data
)
{
const
sparseBurnupData
=
data
?.
milestone
?.
burnupTimeSeries
||
[];
return
this
.
padSparseBurnupData
(
sparseBurnupData
);
},
error
()
{
this
.
error
=
__
(
'
Error fetching burnup chart data
'
);
},
},
},
data
()
{
return
{
issuesSelected
:
true
,
burnupData
:
[],
error
:
''
,
};
},
computed
:
{
...
...
@@ -58,6 +85,79 @@ export default {
setIssueSelected
(
selected
)
{
this
.
issuesSelected
=
selected
;
},
padSparseBurnupData
(
sparseBurnupData
)
{
// if we don't have data for the startDate, we still want to draw a point at 0
// on the chart, so add an item to the start of the array
const
hasDataForStartDate
=
sparseBurnupData
.
find
(
d
=>
d
.
date
===
this
.
startDate
);
if
(
!
hasDataForStartDate
)
{
sparseBurnupData
.
unshift
({
date
:
this
.
startDate
,
completedCount
:
0
,
completedWeight
:
0
,
scopeCount
:
0
,
scopeWeight
:
0
,
});
}
// chart runs to dueDate or the current date, whichever is earlier
const
lastDate
=
dateFormat
(
Math
.
min
(
Date
.
parse
(
this
.
dueDate
),
Date
.
parse
(
new
Date
())),
'
yyyy-mm-dd
'
,
);
// similar to the startDate padding, if we don't have a value for the
// last item in the array, we should add one. If no events occur on
// a day then we don't get any data for that day in the response
const
hasDataForLastDate
=
sparseBurnupData
.
find
(
d
=>
d
.
date
===
lastDate
);
if
(
!
hasDataForLastDate
)
{
const
lastItem
=
sparseBurnupData
[
sparseBurnupData
.
length
-
1
];
sparseBurnupData
.
push
({
...
lastItem
,
date
:
lastDate
,
});
}
return
sparseBurnupData
.
reduce
(
this
.
addMissingDates
,
[]);
},
addMissingDates
(
acc
,
current
)
{
const
{
date
}
=
current
;
// we might not have data for every day in the timebox, as graphql
// endpoint only returns days when events have happened
// if the previous array item is >1 day, then fill in the gap
// using the data from the previous entry.
// example: [
// { date: '2020-08-01', count: 10 }
// { date: '2020-08-04', count: 12 }
// ]
// should be transformed to
// example: [
// { date: '2020-08-01', count: 10 }
// { date: '2020-08-02', count: 10 }
// { date: '2020-08-03', count: 10 }
// { date: '2020-08-04', count: 12 }
// ]
// skip the start date since we have no previous values
if
(
date
!==
this
.
startDate
)
{
const
{
date
:
prevDate
,
...
previousValues
}
=
acc
[
acc
.
length
-
1
]
||
{};
const
currentDateUTC
=
newDateAsLocaleTime
(
date
);
const
prevDateUTC
=
newDateAsLocaleTime
(
prevDate
);
const
gap
=
getDayDifference
(
prevDateUTC
,
currentDateUTC
);
for
(
let
i
=
1
;
i
<
gap
;
i
+=
1
)
{
acc
.
push
({
date
:
dateFormat
(
nDaysAfter
(
prevDateUTC
,
i
),
'
yyyy-mm-dd
'
),
...
previousValues
,
});
}
}
acc
.
push
(
current
);
return
acc
;
},
},
};
</
script
>
...
...
@@ -89,6 +189,9 @@ export default {
</gl-button-group>
</div>
<div
v-if=
"glFeatures.burnupCharts"
class=
"row"
>
<gl-alert
v-if=
"error"
variant=
"danger"
class=
"col-12"
@
dismiss=
"error = ''"
>
{{
error
}}
</gl-alert>
<burndown-chart
:start-date=
"startDate"
:due-date=
"dueDate"
...
...
@@ -100,7 +203,8 @@ export default {
<burnup-chart
:start-date=
"startDate"
:due-date=
"dueDate"
:scope=
"burnupScope"
:burnup-data=
"burnupData"
:issues-selected=
"issuesSelected"
class=
"col-md-6"
/>
</div>
...
...
ee/app/assets/javascripts/burndown_chart/components/burndown_chart.vue
View file @
88d762ca
...
...
@@ -3,7 +3,7 @@ import { merge } from 'lodash';
import
{
GlLineChart
}
from
'
@gitlab/ui/dist/charts
'
;
import
dateFormat
from
'
dateformat
'
;
import
ResizableChartContainer
from
'
~/vue_shared/components/resizable_chart/resizable_chart_container.vue
'
;
import
{
s__
,
__
,
sprintf
}
from
'
~/locale
'
;
import
{
__
,
n__
,
s
__
,
sprintf
}
from
'
~/locale
'
;
import
commonChartOptions
from
'
./common_chart_options
'
;
export
default
{
...
...
@@ -103,12 +103,14 @@ export default {
methods
:
{
formatTooltipText
(
params
)
{
const
[
seriesData
]
=
params
.
seriesData
;
if
(
!
seriesData
)
{
return
;
}
this
.
tooltip
.
title
=
dateFormat
(
params
.
value
,
'
dd mmm yyyy
'
);
if
(
this
.
issuesSelected
)
{
this
.
tooltip
.
content
=
sprintf
(
__
(
'
%{total} open issues
'
),
{
total
:
seriesData
.
value
[
1
],
});
this
.
tooltip
.
content
=
n__
(
'
%d open issue
'
,
'
%d open issues
'
,
seriesData
.
value
[
1
]);
}
else
{
this
.
tooltip
.
content
=
sprintf
(
__
(
'
%{total} open issue weight
'
),
{
total
:
seriesData
.
value
[
1
],
...
...
ee/app/assets/javascripts/burndown_chart/components/burnup_chart.vue
View file @
88d762ca
...
...
@@ -3,7 +3,7 @@ import { merge } from 'lodash';
import
{
GlLineChart
}
from
'
@gitlab/ui/dist/charts
'
;
import
dateFormat
from
'
dateformat
'
;
import
ResizableChartContainer
from
'
~/vue_shared/components/resizable_chart/resizable_chart_container.vue
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
import
{
__
,
n__
,
sprintf
}
from
'
~/locale
'
;
import
commonChartOptions
from
'
./common_chart_options
'
;
export
default
{
...
...
@@ -20,7 +20,12 @@ export default {
type
:
String
,
required
:
true
,
},
scope
:
{
issuesSelected
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
burnupData
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
...
...
@@ -35,11 +40,27 @@ export default {
};
},
computed
:
{
scopeCount
()
{
return
this
.
transform
(
'
scopeCount
'
);
},
completedCount
()
{
return
this
.
transform
(
'
completedCount
'
);
},
scopeWeight
()
{
return
this
.
transform
(
'
scopeWeight
'
);
},
completedWeight
()
{
return
this
.
transform
(
'
completedWeight
'
);
},
dataSeries
()
{
const
series
=
[
{
name
:
__
(
'
Total
'
),
data
:
this
.
scope
,
data
:
this
.
issuesSelected
?
this
.
scopeCount
:
this
.
scopeWeight
,
},
{
name
:
__
(
'
Completed
'
),
data
:
this
.
issuesSelected
?
this
.
completedCount
:
this
.
completedWeight
,
},
];
...
...
@@ -58,15 +79,31 @@ export default {
},
},
methods
:
{
// transform the object to a chart-friendly array of date + value
transform
(
key
)
{
return
this
.
burnupData
.
map
(
val
=>
[
val
.
date
,
val
[
key
]]);
},
formatTooltipText
(
params
)
{
const
[
seriesData
]
=
params
.
seriesData
;
const
[
total
,
completed
]
=
params
.
seriesData
;
if
(
!
total
||
!
completed
)
{
return
;
}
this
.
tooltip
.
title
=
dateFormat
(
params
.
value
,
'
dd mmm yyyy
'
);
const
text
=
__
(
'
%{total} open issues
'
);
const
count
=
total
.
value
[
1
];
const
completedCount
=
completed
.
value
[
1
];
this
.
tooltip
.
content
=
sprintf
(
text
,
{
total
:
seriesData
.
value
[
1
],
});
let
totalText
=
n__
(
'
%d open issue
'
,
'
%d open issues
'
,
count
);
let
completedText
=
n__
(
'
%d completed issue
'
,
'
%d completed issues
'
,
completedCount
);
if
(
!
this
.
issuesSelected
)
{
totalText
=
sprintf
(
__
(
'
%{count} total weight
'
),
{
count
});
completedText
=
sprintf
(
__
(
'
%{completedCount} completed weight
'
),
{
completedCount
});
}
this
.
tooltip
.
total
=
totalText
;
this
.
tooltip
.
completed
=
completedText
;
},
},
};
...
...
@@ -85,7 +122,10 @@ export default {
:include-legend-avg-max=
"false"
>
<template
slot=
"tooltipTitle"
>
{{
tooltip
.
title
}}
</
template
>
<
template
slot=
"tooltipContent"
>
{{
tooltip
.
content
}}
</
template
>
<
template
slot=
"tooltipContent"
>
<div>
{{
tooltip
.
total
}}
</div>
<div>
{{
tooltip
.
completed
}}
</div>
</
template
>
</gl-line-chart>
</resizable-chart-container>
</div>
...
...
ee/app/assets/javascripts/burndown_chart/index.js
View file @
88d762ca
import
Vue
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
$
from
'
jquery
'
;
import
Cookies
from
'
js-cookie
'
;
import
createDefaultClient
from
'
~/lib/graphql
'
;
import
BurnCharts
from
'
./components/burn_charts.vue
'
;
import
BurndownChartData
from
'
./burn_chart_data
'
;
import
{
deprecatedCreateFlash
as
createFlash
}
from
'
~/flash
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
__
}
from
'
~/locale
'
;
Vue
.
use
(
VueApollo
);
const
apolloProvider
=
new
VueApollo
({
defaultClient
:
createDefaultClient
(),
});
export
default
()
=>
{
// handle hint dismissal
const
hint
=
$
(
'
.burndown-hint
'
);
...
...
@@ -24,16 +32,10 @@ export default () => {
const
dueDate
=
$chartEl
.
data
(
'
dueDate
'
);
const
milestoneId
=
$chartEl
.
data
(
'
milestoneId
'
);
const
burndownEventsPath
=
$chartEl
.
data
(
'
burndownEventsPath
'
);
const
burnupEventsPath
=
$chartEl
.
data
(
'
burnupEventsPath
'
);
const
fetchData
=
[
axios
.
get
(
burndownEventsPath
)];
if
(
gon
.
features
.
burnupCharts
)
{
fetchData
.
push
(
axios
.
get
(
burnupEventsPath
));
}
Promise
.
all
(
fetchData
)
.
then
(([
burndownResponse
,
burnupResponse
])
=>
{
axios
.
get
(
burndownEventsPath
)
.
then
(
burndownResponse
=>
{
const
burndownEvents
=
burndownResponse
.
data
;
const
burndownChartData
=
new
BurndownChartData
(
burndownEvents
,
...
...
@@ -41,13 +43,6 @@ export default () => {
dueDate
,
).
generateBurndownTimeseries
();
const
burnupEvents
=
burnupResponse
?.
data
||
[];
const
{
burnupScope
}
=
new
BurndownChartData
(
burnupEvents
,
startDate
,
dueDate
).
generateBurnupTimeseries
({
milestoneId
,
})
||
{};
const
openIssuesCount
=
burndownChartData
.
map
(
d
=>
[
d
[
0
],
d
[
1
]]);
const
openIssuesWeight
=
burndownChartData
.
map
(
d
=>
[
d
[
0
],
d
[
2
]]);
...
...
@@ -56,6 +51,7 @@ export default () => {
components
:
{
BurnCharts
,
},
apolloProvider
,
render
(
createElement
)
{
return
createElement
(
'
burn-charts
'
,
{
props
:
{
...
...
@@ -63,7 +59,7 @@ export default () => {
dueDate
,
openIssuesCount
,
openIssuesWeight
,
burnupScope
,
milestoneId
,
},
});
},
...
...
ee/app/assets/javascripts/burndown_chart/queries/burnup.query.graphql
0 → 100644
View file @
88d762ca
query
IterationBurnupTimesSeriesData
(
$milestoneId
:
MilestoneID
!)
{
milestone
(
id
:
$milestoneId
)
{
title
id
burnupTimeSeries
{
date
scopeCount
scopeWeight
completedCount
completedWeight
}
}
}
ee/app/views/shared/milestones/_burndown.html.haml
View file @
88d762ca
...
...
@@ -9,7 +9,7 @@
-
if
can_generate_chart?
(
milestone
,
burndown
)
.burndown-chart.mb-2
{
data:
{
start_date:
burndown
.
start_date
.
strftime
(
"%Y-%m-%d"
),
due_date:
burndown
.
due_date
.
strftime
(
"%Y-%m-%d"
),
milestone_id:
milestone
.
id
,
milestone_id:
milestone
.
to_global_
id
,
burndown_events_path:
expose_url
(
burndown_endpoint
),
burnup_events_path:
expose_url
(
burnup_endpoint
)
}
}
-
elsif
show_burndown_placeholder?
(
milestone
,
warning
)
...
...
ee/spec/frontend/burndown_chart/components/burn_charts_spec.js
View file @
88d762ca
...
...
@@ -2,6 +2,9 @@ import { shallowMount } from '@vue/test-utils';
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
BurnCharts
from
'
ee/burndown_chart/components/burn_charts.vue
'
;
import
BurndownChart
from
'
ee/burndown_chart/components/burndown_chart.vue
'
;
import
BurnupChart
from
'
ee/burndown_chart/components/burnup_chart.vue
'
;
import
{
useFakeDate
}
from
'
helpers/fake_date
'
;
import
{
day1
,
day2
,
day3
,
day4
}
from
'
../mock_data
'
;
describe
(
'
burndown_chart
'
,
()
=>
{
let
wrapper
;
...
...
@@ -12,10 +15,11 @@ describe('burndown_chart', () => {
const
findActiveButtons
=
()
=>
wrapper
.
findAll
(
GlButton
).
filter
(
button
=>
button
.
attributes
().
category
===
'
primary
'
);
const
findBurndownChart
=
()
=>
wrapper
.
find
(
BurndownChart
);
const
findBurnupChart
=
()
=>
wrapper
.
find
(
BurnupChart
);
const
defaultProps
=
{
startDate
:
'
2019-08-07
T00:00:00.000Z
'
,
dueDate
:
'
2019-09-09
T00:00:00.000Z
'
,
startDate
:
'
2019-08-07
'
,
dueDate
:
'
2019-09-09
'
,
openIssuesCount
:
[],
openIssuesWeight
:
[],
};
...
...
@@ -48,22 +52,23 @@ describe('burndown_chart', () => {
.
at
(
0
)
.
text
(),
).
toBe
(
'
Issues
'
);
expect
(
findBurndownChart
().
props
(
).
issuesSelected
).
toBe
(
true
);
expect
(
findBurndownChart
().
props
(
'
issuesSelected
'
)
).
toBe
(
true
);
});
it
(
'
toggles Issue weight
'
,
()
=>
{
it
(
'
toggles Issue weight
'
,
async
()
=>
{
createComponent
();
findWeightButton
().
vm
.
$emit
(
'
click
'
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
findActiveButtons
()).
toHaveLength
(
1
);
expect
(
findActiveButtons
()
.
at
(
0
)
.
text
(),
).
toBe
(
'
Issue weight
'
);
});
await
wrapper
.
vm
.
$nextTick
();
expect
(
findActiveButtons
()).
toHaveLength
(
1
);
expect
(
findActiveButtons
()
.
at
(
0
)
.
text
(),
).
toBe
(
'
Issue weight
'
);
expect
(
findBurndownChart
().
props
(
'
issuesSelected
'
)).
toBe
(
false
);
});
describe
(
'
feature disabled
'
,
()
=>
{
...
...
@@ -94,5 +99,84 @@ describe('burndown_chart', () => {
expect
(
findChartsTitle
().
text
()).
toBe
(
'
Charts
'
);
expect
(
findBurndownChart
().
props
().
showTitle
).
toBe
(
true
);
});
it
(
'
sets weight prop of burnup chart
'
,
async
()
=>
{
findWeightButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findBurnupChart
().
props
(
'
issuesSelected
'
)).
toBe
(
false
);
});
});
// some separate tests for the update function since it has a bunch of logic
describe
(
'
padSparseBurnupData function
'
,
()
=>
{
function
fakeDate
({
date
})
{
const
[
year
,
month
,
day
]
=
date
.
split
(
'
-
'
);
useFakeDate
(
year
,
month
-
1
,
day
);
}
beforeEach
(()
=>
{
createComponent
({
props
:
{
startDate
:
day1
.
date
,
dueDate
:
day4
.
date
},
featureEnabled
:
true
,
});
fakeDate
(
day4
);
});
it
(
'
pads data from startDate if no startDate values
'
,
()
=>
{
const
result
=
wrapper
.
vm
.
padSparseBurnupData
([
day2
,
day3
,
day4
]);
expect
(
result
.
length
).
toBe
(
4
);
expect
(
result
[
0
]).
toEqual
({
date
:
day1
.
date
,
completedCount
:
0
,
completedWeight
:
0
,
scopeCount
:
0
,
scopeWeight
:
0
,
});
});
it
(
'
if dueDate is in the past, pad data using last existing value
'
,
()
=>
{
const
result
=
wrapper
.
vm
.
padSparseBurnupData
([
day1
,
day2
]);
expect
(
result
.
length
).
toBe
(
4
);
expect
(
result
[
2
]).
toEqual
({
...
day2
,
date
:
day3
.
date
,
});
expect
(
result
[
3
]).
toEqual
({
...
day2
,
date
:
day4
.
date
,
});
});
it
(
'
if dueDate is in the future, pad data up to current date using last existing value
'
,
()
=>
{
fakeDate
(
day3
);
const
result
=
wrapper
.
vm
.
padSparseBurnupData
([
day1
,
day2
]);
expect
(
result
.
length
).
toBe
(
3
);
expect
(
result
[
2
]).
toEqual
({
...
day2
,
date
:
day3
.
date
,
});
});
it
(
'
pads missing days with data from previous days
'
,
()
=>
{
const
result
=
wrapper
.
vm
.
padSparseBurnupData
([
day1
,
day4
]);
expect
(
result
.
length
).
toBe
(
4
);
expect
(
result
[
1
]).
toEqual
({
...
day1
,
date
:
day2
.
date
,
});
expect
(
result
[
2
]).
toEqual
({
...
day1
,
date
:
day3
.
date
,
});
});
});
});
ee/spec/frontend/burndown_chart/components/burnup_chart_spec.js
View file @
88d762ca
...
...
@@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import
{
GlLineChart
}
from
'
@gitlab/ui/dist/charts
'
;
import
BurnupChart
from
'
ee/burndown_chart/components/burnup_chart.vue
'
;
import
ResizableChartContainer
from
'
~/vue_shared/components/resizable_chart/resizable_chart_container.vue
'
;
import
{
day1
,
day2
,
day3
}
from
'
../mock_data
'
;
describe
(
'
Burnup chart
'
,
()
=>
{
let
wrapper
;
...
...
@@ -25,18 +26,31 @@ describe('Burnup chart', () => {
});
};
it
.
each
`
scope
${[{
'
2019-08-07T00:00:00.000Z
'
:
100
}]}
${[{
'
2019-08-07T00:00:00.000Z
'
:
100
},
{
'
2019-08-08T00:00:00.000Z
'
:
99
},
{
'
2019-09-08T00:00:00.000Z
'
:
1
}]}
`
(
'
renders the lineChart correctly
'
,
({
scope
})
=>
{
createComponent
({
scope
});
it
(
'
renders the lineChart correctly
'
,
()
=>
{
const
burnupData
=
[
day1
,
day2
,
day3
];
const
expectedScopeCount
=
[
[
day1
.
date
,
day1
.
scopeCount
],
[
day2
.
date
,
day2
.
scopeCount
],
[
day3
.
date
,
day3
.
scopeCount
],
];
const
expectedCompletedCount
=
[
[
day1
.
date
,
day1
.
completedCount
],
[
day2
.
date
,
day2
.
completedCount
],
[
day3
.
date
,
day3
.
completedCount
],
];
createComponent
({
burnupData
});
const
chartData
=
findChart
().
props
(
'
data
'
);
expect
(
chartData
).
toEqual
([
{
name
:
'
Total
'
,
data
:
scope
,
data
:
expectedScopeCount
,
},
{
name
:
'
Completed
'
,
data
:
expectedCompletedCount
,
},
]);
});
...
...
ee/spec/frontend/burndown_chart/mock_data.js
0 → 100644
View file @
88d762ca
export
const
day1
=
{
date
:
'
2020-08-08
'
,
completedCount
:
0
,
completedWeight
:
0
,
scopeCount
:
10
,
scopeWeight
:
20
,
};
export
const
day2
=
{
date
:
'
2020-08-09
'
,
completedCount
:
1
,
completedWeight
:
1
,
scopeCount
:
11
,
scopeWeight
:
20
,
};
export
const
day3
=
{
date
:
'
2020-08-10
'
,
completedCount
:
2
,
completedWeight
:
4
,
scopeCount
:
11
,
scopeWeight
:
22
,
};
export
const
day4
=
{
date
:
'
2020-08-11
'
,
completedCount
:
3
,
completedWeight
:
5
,
scopeCount
:
11
,
scopeWeight
:
22
,
};
locale/gitlab.pot
View file @
88d762ca
...
...
@@ -8,6 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-11 14:23+1000\n"
"PO-Revision-Date: 2020-09-11 14:23+1000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
...
...
@@ -140,6 +142,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
msgid "%d completed issue"
msgid_plural "%d completed issues"
msgstr[0] ""
msgstr[1] ""
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
...
...
@@ -240,6 +247,11 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
msgid "%d open issue"
msgid_plural "%d open issues"
msgstr[0] ""
msgstr[1] ""
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
...
...
@@ -333,6 +345,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
msgid "%{completedCount} completed weight"
msgstr ""
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
...
...
@@ -389,6 +404,9 @@ msgstr[1] ""
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
msgid "%{count} total weight"
msgstr ""
msgid "%{dashboard_path} could not be found."
msgstr ""
...
...
@@ -806,9 +824,6 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
msgid "%{total} open issues"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr ""
...
...
@@ -9996,6 +10011,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
msgid "Error fetching burnup chart data"
msgstr ""
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
...
...
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