setup blueprint course sidebar

refs MC-145

test plan:
- navigate to a blueprint course
- note the blue line / bar and button on the right side
- click the button
- a tray sidebar should open from the right side of the screen
- click the close button on the tray
- note that the tray closes
- note that the sidebar shows up on every page in a blueprint course
- note that the sidebar does not show up in non-blueprint course pages
  or any other pages throughout canvas

Change-Id: I4dcadb82e32bf2af01b25ed3b6167ecffc594dd8
Reviewed-on: https://gerrit.instructure.com/107373
Reviewed-by: Ed Schiebel <eschiebel@instructure.com>
Tested-by: Jenkins
QA-Review: Heath Hales <hhales@instructure.com>
Product-Review: Felix Milea-Ciobanu <fmileaciobanu@instructure.com>
This commit is contained in:
Felix Milea-Ciobanu 2017-04-03 21:09:23 -06:00
parent 62c2cb5dfc
commit 0d7898fe11
7 changed files with 175 additions and 1 deletions

View File

@ -269,6 +269,11 @@ class ApplicationController < ActionController::Base
end
helper_method :set_master_course_js_env_data
def should_load_master_course_sidebar?
@context && @context.is_a?(Course) && MasterCourses::MasterTemplate.is_master_course?(@context) && @context.grants_right?(@current_user, :manage)
end
helper_method :should_load_master_course_sidebar?
def editing_restricted?(content, edit_type=:any)
return false unless master_courses? && content.respond_to?(:editing_restricted?)
content.editing_restricted?(edit_type)

View File

@ -0,0 +1,9 @@
import App from 'jsx/course_blueprint_settings/sidebar'
const wrapper = document.getElementById('wrapper')
const root = document.createElement('div')
root.className = 'bcs__root'
wrapper.appendChild(root)
const app = new App(root)
app.render()

View File

@ -0,0 +1,60 @@
import I18n from 'i18n!blueprint_course_sidebar'
import React, { Component } from 'react'
import Tray from 'instructure-ui/lib/components/Tray'
import Button from 'instructure-ui/lib/components/Button'
import Typography from 'instructure-ui/lib/components/Typography'
import Heading from 'instructure-ui/lib/components/Heading'
import IconCopyLine from 'instructure-icons/react/Line/IconCopyLine'
import IconXSolid from 'instructure-icons/react/Solid/IconXSolid'
export default class BlueprintCourseSidebar extends Component {
constructor (props) {
super(props)
this.state = {
isOpen: false,
}
}
handleOpen = () => {
this.setState({ isOpen: true })
}
handleClose = () => {
this.setState({ isOpen: false })
}
render () {
return (
<div className="bcs__wrapper">
<div className="bcs__trigger">
<Button variant="icon" onClick={this.handleOpen}>
<Typography color="primary-inverse" size="large">
<IconCopyLine title={I18n.t('Open sidebar')} />
</Typography>
</Button>
</div>
<Tray
label={I18n.t('Blueprint Settings')}
isDismissable={false}
isOpen={this.state.isOpen}
placement="right"
>
<div className="bcs__content">
<header className="bcs__header">
<Heading color="primary-inverse" level="h3">
<div className="bcs__close-wrapper">
<Button variant="icon" onClick={this.handleClose} ref={(c) => { this.closeBtn = c }}>
<Typography color="primary-inverse" size="small">
<IconXSolid title={I18n.t('Close sidebar')} />
</Typography>
</Button>
</div>
<IconCopyLine />&nbsp;{I18n.t('Blueprint')}
</Heading>
</header>
</div>
</Tray>
</div>
)
}
}

View File

@ -0,0 +1,16 @@
import React from 'react'
import ReactDOM from 'react-dom'
import Sidebar from './components/BlueprintCourseSidebar'
export default class BlueprintCourseSidebar {
constructor (root) {
this.root = root
}
render () {
ReactDOM.render(
<Sidebar />,
this.root)
}
}

View File

@ -0,0 +1,41 @@
@import "base/environment";
.bcs__trigger {
position: fixed;
top: 0;
right: 0;
padding: 10px 3px;
border-bottom-left-radius: 5px;
background-color: $ic-brand-primary;
box-shadow: -1px 1px 2px 0 rgba(0,0,0,.2);
&:after {
content: '';
display: block;
position: fixed;
top: 58px;
right: 0;
bottom: 0;
width: 8px;
background-color: $ic-brand-primary;
box-shadow: -1px 0 1px 0 rgba(0,0,0,.2)
}
}
.bcs__content {
width: 270px;
}
.bcs__header {
background: $ic-brand-primary;
position: relative;
text-align: center;
padding: 1.2em 0;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .2)
}
.bcs__close-wrapper {
position: absolute;
top: 0.5em;
left: 0.5em;
}

View File

@ -56,6 +56,10 @@
content_for :head, include_common_stylesheets
if should_load_master_course_sidebar?
js_bundle :blueprint_course_sidebar
css_bundle :blueprint_course_sidebar
end
-%>
<%= render :partial => "layouts/head" %>
<body class="<%= (@body_classes).uniq.join(" ") %>">
@ -198,7 +202,6 @@
<div class="NewUserTutorialTray__Container"></div>
<% end %>
<%= render :partial => 'layouts/foot', :locals => { :include_common_bundle => true } %>
</div> <!-- #application -->
</body>
</html>

View File

@ -0,0 +1,40 @@
import React from 'react'
import * as enzyme from 'enzyme'
import BlueprintCourseSidebar from 'jsx/course_blueprint_settings/components/BlueprintCourseSidebar'
QUnit.module('BlueprintCourseSidebar component')
const defaultProps = () => ({
})
test('renders the BlueprintCourseSidebar component', () => {
const tree = enzyme.shallow(<BlueprintCourseSidebar {...defaultProps()} />)
const node = tree.find('.bcs__wrapper')
ok(node.exists())
})
test('clicking open button sets isOpen to true', () => {
const props = defaultProps()
const tree = enzyme.mount(<BlueprintCourseSidebar {...props} />)
const button = tree.find('.bcs__trigger button')
button.at(0).simulate('click')
const instance = tree.instance()
equal(instance.state.isOpen, true)
})
test('clicking close button sets isOpen to false', () => {
const props = defaultProps()
const tree = enzyme.mount(<BlueprintCourseSidebar {...props} />)
const instance = tree.instance()
instance.setState({ isOpen: true })
const closeBtn = instance.closeBtn
const btnWrapper = new enzyme.ReactWrapper(closeBtn, closeBtn)
btnWrapper.at(0).simulate('click')
equal(instance.state.isOpen, false)
})