diff --git a/services/web/frontend/js/features/ide-react/create-ide-event-emitter.ts b/services/web/frontend/js/features/ide-react/create-ide-event-emitter.ts index 4660a96bdf..8959e9f0dc 100644 --- a/services/web/frontend/js/features/ide-react/create-ide-event-emitter.ts +++ b/services/web/frontend/js/features/ide-react/create-ide-event-emitter.ts @@ -26,6 +26,7 @@ export type IdeEvents = { 'scroll:editor:update': [] 'comment:start_adding': [] 'references:should-reindex': [] + 'history:toggle': [] 'entity:deleted': [entity: FileTreeFindResult] } diff --git a/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts b/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts index bbea6b814d..a608de63ed 100644 --- a/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts +++ b/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts @@ -5,10 +5,6 @@ const reviewPanelStorageKey = `ui.reviewPanelOpen.${getMeta('ol-project_id')}` export default function populateLayoutScope(store: ReactScopeValueStore) { store.set('ui.view', 'editor') - - // TODO: Find out what this needs to do and make it do it - store.set('toggleHistory', () => {}) - store.set('openFile', null) store.persisted('ui.chatOpen', false, 'ui.chatOpen') store.persisted('ui.reviewPanelOpen', false, reviewPanelStorageKey) diff --git a/services/web/frontend/js/ide.js b/services/web/frontend/js/ide.js index 9c5199c128..c0b110a385 100644 --- a/services/web/frontend/js/ide.js +++ b/services/web/frontend/js/ide.js @@ -22,7 +22,6 @@ import LoadingManager from './ide/LoadingManager' import ConnectionManager from './ide/connection/ConnectionManager' import EditorManager from './ide/editor/EditorManager' import OnlineUsersManager from './ide/online-users/OnlineUsersManager' -import HistoryV2Manager from './ide/history/HistoryV2Manager' import PermissionsManager from './ide/permissions/PermissionsManager' import BinaryFilesManager from './ide/binary-files/BinaryFilesManager' import ReferencesManager from './ide/references/ReferencesManager' @@ -205,7 +204,6 @@ App.controller('IdeController', [ eventTracking ) ide.onlineUsersManager = new OnlineUsersManager(ide, $scope) - ide.historyManager = new HistoryV2Manager(ide, $scope, localStorage) ide.permissionsManager = new PermissionsManager(ide, $scope) ide.binaryFilesManager = new BinaryFilesManager(ide, $scope) ide.metadataManager = new MetadataManager(ide, $scope, metadata) diff --git a/services/web/frontend/js/ide/history/HistoryV2Manager.js b/services/web/frontend/js/ide/history/HistoryV2Manager.js deleted file mode 100644 index 9169f80776..0000000000 --- a/services/web/frontend/js/ide/history/HistoryV2Manager.js +++ /dev/null @@ -1,1006 +0,0 @@ -import _ from 'lodash' -/* eslint-disable - camelcase, - max-len, - no-return-assign, - no-unused-vars, -*/ -// 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 - * DS103: Rewrite code to no longer use __guard__ - * DS205: Consider reworking code to avoid use of IIFEs - * DS206: Consider reworking classes to avoid initClass - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import moment from 'moment' -import ColorManager from '../colors/ColorManager' -import displayNameForUser from './util/displayNameForUser' -import HistoryViewModes from './util/HistoryViewModes' -import './controllers/HistoryV2ListController' -import './controllers/HistoryV2FileTreeController' -import './controllers/HistoryV2ToolbarController' -import './controllers/HistoryV2AddLabelModalController' -import './controllers/HistoryV2DeleteLabelModalController' -import './directives/infiniteScroll' -import './directives/historyDraggableBoundary' -import './directives/historyDroppableArea' -import './components/historyEntriesList' -import './components/historyEntry' -import './components/historyLabelsList' -import './components/historyLabel' -import './components/historyFileTree' -import './components/historyFileEntity' -import { paywallPrompt } from '../../../../frontend/js/main/account-upgrade' -import getMeta from '../../utils/meta' -let HistoryManager - -export default HistoryManager = (function () { - HistoryManager = class HistoryManager { - static initClass() { - this.prototype.MAX_RECENT_UPDATES_TO_SELECT = 5 - this.prototype.BATCH_SIZE = 10 - } - - constructor(ide, $scope, localStorage) { - this.labelCurrentVersion = this.labelCurrentVersion.bind(this) - this.deleteLabel = this.deleteLabel.bind(this) - this._addLabelLocally = this._addLabelLocally.bind(this) - this.ide = ide - this.$scope = $scope - this.localStorage = localStorage - this.$scope.HistoryViewModes = HistoryViewModes - this._localStorageViewModeProjKey = `history.userPrefs.viewMode.${$scope.project_id}` - this._localStorageShowOnlyLabelsProjKey = `history.userPrefs.showOnlyLabels.${$scope.project_id}` - this._previouslySelectedPathname = null - this._loadFileTreeRequestCanceller = null - this.hardReset() - - this.$scope.toggleHistory = () => { - if (this.$scope.ui.view === 'history') { - this.hide() - } else { - this.show() - this._handleHistoryUIStateChange() - } - this.ide.$timeout(() => { - this.$scope.$broadcast('history:toggle') - }, 0) - } - - this.$scope.isHistoryLoading = () => { - const selection = this.$scope.history.selection - return ( - this.$scope.history.loadingFileTree || - (this.$scope.history.viewMode === HistoryViewModes.POINT_IN_TIME && - selection.file && - selection.file.loading) || - (this.$scope.history.viewMode === HistoryViewModes.COMPARE && - selection.diff && - selection.diff.loading) - ) - } - } - - show() { - this.$scope.ui.view = 'history' - this.hardReset() - if (this.$scope.history.showOnlyLabels) { - this.fetchNextBatchOfUpdates() - } - } - - hide() { - this.$scope.ui.view = 'editor' - } - - _getViewModeUserPref() { - return ( - this.localStorage(this._localStorageViewModeProjKey) || - HistoryViewModes.POINT_IN_TIME - ) - } - - _getShowOnlyLabelsUserPref() { - return this.localStorage(this._localStorageShowOnlyLabelsProjKey) || false - } - - _setViewModeUserPref(viewModeUserPref) { - if ( - viewModeUserPref === HistoryViewModes.POINT_IN_TIME || - viewModeUserPref === HistoryViewModes.COMPARE - ) { - this.localStorage(this._localStorageViewModeProjKey, viewModeUserPref) - } - } - - _setShowOnlyLabelsUserPref(showOnlyLabelsUserPref) { - this.localStorage( - this._localStorageShowOnlyLabelsProjKey, - !!showOnlyLabelsUserPref - ) - } - - hardReset() { - this.$scope.history = { - updates: [], - viewMode: this._getViewModeUserPref(), - nextBeforeTimestamp: null, - loading: false, - atEnd: false, - userHasFullFeature: undefined, - freeHistoryLimitHit: false, - selection: { - docs: {}, - pathname: null, - range: { - fromV: null, - toV: null, - }, - hoveredRange: { - fromV: null, - toV: null, - }, - diff: null, - files: [], - file: null, - }, - error: null, - showOnlyLabels: this._getShowOnlyLabelsUserPref(), - labels: null, - loadingFileTree: true, - } - const _deregisterFeatureWatcher = this.$scope.$watch( - 'project.features.versioning', - hasVersioning => { - if (hasVersioning != null) { - this.$scope.history.userHasFullFeature = hasVersioning - if (this.$scope.user.isAdmin) { - this.$scope.history.userHasFullFeature = true - } - _deregisterFeatureWatcher() - } - } - ) - } - - softReset() { - this.$scope.history.viewMode = this._getViewModeUserPref() - this.$scope.history.selection = { - docs: {}, - pathname: null, - range: { - fromV: null, - toV: null, - }, - hoveredRange: { - fromV: null, - toV: null, - }, - diff: null, // When history.viewMode == HistoryViewModes.COMPARE - files: [], // When history.viewMode == HistoryViewModes.COMPARE - file: null, - } - this.$scope.history.error = null - this.$scope.history.showOnlyLabels = this._getShowOnlyLabelsUserPref() - } - - toggleHistoryViewMode() { - if (this.$scope.history.viewMode === HistoryViewModes.COMPARE) { - this.softReset() - this.$scope.history.viewMode = HistoryViewModes.POINT_IN_TIME - this._setViewModeUserPref(HistoryViewModes.POINT_IN_TIME) - } else { - this.softReset() - this.$scope.history.viewMode = HistoryViewModes.COMPARE - this._setViewModeUserPref(HistoryViewModes.COMPARE) - } - this._handleHistoryUIStateChange() - this.ide.$timeout(() => { - this.$scope.$broadcast('history:toggle') - }, 0) - } - - _handleHistoryUIStateChange() { - if (this.$scope.history.viewMode === HistoryViewModes.COMPARE) { - if (this.$scope.history.showOnlyLabels) { - this.autoSelectLabelsForComparison() - } else { - this.autoSelectRecentUpdates() - } - } else { - // Point-in-time mode - if (this.$scope.history.showOnlyLabels) { - this.autoSelectLabelForPointInTime() - } else { - this.autoSelectVersionForPointInTime() - } - } - } - - setHoverFrom(fromV) { - const selection = this.$scope.history.selection - selection.hoveredRange.fromV = fromV - selection.hoveredRange.toV = selection.range.toV - this.$scope.history.hoveringOverListSelectors = true - } - - setHoverTo(toV) { - const selection = this.$scope.history.selection - selection.hoveredRange.toV = toV - selection.hoveredRange.fromV = selection.range.fromV - this.$scope.history.hoveringOverListSelectors = true - } - - resetHover() { - const selection = this.$scope.history.selection - selection.hoveredRange.toV = null - selection.hoveredRange.fromV = null - this.$scope.history.hoveringOverListSelectors = false - } - - showAllUpdates() { - if (this.$scope.history.showOnlyLabels) { - this.$scope.history.showOnlyLabels = false - this._setShowOnlyLabelsUserPref(false) - this._handleHistoryUIStateChange() - } - } - - showOnlyLabels() { - if (!this.$scope.history.showOnlyLabels) { - this.$scope.history.showOnlyLabels = true - this._setShowOnlyLabelsUserPref(true) - this._handleHistoryUIStateChange() - } - } - - restoreFile(version, pathname) { - const url = `/project/${this.$scope.project_id}/restore_file` - - return this.ide.$http.post(url, { - version, - pathname, - _csrf: window.csrfToken, - }) - } - - loadFileTreeForVersion(version) { - return this._loadFileTree(version, version) - } - - loadFileTreeDiff(toV, fromV) { - return this._loadFileTree(toV, fromV) - } - - _loadFileTree(toV, fromV) { - let url = `/project/${this.$scope.project_id}/filetree/diff` - const selection = this.$scope.history.selection - const query = [`from=${fromV}`, `to=${toV}`] - url += `?${query.join('&')}` - - this.$scope.$applyAsync( - () => (this.$scope.history.loadingFileTree = true) - ) - - selection.file = null - selection.pathname = null - - // If `this._loadFileTreeRequestCanceller` is not null, then we have a request inflight - if (this._loadFileTreeRequestCanceller != null) { - // Resolving it will cancel the inflight request (or, rather, ignore its result) - this._loadFileTreeRequestCanceller.resolve() - } - this._loadFileTreeRequestCanceller = this.ide.$q.defer() - - return this.ide.$http - .get(url, { timeout: this._loadFileTreeRequestCanceller.promise }) - .then(response => { - this.$scope.history.selection.files = response.data.diff - for (const file of this.$scope.history.selection.files) { - if (file.newPathname != null) { - file.oldPathname = file.pathname - file.pathname = file.newPathname - delete file.newPathname - } - } - this._loadFileTreeRequestCanceller = null - this.$scope.history.loadingFileTree = false - this.autoSelectFile() - }) - .catch(err => { - if (err.status !== -1) { - this._loadFileTreeRequestCanceller = null - } else { - this.$scope.history.loadingFileTree = false - } - }) - } - - selectFile(file) { - if (file != null && file.pathname != null) { - this.$scope.history.selection.pathname = - this._previouslySelectedPathname = file.pathname - this.$scope.history.selection.file = file - if (this.$scope.history.viewMode === HistoryViewModes.POINT_IN_TIME) { - this.loadFileAtPointInTime() - } else { - this.reloadDiff() - } - } - } - - autoSelectFile() { - const selectedPathname = null - const files = this.$scope.history.selection.files - let fileToSelect = null - let previouslySelectedFile = null - let previouslySelectedFileHasOp = false - const filesWithOps = this._getFilesWithOps() - const orderedOpTypes = ['edited', 'added', 'renamed', 'removed'] - - if (this._previouslySelectedPathname != null) { - previouslySelectedFile = _.find(files, { - pathname: this._previouslySelectedPathname, - }) - previouslySelectedFileHasOp = _.some(filesWithOps, { - pathname: this._previouslySelectedPathname, - }) - } - if (previouslySelectedFile != null && previouslySelectedFileHasOp) { - fileToSelect = previouslySelectedFile - } else { - for (const opType of orderedOpTypes) { - const fileWithMatchingOpType = _.find(filesWithOps, { - operation: opType, - }) - if (fileWithMatchingOpType != null) { - fileToSelect = _.find(files, { - pathname: fileWithMatchingOpType.pathname, - }) - break - } - } - if (fileToSelect == null) { - if (previouslySelectedFile != null) { - fileToSelect = previouslySelectedFile - } else { - const mainFile = _.find(files, function (file) { - return /main\.tex$/.test(file.pathname) - }) - if (mainFile != null) { - fileToSelect = mainFile - } else { - const anyTeXFile = _.find(files, function (file) { - return /\.tex$/.test(file.pathname) - }) - if (anyTeXFile != null) { - fileToSelect = anyTeXFile - } else { - fileToSelect = files[0] - } - } - } - } - } - - this.selectFile(fileToSelect) - } - - _getFilesWithOps() { - let filesWithOps - if (this.$scope.history.viewMode === HistoryViewModes.POINT_IN_TIME) { - const currentUpdate = this.getUpdateForVersion( - this.$scope.history.selection.range.toV - ) - filesWithOps = [] - if (currentUpdate != null) { - for (const pathname of currentUpdate.pathnames) { - filesWithOps.push({ - pathname, - operation: 'edited', - }) - } - for (const op of currentUpdate.project_ops) { - let fileWithOp - if (op.add != null) { - fileWithOp = { - pathname: op.add.pathname, - operation: 'added', - } - } else if (op.remove != null) { - fileWithOp = { - pathname: op.remove.pathname, - operation: 'removed', - } - } else if (op.rename != null) { - fileWithOp = { - pathname: op.rename.newPathname, - operation: 'renamed', - } - } - if (fileWithOp != null) { - filesWithOps.push(fileWithOp) - } - } - } - } else { - filesWithOps = _.reduce( - this.$scope.history.selection.files, - (curFilesWithOps, file) => { - if (file.operation) { - curFilesWithOps.push({ - pathname: file.pathname, - operation: file.operation, - }) - } - return curFilesWithOps - }, - [] - ) - } - return filesWithOps - } - - autoSelectRecentUpdates() { - if (this.$scope.history.updates.length === 0) { - return - } - - const toV = this.$scope.history.updates[0].toV - let fromV = null - - let indexOfLastUpdateNotByMe = 0 - for (let i = 0; i < this.$scope.history.updates.length; i++) { - const update = this.$scope.history.updates[i] - if ( - this._updateContainsUserId(update, this.$scope.user.id) || - i > this.MAX_RECENT_UPDATES_TO_SELECT - ) { - break - } - indexOfLastUpdateNotByMe = i - } - - fromV = this.$scope.history.updates[indexOfLastUpdateNotByMe].fromV - this.selectVersionsForCompare(toV, fromV) - } - - autoSelectVersionForPointInTime() { - if (this.$scope.history.updates.length === 0) { - return - } - let versionToSelect = this.$scope.history.updates[0].toV - const range = this.$scope.history.selection.range - if ( - range.toV != null && - range.fromV != null && - range.toV === range.fromV - ) { - versionToSelect = range.toV - } - this.selectVersionForPointInTime(versionToSelect) - } - - autoSelectLastLabel() { - if ( - this.$scope.history.labels == null || - this.$scope.history.labels.length === 0 - ) { - return - } - return this.selectLabelForPointInTime(this.$scope.history.labels[0]) - } - - expandSelectionToVersion(version) { - if (version > this.$scope.history.selection.range.toV) { - this.$scope.history.selection.range.toV = version - } else if (version < this.$scope.history.selection.range.fromV) { - this.$scope.history.selection.range.fromV = version - } - } - - selectVersionForPointInTime(version) { - const selection = this.$scope.history.selection - if ( - selection.range.toV !== version && - selection.range.fromV !== version - ) { - selection.range.toV = version - selection.range.fromV = version - this.loadFileTreeForVersion(version) - } - } - - selectVersionsForCompare(toV, fromV) { - const range = this.$scope.history.selection.range - if (range.toV !== toV || range.fromV !== fromV) { - range.toV = toV - range.fromV = fromV - this.loadFileTreeDiff(toV, fromV) - } - } - - autoSelectLabelForPointInTime() { - const selectedUpdate = this.getUpdateForVersion( - this.$scope.history.selection.range.toV - ) - let nSelectedLabels = 0 - - if (selectedUpdate != null && selectedUpdate.labels != null) { - nSelectedLabels = selectedUpdate.labels.length - } - - // If the currently selected update has no labels, select the last one (version-wise) - if (nSelectedLabels === 0) { - this.autoSelectLastLabel() - // If the update has one label, select it - } else if (nSelectedLabels === 1) { - this.selectLabelForPointInTime(selectedUpdate.labels[0]) - // If there are multiple labels for the update, select the latest - } else if (nSelectedLabels > 1) { - const sortedLabels = this.ide.$filter('orderBy')( - selectedUpdate.labels, - '-created_at' - ) - const lastLabelFromUpdate = sortedLabels[0] - this.selectLabelForPointInTime(lastLabelFromUpdate) - } - } - - selectLabelForPointInTime(labelToSelect) { - let updateToSelect = null - - if (this._isLabelSelected(labelToSelect)) { - // Label already selected - return - } - - for (const update of Array.from(this.$scope.history.updates)) { - if (update.toV === labelToSelect.version) { - updateToSelect = update - break - } - } - - if (updateToSelect != null) { - this.selectVersionForPointInTime(updateToSelect.toV) - } else { - const selection = this.$scope.history.selection - selection.range.toV = labelToSelect.version - selection.range.fromV = labelToSelect.version - this.loadFileTreeForVersion(labelToSelect.version) - } - } - - getUpdateForVersion(version) { - for (const update of this.$scope.history.updates) { - if (update.toV === version) { - return update - } - } - } - - autoSelectLabelsForComparison() { - const labels = this.$scope.history.labels - let nLabels = 0 - if (Array.isArray(labels)) { - nLabels = labels.length - } - if (nLabels === 0) { - // TODO better handling - } else if (nLabels === 1) { - this.selectVersionsForCompare(labels[0].version, labels[0].version) - } else if (nLabels > 1) { - this.selectVersionsForCompare(labels[0].version, labels[1].version) - } - } - - fetchNextBatchOfUpdates() { - if (this.$scope.history.atEnd) { - return - } - - let updatesURL = `/project/${this.ide.project_id}/updates?min_count=${this.BATCH_SIZE}` - if (this.$scope.history.nextBeforeTimestamp != null) { - updatesURL += `&before=${this.$scope.history.nextBeforeTimestamp}` - } - const labelsURL = `/project/${this.ide.project_id}/labels` - - const requests = { updates: this.ide.$http.get(updatesURL) } - - if (this.$scope.history.labels == null) { - requests.labels = this.ide.$http.get(labelsURL) - } - - this.$scope.history.loading = true - return this.ide.$q - .all(requests) - .then(response => { - this.$scope.history.loading = false - const updatesData = response.updates.data - let lastUpdateToV = null - - if (updatesData.updates.length > 0) { - lastUpdateToV = updatesData.updates[0].toV - } - if (response.labels != null) { - this.$scope.history.labels = this._loadLabels( - response.labels.data, - lastUpdateToV - ) - } - this._loadUpdates(updatesData.updates) - this.$scope.history.nextBeforeTimestamp = - updatesData.nextBeforeTimestamp - if ( - updatesData.nextBeforeTimestamp == null || - this.$scope.history.freeHistoryLimitHit || - this.$scope.history.updates.length === 0 - ) { - this.$scope.history.atEnd = true - } - if (this.$scope.history.updates.length === 0) { - this.$scope.history.loadingFileTree = false - } - }) - .catch(error => { - this.$scope.history.loading = false - const { status, statusText } = error - this.$scope.history.error = { status, statusText } - this.$scope.history.atEnd = true - this.$scope.history.loadingFileTree = false - }) - } - - _loadLabels(labels, lastUpdateToV) { - const sortedLabels = this._sortLabelsByVersionAndDate(labels) - const labelsWithoutPseudoLabel = - this._deletePseudoCurrentStateLabelIfExistent(sortedLabels) - const labelsWithPseudoLabelIfNeeded = - this._addPseudoCurrentStateLabelIfNeeded( - labelsWithoutPseudoLabel, - lastUpdateToV - ) - return labelsWithPseudoLabelIfNeeded - } - - _deletePseudoCurrentStateLabelIfExistent(labels) { - if (labels.length && labels[0].isPseudoCurrentStateLabel) { - labels.shift() - } - return labels - } - - _addPseudoCurrentStateLabelIfNeeded(labels, mostRecentVersion) { - if ( - (labels.length && labels[0].version !== mostRecentVersion) || - labels.length === 0 - ) { - const pseudoCurrentStateLabel = { - id: '1', - isPseudoCurrentStateLabel: true, - version: mostRecentVersion, - created_at: new Date().toISOString(), - } - labels.unshift(pseudoCurrentStateLabel) - } - return labels - } - - _sortLabelsByVersionAndDate(labels) { - return this.ide.$filter('orderBy')(labels, [ - 'isPseudoCurrentStateLabel', - '-version', - '-created_at', - ]) - } - - loadFileAtPointInTime() { - const toV = this.$scope.history.selection.range.toV - const { pathname } = this.$scope.history.selection - if (toV == null) { - return - } - let url = `/project/${this.$scope.project_id}/diff` - const query = [ - `pathname=${encodeURIComponent(pathname)}`, - `from=${toV}`, - `to=${toV}`, - ] - url += `?${query.join('&')}` - this.$scope.history.selection.file.loading = true - return this.ide.$http - .get(url) - .then(response => { - const { text, binary } = this._parseDiff(response.data.diff) - this.$scope.history.selection.file.binary = binary - this.$scope.history.selection.file.text = text - this.$scope.history.selection.file.loading = false - }) - .catch(function () {}) - } - - reloadDiff() { - let { diff } = this.$scope.history.selection - const { range, pathname } = this.$scope.history.selection - const { fromV, toV } = range - - if (pathname == null) { - this.$scope.history.selection.diff = null - return - } - - if ( - diff != null && - diff.pathname === pathname && - diff.fromV === fromV && - diff.toV === toV - ) { - return - } - - this.$scope.history.selection.diff = diff = { - fromV, - toV, - pathname, - error: false, - } - - diff.loading = true - let url = `/project/${this.$scope.project_id}/diff` - const query = [`pathname=${encodeURIComponent(pathname)}`] - if (diff.fromV != null && diff.toV != null) { - query.push(`from=${diff.fromV}`, `to=${diff.toV}`) - } - url += `?${query.join('&')}` - return this.ide.$http - .get(url) - .then(response => { - const { data } = response - diff.loading = false - const { text, highlights, binary } = this._parseDiff(data.diff) - diff.binary = binary - diff.text = text - diff.highlights = highlights - }) - .catch(function () { - diff.loading = false - diff.error = true - }) - } - - labelCurrentVersion(labelComment) { - return this._labelVersion( - labelComment, - this.$scope.history.selection.range.toV - ) - } - - deleteLabel(label) { - const url = `/project/${this.$scope.project_id}/labels/${label.id}` - - return this.ide - .$http({ - url, - method: 'DELETE', - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - .then(response => { - return this._deleteLabelLocally(label) - }) - } - - _deleteLabelLocally(labelToDelete) { - for (let i = 0; i < this.$scope.history.updates.length; i++) { - const update = this.$scope.history.updates[i] - if (update.toV === labelToDelete.version) { - update.labels = _.filter( - update.labels, - label => label.id !== labelToDelete.id - ) - break - } - } - this.$scope.history.labels = this._loadLabels( - _.filter( - this.$scope.history.labels, - label => label.id !== labelToDelete.id - ), - this.$scope.history.updates[0].toV - ) - this._handleHistoryUIStateChange() - } - - _isLabelSelected(label) { - if (label) { - return ( - label.version <= this.$scope.history.selection.range.toV && - label.version >= this.$scope.history.selection.range.fromV - ) - } else { - return false - } - } - - _parseDiff(diff) { - if (diff.binary) { - return { binary: true } - } - let row = 0 - let column = 0 - const highlights = [] - let text = '' - const iterable = diff || [] - for (let i = 0; i < iterable.length; i++) { - let endColumn, endRow - const entry = iterable[i] - let content = entry.u || entry.i || entry.d - if (!content) { - content = '' - } - text += content - const lines = content.split('\n') - const startRow = row - const 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 - - const range = { - start: { - row: startRow, - column: startColumn, - }, - end: { - row: endRow, - column: endColumn, - }, - } - - if (entry.i != null || entry.d != null) { - const user = - entry.meta.users != null ? entry.meta.users[0] : undefined - const name = displayNameForUser(user) - const date = moment(entry.meta.end_ts).format('Do MMM YYYY, h:mm a') - if (entry.i != null) { - highlights.push({ - label: `Added by ${name} on ${date}`, - highlight: range, - hue: ColorManager.getHueForUserId( - user != null ? user.id : undefined - ), - }) - } else if (entry.d != null) { - highlights.push({ - label: `Deleted by ${name} on ${date}`, - strikeThrough: range, - hue: ColorManager.getHueForUserId( - user != null ? user.id : undefined - ), - }) - } - } - } - - return { text, highlights } - } - - _loadUpdates(updates) { - if (updates == null) { - updates = [] - } - let previousUpdate = - this.$scope.history.updates[this.$scope.history.updates.length - 1] - const dateTimeNow = new Date() - const timestamp24hoursAgo = dateTimeNow.setDate(dateTimeNow.getDate() - 1) - let cutOffIndex = null - - const iterable = updates || [] - for (let i = 0; i < iterable.length; i++) { - const update = iterable[i] - for (const user of Array.from(update.meta.users || [])) { - if (user != null) { - user.hue = ColorManager.getHueForUserId(user.id) - } - } - if ( - previousUpdate == null || - !moment(previousUpdate.meta.end_ts).isSame(update.meta.end_ts, 'day') - ) { - update.meta.first_in_day = true - } - - previousUpdate = update - - if ( - !this.$scope.history.userHasFullFeature && - update.meta.end_ts < timestamp24hoursAgo - ) { - cutOffIndex = i || 1 // Make sure that we show at least one entry (to allow labelling). - this.$scope.history.freeHistoryLimitHit = true - if (this.$scope.project.owner._id === this.$scope.user.id) { - ga( - 'send', - 'event', - 'subscription-funnel', - 'editor-click-feature', - 'history' - ) - paywallPrompt('history') - } - break - } - } - - const firstLoad = this.$scope.history.updates.length === 0 - - if (!this.$scope.history.userHasFullFeature && cutOffIndex != null) { - updates = updates.slice(0, cutOffIndex) - } - - this.$scope.history.updates = this.$scope.history.updates.concat(updates) - - if (firstLoad) { - this._handleHistoryUIStateChange() - } - } - - _labelVersion(comment, version) { - const url = `/project/${this.$scope.project_id}/labels` - return this.ide.$http - .post(url, { - comment, - version, - _csrf: window.csrfToken, - }) - .then(response => { - return this._addLabelLocally(response.data) - }) - } - - _addLabelLocally(label) { - const localUpdate = _.find( - this.$scope.history.updates, - update => update.toV === label.version - ) - if (localUpdate != null) { - localUpdate.labels = localUpdate.labels.concat(label) - } - this.$scope.history.labels = this._loadLabels( - this.$scope.history.labels.concat(label), - this.$scope.history.updates[0].toV - ) - this._handleHistoryUIStateChange() - } - - _updateContainsUserId(update, user_id) { - for (const user of Array.from(update.meta.users)) { - if ((user != null ? user.id : undefined) === user_id) { - return true - } - } - return false - } - } - HistoryManager.initClass() - return HistoryManager -})() - -function __guard__(value, transform) { - return typeof value !== 'undefined' && value !== null - ? transform(value) - : undefined -} diff --git a/services/web/frontend/js/ide/history/components/historyEntriesList.js b/services/web/frontend/js/ide/history/components/historyEntriesList.js deleted file mode 100644 index ab158ff4d3..0000000000 --- a/services/web/frontend/js/ide/history/components/historyEntriesList.js +++ /dev/null @@ -1,138 +0,0 @@ -/* eslint-disable - max-len, - no-return-assign, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' -const historyEntriesListController = function ($scope, $element) { - const ctrl = this - ctrl.$entryListViewportEl = null - ctrl.isDragging = false - - const _isEntryElVisible = function ($entryEl) { - const entryElTop = $entryEl.offset().top - const entryElBottom = entryElTop + $entryEl.outerHeight() - const entryListViewportElTop = ctrl.$entryListViewportEl.offset().top - const entryListViewportElBottom = - entryListViewportElTop + ctrl.$entryListViewportEl.height() - - return ( - entryElTop >= entryListViewportElTop && - entryElBottom <= entryListViewportElBottom - ) - } - const _getScrollTopPosForEntry = function ($entryEl) { - const halfViewportElHeight = ctrl.$entryListViewportEl.height() / 2 - return $entryEl.offset().top - halfViewportElHeight - } - ctrl.onEntryLinked = function (entry, $entryEl) { - if ( - !ctrl.rangeSelectionEnabled && - entry.toV === ctrl.selectedHistoryVersion - ) { - $scope.$applyAsync(() => { - if (!_isEntryElVisible($entryEl)) { - ctrl.$entryListViewportEl.scrollTop( - _getScrollTopPosForEntry($entryEl) - ) - } - }) - } - } - ctrl.handleEntrySelect = entry => { - if (ctrl.rangeSelectionEnabled) { - ctrl.onRangeSelect({ - selectedToV: entry.toV, - selectedFromV: entry.fromV, - }) - } else { - ctrl.onVersionSelect({ version: entry.toV }) - } - } - ctrl.setRangeToV = toV => { - if (toV > ctrl.selectedHistoryRange.fromV) { - ctrl.onRangeSelect({ - selectedToV: toV, - selectedFromV: ctrl.selectedHistoryRange.fromV, - }) - } - } - ctrl.setRangeFromV = fromV => { - if (fromV < ctrl.selectedHistoryRange.toV) { - ctrl.onRangeSelect({ - selectedToV: ctrl.selectedHistoryRange.toV, - selectedFromV: fromV, - }) - } - } - ctrl.initHoveredRange = () => { - ctrl.hoveredHistoryRange = { - toV: ctrl.selectedHistoryRange.toV, - fromV: ctrl.selectedHistoryRange.fromV, - } - } - ctrl.resetHoveredRange = () => { - ctrl.hoveredHistoryRange = { toV: null, fromV: null } - } - ctrl.setHoveredRangeToV = toV => { - if (toV > ctrl.hoveredHistoryRange.fromV) { - $scope.$applyAsync(() => (ctrl.hoveredHistoryRange.toV = toV)) - } - } - ctrl.setHoveredRangeFromV = fromV => { - if (fromV < ctrl.hoveredHistoryRange.toV) { - $scope.$applyAsync(() => (ctrl.hoveredHistoryRange.fromV = fromV)) - } - } - ctrl.onDraggingStart = () => { - $scope.$applyAsync(() => { - ctrl.isDragging = true - ctrl.initHoveredRange() - }) - } - ctrl.onDraggingStop = (isValidDrop, boundary) => { - $scope.$applyAsync(() => { - ctrl.isDragging = false - if (!isValidDrop) { - if (boundary === 'toV') { - ctrl.setRangeToV(ctrl.hoveredHistoryRange.toV) - } else if (boundary === 'fromV') { - ctrl.setRangeFromV(ctrl.hoveredHistoryRange.fromV) - } - } - ctrl.resetHoveredRange() - }) - } - ctrl.$onInit = () => { - ctrl.$entryListViewportEl = $element.find('> .history-entries') - ctrl.resetHoveredRange() - } -} - -export default App.component('historyEntriesList', { - bindings: { - entries: '<', - users: '<', - loadEntries: '&', - loadDisabled: '<', - loadInitialize: '<', - isLoading: '<', - currentUser: '<', - freeHistoryLimitHit: '<', - currentUserIsOwner: '<', - rangeSelectionEnabled: '<', - selectedHistoryVersion: ' - _.find(ctrl.users, function (user) { - const curUserId = - (user != null ? user._id : undefined) || - (user != null ? user.id : undefined) - return curUserId === id - }) - ctrl.displayName = displayNameForUser - ctrl.displayNameById = id => displayNameForUser(_getUserById(id)) - ctrl.getProjectOpDoc = function (projectOp) { - if (projectOp.rename != null) { - return `${projectOp.rename.pathname} → ${projectOp.rename.newPathname}` - } else if (projectOp.add != null) { - return `${projectOp.add.pathname}` - } else if (projectOp.remove != null) { - return `${projectOp.remove.pathname}` - } - } - ctrl.getUserCSSStyle = function (user) { - const curUserId = - (user != null ? user._id : undefined) || - (user != null ? user.id : undefined) - const hue = ColorManager.getHueForUserId(curUserId) || 100 - if (ctrl.isEntrySelected() || ctrl.isEntryHoverSelected()) { - return { color: '#FFF' } - } else { - return { color: `hsl(${hue}, 70%, 50%)` } - } - } - ctrl.isEntrySelected = function () { - if (ctrl.rangeSelectionEnabled) { - return ( - ctrl.entry.toV <= ctrl.selectedHistoryRange.toV && - ctrl.entry.fromV >= ctrl.selectedHistoryRange.fromV - ) - } else { - return ctrl.entry.toV === ctrl.selectedHistoryVersion - } - } - - ctrl.isEntryHoverSelected = function () { - return ( - ctrl.rangeSelectionEnabled && - ctrl.entry.toV <= ctrl.hoveredHistoryRange.toV && - ctrl.entry.fromV >= ctrl.hoveredHistoryRange.fromV - ) - } - - ctrl.onDraggingStart = () => { - ctrl.historyEntriesList.onDraggingStart() - } - ctrl.onDraggingStop = (isValidDrop, boundary) => - ctrl.historyEntriesList.onDraggingStop(isValidDrop, boundary) - - ctrl.onDrop = boundary => { - if (boundary === 'toV') { - $scope.$applyAsync(() => - ctrl.historyEntriesList.setRangeToV(ctrl.entry.toV) - ) - } else if (boundary === 'fromV') { - $scope.$applyAsync(() => - ctrl.historyEntriesList.setRangeFromV(ctrl.entry.fromV) - ) - } - } - ctrl.onOver = boundary => { - if (boundary === 'toV') { - $scope.$applyAsync(() => - ctrl.historyEntriesList.setHoveredRangeToV(ctrl.entry.toV) - ) - } else if (boundary === 'fromV') { - $scope.$applyAsync(() => - ctrl.historyEntriesList.setHoveredRangeFromV(ctrl.entry.fromV) - ) - } - } - - ctrl.$onInit = () => { - ctrl.$entryEl = $element.find('> .history-entry') - ctrl.$entryDetailsEl = $element.find('.history-entry-details') - ctrl.$toVHandleEl = $element.find('.history-entry-toV-handle') - ctrl.$fromVHandleEl = $element.find('.history-entry-fromV-handle') - ctrl.historyEntriesList.onEntryLinked(ctrl.entry, ctrl.$entryEl) - } -} - -export default App.component('historyEntry', { - bindings: { - entry: '<', - currentUser: '<', - users: '<', - rangeSelectionEnabled: '<', - isDragging: '<', - selectedHistoryVersion: ' { - const [simplifiedOldPathname, simplifiedPathname] = _getSimplifiedPaths( - ctrl.fileEntity.oldPathname, - ctrl.fileEntity.pathname - ) - return `${fileOperationI18nNames.renamed} ${simplifiedOldPathname}${simplifiedPathname}` - } - ctrl.getFileOperationName = () => { - if (ctrl.fileEntity.operation === 'edited') { - return fileOperationI18nNames.edited - } else if (ctrl.fileEntity.operation === 'renamed') { - return fileOperationI18nNames.renamed - } else if (ctrl.fileEntity.operation === 'added') { - return fileOperationI18nNames.created - } else if (ctrl.fileEntity.operation === 'removed') { - return fileOperationI18nNames.deleted - } else { - return '' - } - } - - const _getSimplifiedPaths = (path1, path2) => { - const path1Parts = path1.split('/') - const path2Parts = path2.split('/') - const maxIterations = Math.min(path1Parts.length, path2Parts.length) - 1 - let commonPartIndex - for ( - commonPartIndex = 0; - commonPartIndex < maxIterations; - commonPartIndex++ - ) { - if (path1Parts[commonPartIndex] !== path2Parts[commonPartIndex]) { - break - } - } - path1Parts.splice(0, commonPartIndex) - path2Parts.splice(0, commonPartIndex) - return [path1Parts.join('/'), path2Parts.join('/')] - } - - const _handleFolderClick = function () { - ctrl.isOpen = !ctrl.isOpen - ctrl.entityTypeIconClass = _getFolderIcon() - } - - const _handleFileClick = () => - ctrl.historyFileTreeController.handleEntityClick(ctrl.fileEntity) - function _getFolderIcon() { - if (ctrl.isOpen) { - return 'fa-folder-open' - } else { - return 'fa-folder' - } - } - ctrl.$onInit = function () { - if (ctrl.fileEntity.type === 'folder') { - ctrl.isOpen = true - ctrl.entityTypeIconClass = _getFolderIcon() - ctrl.handleClick = _handleFolderClick - } else { - if (ctrl.fileEntity.operation) { - ctrl.hasOperation = true - } - ctrl.entityTypeIconClass = `fa-${iconTypeFromName(ctrl.fileEntity.name)}` - ctrl.entityOpTextClass = ctrl.fileEntity.operation - ? `history-file-entity-name-${ctrl.fileEntity.operation}` - : null - ctrl.handleClick = _handleFileClick - $scope.$watch( - () => ctrl.historyFileTreeController.selectedPathname, - selectedPathname => - (ctrl.isSelected = ctrl.fileEntity.pathname === selectedPathname) - ) - } - } -} - -export default App.component('historyFileEntity', { - require: { - historyFileTreeController: '^historyFileTree', - }, - bindings: { - fileEntity: '<', - }, - controller: ['$scope', historyFileEntityController], - templateUrl: 'historyFileEntityTpl', -}) diff --git a/services/web/frontend/js/ide/history/components/historyFileTree.js b/services/web/frontend/js/ide/history/components/historyFileTree.js deleted file mode 100644 index 39ff9dfd9e..0000000000 --- a/services/web/frontend/js/ide/history/components/historyFileTree.js +++ /dev/null @@ -1,63 +0,0 @@ -import _ from 'lodash' - -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' -const historyFileTreeController = function ($scope) { - const ctrl = this - ctrl.handleEntityClick = file => ctrl.onSelectedFileChange({ file }) - ctrl._fileTree = [] - - $scope.$watch('$ctrl.files', function (files) { - if (files != null && files.length > 0) { - ctrl._fileTree = _.reduce(files, _reducePathsToTree, []) - } - }) - - function _reducePathsToTree(currentFileTree, fileObject) { - const filePathParts = fileObject.pathname.split('/') - let currentFileTreeLocation = currentFileTree - for (let index = 0; index < filePathParts.length; index++) { - let fileTreeEntity - const pathPart = filePathParts[index] - const isFile = index === filePathParts.length - 1 - if (isFile) { - fileTreeEntity = _.clone(fileObject) - fileTreeEntity.name = pathPart - fileTreeEntity.type = 'file' - currentFileTreeLocation.push(fileTreeEntity) - } else { - fileTreeEntity = _.find( - currentFileTreeLocation, - entity => entity.name === pathPart - ) - if (fileTreeEntity == null) { - fileTreeEntity = { - name: pathPart, - type: 'folder', - children: [], - } - currentFileTreeLocation.push(fileTreeEntity) - } - currentFileTreeLocation = fileTreeEntity.children - } - } - return currentFileTree - } -} - -export default App.component('historyFileTree', { - bindings: { - files: '<', - selectedPathname: '<', - onSelectedFileChange: '&', - isLoading: '<', - }, - controller: ['$scope', historyFileTreeController], - templateUrl: 'historyFileTreeTpl', -}) diff --git a/services/web/frontend/js/ide/history/components/historyLabel.js b/services/web/frontend/js/ide/history/components/historyLabel.js deleted file mode 100644 index 3dd2333861..0000000000 --- a/services/web/frontend/js/ide/history/components/historyLabel.js +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable - max-len, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' -const historyLabelController = function () { - const ctrl = this - ctrl.$onInit = () => { - if (ctrl.showTooltip == null) { - ctrl.showTooltip = true - } - if (ctrl.isPseudoCurrentStateLabel == null) { - ctrl.isPseudoCurrentStateLabel = false - } - } -} - -export default App.component('historyLabel', { - bindings: { - labelText: '<', - labelOwnerName: ' { - return { - version: parseInt(version, 10), - labels, - } - }) - } - }) - ctrl.initHoveredRange = () => { - ctrl.hoveredHistoryRange = { - toV: ctrl.selectedHistoryRange.toV, - fromV: ctrl.selectedHistoryRange.fromV, - } - } - ctrl.resetHoveredRange = () => { - ctrl.hoveredHistoryRange = { toV: null, fromV: null } - } - ctrl.setHoveredRangeToV = toV => { - if (toV >= ctrl.hoveredHistoryRange.fromV) { - ctrl.hoveredHistoryRange.toV = toV - } - } - ctrl.setHoveredRangeFromV = fromV => { - if (fromV <= ctrl.hoveredHistoryRange.toV) { - ctrl.hoveredHistoryRange.fromV = fromV - } - } - - ctrl.isVersionSelected = function (version) { - if (ctrl.rangeSelectionEnabled) { - return ( - version <= ctrl.selectedHistoryRange.toV && - version >= ctrl.selectedHistoryRange.fromV - ) - } else { - return version === ctrl.selectedHistoryVersion - } - } - ctrl.isVersionHoverSelected = function (version) { - return ( - ctrl.rangeSelectionEnabled && - version <= ctrl.hoveredHistoryRange.toV && - version >= ctrl.hoveredHistoryRange.fromV - ) - } - ctrl.onDraggingStart = () => { - $scope.$applyAsync(() => { - ctrl.isDragging = true - ctrl.initHoveredRange() - }) - } - ctrl.onDraggingStop = (isValidDrop, boundary) => { - $scope.$applyAsync(() => { - if (!isValidDrop) { - if (boundary === 'toV') { - ctrl.setRangeToV(ctrl.hoveredHistoryRange.toV) - } else if (boundary === 'fromV') { - ctrl.setRangeFromV(ctrl.hoveredHistoryRange.fromV) - } - } - ctrl.isDragging = false - ctrl.resetHoveredRange() - }) - } - ctrl.onDrop = (boundary, versionWithLabel) => { - if (boundary === 'toV') { - $scope.$applyAsync(() => ctrl.setRangeToV(versionWithLabel.version)) - } else if (boundary === 'fromV') { - $scope.$applyAsync(() => ctrl.setRangeFromV(versionWithLabel.version)) - } - } - ctrl.onOver = (boundary, versionWithLabel) => { - if (boundary === 'toV') { - $scope.$applyAsync(() => - ctrl.setHoveredRangeToV(versionWithLabel.version) - ) - } else if (boundary === 'fromV') { - $scope.$applyAsync(() => - ctrl.setHoveredRangeFromV(versionWithLabel.version) - ) - } - } - ctrl.handleVersionSelect = versionWithLabel => { - if (ctrl.rangeSelectionEnabled) { - // TODO - ctrl.onRangeSelect({ - selectedToV: versionWithLabel.version, - selectedFromV: versionWithLabel.version, - }) - } else { - ctrl.onVersionSelect({ version: versionWithLabel.version }) - } - } - ctrl.setRangeToV = version => { - if (version >= ctrl.selectedHistoryRange.fromV) { - ctrl.onRangeSelect({ - selectedToV: version, - selectedFromV: ctrl.selectedHistoryRange.fromV, - }) - } - } - ctrl.setRangeFromV = version => { - if (version <= ctrl.selectedHistoryRange.toV) { - ctrl.onRangeSelect({ - selectedToV: ctrl.selectedHistoryRange.toV, - selectedFromV: version, - }) - } - } - ctrl.buildUserView = label => { - const user = { - _id: label.user_id, - displayName: label.user_display_name, - } - return user - } - ctrl.displayName = displayNameForUser - ctrl.getUserCSSStyle = function (user, versionWithLabel) { - const curUserId = - (user != null ? user._id : undefined) || - (user != null ? user.id : undefined) - const hue = ColorManager.getHueForUserId(curUserId) || 100 - if ( - ctrl.isVersionSelected(versionWithLabel.version) || - ctrl.isVersionHoverSelected(versionWithLabel.version) - ) { - return { color: '#FFF' } - } else { - return { color: `hsl(${hue}, 70%, 50%)` } - } - } - - ctrl.$onInit = () => { - ctrl.resetHoveredRange() - } -} - -export default App.component('historyLabelsList', { - bindings: { - labels: '<', - rangeSelectionEnabled: '<', - users: '<', - currentUser: '<', - isLoading: '<', - selectedHistoryVersion: ' - $scope.$applyAsync(() => $scope.$broadcast('open')) - ) - - return ($scope.addLabelModalFormSubmit = function () { - $scope.state.inflight = true - return ide.historyManager - .labelCurrentVersion($scope.inputs.labelName) - .then(function (response) { - $scope.state.inflight = false - return $modalInstance.close() - }) - .catch(function (response) { - const { data, status } = response - $scope.state.inflight = false - if (status === 400) { - return ($scope.state.error = { message: data }) - } else { - return ($scope.state.error = true) - } - }) - }) - }, -]) diff --git a/services/web/frontend/js/ide/history/controllers/HistoryV2DeleteLabelModalController.js b/services/web/frontend/js/ide/history/controllers/HistoryV2DeleteLabelModalController.js deleted file mode 100644 index 4db555e4e9..0000000000 --- a/services/web/frontend/js/ide/history/controllers/HistoryV2DeleteLabelModalController.js +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable - max-len, - no-return-assign, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' - -export default App.controller('HistoryV2DeleteLabelModalController', [ - '$scope', - '$modalInstance', - 'ide', - 'labelDetails', - function ($scope, $modalInstance, ide, labelDetails) { - $scope.labelDetails = labelDetails - $scope.state = { - inflight: false, - error: false, - } - - return ($scope.deleteLabel = function () { - $scope.state.inflight = true - return ide.historyManager - .deleteLabel(labelDetails) - .then(function (response) { - $scope.state.inflight = false - return $modalInstance.close() - }) - .catch(function (response) { - const { data, status } = response - $scope.state.inflight = false - if (status === 400) { - return ($scope.state.error = { message: data }) - } else { - return ($scope.state.error = true) - } - }) - }) - }, -]) diff --git a/services/web/frontend/js/ide/history/controllers/HistoryV2FileTreeController.js b/services/web/frontend/js/ide/history/controllers/HistoryV2FileTreeController.js deleted file mode 100644 index fb97dec47f..0000000000 --- a/services/web/frontend/js/ide/history/controllers/HistoryV2FileTreeController.js +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable - max-len, - no-return-assign, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' - -export default App.controller('HistoryV2FileTreeController', [ - '$scope', - 'ide', - function ($scope, ide) { - $scope.handleFileSelection = file => { - ide.historyManager.selectFile(file) - } - }, -]) diff --git a/services/web/frontend/js/ide/history/controllers/HistoryV2ListController.js b/services/web/frontend/js/ide/history/controllers/HistoryV2ListController.js deleted file mode 100644 index 3394cb2aa7..0000000000 --- a/services/web/frontend/js/ide/history/controllers/HistoryV2ListController.js +++ /dev/null @@ -1,56 +0,0 @@ -/* eslint-disable - max-len, - no-return-assign, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' - -export default App.controller('HistoryV2ListController', [ - '$scope', - '$modal', - 'ide', - function ($scope, $modal, ide) { - $scope.hoveringOverListSelectors = false - $scope.listConfig = { showOnlyLabelled: false } - - $scope.projectUsers = [] - - $scope.$watch('project.members', function (newVal) { - if (newVal != null) { - return ($scope.projectUsers = newVal.concat($scope.project.owner)) - } - }) - - $scope.loadMore = () => { - return ide.historyManager.fetchNextBatchOfUpdates() - } - - $scope.handleVersionSelect = version => - $scope.$applyAsync(() => - ide.historyManager.selectVersionForPointInTime(version) - ) - - $scope.handleRangeSelect = (selectedToV, selectedFromV) => - $scope.$applyAsync(() => - ide.historyManager.selectVersionsForCompare(selectedToV, selectedFromV) - ) - - return ($scope.handleLabelDelete = labelDetails => - $modal.open({ - templateUrl: 'historyV2DeleteLabelModalTemplate', - controller: 'HistoryV2DeleteLabelModalController', - resolve: { - labelDetails() { - return labelDetails - }, - }, - })) - }, -]) diff --git a/services/web/frontend/js/ide/history/controllers/HistoryV2ToolbarController.js b/services/web/frontend/js/ide/history/controllers/HistoryV2ToolbarController.js deleted file mode 100644 index d15c09202c..0000000000 --- a/services/web/frontend/js/ide/history/controllers/HistoryV2ToolbarController.js +++ /dev/null @@ -1,128 +0,0 @@ -/* eslint-disable - max-len, - no-return-assign, - camelcase, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' -import { debugConsole } from '@/utils/debugging' - -export default App.controller('HistoryV2ToolbarController', [ - '$scope', - '$modal', - 'ide', - 'eventTracking', - 'waitFor', - function ($scope, $modal, ide, eventTracking, waitFor) { - $scope.currentUpdate = null - $scope.currentLabel = null - - $scope.restoreState = { - inflight: false, - error: false, - } - - $scope.toolbarUIConfig = { - showOnlyLabels: false, - } - - const _deregistershowOnlyLabelsWatcher = $scope.$watch( - 'history.showOnlyLabels', - showOnlyLabels => { - if (showOnlyLabels != null) { - $scope.toolbarUIConfig.showOnlyLabels = showOnlyLabels - _deregistershowOnlyLabelsWatcher() - } - } - ) - - $scope.$watch('toolbarUIConfig.showOnlyLabels', (newVal, oldVal) => { - if (newVal != null && newVal !== oldVal) { - if (newVal) { - ide.historyManager.showOnlyLabels() - } else { - ide.historyManager.showAllUpdates() - } - } - }) - - $scope.$watch('history.viewMode', (newVal, oldVal) => { - if (newVal != null && newVal !== oldVal) { - $scope.currentUpdate = ide.historyManager.getUpdateForVersion(newVal) - } - }) - - $scope.$watch('history.selection.range.toV', (newVal, oldVal) => { - if ( - newVal != null && - newVal !== oldVal && - $scope.history.viewMode === $scope.HistoryViewModes.POINT_IN_TIME - ) { - $scope.currentUpdate = ide.historyManager.getUpdateForVersion(newVal) - } - }) - - $scope.toggleHistoryViewMode = () => { - ide.historyManager.toggleHistoryViewMode() - } - - $scope.restoreDeletedFile = function () { - const { pathname, deletedAtV } = $scope.history.selection.file - if (pathname == null || deletedAtV == null) { - return - } - - eventTracking.sendMB('history-v2-restore-deleted') - $scope.restoreState.inflight = true - return ide.historyManager - .restoreFile(deletedAtV, pathname) - .then(function (response) { - const { data } = response - return openEntity(data) - }) - .catch(() => - ide.showGenericMessageModal( - 'Sorry, something went wrong with the restore' - ) - ) - .finally(() => ($scope.restoreState.inflight = false)) - } - - $scope.showAddLabelDialog = () => { - $modal.open({ - templateUrl: 'historyV2AddLabelModalTemplate', - controller: 'HistoryV2AddLabelModalController', - resolve: { - update() { - return $scope.history.selection.update - }, - }, - }) - } - - function openEntity(data) { - const { id, type } = data - return waitFor(() => ide.fileTreeManager.findEntityById(id), 3000) - .then(function (entity) { - if (type === 'doc') { - ide.editorManager.openDoc(entity) - ide.$timeout(() => { - $scope.$broadcast('history:toggle') - }, 0) - } else if (type === 'file') { - ide.binaryFilesManager.openFile(entity) - ide.$timeout(() => { - $scope.$broadcast('history:toggle') - }, 0) - } - }) - .catch(debugConsole.error) - } - }, -]) diff --git a/services/web/frontend/js/ide/history/directives/historyDraggableBoundary.js b/services/web/frontend/js/ide/history/directives/historyDraggableBoundary.js deleted file mode 100644 index 9a115108d6..0000000000 --- a/services/web/frontend/js/ide/history/directives/historyDraggableBoundary.js +++ /dev/null @@ -1,35 +0,0 @@ -import App from '../../../base' - -export default App.directive('historyDraggableBoundary', function () { - return { - scope: { - historyDraggableBoundary: '@', - historyDraggableBoundaryOnDragStart: '&', - historyDraggableBoundaryOnDragStop: '&', - }, - restrict: 'A', - link(scope, element, attrs) { - element.data('selectionBoundary', { - boundary: scope.historyDraggableBoundary, - }) - element.draggable({ - axis: 'y', - opacity: false, - helper: 'clone', - revert: true, - scroll: true, - cursor: 'row-resize', - start(e, ui) { - ui.helper.data('wasProperlyDropped', false) - scope.historyDraggableBoundaryOnDragStart() - }, - stop(e, ui) { - scope.historyDraggableBoundaryOnDragStop({ - isValidDrop: ui.helper.data('wasProperlyDropped'), - boundary: scope.historyDraggableBoundary, - }) - }, - }) - }, - } -}) diff --git a/services/web/frontend/js/ide/history/directives/historyDroppableArea.js b/services/web/frontend/js/ide/history/directives/historyDroppableArea.js deleted file mode 100644 index 082c1b553e..0000000000 --- a/services/web/frontend/js/ide/history/directives/historyDroppableArea.js +++ /dev/null @@ -1,28 +0,0 @@ -import App from '../../../base' - -export default App.directive('historyDroppableArea', function () { - return { - scope: { - historyDroppableAreaOnDrop: '&', - historyDroppableAreaOnOver: '&', - historyDroppableAreaOnOut: '&', - }, - restrict: 'A', - link(scope, element, attrs) { - element.droppable({ - accept: e => '.history-entry-toV-handle, .history-entry-fromV-handle', - drop: (e, ui) => { - const draggedBoundary = - ui.draggable.data('selectionBoundary').boundary - ui.helper.data('wasProperlyDropped', true) - scope.historyDroppableAreaOnDrop({ boundary: draggedBoundary }) - }, - over: (e, ui) => { - const draggedBoundary = - ui.draggable.data('selectionBoundary').boundary - scope.historyDroppableAreaOnOver({ boundary: draggedBoundary }) - }, - }) - }, - } -}) diff --git a/services/web/frontend/js/ide/history/directives/infiniteScroll.js b/services/web/frontend/js/ide/history/directives/infiniteScroll.js deleted file mode 100644 index dbc5cc704c..0000000000 --- a/services/web/frontend/js/ide/history/directives/infiniteScroll.js +++ /dev/null @@ -1,55 +0,0 @@ -/* eslint-disable - max-len, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' - -export default App.directive('infiniteScroll', function () { - return { - link(scope, element, attrs, ctrl) { - const innerElement = element.find('.infinite-scroll-inner') - element.css({ 'overflow-y': 'auto' }) - - const atEndOfListView = function () { - if (attrs.infiniteScrollUpwards != null) { - return atTopOfListView() - } else { - return atBottomOfListView() - } - } - - const atTopOfListView = () => element.scrollTop() < 30 - - const atBottomOfListView = () => - element.scrollTop() + element.height() >= innerElement.height() - 30 - - const listShorterThanContainer = () => - element.height() > innerElement.height() - - function loadUntilFull() { - if ( - (listShorterThanContainer() || atEndOfListView()) && - !scope.$eval(attrs.infiniteScrollDisabled) - ) { - const promise = scope.$eval(attrs.infiniteScroll) - return promise.then(() => setTimeout(() => loadUntilFull(), 0)) - } - } - - element.on('scroll', event => loadUntilFull()) - - return scope.$watch(attrs.infiniteScrollInitialize, function (value) { - if (value) { - return loadUntilFull() - } - }) - }, - } -}) diff --git a/services/web/frontend/js/ide/history/util/HistoryViewModes.js b/services/web/frontend/js/ide/history/util/HistoryViewModes.js deleted file mode 100644 index 4ef6ab7847..0000000000 --- a/services/web/frontend/js/ide/history/util/HistoryViewModes.js +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable - no-return-assign, - no-unused-vars, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -let HistoryViewModes - -export default HistoryViewModes = { - POINT_IN_TIME: 'point_in_time', - COMPARE: 'compare', -} diff --git a/services/web/frontend/js/shared/context/layout-context.tsx b/services/web/frontend/js/shared/context/layout-context.tsx index efb7a7906c..44a547217a 100644 --- a/services/web/frontend/js/shared/context/layout-context.tsx +++ b/services/web/frontend/js/shared/context/layout-context.tsx @@ -14,6 +14,7 @@ import localStorage from '../../infrastructure/local-storage' import getMeta from '../../utils/meta' import { debugConsole } from '@/utils/debugging' import { BinaryFile } from '@/features/file-view/types/binary-file' +import useScopeEventEmitter from '@/shared/hooks/use-scope-event-emitter' export type IdeLayout = 'sideBySide' | 'flat' export type IdeView = 'editor' | 'file' | 'pdf' | 'history' @@ -60,15 +61,15 @@ function setLayoutInLocalStorage(pdfLayout: IdeLayout) { export const LayoutProvider: FC = ({ children }) => { // what to show in the "flat" view (editor or pdf) const [view, _setView] = useScopeValue('ui.view') - const [toggleHistory] = useScopeValue<() => void>('toggleHistory') const [openFile] = useScopeValue('openFile') + const historyToggleEmitter = useScopeEventEmitter('history:toggle', true) const setView = useCallback( (value: IdeView) => { _setView(oldValue => { // ensure that the "history:toggle" event is broadcast when switching in or out of history view if (value === 'history' || oldValue === 'history') { - toggleHistory() + historyToggleEmitter() } if (value === 'editor' && openFile) { @@ -82,7 +83,7 @@ export const LayoutProvider: FC = ({ children }) => { return value }) }, - [_setView, openFile, toggleHistory] + [_setView, openFile, historyToggleEmitter] ) // whether the chat pane is open diff --git a/services/web/frontend/stories/decorators/scope.tsx b/services/web/frontend/stories/decorators/scope.tsx index 127f8c0cf2..8fae643504 100644 --- a/services/web/frontend/stories/decorators/scope.tsx +++ b/services/web/frontend/stories/decorators/scope.tsx @@ -89,7 +89,6 @@ const initialize = () => { pdfViewer: 'js', syntaxValidation: true, }, - toggleHistory: () => {}, editor: { richText: false, sharejs_doc: { diff --git a/services/web/test/frontend/helpers/editor-providers.jsx b/services/web/test/frontend/helpers/editor-providers.jsx index d2a92510e4..007a143345 100644 --- a/services/web/test/frontend/helpers/editor-providers.jsx +++ b/services/web/test/frontend/helpers/editor-providers.jsx @@ -116,7 +116,6 @@ export function EditorProviders({ }, $on: sinon.stub(), $applyAsync: sinon.stub(), - toggleHistory: sinon.stub(), permissionsLevel, }, scope