2014-07-08 07:02:26 -04:00
|
|
|
define [
|
2016-09-22 06:36:53 -04:00
|
|
|
"moment"
|
2016-10-20 07:15:22 -04:00
|
|
|
"ide/colors/ColorManager"
|
2016-10-05 06:04:39 -04:00
|
|
|
"ide/history/controllers/HistoryListController"
|
|
|
|
"ide/history/controllers/HistoryDiffController"
|
|
|
|
"ide/history/directives/infiniteScroll"
|
2016-10-20 07:15:22 -04:00
|
|
|
], (moment, ColorManager) ->
|
2016-10-05 06:04:39 -04:00
|
|
|
class HistoryManager
|
2014-07-08 07:02:26 -04:00
|
|
|
constructor: (@ide, @$scope) ->
|
|
|
|
@reset()
|
|
|
|
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.toggleHistory = () =>
|
|
|
|
if @$scope.ui.view == "history"
|
2014-07-08 07:02:26 -04:00
|
|
|
@hide()
|
|
|
|
else
|
|
|
|
@show()
|
|
|
|
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.$watch "history.selection.updates", (updates) =>
|
2014-07-08 07:02:26 -04:00
|
|
|
if updates? and updates.length > 0
|
|
|
|
@_selectDocFromUpdates()
|
|
|
|
@reloadDiff()
|
|
|
|
|
|
|
|
@$scope.$on "entity:selected", (event, entity) =>
|
2016-10-05 06:04:39 -04:00
|
|
|
if (@$scope.ui.view == "history") and (entity.type == "doc")
|
2017-11-28 13:18:15 -05:00
|
|
|
# TODO: Set selection.doc_path to entity path name
|
|
|
|
# @$scope.history.selection.doc = entity
|
2014-07-08 07:02:26 -04:00
|
|
|
@reloadDiff()
|
|
|
|
|
|
|
|
show: () ->
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.ui.view = "history"
|
2014-07-08 07:02:26 -04:00
|
|
|
@reset()
|
|
|
|
|
|
|
|
hide: () ->
|
|
|
|
@$scope.ui.view = "editor"
|
|
|
|
# Make sure we run the 'open' logic for whatever is currently selected
|
|
|
|
@$scope.$emit "entity:selected", @ide.fileTreeManager.findSelectedEntity()
|
|
|
|
|
|
|
|
reset: () ->
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.history = {
|
2014-07-08 07:02:26 -04:00
|
|
|
updates: []
|
|
|
|
nextBeforeTimestamp: null
|
|
|
|
atEnd: false
|
|
|
|
selection: {
|
|
|
|
updates: []
|
|
|
|
doc: null
|
|
|
|
range: {
|
|
|
|
fromV: null
|
|
|
|
toV: null
|
|
|
|
start_ts: null
|
|
|
|
end_ts: null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
diff: null
|
|
|
|
}
|
|
|
|
|
|
|
|
autoSelectRecentUpdates: () ->
|
2016-10-05 06:04:39 -04:00
|
|
|
return if @$scope.history.updates.length == 0
|
2014-07-08 07:02:26 -04:00
|
|
|
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.history.updates[0].selectedTo = true
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
indexOfLastUpdateNotByMe = 0
|
2016-10-05 06:04:39 -04:00
|
|
|
for update, i in @$scope.history.updates
|
2014-07-08 07:02:26 -04:00
|
|
|
if @_updateContainsUserId(update, @$scope.user.id)
|
|
|
|
break
|
|
|
|
indexOfLastUpdateNotByMe = i
|
|
|
|
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.history.updates[indexOfLastUpdateNotByMe].selectedFrom = true
|
2014-07-08 07:02:26 -04:00
|
|
|
|
2014-07-15 13:25:12 -04:00
|
|
|
BATCH_SIZE: 10
|
2014-07-08 07:02:26 -04:00
|
|
|
fetchNextBatchOfUpdates: () ->
|
|
|
|
url = "/project/#{@ide.project_id}/updates?min_count=#{@BATCH_SIZE}"
|
2016-10-05 06:04:39 -04:00
|
|
|
if @$scope.history.nextBeforeTimestamp?
|
|
|
|
url += "&before=#{@$scope.history.nextBeforeTimestamp}"
|
|
|
|
@$scope.history.loading = true
|
2014-07-08 07:02:26 -04:00
|
|
|
@ide.$http
|
|
|
|
.get(url)
|
2017-06-20 11:04:06 -04:00
|
|
|
.then (response) =>
|
|
|
|
{ data } = response
|
2014-07-08 07:02:26 -04:00
|
|
|
@_loadUpdates(data.updates)
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.history.nextBeforeTimestamp = data.nextBeforeTimestamp
|
2014-07-08 07:02:26 -04:00
|
|
|
if !data.nextBeforeTimestamp?
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.history.atEnd = true
|
|
|
|
@$scope.history.loading = false
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
reloadDiff: () ->
|
2016-10-05 06:04:39 -04:00
|
|
|
diff = @$scope.history.diff
|
2017-11-28 13:18:15 -05:00
|
|
|
{updates} = @$scope.history.selection
|
|
|
|
{fromV, toV, start_ts, end_ts, original_path} = @_calculateDiffDataFromSelection()
|
|
|
|
console.log "[reloadDiff] current diff", diff
|
|
|
|
console.log "[reloadDiff] new diff data", {fromV, toV, start_ts, end_ts, original_path}
|
2014-07-08 07:02:26 -04:00
|
|
|
|
2017-11-28 13:18:15 -05:00
|
|
|
return if !original_path?
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
return if diff? and
|
2017-11-28 13:18:15 -05:00
|
|
|
diff.doc_path == original_path and
|
|
|
|
diff.fromV == fromV and
|
|
|
|
diff.toV == toV
|
2014-07-08 07:02:26 -04:00
|
|
|
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.history.diff = diff = {
|
2014-07-11 08:55:14 -04:00
|
|
|
fromV: fromV
|
|
|
|
toV: toV
|
|
|
|
start_ts: start_ts
|
|
|
|
end_ts: end_ts
|
2017-11-28 13:18:15 -05:00
|
|
|
doc_path: original_path
|
2014-07-11 08:55:14 -04:00
|
|
|
error: false
|
2014-07-08 07:02:26 -04:00
|
|
|
}
|
|
|
|
|
2017-11-28 13:18:15 -05:00
|
|
|
# TODO: How do we track deleted files now? We can probably show the diffs easily
|
|
|
|
# with the new system!
|
|
|
|
if true # !doc.deleted
|
2014-07-08 07:02:26 -04:00
|
|
|
diff.loading = true
|
2017-11-28 13:18:15 -05:00
|
|
|
url = "/project/#{@$scope.project_id}/doc/by_path/diff"
|
|
|
|
query = ["path=#{encodeURIComponent(original_path)}"]
|
2014-07-08 07:02:26 -04:00
|
|
|
if diff.fromV? and diff.toV?
|
2017-11-28 13:18:15 -05:00
|
|
|
query.push "from=#{diff.fromV}", "to=#{diff.toV}"
|
|
|
|
url += "?" + query.join("&")
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
@ide.$http
|
|
|
|
.get(url)
|
2017-06-20 11:04:06 -04:00
|
|
|
.then (response) =>
|
|
|
|
{ data } = response
|
2014-07-08 07:02:26 -04:00
|
|
|
diff.loading = false
|
|
|
|
{text, highlights} = @_parseDiff(data)
|
|
|
|
diff.text = text
|
|
|
|
diff.highlights = highlights
|
2017-06-20 06:49:55 -04:00
|
|
|
.catch () ->
|
2014-07-08 07:02:26 -04:00
|
|
|
diff.loading = false
|
|
|
|
diff.error = true
|
|
|
|
else
|
|
|
|
diff.deleted = true
|
2016-08-03 11:05:19 -04:00
|
|
|
diff.restoreInProgress = false
|
|
|
|
diff.restoreDeletedSuccess = false
|
|
|
|
diff.restoredDocNewId = null
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
restoreDeletedDoc: (doc) ->
|
2014-07-11 08:55:14 -04:00
|
|
|
url = "/project/#{@$scope.project_id}/doc/#{doc.id}/restore"
|
|
|
|
@ide.$http.post(url, name: doc.name, _csrf: window.csrfToken)
|
|
|
|
|
|
|
|
restoreDiff: (diff) ->
|
|
|
|
url = "/project/#{@$scope.project_id}/doc/#{diff.doc.id}/version/#{diff.fromV}/restore"
|
|
|
|
@ide.$http.post(url, _csrf: window.csrfToken)
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
_parseDiff: (diff) ->
|
|
|
|
row = 0
|
|
|
|
column = 0
|
|
|
|
highlights = []
|
|
|
|
text = ""
|
|
|
|
for entry, i in diff.diff or []
|
|
|
|
content = entry.u or entry.i or entry.d
|
|
|
|
content ||= ""
|
|
|
|
text += content
|
|
|
|
lines = content.split("\n")
|
|
|
|
startRow = row
|
|
|
|
startColumn = column
|
|
|
|
if lines.length > 1
|
|
|
|
endRow = startRow + lines.length - 1
|
|
|
|
endColumn = lines[lines.length - 1].length
|
|
|
|
else
|
|
|
|
endRow = startRow
|
|
|
|
endColumn = startColumn + lines[0].length
|
|
|
|
row = endRow
|
|
|
|
column = endColumn
|
|
|
|
|
|
|
|
range = {
|
|
|
|
start:
|
|
|
|
row: startRow
|
|
|
|
column: startColumn
|
|
|
|
end:
|
|
|
|
row: endRow
|
|
|
|
column: endColumn
|
|
|
|
}
|
|
|
|
|
|
|
|
if entry.i? or entry.d?
|
|
|
|
if entry.meta.user?
|
|
|
|
name = "#{entry.meta.user.first_name} #{entry.meta.user.last_name}"
|
|
|
|
else
|
|
|
|
name = "Anonymous"
|
|
|
|
if entry.meta.user?.id == @$scope.user.id
|
|
|
|
name = "you"
|
|
|
|
date = moment(entry.meta.end_ts).format("Do MMM YYYY, h:mm a")
|
|
|
|
if entry.i?
|
|
|
|
highlights.push {
|
|
|
|
label: "Added by #{name} on #{date}"
|
|
|
|
highlight: range
|
2016-10-20 07:15:22 -04:00
|
|
|
hue: ColorManager.getHueForUserId(entry.meta.user?.id)
|
2014-07-08 07:02:26 -04:00
|
|
|
}
|
|
|
|
else if entry.d?
|
|
|
|
highlights.push {
|
|
|
|
label: "Deleted by #{name} on #{date}"
|
|
|
|
strikeThrough: range
|
2016-10-20 07:15:22 -04:00
|
|
|
hue: ColorManager.getHueForUserId(entry.meta.user?.id)
|
2014-07-08 07:02:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return {text, highlights}
|
|
|
|
|
|
|
|
_loadUpdates: (updates = []) ->
|
2016-10-05 06:04:39 -04:00
|
|
|
previousUpdate = @$scope.history.updates[@$scope.history.updates.length - 1]
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
for update in updates
|
2017-11-28 13:18:15 -05:00
|
|
|
for doc_path, doc of update.docs or {}
|
|
|
|
doc.path = doc_path
|
|
|
|
doc.entity = @ide.fileTreeManager.findEntityByPath(doc_path, includeDeleted: true)
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
for user in update.meta.users or []
|
2015-09-10 09:35:09 -04:00
|
|
|
if user?
|
2016-10-20 07:15:22 -04:00
|
|
|
user.hue = ColorManager.getHueForUserId(user.id)
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
if !previousUpdate? or !moment(previousUpdate.meta.end_ts).isSame(update.meta.end_ts, "day")
|
|
|
|
update.meta.first_in_day = true
|
|
|
|
|
|
|
|
update.selectedFrom = false
|
|
|
|
update.selectedTo = false
|
|
|
|
update.inSelection = false
|
|
|
|
|
|
|
|
previousUpdate = update
|
|
|
|
|
2016-10-05 06:04:39 -04:00
|
|
|
firstLoad = @$scope.history.updates.length == 0
|
2014-07-08 07:02:26 -04:00
|
|
|
|
2016-10-05 06:04:39 -04:00
|
|
|
@$scope.history.updates =
|
|
|
|
@$scope.history.updates.concat(updates)
|
2017-11-28 13:18:15 -05:00
|
|
|
console.log "[_loadUpdates] updates", @$scope.history.updates
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
@autoSelectRecentUpdates() if firstLoad
|
|
|
|
|
2017-11-28 13:18:15 -05:00
|
|
|
_perDocSummaryOfUpdates: (updates) ->
|
|
|
|
current_paths = {}
|
|
|
|
docs_summary = {}
|
|
|
|
|
|
|
|
for update in updates # Updates are reverse chronologically ordered
|
|
|
|
console.log "[_perDocSummaryOfUpdates] update", update
|
|
|
|
if update.docs?
|
|
|
|
for doc_path, doc of update.docs
|
|
|
|
# doc_path may not be the latest doc path that this doc has had
|
|
|
|
if !current_paths[doc_path]?
|
|
|
|
current_paths[doc_path] = doc_path
|
|
|
|
current_path = current_paths[doc_path]
|
|
|
|
console.log "[_perDocSummaryOfUpdates] doc", doc, current_path
|
|
|
|
if !docs_summary[current_path]?
|
|
|
|
# todo start_ts and end_ts
|
|
|
|
docs_summary[current_path] = {
|
|
|
|
fromV: doc.fromV, toV: doc.toV,
|
|
|
|
original_path: doc_path
|
|
|
|
}
|
2014-07-08 07:02:26 -04:00
|
|
|
else
|
2017-11-28 13:18:15 -05:00
|
|
|
docs_summary[current_path] = {
|
|
|
|
fromV: Math.min(docs_summary[current_path].fromV, doc.fromV),
|
|
|
|
toV: Math.max(docs_summary[current_path].toV, doc.toV),
|
|
|
|
original_path: doc_path
|
|
|
|
}
|
|
|
|
else if update.renames?
|
|
|
|
for rename in update.renames
|
|
|
|
console.log "[_perDocSummaryOfUpdates] rename", rename
|
|
|
|
if !current_paths[rename.newPathname]?
|
|
|
|
current_paths[rename.newPathname] = rename.newPathname
|
|
|
|
current_paths[rename.pathname] = current_paths[rename.newPathname]
|
|
|
|
delete current_paths[rename.newPathname]
|
|
|
|
|
|
|
|
console.log "[_perDocSummaryOfUpdates] docs_summary", docs_summary
|
|
|
|
console.log "[_perDocSummaryOfUpdates] current_paths", current_paths
|
|
|
|
|
|
|
|
return docs_summary
|
|
|
|
|
|
|
|
_calculateDiffDataFromSelection: () ->
|
|
|
|
fromV = toV = start_ts = end_ts = original_path = null
|
|
|
|
|
|
|
|
selected_doc_path = @$scope.history.selection.doc_path
|
|
|
|
console.log "[_calculateDiffDataFromSelection] selected_doc_path", selected_doc_path
|
|
|
|
|
|
|
|
for doc_path, doc of @_perDocSummaryOfUpdates(@$scope.history.selection.updates)
|
|
|
|
if doc_path == selected_doc_path
|
|
|
|
fromV = doc.fromV
|
|
|
|
toV = doc.toV
|
|
|
|
start_ts = doc.start_ts
|
|
|
|
end_ts = doc.end_ts
|
|
|
|
original_path = doc.original_path
|
|
|
|
break
|
2014-07-08 07:02:26 -04:00
|
|
|
|
2017-11-28 13:18:15 -05:00
|
|
|
return {fromV, toV, start_ts, end_ts, original_path}
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
# Set the track changes selected doc to one of the docs in the range
|
|
|
|
# of currently selected updates. If we already have a selected doc
|
|
|
|
# then prefer this one if present.
|
|
|
|
_selectDocFromUpdates: () ->
|
2017-11-28 13:18:15 -05:00
|
|
|
affected_docs = @_perDocSummaryOfUpdates(@$scope.history.selection.updates)
|
|
|
|
console.log "[_selectDocFromUpdates] affected_docs", affected_docs
|
2014-07-08 07:02:26 -04:00
|
|
|
|
2017-11-28 13:18:15 -05:00
|
|
|
selected_doc_path = @$scope.history.selection.doc_path
|
|
|
|
console.log "[_selectDocFromUpdates] current selected_doc_path", selected_doc_path
|
|
|
|
if selected_doc_path? and affected_docs[selected_doc_path]
|
2014-07-09 11:18:09 -04:00
|
|
|
# Selected doc is already open
|
2014-07-08 07:02:26 -04:00
|
|
|
else
|
2017-11-28 13:18:15 -05:00
|
|
|
# Set to first possible candidate
|
|
|
|
for doc_path, doc of affected_docs
|
|
|
|
selected_doc_path = doc_path
|
2014-07-08 07:02:26 -04:00
|
|
|
break
|
|
|
|
|
2017-11-28 13:18:15 -05:00
|
|
|
console.log "[_selectDocFromUpdates] new selected_doc_path", selected_doc_path
|
|
|
|
|
|
|
|
@$scope.history.selection.doc_path = selected_doc_path
|
|
|
|
if selected_doc_path?
|
|
|
|
entity = @ide.fileTreeManager.findEntityByPath(selected_doc_path)
|
|
|
|
if entity?
|
|
|
|
@ide.fileTreeManager.selectEntity(entity)
|
2014-07-08 07:02:26 -04:00
|
|
|
|
|
|
|
_updateContainsUserId: (update, user_id) ->
|
|
|
|
for user in update.meta.users
|
2015-09-14 07:08:05 -04:00
|
|
|
return true if user?.id == user_id
|
2014-07-08 07:02:26 -04:00
|
|
|
return false
|