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
73ed71f5
Commit
73ed71f5
authored
Feb 08, 2018
by
Kushal Pandya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Roadmap App Component
parent
84629f73
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
316 additions
and
0 deletions
+316
-0
ee/app/assets/javascripts/roadmap/components/app.vue
ee/app/assets/javascripts/roadmap/components/app.vue
+132
-0
spec/javascripts/roadmap/components/app_spec.js
spec/javascripts/roadmap/components/app_spec.js
+184
-0
No files found.
ee/app/assets/javascripts/roadmap/components/app.vue
0 → 100644
View file @
73ed71f5
<
script
>
import
_
from
'
underscore
'
;
import
Flash
from
'
~/flash
'
;
import
{
s__
}
from
'
~/locale
'
;
import
loadingIcon
from
'
~/vue_shared/components/loading_icon.vue
'
;
import
epicsListEmpty
from
'
./epics_list_empty.vue
'
;
import
roadmapShell
from
'
./roadmap_shell.vue
'
;
export
default
{
components
:
{
loadingIcon
,
epicsListEmpty
,
roadmapShell
,
},
props
:
{
store
:
{
type
:
Object
,
required
:
true
,
},
service
:
{
type
:
Object
,
required
:
true
,
},
emptyStateIllustrationPath
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
isLoading
:
true
,
isEpicsListEmpty
:
false
,
hasError
:
false
,
handleResizeThrottled
:
{},
};
},
computed
:
{
epics
()
{
return
this
.
store
.
getEpics
();
},
timeframe
()
{
return
this
.
store
.
getTimeframe
();
},
timeframeStart
()
{
return
this
.
timeframe
[
0
];
},
timeframeEnd
()
{
const
last
=
this
.
timeframe
.
length
-
1
;
return
this
.
timeframe
[
last
];
},
currentGroupId
()
{
return
this
.
store
.
getCurrentGroupId
();
},
showRoadmap
()
{
return
!
this
.
hasError
&&
!
this
.
isLoading
&&
!
this
.
isEpicsListEmpty
;
},
},
mounted
()
{
this
.
fetchEpics
();
this
.
handleResizeThrottled
=
_
.
throttle
(
this
.
handleResize
,
600
);
window
.
addEventListener
(
'
resize
'
,
this
.
handleResizeThrottled
,
false
);
},
beforeDestroy
()
{
window
.
removeEventListener
(
'
resize
'
,
this
.
handleResizeThrottled
,
false
);
},
methods
:
{
fetchEpics
()
{
this
.
hasError
=
false
;
this
.
service
.
getEpics
()
.
then
(
res
=>
res
.
data
)
.
then
((
epics
)
=>
{
this
.
isLoading
=
false
;
if
(
epics
.
length
)
{
this
.
store
.
setEpics
(
epics
);
}
else
{
this
.
isEpicsListEmpty
=
true
;
}
})
.
catch
(()
=>
{
this
.
isLoading
=
false
;
this
.
hasError
=
true
;
Flash
(
s__
(
'
GroupRoadmap|Something went wrong while fetching epics
'
));
});
},
/**
* Roadmap view works with absolute sizing and positioning
* of following child components of RoadmapShell;
*
* - RoadmapTimelineSection
* - TimelineTodayIndicator
* - EpicItemTimeline
*
* And hence when window is resized, any size attributes passed
* down to child components are no longer valid, so best approach
* to refresh entire app is to re-render it on resize, hence
* we toggle `isLoading` variable which is bound to `RoadmapShell`.
*/
handleResize
()
{
this
.
isLoading
=
true
;
// We need to debounce the toggle to make sure loading animation
// shows up while app is being rerendered.
_
.
debounce
(()
=>
{
this
.
isLoading
=
false
;
},
200
)();
},
},
};
</
script
>
<
template
>
<div
class=
"roadmap-container"
>
<loading-icon
class=
"loading-animation prepend-top-20 append-bottom-20"
size=
"2"
v-if=
"isLoading"
:label=
"s__('GroupRoadmap|Loading roadmap')"
/>
<roadmap-shell
v-if=
"showRoadmap"
:epics=
"epics"
:timeframe=
"timeframe"
:current-group-id=
"currentGroupId"
/>
<epics-list-empty
v-if=
"isEpicsListEmpty"
:timeframe-start=
"timeframeStart"
:timeframe-end=
"timeframeEnd"
:empty-state-illustration-path=
"emptyStateIllustrationPath"
/>
</div>
</
template
>
spec/javascripts/roadmap/components/app_spec.js
0 → 100644
View file @
73ed71f5
import
Vue
from
'
vue
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
appComponent
from
'
ee/roadmap/components/app.vue
'
;
import
RoadmapStore
from
'
ee/roadmap/store/roadmap_store
'
;
import
RoadmapService
from
'
ee/roadmap/service/roadmap_service
'
;
import
{
mockTimeframe
,
mockGroupId
,
epicsPath
,
rawEpics
,
mockSvgPath
}
from
'
../mock_data
'
;
import
mountComponent
from
'
../../helpers/vue_mount_component_helper
'
;
const
createComponent
=
()
=>
{
const
Component
=
Vue
.
extend
(
appComponent
);
const
timeframe
=
mockTimeframe
;
const
store
=
new
RoadmapStore
(
mockGroupId
,
timeframe
);
const
service
=
new
RoadmapService
(
epicsPath
);
return
mountComponent
(
Component
,
{
store
,
service
,
emptyStateIllustrationPath
:
mockSvgPath
,
});
};
describe
(
'
AppComponent
'
,
()
=>
{
let
vm
;
beforeEach
(()
=>
{
vm
=
createComponent
();
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
describe
(
'
data
'
,
()
=>
{
it
(
'
returns default data props
'
,
()
=>
{
expect
(
vm
.
isLoading
).
toBe
(
true
);
expect
(
vm
.
isEpicsListEmpty
).
toBe
(
false
);
expect
(
vm
.
hasError
).
toBe
(
false
);
expect
(
vm
.
handleResizeThrottled
).
toBeDefined
();
});
});
describe
(
'
computed
'
,
()
=>
{
describe
(
'
epics
'
,
()
=>
{
it
(
'
returns array of epics
'
,
()
=>
{
expect
(
Array
.
isArray
(
vm
.
epics
)).
toBe
(
true
);
});
});
describe
(
'
timeframe
'
,
()
=>
{
it
(
'
returns array of timeframe
'
,
()
=>
{
expect
(
Array
.
isArray
(
vm
.
timeframe
)).
toBe
(
true
);
});
});
describe
(
'
timeframeStart
'
,
()
=>
{
it
(
'
returns first item of timeframe array
'
,
()
=>
{
expect
(
vm
.
timeframeStart
instanceof
Date
).
toBe
(
true
);
});
});
describe
(
'
timeframeEnd
'
,
()
=>
{
it
(
'
returns last item of timeframe array
'
,
()
=>
{
expect
(
vm
.
timeframeEnd
instanceof
Date
).
toBe
(
true
);
});
});
describe
(
'
currentGroupId
'
,
()
=>
{
it
(
'
returns current group Id
'
,
()
=>
{
expect
(
vm
.
currentGroupId
).
toBe
(
mockGroupId
);
});
});
describe
(
'
showRoadmap
'
,
()
=>
{
it
(
'
returns true if `isLoading`, `isEpicsListEmpty` and `hasError` are all `false`
'
,
()
=>
{
vm
.
isLoading
=
false
;
vm
.
isEpicsListEmpty
=
false
;
vm
.
hasError
=
false
;
expect
(
vm
.
showRoadmap
).
toBe
(
true
);
});
it
(
'
returns false if either of `isLoading`, `isEpicsListEmpty` and `hasError` is `true`
'
,
()
=>
{
vm
.
isLoading
=
true
;
vm
.
isEpicsListEmpty
=
false
;
vm
.
hasError
=
false
;
expect
(
vm
.
showRoadmap
).
toBe
(
false
);
vm
.
isLoading
=
false
;
vm
.
isEpicsListEmpty
=
true
;
vm
.
hasError
=
false
;
expect
(
vm
.
showRoadmap
).
toBe
(
false
);
vm
.
isLoading
=
false
;
vm
.
isEpicsListEmpty
=
false
;
vm
.
hasError
=
true
;
expect
(
vm
.
showRoadmap
).
toBe
(
false
);
});
});
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
fetchEpics
'
,
()
=>
{
let
mock
;
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
document
.
body
.
innerHTML
+=
'
<div class="flash-container"></div>
'
;
});
afterEach
(()
=>
{
mock
.
restore
();
document
.
querySelector
(
'
.flash-container
'
).
remove
();
});
it
(
'
calls service.getEpics and sets response to the store on success
'
,
(
done
)
=>
{
mock
.
onGet
(
vm
.
service
.
epicsPath
).
reply
(
200
,
rawEpics
);
spyOn
(
vm
.
store
,
'
setEpics
'
);
vm
.
fetchEpics
();
expect
(
vm
.
hasError
).
toBe
(
false
);
setTimeout
(()
=>
{
expect
(
vm
.
isLoading
).
toBe
(
false
);
expect
(
vm
.
store
.
setEpics
).
toHaveBeenCalledWith
(
rawEpics
);
done
();
},
0
);
});
it
(
'
calls service.getEpics and sets `isEpicsListEmpty` to true if response is empty
'
,
(
done
)
=>
{
mock
.
onGet
(
vm
.
service
.
epicsPath
).
reply
(
200
,
[]);
spyOn
(
vm
.
store
,
'
setEpics
'
);
vm
.
fetchEpics
();
expect
(
vm
.
isEpicsListEmpty
).
toBe
(
false
);
setTimeout
(()
=>
{
expect
(
vm
.
isEpicsListEmpty
).
toBe
(
true
);
expect
(
vm
.
store
.
setEpics
).
not
.
toHaveBeenCalled
();
done
();
},
0
);
});
it
(
'
calls service.getEpics and sets `hasError` to true and shows flash message if request failed
'
,
(
done
)
=>
{
mock
.
onGet
(
vm
.
service
.
epicsPath
).
reply
(
500
,
{});
vm
.
fetchEpics
();
expect
(
vm
.
hasError
).
toBe
(
false
);
setTimeout
(()
=>
{
expect
(
vm
.
hasError
).
toBe
(
true
);
expect
(
document
.
querySelector
(
'
.flash-text
'
).
innerText
.
trim
()).
toBe
(
'
Something went wrong while fetching epics
'
);
done
();
},
0
);
});
});
});
describe
(
'
mounted
'
,
()
=>
{
it
(
'
binds window resize event listener
'
,
()
=>
{
spyOn
(
window
,
'
addEventListener
'
);
const
vmX
=
createComponent
();
expect
(
vmX
.
handleResizeThrottled
).
toBeDefined
();
expect
(
window
.
addEventListener
).
toHaveBeenCalledWith
(
'
resize
'
,
vmX
.
handleResizeThrottled
,
false
);
vmX
.
$destroy
();
});
});
describe
(
'
beforeDestroy
'
,
()
=>
{
it
(
'
unbinds window resize event listener
'
,
()
=>
{
spyOn
(
window
,
'
removeEventListener
'
);
const
vmX
=
createComponent
();
vmX
.
$destroy
();
expect
(
window
.
removeEventListener
).
toHaveBeenCalledWith
(
'
resize
'
,
vmX
.
handleResizeThrottled
,
false
);
});
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders roadmap container with class `roadmap-container`
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
roadmap-container
'
)).
toBe
(
true
);
});
});
});
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