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
96283344
Commit
96283344
authored
Jun 07, 2018
by
Kushal Pandya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Quarters Preset Mixin
parent
aeff2f4f
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
289 additions
and
0 deletions
+289
-0
ee/app/assets/javascripts/roadmap/mixins/quarters_preset_mixin.js
...ssets/javascripts/roadmap/mixins/quarters_preset_mixin.js
+146
-0
spec/javascripts/roadmap/mixins/quarters_preset_mixin_spec.js
.../javascripts/roadmap/mixins/quarters_preset_mixin_spec.js
+143
-0
No files found.
ee/app/assets/javascripts/roadmap/mixins/quarters_preset_mixin.js
0 → 100644
View file @
96283344
import
{
totalDaysInQuarter
,
dayInQuarter
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
TIMELINE_END_OFFSET_HALF
}
from
'
../constants
'
;
export
default
{
methods
:
{
/**
* Check if current epic starts within current quarter (timeline cell)
*/
hasStartDateForQuarter
()
{
const
quarterStart
=
this
.
timeframeItem
.
range
[
0
];
const
quarterEnd
=
this
.
timeframeItem
.
range
[
2
];
return
this
.
epic
.
startDate
>=
quarterStart
&&
this
.
epic
.
startDate
<=
quarterEnd
;
},
/**
* Check if current epic ends within current quarter (timeline cell)
*/
isTimeframeUnderEndDateForQuarter
(
timeframeItem
,
epicEndDate
)
{
const
quarterEnd
=
timeframeItem
.
range
[
2
];
return
epicEndDate
<=
quarterEnd
;
},
/**
* Return timeline bar width for current quarter (timeline cell) based on
* cellWidth, days in quarter and day of the quarter
*/
getBarWidthForSingleQuarter
(
cellWidth
,
daysInQuarter
,
day
)
{
const
dayWidth
=
cellWidth
/
daysInQuarter
;
const
barWidth
=
day
===
daysInQuarter
?
cellWidth
:
dayWidth
*
day
;
return
Math
.
min
(
cellWidth
,
barWidth
);
},
/**
* In case startDate for any epic is undefined or is out of range
* for current timeframe, we have to provide specific offset while
* positioning it to ensure that;
*
* 1. Timeline bar starts at correct position based on start date.
* 2. Bar starts exactly at the start of cell in case start date is `1`.
* 3. A "triangle" shape is shown at the beginning of timeline bar
* when startDate is out of range.
*
* Implementation of this method is identical to
* MonthsPresetMixin#getTimelineBarStartOffsetForMonths
*/
getTimelineBarStartOffsetForQuarters
()
{
const
daysInQuarter
=
totalDaysInQuarter
(
this
.
timeframeItem
.
range
);
const
startDay
=
dayInQuarter
(
this
.
epic
.
startDate
,
this
.
timeframeItem
.
range
);
if
(
this
.
epic
.
startDateOutOfRange
||
(
this
.
epic
.
startDateUndefined
&&
this
.
epic
.
endDateOutOfRange
)
)
{
return
''
;
}
else
if
(
startDay
===
1
)
{
return
'
left: 0;
'
;
}
const
lastTimeframeItem
=
this
.
timeframe
[
this
.
timeframe
.
length
-
1
].
range
[
2
];
if
(
this
.
epic
.
startDate
>=
this
.
timeframe
[
this
.
timeframe
.
length
-
1
].
range
[
0
]
&&
this
.
epic
.
startDate
<=
lastTimeframeItem
)
{
return
`right:
${
TIMELINE_END_OFFSET_HALF
}
px;`
;
}
return
`left:
${
startDay
/
daysInQuarter
*
100
}
%;`
;
},
/**
* This method is externally only called when current timeframe cell has timeline
* bar to show. So when this method is called, we iterate over entire timeframe
* array starting from current timeframeItem.
*
* For eg;
* If timeframe range for 6 quarters is;
* [2017 Oct Nov Dec], [2018 Jan Feb Mar], [Apr May Jun],
* [Jul Aug Sep], [Oct Nov Dec], [2019 Jan Feb Mar]
*
* And if Epic starts in 2017 Dec and ends in 2018 May.
*
* Then this method will iterate over timeframe as;
* [2017 Oct Nov Dec] => [2018 Apr May Jun]
* And will add up width(see 1.) for timeline bar for each quarter in iteration
* based on provided start and end dates.
*
* 1. Width from date is calculated by totalWidthCell / totalDaysInQuarter = widthOfSingleDay
* and then dayOfQuarter x widthOfSingleDay = totalBarWidth
*
* Implementation of this method is identical to
* MonthsPresetMixin#getTimelineBarWidthForMonths
*/
getTimelineBarWidthForQuarters
()
{
let
timelineBarWidth
=
0
;
const
indexOfCurrentQuarter
=
this
.
timeframe
.
indexOf
(
this
.
timeframeItem
);
const
cellWidth
=
this
.
getCellWidth
();
const
offsetEnd
=
this
.
getTimelineBarEndOffset
();
const
epicStartDate
=
this
.
epic
.
startDate
;
const
epicEndDate
=
this
.
epic
.
endDate
;
for
(
let
i
=
indexOfCurrentQuarter
;
i
<
this
.
timeframe
.
length
;
i
+=
1
)
{
const
currentQuarter
=
this
.
timeframe
[
i
].
range
;
if
(
i
===
indexOfCurrentQuarter
)
{
if
(
this
.
isTimeframeUnderEndDateForQuarter
(
this
.
timeframe
[
i
],
epicEndDate
))
{
timelineBarWidth
+=
this
.
getBarWidthForSingleQuarter
(
cellWidth
,
totalDaysInQuarter
(
currentQuarter
),
dayInQuarter
(
epicEndDate
,
currentQuarter
)
-
dayInQuarter
(
epicStartDate
,
currentQuarter
)
+
1
,
);
break
;
}
else
{
const
daysInQuarter
=
totalDaysInQuarter
(
currentQuarter
);
const
day
=
dayInQuarter
(
epicStartDate
,
currentQuarter
);
const
date
=
day
===
1
?
daysInQuarter
:
daysInQuarter
-
day
;
timelineBarWidth
+=
this
.
getBarWidthForSingleQuarter
(
cellWidth
,
totalDaysInQuarter
(
currentQuarter
),
date
,
);
}
}
else
if
(
this
.
isTimeframeUnderEndDateForQuarter
(
this
.
timeframe
[
i
],
epicEndDate
))
{
timelineBarWidth
+=
this
.
getBarWidthForSingleQuarter
(
cellWidth
,
totalDaysInQuarter
(
currentQuarter
),
dayInQuarter
(
epicEndDate
,
currentQuarter
),
);
break
;
}
else
{
const
daysInQuarter
=
totalDaysInQuarter
(
currentQuarter
);
timelineBarWidth
+=
this
.
getBarWidthForSingleQuarter
(
cellWidth
,
daysInQuarter
,
daysInQuarter
,
);
}
}
return
timelineBarWidth
-
offsetEnd
;
},
},
};
spec/javascripts/roadmap/mixins/quarters_preset_mixin_spec.js
0 → 100644
View file @
96283344
import
Vue
from
'
vue
'
;
import
EpicItemTimelineComponent
from
'
ee/roadmap/components/epic_item_timeline.vue
'
;
import
{
PRESET_TYPES
}
from
'
ee/roadmap/constants
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
mockTimeframeQuarters
,
mockEpic
,
mockShellWidth
,
mockItemWidth
}
from
'
../mock_data
'
;
const
createComponent
=
({
presetType
=
PRESET_TYPES
.
QUARTERS
,
timeframe
=
mockTimeframeQuarters
,
timeframeItem
=
mockTimeframeQuarters
[
0
],
epic
=
mockEpic
,
shellWidth
=
mockShellWidth
,
itemWidth
=
mockItemWidth
,
})
=>
{
const
Component
=
Vue
.
extend
(
EpicItemTimelineComponent
);
return
mountComponent
(
Component
,
{
presetType
,
timeframe
,
timeframeItem
,
epic
,
shellWidth
,
itemWidth
,
});
};
describe
(
'
QuartersPresetMixin
'
,
()
=>
{
let
vm
;
afterEach
(()
=>
{
vm
.
$destroy
();
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
hasStartDateForQuarter
'
,
()
=>
{
it
(
'
returns true when Epic.startDate falls within timeframeItem
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeQuarters
[
1
].
range
[
0
]
}),
timeframeItem
:
mockTimeframeQuarters
[
1
],
});
expect
(
vm
.
hasStartDateForQuarter
()).
toBe
(
true
);
});
it
(
'
returns false when Epic.startDate does not fall within timeframeItem
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeQuarters
[
0
].
range
[
0
]
}),
timeframeItem
:
mockTimeframeQuarters
[
1
],
});
expect
(
vm
.
hasStartDateForQuarter
()).
toBe
(
false
);
});
});
describe
(
'
isTimeframeUnderEndDateForQuarter
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
createComponent
({});
});
it
(
'
returns true if provided timeframeItem is under epicEndDate
'
,
()
=>
{
const
timeframeItem
=
mockTimeframeQuarters
[
1
];
const
epicEndDate
=
mockTimeframeQuarters
[
1
].
range
[
2
];
expect
(
vm
.
isTimeframeUnderEndDateForQuarter
(
timeframeItem
,
epicEndDate
)).
toBe
(
true
);
});
it
(
'
returns false if provided timeframeItem is NOT under epicEndDate
'
,
()
=>
{
const
timeframeItem
=
mockTimeframeQuarters
[
1
];
const
epicEndDate
=
mockTimeframeQuarters
[
2
].
range
[
1
];
expect
(
vm
.
isTimeframeUnderEndDateForQuarter
(
timeframeItem
,
epicEndDate
)).
toBe
(
false
);
});
});
describe
(
'
getBarWidthForSingleQuarter
'
,
()
=>
{
it
(
'
returns calculated bar width based on provided cellWidth, daysInQuarter and day of quarter
'
,
()
=>
{
vm
=
createComponent
({});
expect
(
Math
.
floor
(
vm
.
getBarWidthForSingleQuarter
(
300
,
91
,
1
))).
toBe
(
3
);
// 10% size
expect
(
Math
.
floor
(
vm
.
getBarWidthForSingleQuarter
(
300
,
91
,
45
))).
toBe
(
148
);
// 50% size
expect
(
vm
.
getBarWidthForSingleQuarter
(
300
,
91
,
91
)).
toBe
(
300
);
// Full size
});
});
describe
(
'
getTimelineBarStartOffsetForQuarters
'
,
()
=>
{
it
(
'
returns empty string when Epic startDate is out of range
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDateOutOfRange
:
true
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForQuarters
()).
toBe
(
''
);
});
it
(
'
returns empty string when Epic startDate is undefined and endDate is out of range
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDateUndefined
:
true
,
endDateOutOfRange
:
true
,
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForQuarters
()).
toBe
(
''
);
});
it
(
'
return `left: 0;` when Epic startDate is first day of the quarter
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeQuarters
[
0
].
range
[
0
],
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForQuarters
()).
toBe
(
'
left: 0;
'
);
});
it
(
'
returns `right: 8px;` when Epic startDate is in last timeframe month and endDate is out of range
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeQuarters
[
mockTimeframeQuarters
.
length
-
1
].
range
[
1
],
endDateOutOfRange
:
true
,
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForQuarters
()).
toBe
(
'
right: 8px;
'
);
});
it
(
'
returns proportional `left` value based on Epic startDate and days in the quarter
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeQuarters
[
0
].
range
[
1
],
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForQuarters
()).
toContain
(
'
left: 34
'
);
});
});
describe
(
'
getTimelineBarWidthForQuarters
'
,
()
=>
{
it
(
'
returns calculated width value based on Epic.startDate and Epic.endDate
'
,
()
=>
{
vm
=
createComponent
({
shellWidth
:
2000
,
timeframeItem
:
mockTimeframeQuarters
[
0
],
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeQuarters
[
0
].
range
[
1
],
endDate
:
mockTimeframeQuarters
[
1
].
range
[
1
],
}),
});
expect
(
Math
.
floor
(
vm
.
getTimelineBarWidthForQuarters
())).
toBe
(
282
);
});
});
});
});
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