Merge pull request #418 from sharelatex/pr-review-panel-onboarding

Pr review panel onboarding
This commit is contained in:
James Allen 2017-02-14 15:00:39 +01:00 committed by GitHub
commit 4dbc2c3066
18 changed files with 274 additions and 136 deletions

View file

@ -20,6 +20,7 @@ ProjectGetter = require("./ProjectGetter")
PrivilegeLevels = require("../Authorization/PrivilegeLevels")
AuthenticationController = require("../Authentication/AuthenticationController")
PackageVersions = require("../../infrastructure/PackageVersions")
AnalyticsManager = require "../Analytics/AnalyticsManager"
module.exports = ProjectController =
@ -219,6 +220,19 @@ module.exports = ProjectController =
#don't need to wait for this to complete
ProjectUpdateHandler.markAsOpened project_id, ->
cb()
showTrackChangesOnboarding: (cb) ->
cb = _.once(cb)
if !user_id?
return cb()
timeout = setTimeout cb, 500
AnalyticsManager.getLastOccurance user_id, "shown-track-changes-onboarding", (error, event) ->
clearTimeout timeout
if error?
return cb(null, false)
else if event?
return cb(null, false)
else
return cb(null, true)
}, (err, results)->
if err?
logger.err err:err, "error getting details for project page"
@ -226,7 +240,7 @@ module.exports = ProjectController =
project = results.project
user = results.user
subscription = results.subscription
showTrackChangesOnboarding = results.showTrackChangesOnboarding
daysSinceLastUpdated = (new Date() - project.lastUpdated) /86400000
logger.log project_id:project_id, daysSinceLastUpdated:daysSinceLastUpdated, "got db results for loading editor"
@ -268,6 +282,7 @@ module.exports = ProjectController =
syntaxValidation: user.ace.syntaxValidation
}
trackChangesEnabled: !!project.track_changes
showTrackChangesOnboarding: !!showTrackChangesOnboarding
privilegeLevel: privilegeLevel
chatUrl: Settings.apis.chat.url
anonymous: anonymous

View file

@ -108,6 +108,7 @@ block requirejs
window.anonymous = #{anonymous};
window.maxDocLength = #{maxDocLength};
window.trackChangesEnabled = #{trackChangesEnabled};
window.showTrackChangesOnboarding = #{!!showTrackChangesOnboarding};
window.wikiEnabled = #{!!(settings.apis.wiki && settings.apis.wiki.url)};
window.requirejs = {
"paths" : {

View file

@ -1,54 +1,113 @@
.feat-onboard(
ng-controller="FeatureOnboardingController"
ng-class="('feat-onboard-step' + innerStep)"
ng-if="!state.loading && ui.showCodeCheckerOnboarding"
ng-cloak
)
.feat-onboard-wrapper
h1.feat-onboard-title
| Introducing 
span.feat-onboard-title-name Code check
div(ng-if="innerStep === 1;")
div(ng-controller="FeatureOnboardingController")
.feat-onboard(
ng-class="('feat-onboard-step' + onboarding.innerStep)"
ng-if="!state.loading && showCollabFeaturesOnboarding"
ng-cloak
stop-propagation="click"
)
a.feat-onboard-dismiss(
href
ng-click="dismiss();"
) ×
.feat-onboard-wrapper
h1.feat-onboard-title
span.feat-onboard-highlight Commenting
| &
span.feat-onboard-highlight Track Changes
p.feat-onboard-description
span.feat-onboard-description-name Code check 
| will highlight potential problems in your LaTeX code, allowing you to handle errors earlier and become more productive.
.row
video.feat-onboard-video(autoplay, loop)
source(src="/img/teasers/code-checker/code-checker.mp4", type="video/mp4")
img(src="/img/teasers/code-checker/code-checker.gif")
.row.feat-onboard-adv-wrapper
.col-xs-4
h2.feat-onboard-adv-title
| Missing 
span.feat-onboard-adv-title-highlight brackets
p Forgot to place a closing bracket? We'll warn you.
.col-xs-4
h2.feat-onboard-adv-title
| Unclosed 
span.feat-onboard-adv-title-highlight environments
p
| Know when you are missing an 
code \end{...}
|  command.
.col-xs-4
h2.feat-onboard-adv-title
| Incorrect 
span.feat-onboard-adv-title-highlight nesting
p
| Order matters. Get notified when you use an 
code \end{...}
|   too soon.
.feat-onboard-btn-wrapper
button.btn.btn-primary(ng-click="turnCodeCheckOn();") Yes, turn Code check on
.feat-onboard-btn-wrapper
button.btn.btn-default(ng-click="turnCodeCheckOff();") No, disable it for now
div(ng-if="innerStep === 2;")
| Collaboration features are here!
p.feat-onboard-description
| Remember: you can always turn 
span.feat-onboard-description-name Code check 
em on 
| or 
em off 
|, in the settings menu.
.feat-onboard-btn-wrapper
button.btn.btn-primary(ng-click="dismiss();") OK, got it
span.feat-onboard-highlight Commenting
| and
span.feat-onboard-highlight Track Changes
| will make it easier for you to work with peers in your documents.
.feat-onboard-tutorial-wrapper
button.btn.btn-primary.feat-onboard-nav-btn(
ng-click="gotoPrevStep();"
ng-disabled="onboarding.innerStep === 1;")
i.fa.fa-arrow-left
div(ng-show="onboarding.innerStep === 1;")
video.feat-onboard-video(
video-play-state="onboarding.innerStep === 1;"
autoplay
loop
)
source(src="/img/onboarding/review-panel/open-review.mp4", type="video/mp4")
img(src="/img/onboarding/review-panel/open-review.gif")
div(ng-show="onboarding.innerStep === 2;")
video.feat-onboard-video(
video-play-state="onboarding.innerStep === 2;"
autoplay
loop
)
source(src="/img/onboarding/review-panel/commenting.mp4", type="video/mp4")
img(src="/img/onboarding/review-panel/commenting.gif")
div(ng-show="onboarding.innerStep === 3;")
video.feat-onboard-video(
video-play-state="onboarding.innerStep === 3;"
autoplay
loop
)
source(src="/img/onboarding/review-panel/add-changes.mp4", type="video/mp4")
img(src="/img/onboarding/review-panel/add-changes.gif")
div(ng-show="onboarding.innerStep === 4;")
video.feat-onboard-video(
video-play-state="onboarding.innerStep === 4;"
autoplay
loop
)
source(src="/img/onboarding/review-panel/accept-changes.mp4", type="video/mp4")
img(src="/img/onboarding/review-panel/accept-changes.gif")
button.btn.btn-primary.feat-onboard-nav-btn(
ng-click="gotoNextStep();"
ng-disabled="onboarding.innerStep === onboarding.nSteps;")
i.fa.fa-arrow-right
div(ng-switch="onboarding.innerStep")
.row(ng-switch-when="1")
.col-xs-6
h2.feat-onboard-adv-title Commenting
p.feat-onboard-description Want to discuss specific parts of the text?
p.feat-onboard-description Use our brand-new commenting system.
.col-xs-6
h2.feat-onboard-adv-title Track Changes
p.feat-onboard-description See changes in your documents, live.
p.feat-onboard-description Track, accept and reject changes individually.
.row(ng-switch-when="2")
.col-xs-12
h2.feat-onboard-adv-title Commenting
p.feat-onboard-description Just select a span of text and click on
span.feat-onboard-highlight “Add comment”
| .
p.feat-onboard-description
span.feat-onboard-highlight Comments
| can be
span.feat-onboard-highlight replied
| to,
span.feat-onboard-highlight resolved
| and permanently
span.feat-onboard-highlight deleted
| .
.row(ng-switch-when="3")
.col-xs-12
h2.feat-onboard-adv-title Track Changes
p.feat-onboard-description
| Let your peers know what you've been up to.
p.feat-onboard-description
| Click on the
span.feat-onboard-highlight “Track Changes”
| toggle to start marking your insertions, as well as your deletions.
.row(ng-switch-when="4")
.col-xs-12
h2.feat-onboard-adv-title Track Changes
p.feat-onboard-description Upon reviewing,
span.feat-onboard-highlight changes
| can be accepted or undone.
p.feat-onboard-description
| Click 
span.feat-onboard-highlight “Accept”
| or 
span.feat-onboard-highlight “Reject”
| to incorporate or discard an individual change.

View file

@ -6,7 +6,7 @@
ng-class="{ 'rp-track-changes-indicator-on-dark' : darkTheme }"
) Track changes is
strong on
.review-panel-toolbar
resolved-comments-dropdown(
class="rp-flex-block"
@ -426,4 +426,4 @@ script(type="text/ng-template", id="trackChangesUpgradeModalTemplate")
button.btn.btn-default(
ng-click="cancel()"
)
span #{translate("close")}
span #{translate("close")}

View file

@ -0,0 +1,15 @@
define [
"base"
], (App) ->
App.directive "videoPlayState", ($parse) ->
return {
restrict: "A",
link: (scope, element, attrs) ->
videoDOMEl = element[0]
scope.$watch (() -> $parse(attrs.videoPlayState)(scope)), (shouldPlay) ->
if shouldPlay
videoDOMEl.currentTime = 0
videoDOMEl.play()
else
videoDOMEl.pause()
}

View file

@ -29,6 +29,7 @@ define [
"directives/stopPropagation"
"directives/rightClick"
"directives/expandableTextArea"
"directives/videoPlayState"
"services/queued-http"
"filters/formatDate"
"main/event"
@ -69,7 +70,6 @@ define [
chatOpen: false
pdfLayout: 'sideBySide'
reviewPanelOpen: localStorage("ui.reviewPanelOpen.#{window.project_id}")
showCodeCheckerOnboarding: !window.userSettings.syntaxValidation?
}
$scope.user = window.user

View file

@ -1,35 +1,36 @@
define [
"base"
], (App) ->
App.controller "FeatureOnboardingController", ($scope, settings) ->
$scope.innerStep = 1
$scope.turnCodeCheckOn = () ->
settings.saveSettings({ syntaxValidation: true })
$scope.settings.syntaxValidation = true
navToInnerStep2()
$scope.turnCodeCheckOff = () ->
settings.saveSettings({ syntaxValidation: false })
$scope.settings.syntaxValidation = false
navToInnerStep2()
App.controller "FeatureOnboardingController", ($scope, settings, event_tracking) ->
$scope.onboarding =
innerStep: 1
nSteps: 4
$scope.$watch "project.features.trackChangesVisible", (visible) ->
return if !visible?
$scope.showCollabFeaturesOnboarding = window.showTrackChangesOnboarding and visible
$scope.dismiss = () ->
$scope.ui.leftMenuShown = false
$scope.ui.showCodeCheckerOnboarding = false
event_tracking.sendMB "shown-track-changes-onboarding"
$scope.$applyAsync(() -> $scope.showCollabFeaturesOnboarding = false)
navToInnerStep2 = () ->
$scope.innerStep = 2
$scope.ui.leftMenuShown = true
$scope.gotoPrevStep = () ->
if $scope.onboarding.innerStep > 1
$scope.$applyAsync(() -> $scope.onboarding.innerStep--)
handleKeypress = (e) ->
if e.keyCode == 13
if $scope.innerStep == 1
$scope.turnCodeCheckOn()
else
$scope.dismiss()
$scope.gotoNextStep = () ->
if $scope.onboarding.innerStep < 4
$scope.$applyAsync(() -> $scope.onboarding.innerStep++)
$(document).on "keypress", handleKeypress
handleKeydown = (e) ->
switch e.keyCode
when 37 then $scope.gotoPrevStep() # left directional key
when 39, 13 then $scope.gotoNextStep() # right directional key, enter
when 27 then $scope.dismiss() # escape
$(document).on "keydown", handleKeydown
$(document).on "click", $scope.dismiss
$scope.$on "$destroy", () ->
$(document).off "keypress", handleKeypress
$(document).off "keydown", handleKeydown
$(document).off "click", $scope.dismiss

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View file

@ -1,78 +1,101 @@
@feat-onboard-wrapper-width: 820px;
@feat-onboard-max-text-width: 750px;
@feat-onboard-width: 900px;
.feat-onboard {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
top: 50px;
bottom: 50px;
left: 50%;
width: @feat-onboard-width;
margin-left: -(@feat-onboard-width / 2);
display: flex;
justify-content: center;
align-items: center;
background-image: linear-gradient(rgba(0, 0, 0, .85), rgba(0, 0, 0, .85));
align-items: baseline;
background-color: rgba(0, 0, 0, .85);
background-repeat: no-repeat;
background-position-x: 0;
color: #FFF;
text-align: center;
border-radius: 1em;
z-index: 102;
transition: background-position ease-in-out @left-menu-animation-duration;
overflow: auto;
}
.feat-onboard-step2 {
background-position-x: @left-menu-width;
~ #left-menu {
pointer-events: none;
.code-check-setting {
box-shadow: 0 0 300px 0 #000;
}
}
}
.feat-onboard-wrapper {
width: @feat-onboard-wrapper-width;
padding: 30px 0;
}
.feat-onboard-title {
color: @brand-primary;
margin-bottom: 40px;
.feat-onboard-title {
color: #FFF;
margin-bottom: 30px;
}
.feat-onboard-title-name {
color: #FFF;
font-weight: bold;
}
.feat-onboard-description {
max-width: @feat-onboard-max-text-width;
margin: 0 auto 30px;
padding: 0 80px;
max-width: 35em;
margin: 0 auto 5px;
}
.feat-onboard-description-name {
.feat-onboard-highlight {
font-weight: bold;
white-space: nowrap;
}
.feat-onboard-adv-title {
font-weight: bold;
white-space: nowrap;
color: #FFF;
font-size: 23px;
margin-top: 0;
}
.feat-onboard-video {
box-shadow: 0 0 70px 0 rgba(255, 255, 255, 0.3);
.feat-onboard-tutorial-wrapper {
display: flex;
align-items: center;
padding: 30px 0 15px;
}
.feat-onboard-adv-wrapper {
text-align: left;
margin-bottom: 30px;
}
.feat-onboard-adv-title {
color: #FFF;
font-size: 23px;
}
.feat-onboard-adv-title-highlight {
font-weight: bold;
}
.feat-onboard-btn-wrapper {
margin-bottom: 10px;
> .btn {
.feat-onboard-video {
width: 616px;
margin: 0 30px;
box-shadow: 0 0 70px 0 rgba(255, 255, 255, 0.3);
}
}
.feat-onboard-nav-btn {
border-radius: 1em;
width: 2em;
height: 2em;
text-align: center;
padding: 0;
font-size: 1.3em;
line-height: 1em;
box-shadow: 0 0 70px 0 rgba(255, 255, 255, 0.3);
&[disabled] {
opacity: 0.2;
}
&:focus,
&:active:focus {
outline: 0;
box-shadow: 0 0 70px 0 rgba(255, 255, 255, 0.3);
}
}
a.feat-onboard-dismiss {
position: absolute;
top: 10px;
right: 10px;
width: 1em;
height: 1em;
line-height: 1em;
font-size: 2.5em;
color: #FFF;
background-color: rgba(0,0,0, .25);
opacity: 0.7;
border-radius: 0.5em;
transition: opacity .15s ease-in-out;
&:hover,
&:focus {
text-decoration: none;
color: #FFF;
opacity: 1;
}
}

View file

@ -391,7 +391,7 @@
border-right-width: 0;
}
.rp-layout-left & {
.rp-state-current-file-mini.rp-layout-left & {
&:first-child {
border-bottom-left-radius: 3px;
}

View file

@ -58,6 +58,8 @@ describe "ProjectController", ->
getLoggedInUserId: sinon.stub().returns(@user._id)
getSessionUser: sinon.stub().returns(@user)
isUserLoggedIn: sinon.stub().returns(true)
@AnalyticsManager =
getLastOccurance: sinon.stub()
@ProjectController = SandboxedModule.require modulePath, requires:
"settings-sharelatex":@settings
"logger-sharelatex":
@ -82,6 +84,7 @@ describe "ProjectController", ->
"../ReferencesSearch/ReferencesSearchHandler": @ReferencesSearchHandler
"./ProjectGetter": @ProjectGetter
'../Authentication/AuthenticationController': @AuthenticationController
"../Analytics/AnalyticsManager": @AnalyticsManager
@projectName = "£12321jkj9ujkljds"
@req =
@ -310,9 +313,9 @@ describe "ProjectController", ->
@AuthorizationManager.getPrivilegeLevelForProject.callsArgWith 2, null, "owner"
@ProjectDeleter.unmarkAsDeletedByExternalSource = sinon.stub()
@InactiveProjectManager.reactivateProjectIfRequired.callsArgWith(1)
@AnalyticsManager.getLastOccurance.yields(null, {"mock": "event"})
@ProjectUpdateHandler.markAsOpened.callsArgWith(1)
it "should render the project/editor page", (done)->
@res.render = (pageName, opts)=>
pageName.should.equal "project/editor"
@ -357,3 +360,24 @@ describe "ProjectController", ->
@ProjectUpdateHandler.markAsOpened.calledWith(@project_id).should.equal true
done()
@ProjectController.loadEditor @req, @res
it "should set showTrackChangesOnboarding = false if there is an event", (done) ->
@AnalyticsManager.getLastOccurance.yields(null, {"mock": "event"})
@res.render = (pageName, opts)=>
opts.showTrackChangesOnboarding.should.equal false
done()
@ProjectController.loadEditor @req, @res
it "should set showTrackChangesOnboarding = true if there is no event", (done) ->
@AnalyticsManager.getLastOccurance.yields(null, null)
@res.render = (pageName, opts)=>
opts.showTrackChangesOnboarding.should.equal true
done()
@ProjectController.loadEditor @req, @res
it "should set showTrackChangesOnboarding = false if there is an error", (done) ->
@AnalyticsManager.getLastOccurance.yields(new Error("oops"), null)
@res.render = (pageName, opts)=>
opts.showTrackChangesOnboarding.should.equal false
done()
@ProjectController.loadEditor @req, @res