mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge branch 'master' into pr-hide-review-panel
This commit is contained in:
commit
15980d5427
10 changed files with 211 additions and 26 deletions
|
@ -19,10 +19,10 @@ module.exports = ClsiCookieManager =
|
|||
rclient.get buildKey(project_id), (err, serverId)->
|
||||
if err?
|
||||
return callback(err)
|
||||
if serverId?
|
||||
return callback(null, serverId)
|
||||
else
|
||||
if !serverId? or serverId == ""
|
||||
return ClsiCookieManager._populateServerIdViaRequest project_id, callback
|
||||
else
|
||||
return callback(null, serverId)
|
||||
|
||||
|
||||
_populateServerIdViaRequest :(project_id, callback = (err, serverId)->)->
|
||||
|
@ -44,6 +44,8 @@ module.exports = ClsiCookieManager =
|
|||
if !clsiCookiesEnabled
|
||||
return callback()
|
||||
serverId = ClsiCookieManager._parseServerIdFromResponse(response)
|
||||
if !serverId? # We don't get a cookie back if it hasn't changed
|
||||
return callback()
|
||||
if rclient_secondary?
|
||||
@_setServerIdInRedis rclient_secondary, project_id, serverId
|
||||
@_setServerIdInRedis rclient, project_id, serverId, (err) ->
|
||||
|
|
|
@ -123,20 +123,23 @@ module.exports = DocumentUpdaterHandler =
|
|||
logger.error project_id:project_id, doc_id:doc_id, url: url, "doc updater returned a non-success status code: #{res.statusCode}"
|
||||
callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
|
||||
|
||||
acceptChange: (project_id, doc_id, change_id, callback = (error) ->) ->
|
||||
timer = new metrics.Timer("accept-change")
|
||||
url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}/change/#{change_id}/accept"
|
||||
logger.log {project_id, doc_id, change_id}, "accepting change in document updater"
|
||||
request.post url, (error, res, body)->
|
||||
acceptChanges: (project_id, doc_id, change_ids = [], callback = (error) ->) ->
|
||||
timer = new metrics.Timer("accept-changes")
|
||||
reqSettings =
|
||||
url: "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}/change/accept"
|
||||
json:
|
||||
change_ids: change_ids
|
||||
logger.log {project_id, doc_id }, "accepting #{ change_ids.length } changes"
|
||||
request.post reqSettings, (error, res, body)->
|
||||
timer.done()
|
||||
if error?
|
||||
logger.error {err:error, project_id, doc_id, change_id}, "error accepting change in doc updater"
|
||||
logger.error {err:error, project_id, doc_id }, "error accepting #{ change_ids.length } changes in doc updater"
|
||||
return callback(error)
|
||||
if res.statusCode >= 200 and res.statusCode < 300
|
||||
logger.log {project_id, doc_id, change_id}, "accepted change in document updater"
|
||||
logger.log {project_id, doc_id }, "accepted #{ change_ids.length } changes in document updater"
|
||||
return callback(null)
|
||||
else
|
||||
logger.error {project_id, doc_id, change_id}, "doc updater returned a non-success status code: #{res.statusCode}"
|
||||
logger.error {project_id, doc_id }, "doc updater returned a non-success status code: #{res.statusCode}"
|
||||
callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
|
||||
|
||||
deleteThread: (project_id, doc_id, thread_id, callback = (error) ->) ->
|
||||
|
|
|
@ -6,6 +6,22 @@
|
|||
ng-click="toggleReviewPanel();"
|
||||
ng-class="{ 'rp-track-changes-indicator-on-dark' : darkTheme }"
|
||||
) !{translate("track_changes_is_on")}
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-if="reviewPanel.selectedEntryIds.length > 1"
|
||||
ng-click="showBulkAcceptDialog();"
|
||||
)
|
||||
i.fa.fa-check
|
||||
| #{translate("accept_all")}
|
||||
| ({{ reviewPanel.selectedEntryIds.length }})
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-if="reviewPanel.selectedEntryIds.length > 1"
|
||||
ng-click="showBulkRejectDialog();"
|
||||
)
|
||||
i.fa.fa-times
|
||||
| #{translate("reject_all")}
|
||||
| ({{ reviewPanel.selectedEntryIds.length }})
|
||||
a.rp-add-comment-btn(
|
||||
href
|
||||
ng-if="reviewPanel.entries[editor.open_doc_id]['add-comment'] != null"
|
||||
|
@ -86,6 +102,12 @@
|
|||
on-submit="submitNewComment(content);"
|
||||
on-cancel="cancelNewComment();"
|
||||
)
|
||||
div(ng-if="entry.type === 'bulk-actions'")
|
||||
bulk-actions-entry(
|
||||
on-bulk-accept="showBulkAcceptDialog();"
|
||||
on-bulk-reject="showBulkRejectDialog();"
|
||||
n-entries="reviewPanel.selectedEntryIds.length"
|
||||
)
|
||||
|
||||
.rp-entry-list(
|
||||
ng-if="reviewPanel.subView === SubViews.OVERVIEW"
|
||||
|
@ -357,6 +379,25 @@ script(type='text/ng-template', id='addCommentEntryTemplate')
|
|||
i.fa.fa-comment
|
||||
| #{translate("comment")}
|
||||
|
||||
script(type='text/ng-template', id='bulkActionsEntryTemplate')
|
||||
div(ng-if="nEntries > 1")
|
||||
.rp-entry-callout.rp-entry-callout-bulk-actions
|
||||
.rp-entry.rp-entry-bulk-actions
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-click="bulkReject();"
|
||||
)
|
||||
i.fa.fa-times
|
||||
| #{translate("reject_all")}
|
||||
| ({{ nEntries }})
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-click="bulkAccept();"
|
||||
)
|
||||
i.fa.fa-check
|
||||
| #{translate("accept_all")}
|
||||
| ({{ nEntries }})
|
||||
|
||||
script(type='text/ng-template', id='resolvedCommentsDropdownTemplate')
|
||||
.resolved-comments
|
||||
.resolved-comments-backdrop(
|
||||
|
@ -437,3 +478,24 @@ script(type="text/ng-template", id="trackChangesUpgradeModalTemplate")
|
|||
ng-click="cancel()"
|
||||
)
|
||||
span #{translate("close")}
|
||||
|
||||
script(type="text/ng-template", id="bulkActionsModalTemplate")
|
||||
.modal-header
|
||||
button.close(
|
||||
type="button"
|
||||
data-dismiss="modal"
|
||||
ng-click="cancel()"
|
||||
) ×
|
||||
h3 {{ isAccept ? '#{translate("accept_all")}' : '#{translate("reject_all")}' }}
|
||||
.modal-body
|
||||
p(ng-if="isAccept") #{translate("bulk_accept_confirm", { nChanges: "{{ nChanges }}"})}
|
||||
p(ng-if="!isAccept") #{translate("bulk_reject_confirm", { nChanges: "{{ nChanges }}"})}
|
||||
.modal-footer()
|
||||
button.btn.btn-default(
|
||||
ng-click="cancel()"
|
||||
)
|
||||
span #{translate("cancel")}
|
||||
button.btn.btn-primary(
|
||||
ng-click="confirm()"
|
||||
)
|
||||
span #{translate("ok")}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
define [
|
||||
"ide/review-panel/controllers/ReviewPanelController"
|
||||
"ide/review-panel/controllers/TrackChangesUpgradeModalController"
|
||||
"ide/review-panel/controllers/BulkActionsModalController"
|
||||
"ide/review-panel/directives/reviewPanelSorted"
|
||||
"ide/review-panel/directives/reviewPanelToggle"
|
||||
"ide/review-panel/directives/changeEntry"
|
||||
"ide/review-panel/directives/commentEntry"
|
||||
"ide/review-panel/directives/addCommentEntry"
|
||||
"ide/review-panel/directives/bulkActionsEntry"
|
||||
"ide/review-panel/directives/resolvedCommentEntry"
|
||||
"ide/review-panel/directives/resolvedCommentsDropdown"
|
||||
"ide/review-panel/directives/reviewPanelCollapseHeight"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.controller "BulkActionsModalController", ($scope, $modalInstance, isAccept, nChanges) ->
|
||||
$scope.isAccept = isAccept
|
||||
$scope.nChanges = nChanges
|
||||
$scope.cancel = () ->
|
||||
$modalInstance.dismiss()
|
||||
$scope.confirm = () ->
|
||||
$modalInstance.close(isAccept)
|
|
@ -26,6 +26,7 @@ define [
|
|||
resolvedThreadIds: {}
|
||||
rendererData: {}
|
||||
loadingThreads: false
|
||||
selectedEntryIds: []
|
||||
|
||||
window.addEventListener "beforeunload", () ->
|
||||
collapsedStates = {}
|
||||
|
@ -176,7 +177,7 @@ define [
|
|||
entries = $scope.reviewPanel.entries[$scope.editor.open_doc_id] or {}
|
||||
permEntries = {}
|
||||
for entry, entryData of entries
|
||||
if entry != "add-comment"
|
||||
if entry not in [ "add-comment", "bulk-actions" ]
|
||||
permEntries[entry] = entryData
|
||||
Object.keys(permEntries).length
|
||||
), (nEntries) ->
|
||||
|
@ -294,23 +295,35 @@ define [
|
|||
$scope.$on "editor:focus:changed", (e, selection_offset_start, selection_offset_end, selection) ->
|
||||
doc_id = $scope.editor.open_doc_id
|
||||
entries = getDocEntries(doc_id)
|
||||
$scope.reviewPanel.selectedEntryIds = []
|
||||
|
||||
delete entries["add-comment"]
|
||||
delete entries["bulk-actions"]
|
||||
|
||||
if selection
|
||||
entries["add-comment"] = {
|
||||
type: "add-comment"
|
||||
offset: selection_offset_start
|
||||
length: selection_offset_end - selection_offset_start
|
||||
}
|
||||
entries["bulk-actions"] = {
|
||||
type: "bulk-actions"
|
||||
offset: selection_offset_start
|
||||
length: selection_offset_end - selection_offset_start
|
||||
}
|
||||
|
||||
for id, entry of entries
|
||||
if entry.type == "comment" and not $scope.reviewPanel.resolvedThreadIds[entry.thread_id]
|
||||
entry.focused = (entry.offset <= selection_offset_start <= entry.offset + entry.content.length)
|
||||
else if entry.type == "insert"
|
||||
isEntryWithinSelection = entry.offset >= selection_offset_start and entry.offset + entry.content.length <= selection_offset_end
|
||||
entry.focused = (entry.offset <= selection_offset_start <= entry.offset + entry.content.length)
|
||||
$scope.reviewPanel.selectedEntryIds.push id if isEntryWithinSelection
|
||||
else if entry.type == "delete"
|
||||
isEntryWithinSelection = selection_offset_start <= entry.offset <= selection_offset_end
|
||||
entry.focused = (entry.offset == selection_offset_start)
|
||||
else if entry.type == "add-comment" and selection
|
||||
$scope.reviewPanel.selectedEntryIds.push id if isEntryWithinSelection
|
||||
else if entry.type in [ "add-comment", "bulk-actions" ] and selection
|
||||
entry.focused = true
|
||||
|
||||
$scope.$broadcast "review-panel:recalculate-screen-positions"
|
||||
|
@ -325,6 +338,43 @@ define [
|
|||
$scope.$broadcast "change:reject", entry_id
|
||||
event_tracking.sendMB "rp-change-rejected", { view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini' }
|
||||
|
||||
bulkAccept = () ->
|
||||
entry_ids = $scope.reviewPanel.selectedEntryIds.slice()
|
||||
$http.post "/project/#{$scope.project_id}/doc/#{$scope.editor.open_doc_id}/changes/accept", { change_ids: entry_ids, _csrf: window.csrfToken}
|
||||
$scope.$broadcast "change:bulk-accept", entry_ids
|
||||
$scope.reviewPanel.selectedEntryIds = []
|
||||
event_tracking.sendMB "rp-bulk-accept", {
|
||||
view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini',
|
||||
nEntries: $scope.reviewPanel.selectedEntryIds.length
|
||||
}
|
||||
|
||||
bulkReject = () ->
|
||||
$scope.$broadcast "change:bulk-reject", $scope.reviewPanel.selectedEntryIds.slice()
|
||||
$scope.reviewPanel.selectedEntryIds = []
|
||||
event_tracking.sendMB "rp-bulk-reject", {
|
||||
view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini',
|
||||
nEntries: $scope.reviewPanel.selectedEntryIds.length
|
||||
}
|
||||
|
||||
$scope.showBulkAcceptDialog = () ->
|
||||
showBulkActionsDialog true
|
||||
|
||||
$scope.showBulkRejectDialog = () -> showBulkActionsDialog false
|
||||
|
||||
showBulkActionsDialog = (isAccept) ->
|
||||
$modal.open({
|
||||
templateUrl: "bulkActionsModalTemplate"
|
||||
controller: "BulkActionsModalController"
|
||||
resolve:
|
||||
isAccept: () -> isAccept
|
||||
nChanges: () -> $scope.reviewPanel.selectedEntryIds.length
|
||||
scope: $scope.$new()
|
||||
}).result.then (isAccept) ->
|
||||
if isAccept
|
||||
bulkAccept()
|
||||
else
|
||||
bulkReject()
|
||||
|
||||
$scope.addNewComment = () ->
|
||||
$scope.$broadcast "comment:start_adding"
|
||||
$scope.toggleReviewPanel()
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.directive "bulkActionsEntry", () ->
|
||||
restrict: "E"
|
||||
templateUrl: "bulkActionsEntryTemplate"
|
||||
scope:
|
||||
onBulkAccept: "&"
|
||||
onBulkReject: "&"
|
||||
nEntries: "="
|
||||
link: (scope, element, attrs) ->
|
||||
scope.bulkAccept = () ->
|
||||
scope.onBulkAccept()
|
||||
scope.bulkReject = () ->
|
||||
scope.onBulkReject()
|
|
@ -277,6 +277,9 @@
|
|||
right: 5px;
|
||||
}
|
||||
}
|
||||
&-bulk-actions {
|
||||
right: auto;
|
||||
}
|
||||
}
|
||||
.rp-state-overview & {
|
||||
border-radius: 0;
|
||||
|
@ -335,6 +338,12 @@
|
|||
border-left-color: @rp-yellow;
|
||||
}
|
||||
}
|
||||
|
||||
&-bulk-actions {
|
||||
background-color: transparent;
|
||||
right: auto;
|
||||
border-left-width: 0;
|
||||
}
|
||||
}
|
||||
.rp-entry-body {
|
||||
display: flex;
|
||||
|
@ -451,18 +460,36 @@
|
|||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.rp-add-comment-btn {
|
||||
.rp-add-comment-btn,
|
||||
.rp-bulk-actions-btn {
|
||||
.rp-button();
|
||||
display: block;
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
|
||||
.rp-in-editor-widgets & {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
border-radius: 0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rp-bulk-actions-btn {
|
||||
border-radius: 0;
|
||||
&:first-child {
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
&:last-child {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.rp-new-comment {
|
||||
padding: 5px;
|
||||
|
@ -903,6 +930,9 @@
|
|||
.rp-size-mini & {
|
||||
right: @review-off-width;
|
||||
}
|
||||
.rp-size-expanded & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.rp-track-changes-indicator {
|
||||
display: block;
|
||||
|
@ -931,10 +961,6 @@
|
|||
background-color: rgba(240, 240, 240, 1);
|
||||
color: @rp-type-blue;
|
||||
}
|
||||
|
||||
.rp-size-expanded & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.review-panel-toggler {
|
||||
|
|
|
@ -60,6 +60,13 @@ describe "ClsiCookieManager", ->
|
|||
@ClsiCookieManager._populateServerIdViaRequest.calledWith(@project_id).should.equal true
|
||||
done()
|
||||
|
||||
it "should _populateServerIdViaRequest if no key is blank", (done)->
|
||||
@ClsiCookieManager._populateServerIdViaRequest = sinon.stub().callsArgWith(1)
|
||||
@redis.get.callsArgWith(1, null, "")
|
||||
@ClsiCookieManager._getServerId @project_id, (err, serverId)=>
|
||||
@ClsiCookieManager._populateServerIdViaRequest.calledWith(@project_id).should.equal true
|
||||
done()
|
||||
|
||||
|
||||
describe "_populateServerIdViaRequest", ->
|
||||
|
||||
|
@ -98,7 +105,6 @@ describe "ClsiCookieManager", ->
|
|||
serverId.should.equal "clsi-8"
|
||||
done()
|
||||
|
||||
|
||||
it "should not set the server id if clsiCookies are not enabled", (done)->
|
||||
delete @settings.clsiCookie.key
|
||||
@ClsiCookieManager = SandboxedModule.require modulePath, requires:@requires
|
||||
|
@ -106,6 +112,12 @@ describe "ClsiCookieManager", ->
|
|||
@redisMulti.exec.called.should.equal false
|
||||
done()
|
||||
|
||||
it "should not set the server id there is no server id in the response", (done)->
|
||||
@ClsiCookieManager._parseServerIdFromResponse = sinon.stub().returns(null)
|
||||
@ClsiCookieManager.setServerId @project_id, @response, (err, serverId)=>
|
||||
@redisMulti.exec.called.should.equal false
|
||||
done()
|
||||
|
||||
it "should also set in the secondary if secondary redis is enabled", (done) ->
|
||||
@redisSecondaryMulti =
|
||||
set:sinon.stub()
|
||||
|
|
|
@ -252,7 +252,7 @@ describe 'DocumentUpdaterHandler', ->
|
|||
.calledWith(new Error("doc updater returned failure status code: 500"))
|
||||
.should.equal true
|
||||
|
||||
describe "acceptChange", ->
|
||||
describe "acceptChanges", ->
|
||||
beforeEach ->
|
||||
@change_id = "mock-change-id-1"
|
||||
@callback = sinon.stub()
|
||||
|
@ -260,11 +260,14 @@ describe 'DocumentUpdaterHandler', ->
|
|||
describe "successfully", ->
|
||||
beforeEach ->
|
||||
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 200}, @body)
|
||||
@handler.acceptChange @project_id, @doc_id, @change_id, @callback
|
||||
@handler.acceptChanges @project_id, @doc_id, [ @change_id ], @callback
|
||||
|
||||
it 'should accept the change in the document updater', ->
|
||||
url = "#{@settings.apis.documentupdater.url}/project/#{@project_id}/doc/#{@doc_id}/change/#{@change_id}/accept"
|
||||
@request.post.calledWith(url).should.equal true
|
||||
req =
|
||||
url: "#{@settings.apis.documentupdater.url}/project/#{@project_id}/doc/#{@doc_id}/change/accept"
|
||||
json:
|
||||
change_ids: [ @change_id ]
|
||||
@request.post.calledWith(req).should.equal true
|
||||
|
||||
it "should call the callback", ->
|
||||
@callback.calledWith(null).should.equal true
|
||||
|
@ -272,7 +275,7 @@ describe 'DocumentUpdaterHandler', ->
|
|||
describe "when the document updater API returns an error", ->
|
||||
beforeEach ->
|
||||
@request.post = sinon.stub().callsArgWith(1, @error = new Error("something went wrong"), null, null)
|
||||
@handler.acceptChange @project_id, @doc_id, @change_id, @callback
|
||||
@handler.acceptChanges @project_id, @doc_id, [ @change_id ], @callback
|
||||
|
||||
it "should return an error to the callback", ->
|
||||
@callback.calledWith(@error).should.equal true
|
||||
|
@ -280,7 +283,7 @@ describe 'DocumentUpdaterHandler', ->
|
|||
describe "when the document updater returns a failure error code", ->
|
||||
beforeEach ->
|
||||
@request.post = sinon.stub().callsArgWith(1, null, { statusCode: 500 }, "")
|
||||
@handler.acceptChange @project_id, @doc_id, @change_id, @callback
|
||||
@handler.acceptChanges @project_id, @doc_id, [ @change_id ], @callback
|
||||
|
||||
it "should return the callback with an error", ->
|
||||
@callback
|
||||
|
|
Loading…
Reference in a new issue