Skip to content

Commit be60fac

Browse files
author
Matthew Sessions
committed
Move collaborations tool to own page
Fixes PLAT-1654 & PLAT-1655 Test Plan: - With new collaborations feature flag, and lti_tool_provider_example set up - Go the new collaborations page through the course nav - Click the + Collaboration button (if you have multiple collaboration lti tools set up, click on one of the options) - This should take you to a new page that loads - lti tool in an iframe - Going back should take you back to the collaborations index page - Clicking on the edit link of a collaboration should behave similar to the + Collaboration button, just taking you to the edit portion of the lti tool Change-Id: I2d13ef8d1eeafe3230c157485c15060c0f80f8d4 Reviewed-on: https://gerrit.instructure.com/84820 Tested-by: Jenkins Reviewed-by: Andrew Butterfield <abutterfield@instructure.com> QA-Review: Brad Humphrey <brad@instructure.com> Product-Review: Matthew Sessions <msessions@instructure.com>
1 parent 0612a4d commit be60fac

13 files changed

Lines changed: 132 additions & 127 deletions

app/jsx/collaborations/Collaboration.jsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ define([
1414
this.openConfirmation = this.openConfirmation.bind(this);
1515
this.closeConfirmation = this.closeConfirmation.bind(this);
1616
this.deleteCollaboration = this.deleteCollaboration.bind(this);
17-
this.openModal = this.openModal.bind(this);
1817
}
1918

2019
openConfirmation () {
@@ -36,16 +35,11 @@ define([
3635
store.dispatch(this.props.deleteCollaboration(context, contextId, this.props.collaboration.id));
3736
}
3837

39-
openModal (e, url) {
40-
e.preventDefault()
41-
this.props.openModal(url)
42-
}
43-
4438
render () {
4539
let { collaboration } = this.props;
4640
let [context, contextId] = splitAssetString(ENV.context_asset_string);
4741

48-
let editUrl = `/${context}/${contextId}/external_tools/retrieve?content_item_id=${collaboration.id}&placement=collaboration&url=${collaboration.update_url}`
42+
let editUrl = `/${context}/${contextId}/lti_collaborations/external_tools/retrieve?content_item_id=${collaboration.id}&placement=collaboration&url=${collaboration.update_url}&display=borderless`
4943

5044
return (
5145
<div ref="wrapper" className='Collaboration'>
@@ -62,7 +56,7 @@ define([
6256
<DatetimeDisplay datetime={collaboration.updated_at} format='%b %d, %l:%M %p' />
6357
</div>
6458
<div className='Collaboration-actions'>
65-
<a className='icon-edit' href={editUrl} rel='external' onClick={(e) => this.openModal(e, `${editUrl}&display=borderless`)}>
59+
<a className='icon-edit' href={editUrl}>
6660
<span className='screenreader-only'>{i18n.t('Edit Collaboration')}</span>
6761
</a>
6862
<button ref='deleteButton' className='btn btn-link' onClick={this.openConfirmation}>

app/jsx/collaborations/CollaborationsApp.jsx

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ define([
99
class CollaborationsApp extends React.Component {
1010
constructor (props) {
1111
super(props);
12-
$(window).on('externalContentReady', (e, data) => dispatch(props.actions.externalContentReady(e, data)));
13-
14-
this.state = { isModalOpen: false }
15-
this.openModal = this.openModal.bind(this)
1612
}
1713

1814
static propTypes: {
@@ -22,19 +18,6 @@ define([
2218

2319
componentWillReceiveProps (nextProps) {
2420
let { createCollaborationPending, createCollaborationSuccessful } = nextProps.applicationState.createCollaboration
25-
26-
if (!createCollaborationPending && createCollaborationSuccessful) {
27-
this.setState({
28-
isModalOpen: false
29-
})
30-
}
31-
}
32-
33-
openModal (url) {
34-
this.setState({
35-
isModalOpen: true,
36-
modalUrl: url
37-
})
3821
}
3922

4023
render () {
@@ -44,18 +27,11 @@ define([
4427
<div className='CollaborationsApp'>
4528
<CollaborationsNavigation
4629
ltiCollaborators={this.props.applicationState.ltiCollaborators}
47-
onItemClicked={this.openModal} />
48-
30+
/>
4931
{list.length
50-
? <CollaborationsList collaborationsState={this.props.applicationState.listCollaborations} getCollaborations={this.props.actions.getCollaborations} deleteCollaboration={this.props.actions.deleteCollaboration} openModal={this.openModal} />
32+
? <CollaborationsList collaborationsState={this.props.applicationState.listCollaborations} getCollaborations={this.props.actions.getCollaborations} deleteCollaboration={this.props.actions.deleteCollaboration} />
5133
: <GettingStartedCollaborations ltiCollaborators={this.props.applicationState.ltiCollaborators}/>
5234
}
53-
<Modal
54-
className='CollaborationsModal'
55-
isOpen={this.state.isModalOpen}
56-
>
57-
<iframe className='Collaborations-iframe' src={this.state.modalUrl}></iframe>
58-
</Modal>
5935
</div>
6036
);
6137
}

app/jsx/collaborations/CollaborationsList.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ define([
2424
hasMore={!!this.props.collaborationsState.nextPage}
2525
loadMore={this.loadMoreCollaborations} >
2626
{this.props.collaborationsState.list.map((c, index) => (
27-
<Collaboration ref={`collaboration-${index}`} key={c.id} collaboration={c} deleteCollaboration={this.props.deleteCollaboration} openModal={this.props.openModal} />
27+
<Collaboration ref={`collaboration-${index}`} key={c.id} collaboration={c} deleteCollaboration={this.props.deleteCollaboration} />
2828
))}
2929
</LoadMore>
3030
</div>
@@ -36,7 +36,6 @@ define([
3636
collaborationsState: React.PropTypes.object.isRequired,
3737
deleteCollaboration: React.PropTypes.func.isRequired,
3838
getCollaborations: React.PropTypes.func.isRequired,
39-
openModal: React.PropTypes.func
4039
};
4140

4241
return CollaborationsList;

app/jsx/collaborations/CollaborationsNavigation.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ define([
99
renderNewCollaborationsDropDown () {
1010
if(this.props.ltiCollaborators.ltiCollaboratorsData.length > 0) {
1111
return (<NewCollaborationsDropDown
12-
ltiCollaborators={this.props.ltiCollaborators.ltiCollaboratorsData}
13-
onItemClicked={this.props.onItemClicked} />)
12+
ltiCollaborators={this.props.ltiCollaborators.ltiCollaboratorsData} />)
1413
}
1514
}
1615

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
define([
2+
'react'
3+
], (React) => {
4+
let main = document.querySelector('#main')
5+
6+
class CollaborationsToolLaunch extends React.Component {
7+
constructor (props) {
8+
super(props)
9+
this.state = {height: 500}
10+
11+
this.setHeight = this.setHeight.bind(this)
12+
}
13+
14+
componentDidMount () {
15+
this.setHeight()
16+
window.addEventListener('resize', this.setHeight)
17+
}
18+
19+
componentWillUnMount () {
20+
window.removeEventListener('resize', this.setHeight)
21+
}
22+
23+
setHeight () {
24+
this.setState({
25+
height: main.getBoundingClientRect().height - 48
26+
})
27+
}
28+
29+
render () {
30+
return (
31+
<div className='CollaborationsToolLaunch' style={{height: this.state.height}}>
32+
<iframe
33+
className='tool_launch'
34+
src={this.props.launchUrl}
35+
></iframe>
36+
</div>
37+
)
38+
}
39+
}
40+
41+
return CollaborationsToolLaunch
42+
})

app/jsx/collaborations/NewCollaborationsDropDown.jsx

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ define([
66
class NewCollaborationsDropDown extends React.Component {
77
constructor (props) {
88
super(props);
9-
this.openModal = this.openModal.bind(this)
10-
}
11-
12-
openModal (e, itemUrl) {
13-
e.preventDefault()
14-
this.props.onItemClicked(itemUrl)
159
}
1610

1711
render () {
@@ -21,27 +15,26 @@ define([
2115
<div className="al-dropdown__container create-collaborations-dropdown">
2216
{hasOne
2317
?
24-
<button
25-
className="Button Button--primary"
26-
aria-label={I18n.t('Add Collaboration')}
27-
onClick={(e) => this.openModal(e, `/${context}/${contextId}/external_tools/${this.props.ltiCollaborators[0].id}?launch_type=collaboration&display=borderless`)}
18+
<a
19+
className="Button Button--primary"
20+
aria-label={I18n.t('Add Collaboration')}
21+
href={`/${context}/${contextId}/lti_collaborations/external_tools/${this.props.ltiCollaborators[0].id}?launch_type=collaboration&display=borderless`}
2822
>
29-
{I18n.t('+ Collaboration')}
30-
</button>
23+
{I18n.t('+ Collaboration')}
24+
</a>
3125
:
3226
<div>
3327
<button className="al-trigger Button Button--primary" aria-label={I18n.t('Add Collaboration')} role="button" href="#">{I18n.t('+ Collaboration')}</button>
3428
<ul className="al-options" role="menu" tabIndex="0" aria-hidden="true" aria-expanded="false" aria-activedescendant="new-collaborations-dropdown">
3529
{
3630
this.props.ltiCollaborators.map(ltiCollaborator => {
37-
let itemUrl = `/${context}/${contextId}/external_tools/${ltiCollaborator.id}?launch_type=collaboration`
31+
let itemUrl = `lti_collaborations/external_tools/${ltiCollaborator.id}?launch_type=collaboration&display=borderless`
3832
return(
3933
<li key={ltiCollaborator.id}>
4034
<a
4135
href={itemUrl}
4236
rel="external"
4337
role="menuitem"
44-
onClick={(e) => this.openModal(e, `${itemUrl}&display=borderless`)}
4538
>
4639
{ltiCollaborator.name}
4740
</a>

app/jsx/collaborations/actions/collaborationsActions.jsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ define([
33
'i18n!course_wizard',
44
'axios',
55
'compiled/str/splitAssetString',
6-
'jsx/shared/parseLinkHeader'
7-
], ($, I18n, axios, splitAssetString, parseLinkHeader) => {
6+
'jsx/shared/parseLinkHeader',
7+
'page'
8+
], ($, I18n, axios, splitAssetString, parseLinkHeader, page) => {
89
const actions = {}
910

1011
actions.LIST_COLLABORATIONS_START = 'LIST_COLLABORATIONS_START';
11-
actions.listCollaborationsStart = () => ({ type: actions.LIST_COLLABORATIONS_START });
12+
actions.listCollaborationsStart = (payload) => ({ type: actions.LIST_COLLABORATIONS_START, payload });
1213

1314
actions.LIST_COLLABORATIONS_SUCCESSFUL = 'LIST_COLLABORATIONS_SUCCESSFUL';
1415
actions.listCollaborationsSuccessful = (payload) => ({ type: actions.LIST_COLLABORATIONS_SUCCESSFUL, payload});
@@ -52,9 +53,9 @@ define([
5253
actions.UPDATE_COLLABORATION_FAILED = 'UPDATE_COLLABORATION_FAILED'
5354
actions.updateCollaborationFailed = (error) => ({ type: actions.UPDATE_COLLABORATION_FAILED, payload: error, error: true })
5455

55-
actions.getCollaborations = (url) => {
56+
actions.getCollaborations = (url, newSearch) => {
5657
return (dispatch, getState) => {
57-
dispatch(actions.listCollaborationsStart());
58+
dispatch(actions.listCollaborationsStart(newSearch));
5859

5960
axios.get(url)
6061
.then((response) => {
@@ -105,7 +106,7 @@ define([
105106
}})
106107
.then(({ data }) => {
107108
dispatch(actions.createCollaborationSuccessful(data))
108-
dispatch(actions.getCollaborations(`/api/v1/${context}/${contextId}/collaborations`))
109+
page(`/${context}/${contextId}/lti_collaborations`)
109110
})
110111
.catch(error => {
111112
dispatch(actions.createCollaborationFailed(error))
@@ -121,6 +122,7 @@ define([
121122
'Accept': 'application/json'
122123
}})
123124
.then(({ collaboration }) => {
125+
page(`/${context}/${contextId}/lti_collaborations`)
124126
dispatch(actions.updateCollaborationSuccessful(collaboration))
125127
})
126128
.catch(error => {

app/jsx/collaborations/reducers/listCollaborationsReducer.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ define([
1313
[ACTION_NAMES.LIST_COLLABORATIONS_START]: (state, action) => {
1414
return {
1515
...state,
16+
list: action.payload ? [] : state.list,
1617
listCollaborationsPending: true,
1718
listCollaborationsSuccessful: false,
1819
listCollaborationsError: null

app/jsx/collaborations/router.jsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,41 @@
11
define([
22
'react',
3+
'react-dom',
34
'page',
45
'qs',
56
'redux',
67
'jsx/collaborations/CollaborationsApp',
8+
'jsx/collaborations/CollaborationsToolLaunch',
79
'jsx/collaborations/actions/collaborationsActions',
810
'jsx/collaborations/store/store',
911
'compiled/str/splitAssetString'
10-
], function (React, page, qs, redux, CollaborationsApp, actions, store, splitAssetString) {
12+
], function (React, ReactDOM, page, qs, redux, CollaborationsApp, CollaborationsToolLaunch, actions, store, splitAssetString) {
13+
14+
$(window).on('externalContentReady', (e, data) => store.dispatch(actions.externalContentReady(e, data)));
15+
16+
let unsubscribe
1117
/**
1218
* Route Handlers
1319
*/
1420
function renderShowCollaborations (ctx) {
1521
store.dispatch(actions.getLTICollaborators(ctx.params.context, ctx.params.contextId));
16-
store.dispatch(actions.getCollaborations(`/api/v1/${ctx.params.context}/${ctx.params.contextId}/collaborations`));
22+
store.dispatch(actions.getCollaborations(`/api/v1/${ctx.params.context}/${ctx.params.contextId}/collaborations`, true));
1723

1824
let view = () => {
1925
let state = store.getState();
20-
React.render(<CollaborationsApp applicationState={state} actions={actions} />, document.getElementById('content'));
26+
ReactDOM.render(<CollaborationsApp applicationState={state} actions={actions} />, document.getElementById('content'));
2127
};
22-
store.subscribe(view);
28+
unsubscribe = store.subscribe(view);
2329
view();
2430
}
2531

32+
function renderLaunchTool (ctx) {
33+
let view = () => {
34+
ReactDOM.render(<CollaborationsToolLaunch launchUrl={ctx.path.replace('/lti_collaborations', '')} />, document.getElementById('content'))
35+
}
36+
view()
37+
}
38+
2639
/**
2740
* Middlewares
2841
*/
@@ -36,7 +49,14 @@ define([
3649
* Route Configuration
3750
*/
3851
page('*', parseQueryString); // Middleware to parse querystring to object
52+
3953
page('/:context(courses|groups)/:contextId/lti_collaborations', renderShowCollaborations);
54+
page.exit('/:context(courses|groups)/:contextId/lti_collaborations', (ctx, next) => {
55+
unsubscribe()
56+
next()
57+
})
58+
59+
page('/:context(courses|groups)/:contextId/lti_collaborations/external_tools*', renderLaunchTool);
4060

4161
return {
4262
start () {
Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/* prevent double scroll bar when modal is open and the body is scrollable */
2-
.collaborations.ReactModal__Body--open {
3-
overflow: hidden;
4-
}
5-
61
.GettingStartedCollaborations {
72
width: 600px;
83
margin: 0 auto;
@@ -25,22 +20,3 @@
2520
margin: 0 auto;
2621
line-height: 100px;
2722
}
28-
29-
.CollaborationsModal {
30-
position: absolute;
31-
top: 0;
32-
left: 0;
33-
right: 0;
34-
bottom: 0;
35-
background: #fff;
36-
overflow: auto;
37-
outline: none;
38-
padding: 0;
39-
overflow-y: hidden;
40-
}
41-
42-
.Collaborations-iframe {
43-
width: 100%;
44-
height: 100%;
45-
border: none;
46-
}

0 commit comments

Comments
 (0)