diff --git a/services/web/app/views/project/editor/history/entriesListV1.pug b/services/web/app/views/project/editor/history/entriesListV1.pug index b810b8cbdd..27f9e66fe1 100644 --- a/services/web/app/views/project/editor/history/entriesListV1.pug +++ b/services/web/app/views/project/editor/history/entriesListV1.pug @@ -1,6 +1,6 @@ aside.change-list( ng-if="!history.isV2" - ng-controller="HistoryCompareListController" + ng-controller="HistoryListController" infinite-scroll="loadMore()" infinite-scroll-disabled="history.loading || history.atEnd" infinite-scroll-initialize="ui.view == 'history'" @@ -22,7 +22,7 @@ aside.change-list( 'hover-selected-to': update.hoverSelectedTo,\ 'hover-selected-from': update.hoverSelectedFrom,\ }" - ng-controller="HistoryCompareListItemController" + ng-controller="HistoryListItemController" ) div.day(ng-show="update.meta.first_in_day") {{ update.meta.end_ts | relativeDate }} diff --git a/services/web/public/src/ide/history/HistoryManager.js b/services/web/public/src/ide/history/HistoryManager.js index ff17520969..03f84216c7 100644 --- a/services/web/public/src/ide/history/HistoryManager.js +++ b/services/web/public/src/ide/history/HistoryManager.js @@ -19,7 +19,7 @@ define([ 'moment', 'ide/colors/ColorManager', 'ide/history/util/displayNameForUser', - 'ide/history/controllers/HistoryCompareController', + 'ide/history/controllers/HistoryListController', 'ide/history/controllers/HistoryDiffController', 'ide/history/directives/infiniteScroll' ], function(moment, ColorManager, displayNameForUser) { diff --git a/services/web/public/src/ide/history/controllers/HistoryListController.js b/services/web/public/src/ide/history/controllers/HistoryListController.js new file mode 100644 index 0000000000..51786bcf99 --- /dev/null +++ b/services/web/public/src/ide/history/controllers/HistoryListController.js @@ -0,0 +1,223 @@ +/* eslint-disable + camelcase, + max-len, + no-return-assign, + no-undef, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +define(['base', 'ide/history/util/displayNameForUser'], function( + App, + displayNameForUser +) { + App.controller('HistoryListController', [ + '$scope', + '$modal', + 'ide', + function($scope, $modal, ide) { + $scope.hoveringOverListSelectors = false + + $scope.projectUsers = [] + + $scope.$watch('project.members', function(newVal) { + if (newVal != null) { + return ($scope.projectUsers = newVal.concat($scope.project.owner)) + } + }) + + // This method (and maybe the one below) will be removed soon. User details data will be + // injected into the history API responses, so we won't need to fetch user data from other + // local data structures. + const _getUserById = id => + _.find($scope.projectUsers, function(user) { + const curUserId = + (user != null ? user._id : undefined) || + (user != null ? user.id : undefined) + return curUserId === id + }) + + $scope.getDisplayNameById = id => displayNameForUser(_getUserById(id)) + + $scope.deleteLabel = labelDetails => + $modal.open({ + templateUrl: 'historyV2DeleteLabelModalTemplate', + controller: 'HistoryV2DeleteLabelModalController', + resolve: { + labelDetails() { + return labelDetails + } + } + }) + + $scope.loadMore = () => { + return ide.historyManager.fetchNextBatchOfUpdates() + } + + $scope.recalculateSelectedUpdates = function() { + let beforeSelection = true + let afterSelection = false + $scope.history.selection.updates = [] + return (() => { + const result = [] + for (let update of Array.from($scope.history.updates)) { + var inSelection + if (update.selectedTo) { + inSelection = true + beforeSelection = false + } + + update.beforeSelection = beforeSelection + update.inSelection = inSelection + update.afterSelection = afterSelection + + if (inSelection) { + $scope.history.selection.updates.push(update) + } + + if (update.selectedFrom) { + inSelection = false + result.push((afterSelection = true)) + } else { + result.push(undefined) + } + } + return result + })() + } + + $scope.recalculateHoveredUpdates = function() { + let inHoverSelection + let hoverSelectedFrom = false + let hoverSelectedTo = false + for (var update of Array.from($scope.history.updates)) { + // Figure out whether the to or from selector is hovered over + if (update.hoverSelectedFrom) { + hoverSelectedFrom = true + } + if (update.hoverSelectedTo) { + hoverSelectedTo = true + } + } + + if (hoverSelectedFrom) { + // We want to 'hover select' everything between hoverSelectedFrom and selectedTo + inHoverSelection = false + for (update of Array.from($scope.history.updates)) { + if (update.selectedTo) { + update.hoverSelectedTo = true + inHoverSelection = true + } + update.inHoverSelection = inHoverSelection + if (update.hoverSelectedFrom) { + inHoverSelection = false + } + } + } + if (hoverSelectedTo) { + // We want to 'hover select' everything between hoverSelectedTo and selectedFrom + inHoverSelection = false + return (() => { + const result = [] + for (update of Array.from($scope.history.updates)) { + if (update.hoverSelectedTo) { + inHoverSelection = true + } + update.inHoverSelection = inHoverSelection + if (update.selectedFrom) { + update.hoverSelectedFrom = true + result.push((inHoverSelection = false)) + } else { + result.push(undefined) + } + } + return result + })() + } + } + + $scope.resetHoverState = () => + (() => { + const result = [] + for (let update of Array.from($scope.history.updates)) { + delete update.hoverSelectedFrom + delete update.hoverSelectedTo + result.push(delete update.inHoverSelection) + } + return result + })() + + return $scope.$watch('history.updates.length', () => + $scope.recalculateSelectedUpdates() + ) + } + ]) + + return App.controller('HistoryListItemController', [ + '$scope', + 'event_tracking', + function($scope, event_tracking) { + $scope.$watch('update.selectedFrom', function( + selectedFrom, + oldSelectedFrom + ) { + if (selectedFrom) { + for (let update of Array.from($scope.history.updates)) { + if (update !== $scope.update) { + update.selectedFrom = false + } + } + return $scope.recalculateSelectedUpdates() + } + }) + + $scope.$watch('update.selectedTo', function(selectedTo, oldSelectedTo) { + if (selectedTo) { + for (let update of Array.from($scope.history.updates)) { + if (update !== $scope.update) { + update.selectedTo = false + } + } + return $scope.recalculateSelectedUpdates() + } + }) + + $scope.select = function() { + event_tracking.sendMB('history-view-change') + $scope.update.selectedTo = true + return ($scope.update.selectedFrom = true) + } + + $scope.mouseOverSelectedFrom = function() { + $scope.history.hoveringOverListSelectors = true + $scope.update.hoverSelectedFrom = true + return $scope.recalculateHoveredUpdates() + } + + $scope.mouseOutSelectedFrom = function() { + $scope.history.hoveringOverListSelectors = false + return $scope.resetHoverState() + } + + $scope.mouseOverSelectedTo = function() { + $scope.history.hoveringOverListSelectors = true + $scope.update.hoverSelectedTo = true + return $scope.recalculateHoveredUpdates() + } + + $scope.mouseOutSelectedTo = function() { + $scope.history.hoveringOverListSelectors = false + return $scope.resetHoverState() + } + + return ($scope.displayName = displayNameForUser) + } + ]) +})