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
8f046d62
Commit
8f046d62
authored
Jun 07, 2018
by
Kushal Pandya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Months Preset Mixin
parent
96283344
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
299 additions
and
0 deletions
+299
-0
ee/app/assets/javascripts/roadmap/mixins/months_preset_mixin.js
.../assets/javascripts/roadmap/mixins/months_preset_mixin.js
+156
-0
spec/javascripts/roadmap/mixins/months_preset_mixin_spec.js
spec/javascripts/roadmap/mixins/months_preset_mixin_spec.js
+143
-0
No files found.
ee/app/assets/javascripts/roadmap/mixins/months_preset_mixin.js
0 → 100644
View file @
8f046d62
import
{
totalDaysInMonth
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
TIMELINE_END_OFFSET_HALF
}
from
'
../constants
'
;
export
default
{
methods
:
{
/**
* Check if current epic starts within current month (timeline cell)
*/
hasStartDateForMonth
()
{
return
(
this
.
epic
.
startDate
.
getMonth
()
===
this
.
timeframeItem
.
getMonth
()
&&
this
.
epic
.
startDate
.
getFullYear
()
===
this
.
timeframeItem
.
getFullYear
()
);
},
/**
* Check if current epic ends within current month (timeline cell)
*/
isTimeframeUnderEndDateForMonth
(
timeframeItem
,
epicEndDate
)
{
return
(
timeframeItem
.
getYear
()
<=
epicEndDate
.
getYear
()
&&
timeframeItem
.
getMonth
()
===
epicEndDate
.
getMonth
()
);
},
/**
* Return timeline bar width for current month (timeline cell) based on
* cellWidth, days in month and date of the month
*/
getBarWidthForSingleMonth
(
cellWidth
,
daysInMonth
,
date
)
{
const
dayWidth
=
cellWidth
/
daysInMonth
;
const
barWidth
=
date
===
daysInMonth
?
cellWidth
:
dayWidth
*
date
;
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.
*/
getTimelineBarStartOffsetForMonths
()
{
const
daysInMonth
=
totalDaysInMonth
(
this
.
timeframeItem
);
const
startDate
=
this
.
epic
.
startDate
.
getDate
();
if
(
this
.
epic
.
startDateOutOfRange
||
(
this
.
epic
.
startDateUndefined
&&
this
.
epic
.
endDateOutOfRange
)
)
{
// If Epic startDate is out of timeframe range
// OR
// Epic startDate is undefined AND Epic endDate is out of timeframe range
// no offset is needed.
return
''
;
}
else
if
(
startDate
===
1
)
{
// If Epic startDate is first day of the month
// Set offset to 0.
return
'
left: 0;
'
;
}
// If Epic end date is out of range
const
lastTimeframeItem
=
this
.
timeframe
[
this
.
timeframe
.
length
-
1
];
// Check if Epic start date falls within last month of the timeframe
if
(
this
.
epic
.
startDate
.
getMonth
()
===
lastTimeframeItem
.
getMonth
()
&&
this
.
epic
.
startDate
.
getFullYear
()
===
lastTimeframeItem
.
getFullYear
()
)
{
// Compensate for triangle size
return
`right:
${
TIMELINE_END_OFFSET_HALF
}
px;`
;
}
// Calculate proportional offset based on startDate and total days in
// current month.
return
`left:
${
startDate
/
daysInMonth
*
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 7 months is;
* 2017 Oct, 2017 Nov, 2017 Dec, 2018 Jan, 2018 Feb, 2018 Mar, 2018 Apr
*
* And if Epic starts in 2017 Dec and ends in 2018 Feb.
*
* Then this method will iterate over timeframe as;
* 2017 Dec => 2018 Feb
* And will add up width(see 1.) for timeline bar for each month in iteration
* based on provided start and end dates.
*
* 1. Width from date is calculated by totalWidthCell / totalDaysInMonth = widthOfSingleDay
* and then dateOfMonth x widthOfSingleDay = totalBarWidth
*/
getTimelineBarWidthForMonths
()
{
let
timelineBarWidth
=
0
;
const
indexOfCurrentMonth
=
this
.
timeframe
.
indexOf
(
this
.
timeframeItem
);
const
cellWidth
=
this
.
getCellWidth
();
const
offsetEnd
=
this
.
getTimelineBarEndOffset
();
const
epicStartDate
=
this
.
epic
.
startDate
;
const
epicEndDate
=
this
.
epic
.
endDate
;
// Start iteration from current month
for
(
let
i
=
indexOfCurrentMonth
;
i
<
this
.
timeframe
.
length
;
i
+=
1
)
{
// Get total days for current month
const
daysInMonth
=
totalDaysInMonth
(
this
.
timeframe
[
i
]);
if
(
i
===
indexOfCurrentMonth
)
{
// If this is current month
if
(
this
.
isTimeframeUnderEndDateForMonth
(
this
.
timeframe
[
i
],
epicEndDate
))
{
// If Epic endDate falls under the range of current timeframe month
// then get width for number of days between start and end dates (inclusive)
timelineBarWidth
+=
this
.
getBarWidthForSingleMonth
(
cellWidth
,
daysInMonth
,
epicEndDate
.
getDate
()
-
epicStartDate
.
getDate
()
+
1
,
);
// Break as Epic start and end date fall within current timeframe month itself!
break
;
}
else
{
// Epic end date does NOT fall in current month.
// If start date is first day of the month,
// we need width of full cell (i.e. total days of month)
// otherwise, we need width only for date from total days of month.
const
date
=
epicStartDate
.
getDate
()
===
1
?
daysInMonth
:
daysInMonth
-
epicStartDate
.
getDate
();
timelineBarWidth
+=
this
.
getBarWidthForSingleMonth
(
cellWidth
,
daysInMonth
,
date
);
}
}
else
if
(
this
.
isTimeframeUnderEndDateForMonth
(
this
.
timeframe
[
i
],
epicEndDate
))
{
// If this is NOT current month but epicEndDate falls under
// current timeframe month then calculate width
// based on date of the month
timelineBarWidth
+=
this
.
getBarWidthForSingleMonth
(
cellWidth
,
daysInMonth
,
epicEndDate
.
getDate
(),
);
// Break as Epic end date falls within current timeframe month!
break
;
}
else
{
// This is neither current month,
// nor does the Epic end date fall under current timeframe month
// add width for entire cell of current timeframe.
timelineBarWidth
+=
this
.
getBarWidthForSingleMonth
(
cellWidth
,
daysInMonth
,
daysInMonth
);
}
}
// Reduce any offset from total width and round it off.
return
timelineBarWidth
-
offsetEnd
;
},
},
};
spec/javascripts/roadmap/mixins/months_preset_mixin_spec.js
0 → 100644
View file @
8f046d62
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
{
mockTimeframeMonths
,
mockEpic
,
mockShellWidth
,
mockItemWidth
}
from
'
../mock_data
'
;
const
createComponent
=
({
presetType
=
PRESET_TYPES
.
MONTHS
,
timeframe
=
mockTimeframeMonths
,
timeframeItem
=
mockTimeframeMonths
[
0
],
epic
=
mockEpic
,
shellWidth
=
mockShellWidth
,
itemWidth
=
mockItemWidth
,
})
=>
{
const
Component
=
Vue
.
extend
(
EpicItemTimelineComponent
);
return
mountComponent
(
Component
,
{
presetType
,
timeframe
,
timeframeItem
,
epic
,
shellWidth
,
itemWidth
,
});
};
describe
(
'
MonthsPresetMixin
'
,
()
=>
{
let
vm
;
afterEach
(()
=>
{
vm
.
$destroy
();
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
hasStartDateForMonth
'
,
()
=>
{
it
(
'
returns true when Epic.startDate falls within timeframeItem
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeMonths
[
1
]
}),
timeframeItem
:
mockTimeframeMonths
[
1
],
});
expect
(
vm
.
hasStartDateForMonth
()).
toBe
(
true
);
});
it
(
'
returns false when Epic.startDate does not fall within timeframeItem
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
mockTimeframeMonths
[
0
]
}),
timeframeItem
:
mockTimeframeMonths
[
1
],
});
expect
(
vm
.
hasStartDateForMonth
()).
toBe
(
false
);
});
});
describe
(
'
isTimeframeUnderEndDateForMonth
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
createComponent
({});
});
it
(
'
returns true if provided timeframeItem is under epicEndDate
'
,
()
=>
{
const
timeframeItem
=
new
Date
(
2018
,
0
,
10
);
// Jan 10, 2018
const
epicEndDate
=
new
Date
(
2018
,
0
,
26
);
// Jan 26, 2018
expect
(
vm
.
isTimeframeUnderEndDateForMonth
(
timeframeItem
,
epicEndDate
)).
toBe
(
true
);
});
it
(
'
returns false if provided timeframeItem is NOT under epicEndDate
'
,
()
=>
{
const
timeframeItem
=
new
Date
(
2018
,
0
,
10
);
// Jan 10, 2018
const
epicEndDate
=
new
Date
(
2018
,
1
,
26
);
// Feb 26, 2018
expect
(
vm
.
isTimeframeUnderEndDateForMonth
(
timeframeItem
,
epicEndDate
)).
toBe
(
false
);
});
});
describe
(
'
getBarWidthForSingleMonth
'
,
()
=>
{
it
(
'
returns calculated bar width based on provided cellWidth, daysInMonth and date
'
,
()
=>
{
vm
=
createComponent
({});
expect
(
vm
.
getBarWidthForSingleMonth
(
300
,
30
,
1
)).
toBe
(
10
);
// 10% size
expect
(
vm
.
getBarWidthForSingleMonth
(
300
,
30
,
15
)).
toBe
(
150
);
// 50% size
expect
(
vm
.
getBarWidthForSingleMonth
(
300
,
30
,
30
)).
toBe
(
300
);
// Full size
});
});
describe
(
'
getTimelineBarStartOffsetForMonths
'
,
()
=>
{
it
(
'
returns empty string when Epic startDate is out of range
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDateOutOfRange
:
true
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForMonths
()).
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
.
getTimelineBarStartOffsetForMonths
()).
toBe
(
''
);
});
it
(
'
return `left: 0;` when Epic startDate is first day of the month
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
new
Date
(
2018
,
0
,
1
),
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForMonths
()).
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
:
mockTimeframeMonths
[
mockTimeframeMonths
.
length
-
1
],
endDateOutOfRange
:
true
,
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForMonths
()).
toBe
(
'
right: 8px;
'
);
});
it
(
'
returns proportional `left` value based on Epic startDate and days in the month
'
,
()
=>
{
vm
=
createComponent
({
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
new
Date
(
2018
,
0
,
15
),
}),
});
expect
(
vm
.
getTimelineBarStartOffsetForMonths
()).
toContain
(
'
left: 48
'
);
});
});
describe
(
'
getTimelineBarWidthForMonths
'
,
()
=>
{
it
(
'
returns calculated width value based on Epic.startDate and Epic.endDate
'
,
()
=>
{
vm
=
createComponent
({
shellWidth
:
2000
,
timeframeItem
:
mockTimeframeMonths
[
0
],
epic
:
Object
.
assign
({},
mockEpic
,
{
startDate
:
new
Date
(
2017
,
11
,
15
),
// Dec 15, 2017
endDate
:
new
Date
(
2018
,
1
,
15
),
// Feb 15, 2017
}),
});
expect
(
Math
.
floor
(
vm
.
getTimelineBarWidthForMonths
())).
toBe
(
492
);
});
});
});
});
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