Merge branch 'master' into pr-hide-review-panel

This commit is contained in:
Paulo Reis 2017-05-19 15:31:14 +01:00
commit 15980d5427
10 changed files with 211 additions and 26 deletions

View file

@ -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) ->

View file

@ -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) ->) ->

View file

@ -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
| &nbsp;#{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
| &nbsp;#{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
| &nbsp;#{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
| &nbsp;#{translate("reject_all")}
| ({{ nEntries }})
a.rp-bulk-actions-btn(
href
ng-click="bulkAccept();"
)
i.fa.fa-check
| &nbsp;#{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()"
) &times;
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")}

View file

@ -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"

View file

@ -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)

View file

@ -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()

View file

@ -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()

View file

@ -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,17 +460,35 @@
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 {
@ -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 {

View file

@ -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,13 +105,18 @@ 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
@ClsiCookieManager.setServerId @project_id, @response, (err, serverId)=>
@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 =

View file

@ -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