diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js index 10efe2daf5..6c8d578807 100644 --- a/services/web/app/src/Features/Project/ProjectController.js +++ b/services/web/app/src/Features/Project/ProjectController.js @@ -663,21 +663,6 @@ const ProjectController = { } ) }, - reviewPanelAssignment(cb) { - SplitTestHandler.getAssignment( - req, - res, - 'review-panel', - (error, assignment) => { - // do not fail editor load if assignment fails - if (error) { - cb(null, { variant: 'default' }) - } else { - cb(null, assignment) - } - } - ) - }, idePageAssignment(cb) { SplitTestHandler.getAssignment( req, @@ -713,7 +698,6 @@ const ProjectController = { isInvitedMember, brandVariation, pdfjsAssignment, - reviewPanelAssignment, idePageAssignment, personalAccessTokenAssignment, projectTags, @@ -898,7 +882,6 @@ const ProjectController = { showUpgradePrompt, fixedSizeDocument: true, useOpenTelemetry: Settings.useOpenTelemetryClient, - isReviewPanelReact: reviewPanelAssignment.variant === 'react', idePageReact, showPersonalAccessToken, optionalPersonalAccessToken, diff --git a/services/web/app/views/project/editor/editor-pane.pug b/services/web/app/views/project/editor/editor-pane.pug index 5cf7e220fb..0d86e44678 100644 --- a/services/web/app/views/project/editor/editor-pane.pug +++ b/services/web/app/views/project/editor/editor-pane.pug @@ -45,10 +45,6 @@ div(ng-controller="EditorLoaderController") include ../../source-editor/source-editor - - div(ng-if="!reviewPanel.isReact") - if !isRestrictedTokenMember - include ./review-panel if moduleIncludesAvailable('editor:symbol-palette') .div(vertical-resizable-bottom) diff --git a/services/web/app/views/project/editor/meta.pug b/services/web/app/views/project/editor/meta.pug index 85e3fe2ce1..3530cbba0d 100644 --- a/services/web/app/views/project/editor/meta.pug +++ b/services/web/app/views/project/editor/meta.pug @@ -32,7 +32,6 @@ meta(name="ol-showSupport", data-type="boolean" content=showSupport) meta(name="ol-showTemplatesServerPro", data-type="boolean" content=showTemplatesServerPro) meta(name="ol-showPersonalAccessToken", data-type="boolean" content=showPersonalAccessToken) meta(name="ol-optionalPersonalAccessToken", data-type="boolean" content=optionalPersonalAccessToken) -meta(name="ol-isReviewPanelReact", data-type="boolean" content=isReviewPanelReact) meta(name="ol-hasTrackChangesFeature", data-type="boolean" content=hasTrackChangesFeature) meta(name="ol-mathJax3Path" content=mathJax3Path) meta(name="ol-completedTutorials", data-type="json" content=user.completedTutorials) diff --git a/services/web/app/views/project/editor/review-panel.pug b/services/web/app/views/project/editor/review-panel.pug deleted file mode 100644 index 532ad8da80..0000000000 --- a/services/web/app/views/project/editor/review-panel.pug +++ /dev/null @@ -1,643 +0,0 @@ -#review-panel( - ng-class="{ 'rp-collapsed-displaying-entry': reviewPanel.entryHover, 'rp-offset-widgets': true }" -) - .rp-in-editor-widgets - a.rp-track-changes-indicator( - href - ng-if="editor.wantTrackChanges" - 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.nVisibleSelectedChanges > 1" - ng-click="showBulkAcceptDialog();" - ) - i.fa.fa-check - |  #{translate("accept_all")} - | ({{ reviewPanel.nVisibleSelectedChanges }}) - a.rp-bulk-actions-btn( - href - ng-if="reviewPanel.nVisibleSelectedChanges > 1" - ng-click="showBulkRejectDialog();" - ) - i.fa.fa-times - |  #{translate("reject_all")} - | ({{ reviewPanel.nVisibleSelectedChanges }}) - if hasFeature('track-changes') - a.rp-add-comment-btn( - href - ng-if="reviewPanel.entries[editor.open_doc_id]['add-comment'] != null && permissions.comment" - ng-mousedown="addNewComment($event);" - ) - i.fa.fa-comment - |  #{translate("add_comment")} - a.review-panel-toggler( - href - ng-click="handleTogglerClick($event);" - ) - .review-panel-toolbar - resolved-comments-dropdown( - class="rp-flex-block" - entries="reviewPanel.resolvedComments" - threads="reviewPanel.commentThreads" - resolved-ids="reviewPanel.resolvedThreadIds" - docs="docs" - on-open="refreshResolvedCommentsDropdown();" - on-unresolve="unresolveComment(threadId);" - on-delete="deleteThread(entryId, docId, threadId);" - is-loading="reviewPanel.dropdown.loading" - permissions="permissions" - ) - span.review-panel-toolbar-label - span.review-panel-toolbar-icon-on( - ng-if="editor.wantTrackChanges === true" - ) - i.fa.fa-circle - span(ng-click="toggleFullTCStateCollapse();") - span(ng-if="editor.wantTrackChanges === false") !{translate("track_changes_is_off")} - span(ng-if="editor.wantTrackChanges === true") !{translate("track_changes_is_on")} - span.rp-tc-state-collapse( - ng-class="{ 'rp-tc-state-collapse-on': reviewPanel.fullTCStateCollapsed }" - ) - i.fa.fa-angle-down - ul.rp-tc-state( - review-panel-collapse-height="reviewPanel.fullTCStateCollapsed" - ) - li.rp-tc-state-item.rp-tc-state-item-everyone - span.rp-tc-state-item-name( - tooltip=translate('tc_switch_everyone_tip') - tooltip-placement="left" - tooltip-append-to-body="true" - tooltip-popup-delay="1000" - ) !{translate("tc_everyone")} - review-panel-toggle( - description="Track changes for everyone" - ng-model="reviewPanel.trackChangesOnForEveryone" - on-toggle="toggleTrackChangesForEveryone(isOn);" - is-disabled="!project.features.trackChanges || !permissions.write" - ) - li.rp-tc-state-item( - ng-repeat="member in reviewPanel.formattedProjectMembers" - ) - span.rp-tc-state-item-name( - ng-class="{ 'rp-tc-state-item-name-disabled' : reviewPanel.trackChangesOnForEveryone}" - tooltip=translate('tc_switch_user_tip') - tooltip-placement="left" - tooltip-append-to-body="true" - tooltip-popup-delay="1000" - ) {{ member.name }} - review-panel-toggle( - description="Track changes for {{ member.name }}" - ng-model="reviewPanel.trackChangesState[member.id].value" - on-toggle="toggleTrackChangesForUser(isOn, member.id);" - is-disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write" - ) - - li.rp-tc-state-separator - li.rp-tc-state-item - span.rp-tc-state-item-name( - ng-class="{ 'rp-tc-state-item-name-disabled' : reviewPanel.trackChangesOnForEveryone}" - tooltip=translate('tc_switch_guests_tip') - tooltip-placement="left" - tooltip-append-to-body="true" - tooltip-popup-delay="1000" - ) !{translate("tc_guests")} - review-panel-toggle( - description="Track changes for guests" - ng-model="reviewPanel.trackChangesOnForGuests" - on-toggle="toggleTrackChangesForGuests(isOn);" - is-disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write || !reviewPanel.trackChangesForGuestsAvailable" - ) - - .rp-entry-list( - review-panel-sorted - ng-if="reviewPanel.subView === SubViews.CUR_FILE" - ) - .rp-entry-list-inner - .rp-entry-wrapper( - ng-repeat="(entry_id, entry) in reviewPanel.entries[editor.open_doc_id]" - ng-if="entry.visible" - ) - div(ng-if="entry.type === 'insert' || entry.type === 'delete'") - change-entry( - entry="entry" - user="users[entry.metadata.user_id]" - on-reject="rejectChanges(entry.entry_ids);" - on-accept="acceptChanges(entry.entry_ids);" - on-indicator-click="toggleReviewPanel();" - on-mouse-enter="mouseEnterIndicator()" - on-mouse-leave="mouseLeaveIndicator()" - on-body-click="gotoEntry(editor.open_doc_id, entry.offset)" - permissions="permissions" - ) - - div(ng-if="entry.type === 'aggregate-change'") - aggregate-change-entry( - entry="entry" - user="users[entry.metadata.user_id]" - on-reject="rejectChanges(entry.entry_ids);" - on-accept="acceptChanges(entry.entry_ids);" - on-indicator-click="toggleReviewPanel();" - on-mouse-enter="mouseEnterIndicator()" - on-mouse-leave="mouseLeaveIndicator()" - on-body-click="gotoEntry(editor.open_doc_id, entry.offset)" - permissions="permissions" - ) - - div(ng-if="entry.type === 'comment'") - comment-entry( - entry="entry" - threads="reviewPanel.commentThreads" - on-resolve="resolveComment(editor.open_doc_id, entry_id)" - on-reply="submitReply(entry, entry_id);" - on-indicator-click="toggleReviewPanel();" - on-mouse-enter="mouseEnterIndicator()" - on-mouse-leave="mouseLeaveIndicator()" - on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)" - on-delete="deleteComment(entry.thread_id, comment.id)" - on-body-click="gotoEntry(editor.open_doc_id, entry.offset)" - permissions="permissions" - ng-if="!loadingThreads" - ) - - div(ng-if="entry.type === 'add-comment' && permissions.comment") - add-comment-entry( - on-start-new="startNewComment();" - 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.nVisibleSelectedChanges" - ) - - .rp-entry-list( - ng-if="reviewPanel.subView === SubViews.OVERVIEW" - ) - .rp-loading(ng-if="reviewPanel.overview.loading") - i.fa.fa-spinner.fa-spin - .rp-overview-file( - ng-repeat="doc in docs" - ng-if="!reviewPanel.overview.loading" - ) - .rp-overview-file-header( - ng-if="(reviewPanel.entries[doc.doc.id] != null) && (reviewPanel.entries[doc.doc.id] | notEmpty)" - ng-click="reviewPanel.overview.docsCollapsedState[doc.doc.id] = ! reviewPanel.overview.docsCollapsedState[doc.doc.id]" - ) - span.rp-overview-file-header-collapse( - ng-class="{ 'rp-overview-file-header-collapse-on': reviewPanel.overview.docsCollapsedState[doc.doc.id] }" - ) - i.fa.fa-angle-down - | {{ doc.path }} - span.rp-overview-file-num-entries( - ng-show="reviewPanel.overview.docsCollapsedState[doc.doc.id]" - )  ({{ reviewPanel.entries[doc.doc.id] | numKeys }}) - - .rp-overview-file-entries( - review-panel-collapse-height="reviewPanel.overview.docsCollapsedState[doc.doc.id]" - ) - .rp-entry-wrapper( - ng-repeat="(entry_id, entry) in reviewPanel.entries[doc.doc.id] | orderOverviewEntries" - ng-if="!(entry.type === 'comment' && reviewPanel.commentThreads[entry.thread_id].resolved === true)" - ) - div(ng-if="entry.type === 'insert' || entry.type === 'delete'") - change-entry( - entry="entry" - user="users[entry.metadata.user_id]" - ng-click="gotoEntry(doc.doc.id, entry.offset)" - permissions="permissions" - ) - - div(ng-if="entry.type === 'aggregate-change'") - aggregate-change-entry( - entry="entry" - user="users[entry.metadata.user_id]" - ng-click="gotoEntry(doc.doc.id, entry.offset)" - permissions="permissions" - ) - - div(ng-if="entry.type === 'comment'") - comment-entry( - entry="entry" - threads="reviewPanel.commentThreads" - on-reply="submitReply(entry, entry_id);" - on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)" - on-delete="deleteComment(entry.thread_id, comment.id)" - ng-click="gotoEntry(doc.doc.id, entry.offset)" - permissions="permissions" - ) - - .rp-nav - a.rp-nav-item( - href - ng-click="setSubView(SubViews.CUR_FILE);" - ng-class="{ 'rp-nav-item-active' : reviewPanel.subView === SubViews.CUR_FILE }" - ) - i.fa.fa-file-text-o - span.rp-nav-label #{translate("current_file")} - a.rp-nav-item( - href - ng-click="setSubView(SubViews.OVERVIEW);" - ng-class="{ 'rp-nav-item-active' : reviewPanel.subView === SubViews.OVERVIEW }" - ) - i.fa.fa-list - span.rp-nav-label #{translate("overview")} - - .rp-unsupported-msg-wrapper - .rp-unsupported-msg - i.fa.fa-5x.fa-exclamation-triangle - p.rp-unsupported-msg-title Join our #[a(href="/beta/participate") Beta program] to use Track Changes in Rich Text mode! - p You can #[a(href="/beta/participate") sign up] instantly to test and give feedback on our new version that includes comments and track changes! - - -script(type='text/ng-template', id='changeEntryTemplate') - div( - ng-mouseenter="onMouseEnter();" - ng-mouseleave="onMouseLeave();" - ) - .rp-entry-callout( - ng-class="'rp-entry-callout-' + entry.type" - ) - .rp-entry-indicator( - ng-switch="entry.type" - ng-class="{ 'rp-entry-indicator-focused': entry.focused }" - ng-click="onIndicatorClick();" - ) - i.fa.fa-pencil(ng-switch-when="insert") - i.rp-icon-delete(ng-switch-when="delete") - .rp-entry( - ng-class="[ 'rp-entry-' + entry.type, (entry.focused ? 'rp-entry-focused' : '')]" - ) - .rp-entry-body - .rp-entry-action-icon(ng-switch="entry.type") - i.fa.fa-pencil(ng-switch-when="insert") - i.rp-icon-delete(ng-switch-when="delete") - .rp-entry-details - .rp-entry-description(ng-switch="entry.type") - span(ng-switch-when="insert") #{translate("tracked_change_added")}  - ins.rp-content-highlight {{ entry.content | limitTo:(isCollapsed ? contentLimit : entry.content.length) }} - a.rp-collapse-toggle( - href - ng-if="needsCollapsing" - ng-click="toggleCollapse();" - ) {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }} - span(ng-switch-when="delete") #{translate("tracked_change_deleted")}  - del.rp-content-highlight {{ entry.content | limitTo:(isCollapsed ? contentLimit : entry.content.length) }} - a.rp-collapse-toggle( - href - ng-if="needsCollapsing" - ng-click="toggleCollapse();" - ) {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }} - .rp-entry-metadata - | {{ entry.metadata.ts | date : 'MMM d, y h:mm a' }} •  - span.rp-entry-user(ng-switch="user.name" style="color: hsl({{ user.hue }}, 70%, 40%);") - span(ng-switch-when="undefined") #{translate("anonymous")} - span(ng-switch-default) {{ user.name }} - .rp-entry-actions(ng-if="permissions.write") - a.rp-entry-button(href, ng-click="onReject();") - i.fa.fa-times - |  #{translate("reject")} - a.rp-entry-button(href, ng-click="onAccept();") - i.fa.fa-check - |  #{translate("accept")} - -script(type='text/ng-template', id='aggregateChangeEntryTemplate') - div( - ng-mouseenter="onMouseEnter();" - ng-mouseleave="onMouseLeave();" - ) - .rp-entry-callout.rp-entry-callout-aggregate - .rp-entry-indicator( - ng-class="{ 'rp-entry-indicator-focused': entry.focused }" - ng-click="onIndicatorClick();" - ) - i.fa.fa-pencil - .rp-entry.rp-entry-aggregate( - ng-class="{ 'rp-entry-focused': entry.focused }" - ) - .rp-entry-body - .rp-entry-action-icon - i.fa.fa-pencil - .rp-entry-details - .rp-entry-description - | #{translate("aggregate_changed")}  - del.rp-content-highlight - | {{ entry.metadata.replaced_content | limitTo:(isDeletionCollapsed ? contentLimit : entry.metadata.replaced_content.length) }} - a.rp-collapse-toggle( - href - ng-if="deletionNeedsCollapsing" - ng-click="toggleDeletionCollapse();" - ) {{ isDeletionCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }} - | #{translate("aggregate_to")}  - ins.rp-content-highlight - | {{ entry.content | limitTo:(isInsertionCollapsed ? contentLimit : entry.contentlength) }} - a.rp-collapse-toggle( - href - ng-if="insertionNeedsCollapsing" - ng-click="toggleInsertionCollapse();" - ) {{ isInsertionCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }} - .rp-entry-metadata - | {{ entry.metadata.ts | date : 'MMM d, y h:mm a' }} •  - span.rp-entry-user(ng-switch="user.name" style="color: hsl({{ user.hue }}, 70%, 40%);") - span(ng-switch-when="undefined") #{translate("anonymous")} - span(ng-switch-default) {{ user.name }} - .rp-entry-actions(ng-if="permissions.write") - a.rp-entry-button(href, ng-click="onReject();") - i.fa.fa-times - |  #{translate("reject")} - a.rp-entry-button(href, ng-click="onAccept();") - i.fa.fa-check - |  #{translate("accept")} - -script(type='text/ng-template', id='commentEntryTemplate') - .rp-comment-wrapper( - ng-class="{ 'rp-comment-wrapper-resolving': state.animating }" - ng-mouseenter="onMouseEnter();" - ng-mouseleave="onMouseLeave();" - ) - .rp-entry-callout.rp-entry-callout-comment - .rp-entry-indicator( - ng-class="{ 'rp-entry-indicator-focused': entry.focused }" - ng-click="onIndicatorClick();" - ) - i.fa.fa-comment - .rp-entry.rp-entry-comment( - ng-class="{ 'rp-entry-focused': entry.focused, 'rp-entry-comment-resolving': state.animating }" - ) - - .rp-loading(ng-if="!threads[entry.thread_id].submitting && (!threads[entry.thread_id] || threads[entry.thread_id].messages.length == 0)") - | #{translate("no_comments")} - .rp-comment-loaded - .rp-comment( - ng-repeat="comment in threads[entry.thread_id].messages track by comment.id" - ) - p.rp-comment-content - span(ng-if="!comment.editing") - span.rp-entry-user( - style="color: hsl({{ comment.user.hue }}, 70%, 40%);", - ) {{ comment.user.name }}:  - span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}") - textarea.rp-comment-input( - expandable-text-area - ng-if="comment.editing" - ng-model="comment.content" - ng-keypress="saveEditOnEnter($event, comment);" - ng-blur="saveEdit(comment)" - autofocus - stop-propagation="click" - ) - .rp-entry-metadata(ng-if="!comment.editing") - span(ng-if="!comment.deleting") {{ comment.timestamp | date : 'MMM d, y h:mm a' }} - span.rp-comment-actions(ng-if="comment.user.isSelf && !comment.deleting") - |  •  - a(href, ng-click="startEditing(comment)") #{translate("edit")} - span(ng-if="threads[entry.thread_id].messages.length > 1") - |  •  - a(href, ng-click="confirmDelete(comment)") #{translate("delete")} - span.rp-confim-delete(ng-if="comment.user.isSelf && comment.deleting") - | #{translate("are_you_sure")} - | •  - a(href, ng-click="doDelete(comment)") #{translate("delete")} - |  •  - a(href, ng-click="cancelDelete(comment)") #{translate("cancel")} - - .rp-loading(ng-if="threads[entry.thread_id].submitting") - i.fa.fa-spinner.fa-spin - .rp-comment-reply(ng-if="permissions.comment") - textarea.rp-comment-input( - expandable-text-area - ng-model="entry.replyContent" - ng-keypress="handleCommentReplyKeyPress($event);" - stop-propagation="click" - placeholder=translate("hit_enter_to_reply") - ) - .rp-entry-actions - button.rp-entry-button( - ng-click="animateAndCallOnResolve();" - ng-if="permissions.comment && permissions.write" - ) - i.fa.fa-inbox - |  #{translate("resolve")} - button.rp-entry-button( - ng-click="onReply();" - ng-if="permissions.comment" - ng-disabled="!entry.replyContent.length" - ) - i.fa.fa-reply - |  #{translate("reply")} - -script(type='text/ng-template', id='resolvedCommentEntryTemplate') - .rp-resolved-comment - div - .rp-resolved-comment-context - | #{translate("quoted_text_in")}  - span.rp-resolved-comment-context-file {{ thread.docName }} - p.rp-resolved-comment-context-quote - span {{ thread.content | limitTo:(isCollapsed ? contentLimit : thread.content.length)}} - a.rp-collapse-toggle( - href - ng-if="needsCollapsing" - ng-click="toggleCollapse();" - )  {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }} - .rp-comment( - ng-repeat="comment in thread.messages track by comment.id" - ) - p.rp-comment-content - span.rp-entry-user( - style="color: hsl({{ comment.user.hue }}, 70%, 40%);" - ng-if="$first || comment.user.id !== thread.messages[$index - 1].user.id" - ) {{ comment.user.name }}:  - span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}") - .rp-entry-metadata - | {{ comment.timestamp | date : 'MMM d, y h:mm a' }} - .rp-comment.rp-comment-resolver - p.rp-comment-resolver-content - span.rp-entry-user( - style="color: hsl({{ thread.resolved_by_user.hue }}, 70%, 40%);" - ) {{ thread.resolved_by_user.name }}:  - | #{translate("mark_as_resolved")}. - .rp-entry-metadata - | {{ thread.resolved_at | date : 'MMM d, y h:mm a' }} - - .rp-entry-actions(ng-if="permissions.comment && permissions.write") - a.rp-entry-button( - href - ng-click="onUnresolve({ 'threadId': thread.threadId });" - ) - |  #{translate("reopen")} - a.rp-entry-button( - href - ng-click="onDelete({ 'entryId': thread.entryId, 'docId': thread.docId, 'threadId': thread.threadId });" - ) - |  #{translate("delete")} - - -script(type='text/ng-template', id='addCommentEntryTemplate') - div - .rp-entry-callout.rp-entry-callout-add-comment - .rp-entry.rp-entry-add-comment( - ng-class="[ (state.isAdding ? 'rp-entry-adding-comment' : ''), (entry.focused ? 'rp-entry-focused' : '')]" - ) - a.rp-add-comment-btn( - href - ng-if="!state.isAdding" - ng-click="startNewComment();" - ) - i.fa.fa-comment - |  #{translate("add_comment")} - div(ng-if="state.isAdding") - .rp-new-comment - textarea.rp-comment-input( - expandable-text-area - ng-model="state.content" - ng-keypress="handleCommentKeyPress($event);" - ng-keydown="handleCommentKeyDown($event);" - placeholder=translate("add_your_comment_here") - focus-on="comment:new:open" - ) - .rp-entry-actions - button.rp-entry-button.rp-entry-button-cancel( - ng-click="cancelNewComment();" - ) - i.fa.fa-times - |  #{translate("cancel")} - button.rp-entry-button( - ng-click="submitNewComment()" - ng-disabled="!state.content.length" - ) - i.fa.fa-comment - |  #{translate("comment")} - -script(type='text/ng-template', id='bulkActionsEntryTemplate') - div(ng-if="nEntries > 1") - .rp-entry-callout.rp-entry-callout-bulk-actions - .rp-entry.rp-entry-bulk-actions - a.rp-bulk-actions-btn( - href - ng-click="bulkReject();" - ) - i.fa.fa-times - |  #{translate("reject_all")} - | ({{ nEntries }}) - a.rp-bulk-actions-btn( - href - ng-click="bulkAccept();" - ) - i.fa.fa-check - |  #{translate("accept_all")} - | ({{ nEntries }}) - -script(type='text/ng-template', id='resolvedCommentsDropdownTemplate') - .resolved-comments - .resolved-comments-backdrop( - ng-class="{ 'resolved-comments-backdrop-visible' : state.isOpen }" - ng-click="state.isOpen = false" - ) - a.resolved-comments-toggle( - href - ng-click="toggleOpenState();" - tooltip=translate("resolved_comments") - tooltip-placement="bottom" - tooltip-append-to-body="true" - ) - i.fa.fa-inbox - .resolved-comments-dropdown( - ng-class="{ 'resolved-comments-dropdown-open' : state.isOpen }" - ) - .rp-loading(ng-if="isLoading") - i.fa.fa-spinner.fa-spin - .resolved-comments-scroller( - ng-if="!isLoading" - ) - resolved-comment-entry( - ng-repeat="thread in resolvedComments | orderBy:'resolved_at':true" - thread="thread" - on-unresolve="handleUnresolve(threadId);" - on-delete="handleDelete(entryId, docId, threadId);" - permissions="permissions" - ) - .rp-loading(ng-if="!resolvedComments.length") - | #{translate("no_resolved_threads")}. - -script(type="text/ng-template", id="trackChangesUpgradeModalTemplate") - .modal-header - button.close( - type="button" - data-dismiss="modal" - ng-click="cancel()" - aria-label="Close" - ) - span(aria-hidden="true") × - h3 #{translate("upgrade_to_track_changes")} - .modal-body - .teaser-video-container - video.teaser-video(autoplay, loop) - source(ng-src="{{ '/img/teasers/track-changes/teaser-track-changes.mp4' }}", type="video/mp4") - img(src="/img/teasers/track-changes/teaser-track-changes.gif") - - h4.teaser-title #{translate("see_changes_in_your_documents_live")} - - p.small(ng-show="startedFreeTrial") - | #{translate("refresh_page_after_starting_free_trial")} - - .row - .col-md-10.col-md-offset-1 - ul.list-unstyled - li - i.fa.fa-check   - | #{translate("track_any_change_in_real_time")} - - li - i.fa.fa-check   - | #{translate("review_your_peers_work")} - - li - i.fa.fa-check   - | #{translate("accept_or_reject_each_changes_individually")} - - .row.text-center - div(ng-show="user.allowedFreeTrial" ng-controller="FreeTrialModalController") - a.btn.btn-primary( - href - ng-click="startFreeTrial('track-changes')" - ng-show="project.owner._id == user.id" - ) #{translate("try_it_for_free")} - div(ng-show="!user.allowedFreeTrial" ng-controller="UpgradeModalController") - a.btn.btn-primary( - href - ng-click="upgradePlan('project-sharing')" - ng-show="project.owner._id == user.id" - ) #{translate("upgrade")} - p(ng-show="project.owner._id != user.id"): strong #{translate("please_ask_the_project_owner_to_upgrade_to_track_changes")} - - .modal-footer() - button.btn.btn-secondary( - 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()" - aria-label="Close" - ) - span(aria-hidden="true") × - 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-secondary( - ng-click="cancel()" - ) - span #{translate("cancel")} - button.btn.btn-primary( - ng-click="confirm()" - ) - span #{translate("ok")} diff --git a/services/web/app/views/source-editor/source-editor.pug b/services/web/app/views/source-editor/source-editor.pug index 0ae753f4d6..9aa186fba2 100644 --- a/services/web/app/views/source-editor/source-editor.pug +++ b/services/web/app/views/source-editor/source-editor.pug @@ -1,4 +1,3 @@ -source-editor#editor( - ng-class="{ 'review-panel-react': reviewPanel.isReact }" +source-editor.review-panel-react#editor( ng-show="!!editor.sharejs_doc && !editor.opening && multiSelectedCount === 0 && !editor.error_state" ) diff --git a/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx b/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx index 9ebd55c557..dc4967723d 100644 --- a/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx +++ b/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx @@ -19,8 +19,6 @@ import { dispatchTimer } from '../../../infrastructure/cm6-performance' import importOverleafModules from '../../../../macros/import-overleaf-module.macro' import { FigureModal } from './figure-modal/figure-modal' import ReviewPanel from './review-panel/review-panel' -import getMeta from '../../../utils/meta' -import { useIdeContext } from '@/shared/context/ide-context' const sourceEditorComponents = importOverleafModules( 'sourceEditorComponents' @@ -33,8 +31,6 @@ function CodeMirrorEditor() { }) const isMounted = useIsMounted() - const isReviewPanelReact = getMeta('ol-isReviewPanelReact') - const { isReactIde } = useIdeContext() // create the view using the initial state and intercept transactions const viewRef = useRef(null) @@ -64,7 +60,7 @@ function CodeMirrorEditor() { - {(isReviewPanelReact || isReactIde) && } + {sourceEditorComponents.map( ({ import: { default: Component }, path }) => ( diff --git a/services/web/frontend/js/features/source-editor/extensions/changes/change-manager.ts b/services/web/frontend/js/features/source-editor/extensions/changes/change-manager.ts index c073676c54..b363f7b8e2 100644 --- a/services/web/frontend/js/features/source-editor/extensions/changes/change-manager.ts +++ b/services/web/frontend/js/features/source-editor/extensions/changes/change-manager.ts @@ -11,11 +11,6 @@ import { EditorView, ViewUpdate } from '@codemirror/view' import { CurrentDoc } from '../../../../../../types/current-doc' import { fullHeightCoordsAtPos } from '../../utils/layer' import { debounce } from 'lodash' -import getMeta from '../../../../utils/meta' - -// If a toolbar row sits alongside the review panel, the review panel entries need to be shifted down by 32px. -// Once the review panel is always inside the editor, this offset can be removed. -const offsetTop = getMeta('ol-isReviewPanelReact') ? 0 : 32 // With less than this number of entries, don't bother culling to avoid // little UI jumps when scrolling. @@ -123,7 +118,7 @@ export const createChangeManager = ( visibilityChanged = true } - entry.screenPos = { y: y + offsetTop, height, editorPaddingTop } + entry.screenPos = { y, height, editorPaddingTop } entry.inViewport = true } else { entry.inViewport = false diff --git a/services/web/frontend/js/features/source-editor/extensions/geometry-change-event.ts b/services/web/frontend/js/features/source-editor/extensions/geometry-change-event.ts index ca54335f27..c024568957 100644 --- a/services/web/frontend/js/features/source-editor/extensions/geometry-change-event.ts +++ b/services/web/frontend/js/features/source-editor/extensions/geometry-change-event.ts @@ -5,11 +5,9 @@ import { EditorView } from '@codemirror/view' * changes. This is used to synchronize the editor content and review panel * height in "Current file" mode. */ -export const geometryChangeEvent = (reactReviewPanel: boolean) => - reactReviewPanel - ? EditorView.updateListener.of(update => { - if (update.geometryChanged) { - window.dispatchEvent(new CustomEvent('editor:geometry-change')) - } - }) - : [] +export const geometryChangeEvent = () => + EditorView.updateListener.of(update => { + if (update.geometryChanged) { + window.dispatchEvent(new CustomEvent('editor:geometry-change')) + } + }) diff --git a/services/web/frontend/js/features/source-editor/extensions/index.ts b/services/web/frontend/js/features/source-editor/extensions/index.ts index 9994ad3aab..92e2aa1fce 100644 --- a/services/web/frontend/js/features/source-editor/extensions/index.ts +++ b/services/web/frontend/js/features/source-editor/extensions/index.ts @@ -134,5 +134,5 @@ export const createExtensions = (options: Record): Extension[] => [ moduleExtensions.map(extension => extension()), thirdPartyExtensions(), effectListeners(), - geometryChangeEvent(options.reactReviewPanel), + geometryChangeEvent(), ] diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts index 013e1e1df3..629b28250e 100644 --- a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts +++ b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts @@ -44,7 +44,6 @@ import { EditorView } from '@codemirror/view' import { CurrentDoc } from '../../../../../types/current-doc' import { useErrorHandler } from 'react-error-boundary' import { setVisual } from '../extensions/visual/visual' -import getMeta from '../../../utils/meta' import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path' import { useUserSettingsContext } from '@/shared/context/user-settings-context' @@ -87,7 +86,6 @@ function useCodeMirrorScope(view: EditorView) { ) const [visual] = useScopeValue('editor.showVisual') - const reactReviewPanel: boolean = getMeta('ol-isReviewPanelReact') const [references] = useScopeValue<{ keys: string[] }>('$root._references') @@ -272,7 +270,6 @@ function useCodeMirrorScope(view: EditorView) { visual: visualRef.current, changeManager: createChangeManager(view, currentDoc), handleError, - reactReviewPanel, }), }) view.setState(state) @@ -302,7 +299,7 @@ function useCodeMirrorScope(view: EditorView) { } // IMPORTANT: This effect must not depend on anything variable apart from currentDoc, // as the editor state is recreated when the effect runs. - }, [view, currentDoc, handleError, reactReviewPanel]) + }, [view, currentDoc, handleError]) useEffect(() => { visualRef.current.visual = visual diff --git a/services/web/frontend/js/ide/review-panel/ReviewPanelManager.js b/services/web/frontend/js/ide/review-panel/ReviewPanelManager.js index cc96a898a3..268bb74243 100644 --- a/services/web/frontend/js/ide/review-panel/ReviewPanelManager.js +++ b/services/web/frontend/js/ide/review-panel/ReviewPanelManager.js @@ -1,18 +1 @@ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. import './controllers/ReviewPanelController' -import './controllers/TrackChangesUpgradeModalController' -import './controllers/BulkActionsModalController' -import './directives/reviewPanelSorted' -import './directives/reviewPanelToggle' -import './directives/changeEntry' -import './directives/aggregateChangeEntry' -import './directives/commentEntry' -import './directives/addCommentEntry' -import './directives/bulkActionsEntry' -import './directives/resolvedCommentEntry' -import './directives/resolvedCommentsDropdown' -import './directives/reviewPanelCollapseHeight' -import './filters/notEmpty' -import './filters/numKeys' -import './filters/orderOverviewEntries' diff --git a/services/web/frontend/js/ide/review-panel/controllers/BulkActionsModalController.js b/services/web/frontend/js/ide/review-panel/controllers/BulkActionsModalController.js deleted file mode 100644 index fc972c85d7..0000000000 --- a/services/web/frontend/js/ide/review-panel/controllers/BulkActionsModalController.js +++ /dev/null @@ -1,25 +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('BulkActionsModalController', [ - '$scope', - '$modalInstance', - 'isAccept', - 'nChanges', - function ($scope, $modalInstance, isAccept, nChanges) { - $scope.isAccept = isAccept - $scope.nChanges = nChanges - $scope.cancel = () => $modalInstance.dismiss() - return ($scope.confirm = () => $modalInstance.close(isAccept)) - }, -]) diff --git a/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js b/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js index 9c202d1b6a..e0211988a7 100644 --- a/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js +++ b/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js @@ -111,7 +111,6 @@ export default App.controller('ReviewPanelController', [ // as only one. nVisibleSelectedChanges: 0, entryHover: false, - isReact: getMeta('ol-splitTestVariants')?.['review-panel'] === 'react', } ide.$scope.loadingThreads = true @@ -731,38 +730,6 @@ export default App.controller('ReviewPanelController', [ }) } - ide.$scope.showBulkAcceptDialog = () => showBulkActionsDialog(true) - - ide.$scope.showBulkRejectDialog = () => showBulkActionsDialog(false) - - const showBulkActionsDialog = isAccept => - $modal - .open({ - templateUrl: 'bulkActionsModalTemplate', - controller: 'BulkActionsModalController', - resolve: { - isAccept() { - return isAccept - }, - nChanges() { - return ide.$scope.reviewPanel.nVisibleSelectedChanges - }, - }, - scope: $scope.$new(), - }) - .result.then(function (isAccept) { - if (isAccept) { - return ide.$scope.bulkAcceptActions() - } else { - return ide.$scope.bulkRejectActions() - } - }) - - $scope.handleTogglerClick = function (e) { - e.target.blur() - return $scope.toggleReviewPanel() - } - ide.$scope.addNewComment = function (e) { e.preventDefault() ide.$scope.$broadcast('comment:start_adding') @@ -819,19 +786,13 @@ export default App.controller('ReviewPanelController', [ eventTracking.sendMB('rp-new-comment', { size: content.length }) } - if (ide.$scope.reviewPanel.isReact === false) { - emitCommentAdd() - } - return $http .post(`/project/${$scope.project_id}/thread/${thread_id}/messages`, { content, _csrf: window.csrfToken, }) .then(() => { - if (ide.$scope.reviewPanel.isReact) { - emitCommentAdd() - } + emitCommentAdd() }) .catch(() => { ide.showGenericMessageModal( @@ -1008,27 +969,6 @@ export default App.controller('ReviewPanelController', [ ide.$scope.gotoEntry = (doc_id, entry_offset) => ide.editorManager.openDocId(doc_id, { gotoOffset: entry_offset }) - $scope.toggleFullTCStateCollapse = function () { - if ($scope.project.features.trackChanges) { - return (ide.$scope.reviewPanel.fullTCStateCollapsed = - !ide.$scope.reviewPanel.fullTCStateCollapsed) - } else { - _sendAnalytics() - return $scope.openTrackChangesUpgradeModal() - } - } - - const _sendAnalytics = () => { - eventTracking.send( - 'subscription-funnel', - 'editor-click-feature', - 'real-time-track-changes' - ) - eventTracking.sendMB('paywall-prompt', { - 'paywall-type': 'track-changes', - }) - } - const _setUserTCState = function (userId, newValue, isLocal) { if (isLocal == null) { isLocal = false @@ -1339,13 +1279,6 @@ export default App.controller('ReviewPanelController', [ } } - $scope.openTrackChangesUpgradeModal = () => - $modal.open({ - templateUrl: 'trackChangesUpgradeModalTemplate', - controller: 'TrackChangesUpgradeModalController', - scope: $scope.$new(), - }) - // listen for events from the CodeMirror 6 track changes extension window.addEventListener('editor:event', event => { const { type, payload } = event.detail diff --git a/services/web/frontend/js/ide/review-panel/controllers/TrackChangesUpgradeModalController.js b/services/web/frontend/js/ide/review-panel/controllers/TrackChangesUpgradeModalController.js deleted file mode 100644 index c814d843d4..0000000000 --- a/services/web/frontend/js/ide/review-panel/controllers/TrackChangesUpgradeModalController.js +++ /dev/null @@ -1,20 +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('TrackChangesUpgradeModalController', [ - '$scope', - '$modalInstance', - function ($scope, $modalInstance) { - $scope.cancel = () => $modalInstance.dismiss() - }, -]) diff --git a/services/web/frontend/js/ide/review-panel/directives/addCommentEntry.js b/services/web/frontend/js/ide/review-panel/directives/addCommentEntry.js deleted file mode 100644 index d74258e613..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/addCommentEntry.js +++ /dev/null @@ -1,62 +0,0 @@ -import App from '../../../base' -let content = '' -App.directive('addCommentEntry', function () { - return { - restrict: 'E', - templateUrl: 'addCommentEntryTemplate', - scope: { - onStartNew: '&', - onSubmit: '&', - onCancel: '&', - }, - link(scope, element, attrs) { - scope.state = { - isAdding: false, - content, - } - - scope.$on('comment:start_adding', () => scope.startNewComment()) - scope.$on('$destroy', function () { - content = scope.state.content - }) - - scope.startNewComment = function () { - scope.state.isAdding = true - scope.onStartNew() - setTimeout(() => scope.$broadcast('comment:new:open')) - } - - scope.cancelNewComment = function () { - scope.state.isAdding = false - scope.state.content = '' - scope.onCancel() - } - - const ignoreKeysInTextAreas = ['PageDown', 'PageUp'] - - scope.handleCommentKeyDown = function (ev) { - if (ignoreKeysInTextAreas.includes(ev.key)) { - if (ev.target.closest('textarea')) { - ev.preventDefault() - } - } - } - - scope.handleCommentKeyPress = function (ev) { - if (ev.keyCode === 13 && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) { - ev.preventDefault() - if (scope.state.content.length > 0) { - scope.submitNewComment() - } - } - } - - scope.submitNewComment = function (event) { - scope.onSubmit({ content: scope.state.content }) - content = scope.state.content - scope.state.isAdding = false - scope.state.content = '' - } - }, - } -}) diff --git a/services/web/frontend/js/ide/review-panel/directives/aggregateChangeEntry.js b/services/web/frontend/js/ide/review-panel/directives/aggregateChangeEntry.js deleted file mode 100644 index 568b3c7b52..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/aggregateChangeEntry.js +++ /dev/null @@ -1,74 +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.directive('aggregateChangeEntry', [ - '$timeout', - function ($timeout) { - return { - restrict: 'E', - templateUrl: 'aggregateChangeEntryTemplate', - scope: { - entry: '=', - user: '=', - permissions: '=', - onAccept: '&', - onReject: '&', - onIndicatorClick: '&', - onMouseEnter: '&', - onMouseLeave: '&', - onBodyClick: '&', - }, - link(scope, element, attrs) { - scope.contentLimit = 17 - scope.isDeletionCollapsed = true - scope.isInsertionCollapsed = true - scope.deletionNeedsCollapsing = false - scope.insertionNeedsCollapsing = false - - element.on('click', function (e) { - if ( - $(e.target).is( - '.rp-entry, .rp-entry-description, .rp-entry-body, .rp-entry-action-icon i' - ) - ) { - return scope.onBodyClick() - } - }) - - scope.toggleDeletionCollapse = function () { - scope.isDeletionCollapsed = !scope.isDeletionCollapsed - return $timeout(() => scope.$emit('review-panel:layout')) - } - - scope.toggleInsertionCollapse = function () { - scope.isInsertionCollapsed = !scope.isInsertionCollapsed - return $timeout(() => scope.$emit('review-panel:layout')) - } - - scope.$watch( - 'entry.metadata.replaced_content.length', - deletionContentLength => - (scope.deletionNeedsCollapsing = - deletionContentLength > scope.contentLimit) - ) - - return scope.$watch( - 'entry.content.length', - insertionContentLength => - (scope.insertionNeedsCollapsing = - insertionContentLength > scope.contentLimit) - ) - }, - } - }, -]) diff --git a/services/web/frontend/js/ide/review-panel/directives/bulkActionsEntry.js b/services/web/frontend/js/ide/review-panel/directives/bulkActionsEntry.js deleted file mode 100644 index 2c2c132e8b..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/bulkActionsEntry.js +++ /dev/null @@ -1,27 +0,0 @@ -/* eslint-disable - 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.directive('bulkActionsEntry', function () { - return { - restrict: 'E', - templateUrl: 'bulkActionsEntryTemplate', - scope: { - onBulkAccept: '&', - onBulkReject: '&', - nEntries: '=', - }, - link(scope, element, attrs) { - scope.bulkAccept = () => scope.onBulkAccept() - return (scope.bulkReject = () => scope.onBulkReject()) - }, - } -}) diff --git a/services/web/frontend/js/ide/review-panel/directives/changeEntry.js b/services/web/frontend/js/ide/review-panel/directives/changeEntry.js deleted file mode 100644 index 2ee343efe1..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/changeEntry.js +++ /dev/null @@ -1,59 +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.directive('changeEntry', [ - '$timeout', - function ($timeout) { - return { - restrict: 'E', - templateUrl: 'changeEntryTemplate', - scope: { - entry: '=', - user: '=', - permissions: '=', - onAccept: '&', - onReject: '&', - onIndicatorClick: '&', - onMouseEnter: '&', - onMouseLeave: '&', - onBodyClick: '&', - }, - link(scope, element, attrs) { - scope.contentLimit = 40 - scope.isCollapsed = true - scope.needsCollapsing = false - - element.on('click', function (e) { - if ( - $(e.target).is( - '.rp-entry, .rp-entry-description, .rp-entry-body, .rp-entry-action-icon i' - ) - ) { - return scope.onBodyClick() - } - }) - - scope.toggleCollapse = function () { - scope.isCollapsed = !scope.isCollapsed - return $timeout(() => scope.$emit('review-panel:layout')) - } - - return scope.$watch( - 'entry.content.length', - contentLength => - (scope.needsCollapsing = contentLength > scope.contentLimit) - ) - }, - } - }, -]) diff --git a/services/web/frontend/js/ide/review-panel/directives/commentEntry.js b/services/web/frontend/js/ide/review-panel/directives/commentEntry.js deleted file mode 100644 index befddc3bcd..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/commentEntry.js +++ /dev/null @@ -1,97 +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.directive('commentEntry', [ - '$timeout', - function ($timeout) { - return { - restrict: 'E', - templateUrl: 'commentEntryTemplate', - scope: { - entry: '=', - threads: '=', - permissions: '=', - onResolve: '&', - onReply: '&', - onIndicatorClick: '&', - onMouseEnter: '&', - onMouseLeave: '&', - onSaveEdit: '&', - onDelete: '&', - onBodyClick: '&', - }, - link(scope, element, attrs) { - scope.state = { animating: false } - - element.on('click', function (e) { - if ( - $(e.target).is( - '.rp-entry, .rp-comment-loaded, .rp-comment-content, .rp-comment-reply, .rp-entry-metadata' - ) - ) { - return scope.onBodyClick() - } - }) - - scope.handleCommentReplyKeyPress = function (ev) { - if (ev.keyCode === 13 && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) { - ev.preventDefault() - if (scope.entry.replyContent.length > 0) { - ev.target.blur() - return scope.onReply() - } - } - } - - scope.animateAndCallOnResolve = function () { - scope.state.animating = true - element.find('.rp-entry').css('top', 0) - $timeout(() => scope.onResolve(), 350) - return true - } - - scope.startEditing = function (comment) { - comment.editing = true - return setTimeout(() => scope.$emit('review-panel:layout')) - } - - scope.saveEdit = function (comment) { - comment.editing = false - return scope.onSaveEdit({ comment }) - } - - scope.confirmDelete = function (comment) { - comment.deleting = true - return setTimeout(() => scope.$emit('review-panel:layout')) - } - - scope.cancelDelete = function (comment) { - comment.deleting = false - return setTimeout(() => scope.$emit('review-panel:layout')) - } - - scope.doDelete = function (comment) { - comment.deleting = false - return scope.onDelete({ comment }) - } - - return (scope.saveEditOnEnter = function (ev, comment) { - if (ev.keyCode === 13 && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) { - ev.preventDefault() - return scope.saveEdit(comment) - } - }) - }, - } - }, -]) diff --git a/services/web/frontend/js/ide/review-panel/directives/resolvedCommentEntry.js b/services/web/frontend/js/ide/review-panel/directives/resolvedCommentEntry.js deleted file mode 100644 index a3c3ea589d..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/resolvedCommentEntry.js +++ /dev/null @@ -1,38 +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.directive('resolvedCommentEntry', function () { - return { - restrict: 'E', - templateUrl: 'resolvedCommentEntryTemplate', - scope: { - thread: '=', - permissions: '=', - onUnresolve: '&', - onDelete: '&', - }, - link(scope, element, attrs) { - scope.contentLimit = 40 - scope.needsCollapsing = false - scope.isCollapsed = true - - scope.toggleCollapse = () => (scope.isCollapsed = !scope.isCollapsed) - - return scope.$watch( - 'thread.content.length', - contentLength => - (scope.needsCollapsing = contentLength > scope.contentLimit) - ) - }, - } -}) diff --git a/services/web/frontend/js/ide/review-panel/directives/resolvedCommentsDropdown.js b/services/web/frontend/js/ide/review-panel/directives/resolvedCommentsDropdown.js deleted file mode 100644 index 08d1e576c5..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/resolvedCommentsDropdown.js +++ /dev/null @@ -1,111 +0,0 @@ -import _ from 'lodash' -/* 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 - * 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 - */ -import App from '../../../base' - -export default App.directive('resolvedCommentsDropdown', function () { - return { - restrict: 'E', - templateUrl: 'resolvedCommentsDropdownTemplate', - scope: { - entries: '=', - threads: '=', - resolvedIds: '=', - docs: '=', - permissions: '=', - onOpen: '&', - onUnresolve: '&', - onDelete: '&', - isLoading: '=', - }, - - link(scope, element, attrs) { - let filterResolvedComments - scope.state = { isOpen: false } - - scope.toggleOpenState = function () { - scope.state.isOpen = !scope.state.isOpen - if (scope.state.isOpen) { - return scope.onOpen().then(() => filterResolvedComments()) - } - } - - scope.resolvedComments = [] - - scope.handleUnresolve = function (threadId) { - scope.onUnresolve({ threadId }) - return (scope.resolvedComments = scope.resolvedComments.filter( - c => c.threadId !== threadId - )) - } - - scope.handleDelete = function (entryId, docId, threadId) { - scope.onDelete({ entryId, docId, threadId }) - return (scope.resolvedComments = scope.resolvedComments.filter( - c => c.threadId !== threadId - )) - } - - const getDocNameById = function (docId) { - const doc = _.find(scope.docs, doc => doc.doc.id === docId) - if (doc != null) { - return doc.path - } else { - return null - } - } - - return (filterResolvedComments = function () { - scope.resolvedComments = [] - - return (() => { - const result = [] - for (const docId in scope.entries) { - const docEntries = scope.entries[docId] - result.push( - (() => { - const result1 = [] - for (const entryId in docEntries) { - const entry = docEntries[entryId] - if ( - entry.type === 'comment' && - (scope.threads[entry.thread_id] != null - ? scope.threads[entry.thread_id].resolved - : undefined) != null - ) { - const resolvedComment = angular.copy( - scope.threads[entry.thread_id] - ) - - resolvedComment.content = entry.content - resolvedComment.threadId = entry.thread_id - resolvedComment.entryId = entryId - resolvedComment.docId = docId - resolvedComment.docName = getDocNameById(docId) - - result1.push(scope.resolvedComments.push(resolvedComment)) - } else { - result1.push(undefined) - } - } - return result1 - })() - ) - } - return result - })() - }) - }, - } -}) diff --git a/services/web/frontend/js/ide/review-panel/directives/reviewPanelCollapseHeight.js b/services/web/frontend/js/ide/review-panel/directives/reviewPanelCollapseHeight.js deleted file mode 100644 index c808a5f9e2..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/reviewPanelCollapseHeight.js +++ /dev/null @@ -1,39 +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 - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' - -export default App.directive('reviewPanelCollapseHeight', [ - '$parse', - function ($parse) { - return { - restrict: 'A', - link(scope, element, attrs) { - return scope.$watch( - () => $parse(attrs.reviewPanelCollapseHeight)(scope), - function (shouldCollapse) { - const neededHeight = element.prop('scrollHeight') - if (neededHeight > 0) { - if (shouldCollapse) { - return element.animate({ height: 0 }, 150) - } else { - return element.animate({ height: neededHeight }, 150) - } - } else { - if (shouldCollapse) { - return element.height(0) - } - } - } - ) - }, - } - }, -]) diff --git a/services/web/frontend/js/ide/review-panel/directives/reviewPanelSorted.js b/services/web/frontend/js/ide/review-panel/directives/reviewPanelSorted.js deleted file mode 100644 index 014e741f61..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/reviewPanelSorted.js +++ /dev/null @@ -1,294 +0,0 @@ -/* 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 - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -import App from '../../../base' -import { debugConsole } from '@/utils/debugging' - -export default App.directive('reviewPanelSorted', function () { - return { - link(scope, element, attrs) { - let previous_focused_entry_index = 0 - - const applyEntryVisibility = function (entry) { - const visible = entry.scope.entry.screenPos - if (visible) { - entry.$wrapper_el.removeClass('rp-entry-hidden') - } else { - entry.$wrapper_el.addClass('rp-entry-hidden') - } - return visible - } - - const layout = function (animate) { - let entry, - height, - i, - original_top, - overflowTop, - screenPosHeight, - OVERVIEW_TOGGLE_HEIGHT, - PADDING, - TOOLBAR_HEIGHT, - top - if (animate == null) { - animate = true - } - if (animate) { - element.removeClass('no-animate') - } else { - element.addClass('no-animate') - } - if (scope.ui.reviewPanelOpen) { - PADDING = 8 - TOOLBAR_HEIGHT = 38 - OVERVIEW_TOGGLE_HEIGHT = 57 - } else { - PADDING = 4 - TOOLBAR_HEIGHT = 4 - OVERVIEW_TOGGLE_HEIGHT = 0 - } - - const entries = [] - for (const el of Array.from(element.find('.rp-entry-wrapper'))) { - entry = { - $wrapper_el: $(el), - $indicator_el: $(el).find('.rp-entry-indicator'), - $box_el: $(el).find('.rp-entry'), - $callout_el: $(el).find('.rp-entry-callout'), - scope: angular.element(el).scope(), - } - if (scope.ui.reviewPanelOpen) { - entry.$layout_el = entry.$box_el - } else { - entry.$layout_el = entry.$indicator_el - } - entry.height = entry.$layout_el.height() // Do all of our DOM reads first for performance, see http://wilsonpage.co.uk/preventing-layout-thrashing/ - entries.push(entry) - } - entries.sort((a, b) => a.scope.entry.offset - b.scope.entry.offset) - - if (entries.length === 0) { - return - } - - const line_height = scope.reviewPanel.rendererData.lineHeight - - let focused_entry_index = Math.min( - previous_focused_entry_index, - entries.length - 1 - ) - for (i = 0; i < entries.length; i++) { - entry = entries[i] - if (entry.scope.entry.focused) { - focused_entry_index = i - break - } - } - - const focused_entry = entries[focused_entry_index] - const focusedEntryVisible = applyEntryVisibility(focused_entry) - - // If the focused entry has no screenPos, we can't position other entries - // relative to it, so we position all other entries as though the focused - // entry is at the top and they all follow it - const entries_after = focusedEntryVisible - ? entries.slice(focused_entry_index + 1) - : [...entries] - const entries_before = focusedEntryVisible - ? entries.slice(0, focused_entry_index) - : [] - previous_focused_entry_index = focused_entry_index - - debugConsole.log('focused_entry_index', focused_entry_index) - - const positionLayoutEl = function ( - $callout_el, - original_top, - top, - height - ) { - if (original_top <= top) { - $callout_el.removeClass('rp-entry-callout-inverted') - return $callout_el.css({ - top: original_top + height - 1, - height: top - original_top, - }) - } else { - $callout_el.addClass('rp-entry-callout-inverted') - return $callout_el.css({ - top: top + height, - height: original_top - top, - }) - } - } - - // Put the focused entry as close to where it wants to be as possible - let focused_entry_top = 0 - let previousBottom = 0 - - if (focusedEntryVisible) { - const focusedEntryScreenPos = focused_entry.scope.entry.screenPos - focused_entry_top = Math.max(focusedEntryScreenPos.y, TOOLBAR_HEIGHT) - focused_entry.$box_el.css({ - top: focused_entry_top, - // The entry element is invisible by default, to avoid flickering when positioning for - // the first time. Here we make sure it becomes visible after having a "top" value. - visibility: 'visible', - }) - focused_entry.$indicator_el.css({ top: focused_entry_top }) - // use screenPos.height if set - screenPosHeight = focusedEntryScreenPos.height ?? line_height - positionLayoutEl( - focused_entry.$callout_el, - focusedEntryScreenPos.y, - focused_entry_top, - screenPosHeight - ) - previousBottom = focused_entry_top + focused_entry.$layout_el.height() - } - - for (entry of entries_after) { - const entryVisible = applyEntryVisibility(entry) - if (entryVisible) { - original_top = entry.scope.entry.screenPos.y - // use screenPos.height if set - screenPosHeight = entry.scope.entry.screenPos.height ?? line_height - ;({ height } = entry) - top = Math.max(original_top, previousBottom + PADDING) - previousBottom = top + height - entry.$box_el.css({ - top, - // The entry element is invisible by default, to avoid flickering when positioning for - // the first time. Here we make sure it becomes visible after having a "top" value. - visibility: 'visible', - }) - entry.$indicator_el.css({ top }) - positionLayoutEl( - entry.$callout_el, - original_top, - top, - screenPosHeight - ) - } - debugConsole.log('ENTRY', { entry: entry.scope.entry, top }) - } - - let previousTop = focused_entry_top - entries_before.reverse() // Work through backwards, starting with the one just above - for (entry of entries_before) { - const entryVisible = applyEntryVisibility(entry) - if (entryVisible) { - original_top = entry.scope.entry.screenPos.y - // use screenPos.height if set - screenPosHeight = entry.scope.entry.screenPos.height ?? line_height - ;({ height } = entry) - const original_bottom = original_top + height - const bottom = Math.min(original_bottom, previousTop - PADDING) - top = bottom - height - previousTop = top - entry.$box_el.css({ - top, - // The entry element is invisible by default, to avoid flickering when positioning for - // the first time. Here we make sure it becomes visible after having a "top" value. - visibility: 'visible', - }) - entry.$indicator_el.css({ top }) - positionLayoutEl( - entry.$callout_el, - original_top, - top, - screenPosHeight - ) - } - debugConsole.log('ENTRY', { entry: entry.scope.entry, top }) - } - - const lastTop = top - if (lastTop < TOOLBAR_HEIGHT) { - overflowTop = -lastTop + TOOLBAR_HEIGHT - } else { - overflowTop = 0 - } - - return scope.$emit('review-panel:sizes', { - overflowTop, - height: previousBottom + OVERVIEW_TOGGLE_HEIGHT, - }) - } - - scope.$applyAsync(() => layout()) - - scope.$on('review-panel:layout', function (e, animate) { - if (animate == null) { - animate = true - } - return scope.$applyAsync(() => layout(animate)) - }) - - scope.$watch('reviewPanel.rendererData.lineHeight', () => layout()) - - // # Scroll lock with Ace - const scroller = element - const list = element.find('.rp-entry-list-inner') - - // If we listen for scroll events in the review panel natively, then with a Mac trackpad - // the scroll is very smooth (natively done I'd guess), but we don't get polled regularly - // enough to keep Ace in step, and it noticeably lags. If instead, we borrow the manual - // mousewheel/trackpad scrolling behaviour from Ace, and turn mousewheel events into - // scroll events ourselves, then it makes the review panel slightly less smooth (barely) - // noticeable, but keeps it perfectly in step with Ace. - scroller[0].addEventListener('wheel', e => { - // FIXME (or remove this): https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event - const deltaY = e.wheelY - const old_top = parseInt(list.css('top')) - const top = old_top - deltaY * 4 - dispatchScrollEvent(deltaY * 4) - return e.preventDefault() - }) - - // We always scroll by telling Ace to scroll and then updating the - // review panel. This lets Ace manage the size of the scroller and - // when it overflows. - let ignoreNextAceEvent = false - - const scrollPanel = function (scrollTop, height) { - if (ignoreNextAceEvent) { - return (ignoreNextAceEvent = false) - } else { - list.height(height) - return list.css({ top: -scrollTop }) - } - } - - // receive the scroll position from the CodeMirror 6 track changes extension - window.addEventListener('editor:scroll', event => { - const { scrollTop, height, paddingTop } = event.detail - - scrollPanel(scrollTop - paddingTop, height) - }) - - // Send scroll delta to the CodeMirror 6 track changes extension - const dispatchScrollEvent = scrollTopDelta => { - window.dispatchEvent( - new CustomEvent('review-panel:event', { - detail: { type: 'scroll', payload: scrollTopDelta }, - }) - ) - } - - return scope.reviewPanelEventsBridge.emit('refreshScrollPosition') - }, - } -}) diff --git a/services/web/frontend/js/ide/review-panel/directives/reviewPanelToggle.js b/services/web/frontend/js/ide/review-panel/directives/reviewPanelToggle.js deleted file mode 100644 index 810e4d16dc..0000000000 --- a/services/web/frontend/js/ide/review-panel/directives/reviewPanelToggle.js +++ /dev/null @@ -1,53 +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.directive('reviewPanelToggle', function () { - return { - restrict: 'E', - scope: { - onToggle: '&', - ngModel: '=', - valWhenUndefined: '=?', - isDisabled: '=?', - onDisabledClick: '&?', - description: '@', - }, - link(scope) { - if (scope.disabled == null) { - scope.disabled = false - } - scope.onChange = (...args) => scope.onToggle({ isOn: scope.localModel }) - scope.handleClick = function () { - if (scope.disabled && scope.onDisabledClick != null) { - return scope.onDisabledClick() - } - } - scope.localModel = scope.ngModel - return scope.$watch('ngModel', function (value) { - if (scope.valWhenUndefined != null && value == null) { - value = scope.valWhenUndefined - } - return (scope.localModel = value) - }) - }, - - template: `\ -
-{{description}} - - -
\ -`, - } -}) diff --git a/services/web/frontend/js/ide/review-panel/filters/notEmpty.js b/services/web/frontend/js/ide/review-panel/filters/notEmpty.js deleted file mode 100644 index 7924c07082..0000000000 --- a/services/web/frontend/js/ide/review-panel/filters/notEmpty.js +++ /dev/null @@ -1,12 +0,0 @@ -// 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.filter( - 'notEmpty', - () => object => !angular.equals({}, object) -) diff --git a/services/web/frontend/js/ide/review-panel/filters/numKeys.js b/services/web/frontend/js/ide/review-panel/filters/numKeys.js deleted file mode 100644 index 862fd46f4e..0000000000 --- a/services/web/frontend/js/ide/review-panel/filters/numKeys.js +++ /dev/null @@ -1,21 +0,0 @@ -// 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.filter( - 'numKeys', - () => - function (object) { - if (object != null) { - return Object.keys(object).length - } else { - return 0 - } - } -) diff --git a/services/web/frontend/js/ide/review-panel/filters/orderOverviewEntries.js b/services/web/frontend/js/ide/review-panel/filters/orderOverviewEntries.js deleted file mode 100644 index 7ba26cdc47..0000000000 --- a/services/web/frontend/js/ide/review-panel/filters/orderOverviewEntries.js +++ /dev/null @@ -1,23 +0,0 @@ -// 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.filter( - 'orderOverviewEntries', - () => - function (items) { - const array = [] - for (const key in items) { - const value = items[key] - value.entry_id = key - array.push(value) - } - array.sort((a, b) => a.offset - b.offset) - return array - } -) diff --git a/services/web/test/frontend/features/review-panel/review-panel.spec.tsx b/services/web/test/frontend/features/review-panel/review-panel.spec.tsx index d8d58d18bf..d5b36a3f78 100644 --- a/services/web/test/frontend/features/review-panel/review-panel.spec.tsx +++ b/services/web/test/frontend/features/review-panel/review-panel.spec.tsx @@ -13,7 +13,6 @@ function Container(props: ContainerProps) { describe('', function () { beforeEach(function () { - window.metaAttributesCache.set('ol-isReviewPanelReact', true) window.metaAttributesCache.set('ol-preventCompileOnLoad', true) cy.interceptEvents()