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
bfb5ebd6
Commit
bfb5ebd6
authored
Nov 28, 2016
by
Bryce Johnson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use help_page_path to generate correct time tracking docs url.
parent
28412f81
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
106 additions
and
96 deletions
+106
-96
app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6
.../issuable/time_tracking/components/collapsed_state.js.es6
+3
-3
app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6
.../issuable/time_tracking/components/comparison_pane.js.es6
+3
-3
app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6
...suable/time_tracking/components/estimate_only_pane.js.es6
+2
-2
app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6
...ripts/issuable/time_tracking/components/help_state.js.es6
+3
-7
app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6
...issuable/time_tracking/components/no_tracking_pane.js.es6
+2
-2
app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6
.../issuable/time_tracking/components/spent_only_pane.js.es6
+2
-2
app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6
...pts/issuable/time_tracking/components/time_tracker.js.es6
+6
-3
app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6
...cripts/issuable/time_tracking/time_tracking_bundle.js.es6
+1
-1
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+1
-1
spec/javascripts/issuable_time_tracker_spec.js.es6
spec/javascripts/issuable_time_tracker_spec.js.es6
+75
-72
spec/support/time_tracking_shared_examples.rb
spec/support/time_tracking_shared_examples.rb
+8
-0
No files found.
app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6
View file @
bfb5ebd6
//= require lib/utils/pretty_time
//= require lib/utils/pretty_time
((
app
) => {
(() => {
const PrettyTime = gl.PrettyTime;
const PrettyTime = gl.PrettyTime;
a
pp.collapsedState = {
gl.IssuableTimeTrackingA
pp.collapsedState = {
name: 'time-tracking-collapsed-state',
name: 'time-tracking-collapsed-state',
props: [
props: [
'showComparisonState',
'showComparisonState',
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
'showNoTimeTrackingState',
'showNoTimeTrackingState',
'timeSpentHuman',
'timeSpentHuman',
'timeEstimateHuman',
'timeEstimateHuman',
'stopwatchSvg'
'stopwatchSvg'
,
],
],
methods: {
methods: {
abbreviateTime(timeStr) {
abbreviateTime(timeStr) {
...
...
app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6
View file @
bfb5ebd6
//= require lib/utils/pretty_time
//= require lib/utils/pretty_time
((
app
) => {
(() => {
const PrettyTime = gl.PrettyTime;
const PrettyTime = gl.PrettyTime;
a
pp.comparisonPane = {
gl.IssuableTimeTrackingA
pp.comparisonPane = {
name: 'time-tracking-comparison-pane',
name: 'time-tracking-comparison-pane',
props: [
props: [
'timeSpent',
'timeSpent',
'timeEstimate',
'timeEstimate',
'timeSpentHuman',
'timeSpentHuman',
'timeEstimateHuman'
'timeEstimateHuman'
,
],
],
computed: {
computed: {
parsedRemaining() {
parsedRemaining() {
...
...
app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6
View file @
bfb5ebd6
((
app
) => {
(() => {
a
pp.estimateOnlyPane = {
gl.IssuableTimeTrackingA
pp.estimateOnlyPane = {
name: 'time-tracking-estimate-only-pane',
name: 'time-tracking-estimate-only-pane',
props: ['timeEstimateHuman'],
props: ['timeEstimateHuman'],
template: `
template: `
...
...
app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6
View file @
bfb5ebd6
((
app
) => {
(() => {
a
pp.helpState = {
gl.IssuableTimeTrackingA
pp.helpState = {
name: 'time-tracking-help-state',
name: 'time-tracking-help-state',
data() {
props: ['docsUrl'],
return {
docsUrl: '/help/workflow/time_tracking.md',
};
},
template: `
template: `
<div class='time-tracking-help-state'>
<div class='time-tracking-help-state'>
<div class='time-tracking-info'>
<div class='time-tracking-info'>
...
...
app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6
View file @
bfb5ebd6
((
app
) => {
(() => {
a
pp.noTrackingPane = {
gl.IssuableTimeTrackingA
pp.noTrackingPane = {
name: 'time-tracking-no-tracking-pane',
name: 'time-tracking-no-tracking-pane',
template: `
template: `
<div class='time-tracking-no-tracking-pane'>
<div class='time-tracking-no-tracking-pane'>
...
...
app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6
View file @
bfb5ebd6
((
app
) => {
(() => {
a
pp.spentOnlyPane = {
gl.IssuableTimeTrackingA
pp.spentOnlyPane = {
name: 'time-tracking-spent-only-pane',
name: 'time-tracking-spent-only-pane',
props: ['timeSpentHuman'],
props: ['timeSpentHuman'],
template: `
template: `
...
...
app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6
View file @
bfb5ebd6
((app) => {
(() => {
const app = gl.IssuableTimeTrackingApp;
gl.IssuableTimeTracker = Vue.component('issuable-time-tracker', {
gl.IssuableTimeTracker = Vue.component('issuable-time-tracker', {
name: 'issuable-time-tracker',
name: 'issuable-time-tracker',
props: [
props: [
...
@@ -6,7 +7,8 @@
...
@@ -6,7 +7,8 @@
'time_spent',
'time_spent',
'human_time_estimate',
'human_time_estimate',
'human_time_spent',
'human_time_spent',
'stopwatchSvg'
'stopwatchSvg',
'docsUrl',
],
],
data() {
data() {
return {
return {
...
@@ -98,7 +100,8 @@
...
@@ -98,7 +100,8 @@
</time-tracking-comparison-pane>
</time-tracking-comparison-pane>
<transition name='help-state-toggle'>
<transition name='help-state-toggle'>
<time-tracking-help-state
<time-tracking-help-state
v-if='showHelpState'>
v-if='showHelpState'
:docs-url='docsUrl'>
</time-tracking-help-state>
</time-tracking-help-state>
</transition>
</transition>
</div>
</div>
...
...
app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6
View file @
bfb5ebd6
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
//= require smart_interval
//= require smart_interval
//= require subbable_resource
//= require subbable_resource
((
gl
) => {
(() => {
/* This Vue instance represents what will become the parent instance for the
/* This Vue instance represents what will become the parent instance for the
* sidebar. It will be responsible for managing `issuable` state and propagating
* sidebar. It will be responsible for managing `issuable` state and propagating
* changes to sidebar components.
* changes to sidebar components.
...
...
app/views/shared/issuable/_sidebar.html.haml
View file @
bfb5ebd6
...
@@ -76,7 +76,7 @@
...
@@ -76,7 +76,7 @@
=
dropdown_tag
(
'Milestone'
,
options:
{
title:
'Assign milestone'
,
toggle_class:
'js-milestone-select js-extra-options'
,
filter:
true
,
dropdown_class:
'dropdown-menu-selectable'
,
placeholder:
'Search milestones'
,
data:
{
show_no:
true
,
field_name:
"
#{
issuable
.
to_ability_name
}
[milestone_id]"
,
project_id:
@project
.
id
,
issuable_id:
issuable
.
id
,
milestones:
namespace_project_milestones_path
(
@project
.
namespace
,
@project
,
:json
),
ability_name:
issuable
.
to_ability_name
,
issue_update:
issuable_json_path
(
issuable
),
use_id:
true
}})
=
dropdown_tag
(
'Milestone'
,
options:
{
title:
'Assign milestone'
,
toggle_class:
'js-milestone-select js-extra-options'
,
filter:
true
,
dropdown_class:
'dropdown-menu-selectable'
,
placeholder:
'Search milestones'
,
data:
{
show_no:
true
,
field_name:
"
#{
issuable
.
to_ability_name
}
[milestone_id]"
,
project_id:
@project
.
id
,
issuable_id:
issuable
.
id
,
milestones:
namespace_project_milestones_path
(
@project
.
namespace
,
@project
,
:json
),
ability_name:
issuable
.
to_ability_name
,
issue_update:
issuable_json_path
(
issuable
),
use_id:
true
}})
-
if
issuable
.
has_attribute?
(
:time_estimate
)
-
if
issuable
.
has_attribute?
(
:time_estimate
)
#issuable-time-tracker
.block
#issuable-time-tracker
.block
%issuable-time-tracker
{
':time_estimate'
=>
'issuable.time_estimate'
,
':time_spent'
=>
'issuable.total_time_spent'
,
':human_time_estimate'
=>
'issuable.human_time_estimate'
,
':human_time_spent'
=>
'issuable.human_total_time_spent'
,
'stopwatch-svg'
=>
custom_icon
(
'icon_stopwatch'
)
}
%issuable-time-tracker
{
':time_estimate'
=>
'issuable.time_estimate'
,
':time_spent'
=>
'issuable.total_time_spent'
,
':human_time_estimate'
=>
'issuable.human_time_estimate'
,
':human_time_spent'
=>
'issuable.human_total_time_spent'
,
'stopwatch-svg'
=>
custom_icon
(
'icon_stopwatch'
)
,
'docs-url'
=>
help_page_path
(
'workflow/time_tracking.md'
)
}
// Fallback while content is loading
// Fallback while content is loading
.title.hide-collapsed
.title.hide-collapsed
Time tracking
Time tracking
...
...
spec/javascripts/issuable_time_tracker_spec.js.es6
View file @
bfb5ebd6
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
//= require vue
//= require vue
//= require issuable/time_tracking/time_tracking_bundle
//= require issuable/time_tracking/time_tracking_bundle
function initComponent(
time_estimate = 100000, time_spent = 5000, human_time_estimate = '3d 3h 46m', human_time_spent = '1h 23m'
) {
function initComponent(
opts = {}
) {
fixture.set(`
fixture.set(`
<div>
<div>
<div id="mock-container"></div>
<div id="mock-container"></div>
...
@@ -11,19 +11,16 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
...
@@ -11,19 +11,16 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
`);
`);
this.initialData = {
this.initialData = {
time_estimate,
timeEstimate: opts.timeEstimate || 100000,
time_spent,
timeSpent: opts.timeSpent || 5000,
human_time_estimate,
timeEstimateHuman: opts.timeEstimateHuman || '3d 3h 46m',
human_time_spent,
timeSpentHuman: opts.timeSpentHuman || '1h 23m',
timeEstimateHuman: human_time_estimate,
docsUrl: '/help/workflow/time_tracking.md',
timeSpentHuman: human_time_spent,
timeEstimate: time_estimate,
timeSpent: time_spent,
};
};
this.timeTracker = new gl.IssuableTimeTracker({
this.timeTracker = new gl.IssuableTimeTracker({
el: '#mock-container',
el: '#mock-container',
propsData: this.initialData
data: this.initialData,
});
});
}
}
...
@@ -38,8 +35,8 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
...
@@ -38,8 +35,8 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
expect(this.timeTracker).toBeDefined();
expect(this.timeTracker).toBeDefined();
});
});
it ('should correctly set time
_e
stimate', function() {
it ('should correctly set time
E
stimate', function() {
expect(this.timeTracker.time
_estimate).toBe(this.initialData.time_e
stimate);
expect(this.timeTracker.time
Estimate).toBe(this.initialData.timeE
stimate);
});
});
it ('should correctly set time_spent', function() {
it ('should correctly set time_spent', function() {
expect(this.timeTracker.time_spent).toBe(this.initialData.time_spent);
expect(this.timeTracker.time_spent).toBe(this.initialData.time_spent);
...
@@ -53,10 +50,13 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
...
@@ -53,10 +50,13 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
initComponent.apply(this);
initComponent.apply(this);
});
});
it('should show the "Comparison" pane when time_estimate and time_spent are truthy', function() {
it('should show the "Comparison" pane when timeEstimate and time_spent are truthy', function(done) {
const $comparisonPane = this.timeTracker.$el.querySelector('.time-tracking-comparison-pane');
Vue.nextTick(() => {
expect(this.timeTracker.showComparisonState).toBe(true);
const $comparisonPane = this.timeTracker.$el.querySelector('.time-tracking-comparison-pane');
expect($comparisonPane).toBeVisible();
expect(this.timeTracker.showComparisonState).toBe(true);
expect($comparisonPane).toBeVisible();
done();
});
});
});
it('should display the human readable version of time estimated', function() {
it('should display the human readable version of time estimated', function() {
...
@@ -87,7 +87,7 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
...
@@ -87,7 +87,7 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
});
});
it('should display the remaining meter with the correct background color when over estimate', function() {
it('should display the remaining meter with the correct background color when over estimate', function() {
this.timeTracker.time
_e
stimate = 1;
this.timeTracker.time
E
stimate = 1;
this.timeTracker.time_spent = 2;
this.timeTracker.time_spent = 2;
Vue.nextTick(() => {
Vue.nextTick(() => {
const styledMeter = $(this.timeTracker.$el).find('.time-tracking-comparison-pane .over_estimate .meter-fill');
const styledMeter = $(this.timeTracker.$el).find('.time-tracking-comparison-pane .over_estimate .meter-fill');
...
@@ -99,112 +99,115 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
...
@@ -99,112 +99,115 @@ function initComponent(time_estimate = 100000, time_spent = 5000, human_time_est
describe("Estimate only pane", function() {
describe("Estimate only pane", function() {
beforeEach(function() {
beforeEach(function() {
initComponent.apply(this,
[10000, 0, '2h 46m', 0]
);
initComponent.apply(this,
{ timeEstimate: 10000, timeSpent: '0', timeEstimateHuman: '2h 46m', timeSpentHuman: '0' }
);
});
});
it('should only show the "Estimate only" pane when time_estimate is truthy and time_spent is falsey', function() {
it('should only show the "Estimate only" pane when timeEstimate is truthy and time_spent is falsey', function() {
const $estimateOnlyPane = this.timeTracker.$el.querySelector('.time-tracking-estimate-only-pane');
Vue.nextTick(() => {
const $estimateOnlyPane = this.timeTracker.$el.querySelector('.time-tracking-estimate-only-pane');
expect(this.timeTracker.showEstimateOnlyState).toBe(true);
expect(this.timeTracker.showEstimateOnlyState).toBe(true);
expect($estimateOnlyPane).toBeVisible();
expect($estimateOnlyPane).toBeVisible();
});
});
});
it('should display the human readable version of time estimated', function() {
it('should display the human readable version of time estimated', function() {
const estimateText = this.timeTracker.$el.querySelector('.time-tracking-estimate-only-pane').innerText;
Vue.nextTick(() => {
const correctText = 'Estimated: 2h 46m';
const estimateText = this.timeTracker.$el.querySelector('.time-tracking-estimate-only-pane').innerText;
const correctText = 'Estimated: 2h 46m';
expect(estimateText).toBe(correctText);
expect(estimateText).toBe(correctText);
});
});
});
});
});
describe('Spent only pane', function() {
describe('Spent only pane', function() {
beforeEach(function() {
beforeEach(function() {
initComponent.apply(this,
[0, 5000]
);
initComponent.apply(this,
{ timeEstimate: 0, timeSpent: 5000 }
);
});
});
// Look for the value
// Look for the value
it('should only show the "Spent only" pane when time_estimate is falsey and time_spent is truthy', function() {
it('should only show the "Spent only" pane when timeEstimate is falsey and time_spent is truthy', function() {
const $spentOnlyPane = this.timeTracker.$el.querySelector('.time-tracking-spend-only-pane');
Vue.nextTick(() => {
const $spentOnlyPane = this.timeTracker.$el.querySelector('.time-tracking-spend-only-pane');
expect(this.timeTracker.showSpentOnlyState).toBe(true);
expect(this.timeTracker.showSpentOnlyState).toBe(true);
expect($spentOnlyPane).toBeVisible();
expect($spentOnlyPane).toBeVisible();
});
});
});
it('should display the human readable version of time spent', function() {
it('should display the human readable version of time spent', function() {
const spentText = this.timeTracker.$el.querySelector('.time-tracking-spend-only-pane').innerText;
Vue.nextTick(() => {
const correctText = 'Spent: 1h 23m';
const spentText = this.timeTracker.$el.querySelector('.time-tracking-spend-only-pane').innerText;
const correctText = 'Spent: 1h 23m';
expect(spentText).toBe(correctText);
expect(spentText).toBe(correctText);
});
});
});
});
});
describe('No time tracking pane', function() {
describe('No time tracking pane', function() {
beforeEach(function() {
beforeEach(function() {
initComponent.apply(this,
[0, 0, 0, 0]
);
initComponent.apply(this,
{ timeEstimate: 0, timeSpent: 0, timeEstimateHuman: 0, timeSpentHuman: 0 }
);
});
});
it('should only show the "No time tracking" pane when both time_estimate and time_spent are falsey', function() {
it('should only show the "No time tracking" pane when both timeEstimate and time_spent are falsey', function() {
const $noTrackingPane = this.timeTracker.$el.querySelector('.time-tracking-no-tracking-pane');
Vue.nextTick(() => {
const noTrackingText =$noTrackingPane.innerText;
const $noTrackingPane = this.timeTracker.$el.querySelector('.time-tracking-no-tracking-pane');
const correctText = 'No estimate or time spent';
const noTrackingText =$noTrackingPane.innerText;
const correctText = 'No estimate or time spent';
expect(this.timeTracker.showNoTimeTrackingState).toBe(true);
expect(this.timeTracker.showNoTimeTrackingState).toBe(true);
expect($noTrackingPane).toBeVisible();
expect($noTrackingPane).toBeVisible();
expect(noTrackingText).toBe(correctText);
expect(noTrackingText).toBe(correctText);
});
});
});
});
});
describe("Help pane", function() {
describe("Help pane", function() {
beforeEach(function() {
beforeEach(function() {
initComponent.apply(this,
[0, 0]
);
initComponent.apply(this,
{ timeEstimate: 0, timeSpent: 0 }
);
});
});
it('should not show the "Help" pane by default', function() {
it('should not show the "Help" pane by default', function() {
const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state');
expect(this.timeTracker.showHelpState).toBe(false);
expect($helpPane).toBeNull();
});
it('should link to the correct documentation', function(done) {
const correctUrl = '/help/workflow/time_tracking.md'
$(this.timeTracker.$el).find('.help-button').click();
Vue.nextTick(() => {
Vue.nextTick(() => {
const currentHref = $(this.timeTracker.$el).find('.learn-more-button').attr('href');
const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state');
expect(currentHref).toBe(correctUrl);
done();
});
expect(this.timeTracker.showHelpState).toBe(false);
expect($helpPane).toBeNull();
});
});
});
it('should show the "Help" pane when help button is clicked', function(done) {
it('should show the "Help" pane when help button is clicked', function(done) {
$(this.timeTracker.$el).find('.help-button').click();
Vue.nextTick(() => {
Vue.nextTick(() => {
const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state');
$(this.timeTracker.$el).find('.help-button').click();
expect(this.timeTracker.showHelpState).toBe(true);
expect($helpPane).toBeVisible();
setTimeout(() => {
done();
const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state');
expect(this.timeTracker.showHelpState).toBe(true);
expect($helpPane).toBeVisible();
done();
}, 100);
});
});
});
});
it('should not show the "Help" pane when help button is clicked and then closed', function(done) {
it('should not show the "Help" pane when help button is clicked and then closed', function(done) {
$(this.timeTracker.$el).find('.help-button').click();
Vue.nextTick(() => {
$(this.timeTracker.$el).find('.help-button').click();
setTimeout(() => {
setTimeout(() => {
$(this.timeTracker.$el).find('.close-help-button').click();
$(this.timeTracker.$el).find('.close-help-button').click();
setTimeout(() => {
setTimeout(() => {
const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state');
const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state');
expect(this.timeTracker.showHelpState).toBe(false);
expect(this.timeTracker.showHelpState).toBe(false);
expect($helpPane).toBeNull();
expect($helpPane).toBeNull();
done();
done();
}, 1000);
}, 1000);
}, 1000);
}
, 1000
);
});
});
});
});
});
});
});
...
...
spec/support/time_tracking_shared_examples.rb
View file @
bfb5ebd6
...
@@ -65,6 +65,14 @@ shared_examples 'issuable time tracker' do
...
@@ -65,6 +65,14 @@ shared_examples 'issuable time tracker' do
expect
(
page
).
not_to
have_content
'Learn more'
expect
(
page
).
not_to
have_content
'Learn more'
end
end
end
end
it
'displays the correct help url'
do
page
.
within
'#issuable-time-tracker'
do
find
(
'.help-button'
).
click
expect
(
find_link
(
'Learn more'
)[
:href
]).
to
eq
(
'/help/workflow/time_tracking.md'
)
end
end
end
end
def
submit_time
(
slash_command
)
def
submit_time
(
slash_command
)
...
...
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