mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #13414 from overleaf/ii-review-panel-migration-create-context-api-fix
[web] Create context api for review panel FIX GitOrigin-RevId: fc6d8adf18d07e71b529a28deab4d49d62c43587
This commit is contained in:
parent
88d0254dde
commit
9b930d2849
11 changed files with 432 additions and 124 deletions
|
@ -128,7 +128,7 @@
|
||||||
on-indicator-click="toggleReviewPanel();"
|
on-indicator-click="toggleReviewPanel();"
|
||||||
on-mouse-enter="mouseEnterIndicator()"
|
on-mouse-enter="mouseEnterIndicator()"
|
||||||
on-mouse-leave="mouseLeaveIndicator()"
|
on-mouse-leave="mouseLeaveIndicator()"
|
||||||
on-body-click="gotoEntry(editor.open_doc_id, entry)"
|
on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
|
||||||
permissions="permissions"
|
permissions="permissions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
on-indicator-click="toggleReviewPanel();"
|
on-indicator-click="toggleReviewPanel();"
|
||||||
on-mouse-enter="mouseEnterIndicator()"
|
on-mouse-enter="mouseEnterIndicator()"
|
||||||
on-mouse-leave="mouseLeaveIndicator()"
|
on-mouse-leave="mouseLeaveIndicator()"
|
||||||
on-body-click="gotoEntry(editor.open_doc_id, entry)"
|
on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
|
||||||
permissions="permissions"
|
permissions="permissions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -149,14 +149,14 @@
|
||||||
comment-entry(
|
comment-entry(
|
||||||
entry="entry"
|
entry="entry"
|
||||||
threads="reviewPanel.commentThreads"
|
threads="reviewPanel.commentThreads"
|
||||||
on-resolve="resolveComment(entry, entry_id)"
|
on-resolve="resolveComment(editor.open_doc_id, entry_id)"
|
||||||
on-reply="submitReply(entry, entry_id);"
|
on-reply="submitReply(entry, entry_id);"
|
||||||
on-indicator-click="toggleReviewPanel();"
|
on-indicator-click="toggleReviewPanel();"
|
||||||
on-mouse-enter="mouseEnterIndicator()"
|
on-mouse-enter="mouseEnterIndicator()"
|
||||||
on-mouse-leave="mouseLeaveIndicator()"
|
on-mouse-leave="mouseLeaveIndicator()"
|
||||||
on-save-edit="saveEdit(entry.thread_id, comment)"
|
on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)"
|
||||||
on-delete="deleteComment(entry.thread_id, comment)"
|
on-delete="deleteComment(entry.thread_id, comment.id)"
|
||||||
on-body-click="gotoEntry(editor.open_doc_id, entry)"
|
on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
|
||||||
permissions="permissions"
|
permissions="permissions"
|
||||||
ng-if="!loadingThreads"
|
ng-if="!loadingThreads"
|
||||||
)
|
)
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
change-entry(
|
change-entry(
|
||||||
entry="entry"
|
entry="entry"
|
||||||
user="users[entry.metadata.user_id]"
|
user="users[entry.metadata.user_id]"
|
||||||
ng-click="gotoEntry(doc.doc.id, entry)"
|
ng-click="gotoEntry(doc.doc.id, entry.offset)"
|
||||||
permissions="permissions"
|
permissions="permissions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@
|
||||||
aggregate-change-entry(
|
aggregate-change-entry(
|
||||||
entry="entry"
|
entry="entry"
|
||||||
user="users[entry.metadata.user_id]"
|
user="users[entry.metadata.user_id]"
|
||||||
ng-click="gotoEntry(doc.doc.id, entry)"
|
ng-click="gotoEntry(doc.doc.id, entry.offset)"
|
||||||
permissions="permissions"
|
permissions="permissions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -224,9 +224,9 @@
|
||||||
entry="entry"
|
entry="entry"
|
||||||
threads="reviewPanel.commentThreads"
|
threads="reviewPanel.commentThreads"
|
||||||
on-reply="submitReply(entry, entry_id);"
|
on-reply="submitReply(entry, entry_id);"
|
||||||
on-save-edit="saveEdit(entry.thread_id, comment)"
|
on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)"
|
||||||
on-delete="deleteComment(entry.thread_id, comment)"
|
on-delete="deleteComment(entry.thread_id, comment.id)"
|
||||||
ng-click="gotoEntry(doc.doc.id, entry)"
|
ng-click="gotoEntry(doc.doc.id, entry.offset)"
|
||||||
permissions="permissions"
|
permissions="permissions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ script(type='text/ng-template', id='aggregateChangeEntryTemplate')
|
||||||
.rp-entry-description
|
.rp-entry-description
|
||||||
| #{translate("aggregate_changed")}
|
| #{translate("aggregate_changed")}
|
||||||
del.rp-content-highlight
|
del.rp-content-highlight
|
||||||
| {{ entry.metadata.replaced_content | limitTo:(isDeletionCollapsed ? contentLimit : entry.metadata.replaced_contentlength) }}
|
| {{ entry.metadata.replaced_content | limitTo:(isDeletionCollapsed ? contentLimit : entry.metadata.replaced_content.length) }}
|
||||||
a.rp-collapse-toggle(
|
a.rp-collapse-toggle(
|
||||||
href
|
href
|
||||||
ng-if="deletionNeedsCollapsing"
|
ng-if="deletionNeedsCollapsing"
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import classnames from 'classnames'
|
||||||
|
|
||||||
|
const reviewPanelClasses = ['ol-cm-review-panel']
|
||||||
|
|
||||||
|
type ContainerProps = {
|
||||||
|
children?: React.ReactNode
|
||||||
|
classNames?: Record<string, boolean>
|
||||||
|
style?: React.CSSProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
function Container({ children, classNames, ...rest }: ContainerProps) {
|
||||||
|
return (
|
||||||
|
<div className={classnames(...reviewPanelClasses, classNames)} {...rest}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Container
|
|
@ -0,0 +1,12 @@
|
||||||
|
import Container from './container'
|
||||||
|
|
||||||
|
function CurrentFileContainer() {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<em>ReviewPanelCurrentFileContainer</em>
|
||||||
|
<div className="review-panel-tools">Tools</div>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CurrentFileContainer
|
|
@ -0,0 +1 @@
|
||||||
|
export type SubView = 'cur_file' | 'overview'
|
|
@ -0,0 +1,11 @@
|
||||||
|
import Container from './container'
|
||||||
|
|
||||||
|
function OverviewContainer() {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<em>ReviewPanelOverviewContainer</em>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OverviewContainer
|
|
@ -1,5 +1,39 @@
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import { useCodeMirrorViewContext } from '../codemirror-editor'
|
||||||
|
import {
|
||||||
|
ReviewPanelProvider,
|
||||||
|
useReviewPanelValueContext,
|
||||||
|
} from '../../context/review-panel/review-panel-context'
|
||||||
|
import CurrentFileContainer from './current-file-container'
|
||||||
|
import OverviewContainer from './overview-container'
|
||||||
|
|
||||||
|
type ReviewPanelViewProps = {
|
||||||
|
parentDomNode: Element
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReviewPanelView({ parentDomNode }: ReviewPanelViewProps) {
|
||||||
|
const { subView } = useReviewPanelValueContext()
|
||||||
|
|
||||||
|
return ReactDOM.createPortal(
|
||||||
|
<>
|
||||||
|
{subView === 'cur_file' ? (
|
||||||
|
<CurrentFileContainer />
|
||||||
|
) : (
|
||||||
|
<OverviewContainer />
|
||||||
|
)}
|
||||||
|
</>,
|
||||||
|
parentDomNode
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function ReviewPanel() {
|
function ReviewPanel() {
|
||||||
return <div>Content to be added.</div>
|
const view = useCodeMirrorViewContext()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReviewPanelProvider>
|
||||||
|
<ReviewPanelView parentDomNode={view.scrollDOM} />
|
||||||
|
</ReviewPanelProvider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ReviewPanel
|
export default ReviewPanel
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import useScopeValue from '../../../../../shared/hooks/use-scope-value'
|
||||||
|
import { ReviewPanelState } from '../types/review-panel-state'
|
||||||
|
import * as ReviewPanel from '../types/review-panel-state'
|
||||||
|
|
||||||
|
function useAngularReviewPanelState(): ReviewPanelState {
|
||||||
|
const [subView, setSubView] = useScopeValue<ReviewPanel.Value<'subView'>>(
|
||||||
|
'reviewPanel.subView'
|
||||||
|
)
|
||||||
|
const [collapsed, setCollapsed] = useScopeValue<
|
||||||
|
ReviewPanel.Value<'collapsed'>
|
||||||
|
>('reviewPanel.overview.docsCollapsedState')
|
||||||
|
|
||||||
|
const values = useMemo<ReviewPanelState['values']>(
|
||||||
|
() => ({
|
||||||
|
subView,
|
||||||
|
collapsed,
|
||||||
|
}),
|
||||||
|
[subView, collapsed]
|
||||||
|
)
|
||||||
|
|
||||||
|
const updaterFns = useMemo<ReviewPanelState['updaterFns']>(
|
||||||
|
() => ({
|
||||||
|
setSubView,
|
||||||
|
setCollapsed,
|
||||||
|
}),
|
||||||
|
[setSubView, setCollapsed]
|
||||||
|
)
|
||||||
|
|
||||||
|
return { values, updaterFns }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useAngularReviewPanelState
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { createContext, useContext } from 'react'
|
||||||
|
import useAngularReviewPanelState from './hooks/use-angular-review-panel'
|
||||||
|
import { ReviewPanelState } from './types/review-panel-state'
|
||||||
|
|
||||||
|
const ReviewPanelValueContext = createContext<
|
||||||
|
ReviewPanelState['values'] | undefined
|
||||||
|
>(undefined)
|
||||||
|
|
||||||
|
const ReviewPanelUpdaterFnsContext = createContext<
|
||||||
|
ReviewPanelState['updaterFns'] | undefined
|
||||||
|
>(undefined)
|
||||||
|
|
||||||
|
type ReviewPanelProviderProps = {
|
||||||
|
children?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ReviewPanelProvider({ children }: ReviewPanelProviderProps) {
|
||||||
|
const { values, updaterFns } = useAngularReviewPanelState()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReviewPanelValueContext.Provider value={values}>
|
||||||
|
<ReviewPanelUpdaterFnsContext.Provider value={updaterFns}>
|
||||||
|
{children}
|
||||||
|
</ReviewPanelUpdaterFnsContext.Provider>
|
||||||
|
</ReviewPanelValueContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useReviewPanelValueContext() {
|
||||||
|
const context = useContext(ReviewPanelValueContext)
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
'ReviewPanelValueContext is only available inside ReviewPanelProvider'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useReviewPanelUpdaterFnsContext() {
|
||||||
|
const context = useContext(ReviewPanelUpdaterFnsContext)
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
'ReviewPanelUpdaterFnsContext is only available inside ReviewPanelProvider'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { SubView } from '../../../components/review-panel/nav'
|
||||||
|
|
||||||
|
export interface ReviewPanelState {
|
||||||
|
values: {
|
||||||
|
collapsed: Record<string, boolean>
|
||||||
|
subView: SubView
|
||||||
|
}
|
||||||
|
updaterFns: {
|
||||||
|
setCollapsed: React.Dispatch<
|
||||||
|
React.SetStateAction<ReviewPanelState['values']['collapsed']>
|
||||||
|
>
|
||||||
|
setSubView: React.Dispatch<
|
||||||
|
React.SetStateAction<ReviewPanelState['values']['subView']>
|
||||||
|
>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter for values
|
||||||
|
export type Value<T extends keyof ReviewPanelState['values']> =
|
||||||
|
ReviewPanelState['values'][T]
|
|
@ -71,7 +71,7 @@ export default App.controller(
|
||||||
PENDING: 'pending',
|
PENDING: 'pending',
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.reviewPanel = {
|
ide.$scope.reviewPanel = {
|
||||||
trackChangesState: {},
|
trackChangesState: {},
|
||||||
trackChangesOnForEveryone: false,
|
trackChangesOnForEveryone: false,
|
||||||
trackChangesOnForGuests: false,
|
trackChangesOnForGuests: false,
|
||||||
|
@ -111,8 +111,8 @@ export default App.controller(
|
||||||
|
|
||||||
window.addEventListener('beforeunload', function () {
|
window.addEventListener('beforeunload', function () {
|
||||||
const collapsedStates = {}
|
const collapsedStates = {}
|
||||||
for (const doc in $scope.reviewPanel.overview.docsCollapsedState) {
|
for (const doc in ide.$scope.reviewPanel.overview.docsCollapsedState) {
|
||||||
const state = $scope.reviewPanel.overview.docsCollapsedState[doc]
|
const state = ide.$scope.reviewPanel.overview.docsCollapsedState[doc]
|
||||||
if (state) {
|
if (state) {
|
||||||
collapsedStates[doc] = state
|
collapsedStates[doc] = state
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ export default App.controller(
|
||||||
)
|
)
|
||||||
|
|
||||||
$scope.$on('layout:pdf:resize', (event, state) => {
|
$scope.$on('layout:pdf:resize', (event, state) => {
|
||||||
$scope.reviewPanel.layoutToLeft =
|
ide.$scope.reviewPanel.layoutToLeft =
|
||||||
state.east?.size < 220 || state.east?.initClosed
|
state.east?.size < 220 || state.east?.initClosed
|
||||||
$scope.$broadcast('review-panel:layout', false)
|
$scope.$broadcast('review-panel:layout', false)
|
||||||
})
|
})
|
||||||
|
@ -156,10 +156,11 @@ export default App.controller(
|
||||||
})
|
})
|
||||||
|
|
||||||
$scope.$watch('project.members', function (members) {
|
$scope.$watch('project.members', function (members) {
|
||||||
$scope.reviewPanel.formattedProjectMembers = {}
|
ide.$scope.reviewPanel.formattedProjectMembers = {}
|
||||||
if (($scope.project != null ? $scope.project.owner : undefined) != null) {
|
if (($scope.project != null ? $scope.project.owner : undefined) != null) {
|
||||||
$scope.reviewPanel.formattedProjectMembers[$scope.project.owner._id] =
|
ide.$scope.reviewPanel.formattedProjectMembers[
|
||||||
formatUser($scope.project.owner)
|
$scope.project.owner._id
|
||||||
|
] = formatUser($scope.project.owner)
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
($scope.project != null ? $scope.project.members : undefined) != null
|
($scope.project != null ? $scope.project.members : undefined) != null
|
||||||
|
@ -168,16 +169,18 @@ export default App.controller(
|
||||||
const result = []
|
const result = []
|
||||||
for (const member of Array.from(members)) {
|
for (const member of Array.from(members)) {
|
||||||
if (member.privileges === 'readAndWrite') {
|
if (member.privileges === 'readAndWrite') {
|
||||||
if ($scope.reviewPanel.trackChangesState[member._id] == null) {
|
if (
|
||||||
|
ide.$scope.reviewPanel.trackChangesState[member._id] == null
|
||||||
|
) {
|
||||||
// An added member will have track changes enabled if track changes is on for everyone
|
// An added member will have track changes enabled if track changes is on for everyone
|
||||||
_setUserTCState(
|
_setUserTCState(
|
||||||
member._id,
|
member._id,
|
||||||
$scope.reviewPanel.trackChangesOnForEveryone,
|
ide.$scope.reviewPanel.trackChangesOnForEveryone,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
result.push(
|
result.push(
|
||||||
($scope.reviewPanel.formattedProjectMembers[member._id] =
|
(ide.$scope.reviewPanel.formattedProjectMembers[member._id] =
|
||||||
formatUser(member))
|
formatUser(member))
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -194,9 +197,9 @@ export default App.controller(
|
||||||
content: '',
|
content: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.users = {}
|
ide.$scope.users = $scope.users = {}
|
||||||
|
|
||||||
$scope.reviewPanelEventsBridge = new EventEmitter()
|
ide.$scope.reviewPanelEventsBridge = new EventEmitter()
|
||||||
|
|
||||||
ide.socket.on('new-comment', function (thread_id, comment) {
|
ide.socket.on('new-comment', function (thread_id, comment) {
|
||||||
const thread = getThread(thread_id)
|
const thread = getThread(thread_id)
|
||||||
|
@ -241,37 +244,37 @@ export default App.controller(
|
||||||
const rangesTrackers = {}
|
const rangesTrackers = {}
|
||||||
|
|
||||||
const getDocEntries = function (doc_id) {
|
const getDocEntries = function (doc_id) {
|
||||||
if ($scope.reviewPanel.entries[doc_id] == null) {
|
if (ide.$scope.reviewPanel.entries[doc_id] == null) {
|
||||||
$scope.reviewPanel.entries[doc_id] = {}
|
ide.$scope.reviewPanel.entries[doc_id] = {}
|
||||||
}
|
}
|
||||||
return $scope.reviewPanel.entries[doc_id]
|
return ide.$scope.reviewPanel.entries[doc_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDocResolvedComments = function (doc_id) {
|
const getDocResolvedComments = function (doc_id) {
|
||||||
if ($scope.reviewPanel.resolvedComments[doc_id] == null) {
|
if (ide.$scope.reviewPanel.resolvedComments[doc_id] == null) {
|
||||||
$scope.reviewPanel.resolvedComments[doc_id] = {}
|
ide.$scope.reviewPanel.resolvedComments[doc_id] = {}
|
||||||
}
|
}
|
||||||
return $scope.reviewPanel.resolvedComments[doc_id]
|
return ide.$scope.reviewPanel.resolvedComments[doc_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getThread(thread_id) {
|
function getThread(thread_id) {
|
||||||
if ($scope.reviewPanel.commentThreads[thread_id] == null) {
|
if (ide.$scope.reviewPanel.commentThreads[thread_id] == null) {
|
||||||
$scope.reviewPanel.commentThreads[thread_id] = { messages: [] }
|
ide.$scope.reviewPanel.commentThreads[thread_id] = { messages: [] }
|
||||||
}
|
}
|
||||||
return $scope.reviewPanel.commentThreads[thread_id]
|
return ide.$scope.reviewPanel.commentThreads[thread_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChangeTracker(doc_id) {
|
function getChangeTracker(doc_id) {
|
||||||
if (rangesTrackers[doc_id] == null) {
|
if (rangesTrackers[doc_id] == null) {
|
||||||
rangesTrackers[doc_id] = new RangesTracker()
|
rangesTrackers[doc_id] = new RangesTracker()
|
||||||
rangesTrackers[doc_id].resolvedThreadIds =
|
rangesTrackers[doc_id].resolvedThreadIds =
|
||||||
$scope.reviewPanel.resolvedThreadIds
|
ide.$scope.reviewPanel.resolvedThreadIds
|
||||||
}
|
}
|
||||||
return rangesTrackers[doc_id]
|
return rangesTrackers[doc_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
let scrollbar = {}
|
let scrollbar = {}
|
||||||
$scope.reviewPanelEventsBridge.on(
|
ide.$scope.reviewPanelEventsBridge.on(
|
||||||
'aceScrollbarVisibilityChanged',
|
'aceScrollbarVisibilityChanged',
|
||||||
function (isVisible, scrollbarWidth) {
|
function (isVisible, scrollbarWidth) {
|
||||||
scrollbar = { isVisible, scrollbarWidth }
|
scrollbar = { isVisible, scrollbarWidth }
|
||||||
|
@ -282,7 +285,7 @@ export default App.controller(
|
||||||
function updateScrollbar() {
|
function updateScrollbar() {
|
||||||
if (
|
if (
|
||||||
scrollbar.isVisible &&
|
scrollbar.isVisible &&
|
||||||
$scope.reviewPanel.subView === $scope.SubViews.CUR_FILE &&
|
ide.$scope.reviewPanel.subView === $scope.SubViews.CUR_FILE &&
|
||||||
!$scope.editor.showRichText
|
!$scope.editor.showRichText
|
||||||
) {
|
) {
|
||||||
return $reviewPanelEl.css('right', `${scrollbar.scrollbarWidth}px`)
|
return $reviewPanelEl.css('right', `${scrollbar.scrollbarWidth}px`)
|
||||||
|
@ -310,11 +313,11 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
if (!open) {
|
if (!open) {
|
||||||
// Always show current file when not open, but save current state
|
// Always show current file when not open, but save current state
|
||||||
$scope.reviewPanel.openSubView = $scope.reviewPanel.subView
|
ide.$scope.reviewPanel.openSubView = ide.$scope.reviewPanel.subView
|
||||||
$scope.reviewPanel.subView = $scope.SubViews.CUR_FILE
|
ide.$scope.reviewPanel.subView = $scope.SubViews.CUR_FILE
|
||||||
} else {
|
} else {
|
||||||
// Reset back to what we had when previously open
|
// Reset back to what we had when previously open
|
||||||
$scope.reviewPanel.subView = $scope.reviewPanel.openSubView
|
ide.$scope.reviewPanel.subView = ide.$scope.reviewPanel.openSubView
|
||||||
}
|
}
|
||||||
return $timeout(function () {
|
return $timeout(function () {
|
||||||
$scope.$broadcast('review-panel:toggle')
|
$scope.$broadcast('review-panel:toggle')
|
||||||
|
@ -342,8 +345,8 @@ export default App.controller(
|
||||||
// replace any outdated info with this
|
// replace any outdated info with this
|
||||||
rangesTrackers[doc.doc_id] = doc.ranges
|
rangesTrackers[doc.doc_id] = doc.ranges
|
||||||
rangesTrackers[doc.doc_id].resolvedThreadIds =
|
rangesTrackers[doc.doc_id].resolvedThreadIds =
|
||||||
$scope.reviewPanel.resolvedThreadIds
|
ide.$scope.reviewPanel.resolvedThreadIds
|
||||||
$scope.reviewPanel.rangesTracker = rangesTrackers[doc.doc_id]
|
ide.$scope.reviewPanel.rangesTracker = rangesTrackers[doc.doc_id]
|
||||||
if (old_doc != null) {
|
if (old_doc != null) {
|
||||||
old_doc.off('flipped_pending_to_inflight')
|
old_doc.off('flipped_pending_to_inflight')
|
||||||
}
|
}
|
||||||
|
@ -354,7 +357,7 @@ export default App.controller(
|
||||||
$scope.$watch(
|
$scope.$watch(
|
||||||
function () {
|
function () {
|
||||||
const entries =
|
const entries =
|
||||||
$scope.reviewPanel.entries[$scope.editor.open_doc_id] || {}
|
ide.$scope.reviewPanel.entries[$scope.editor.open_doc_id] || {}
|
||||||
const permEntries = {}
|
const permEntries = {}
|
||||||
for (const entry in entries) {
|
for (const entry in entries) {
|
||||||
const entryData = entries[entry]
|
const entryData = entries[entry]
|
||||||
|
@ -365,7 +368,7 @@ export default App.controller(
|
||||||
return Object.keys(permEntries).length
|
return Object.keys(permEntries).length
|
||||||
},
|
},
|
||||||
nEntries =>
|
nEntries =>
|
||||||
($scope.reviewPanel.hasEntries =
|
(ide.$scope.reviewPanel.hasEntries =
|
||||||
nEntries > 0 && $scope.project.features.trackChangesVisible)
|
nEntries > 0 && $scope.project.features.trackChangesVisible)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -385,9 +388,12 @@ export default App.controller(
|
||||||
const result = []
|
const result = []
|
||||||
for (const doc of Array.from(docs)) {
|
for (const doc of Array.from(docs)) {
|
||||||
if (
|
if (
|
||||||
$scope.reviewPanel.overview.docsCollapsedState[doc.id] == null
|
ide.$scope.reviewPanel.overview.docsCollapsedState[doc.id] ==
|
||||||
|
null
|
||||||
) {
|
) {
|
||||||
$scope.reviewPanel.overview.docsCollapsedState[doc.id] = false
|
ide.$scope.reviewPanel.overview.docsCollapsedState[
|
||||||
|
doc.id
|
||||||
|
] = false
|
||||||
}
|
}
|
||||||
if (doc.id !== $scope.editor.open_doc_id) {
|
if (doc.id !== $scope.editor.open_doc_id) {
|
||||||
// this is kept up to date in real-time, don't overwrite
|
// this is kept up to date in real-time, don't overwrite
|
||||||
|
@ -404,17 +410,17 @@ export default App.controller(
|
||||||
})
|
})
|
||||||
|
|
||||||
function refreshOverviewPanel() {
|
function refreshOverviewPanel() {
|
||||||
$scope.reviewPanel.overview.loading = true
|
ide.$scope.reviewPanel.overview.loading = true
|
||||||
return refreshRanges()
|
return refreshRanges()
|
||||||
.then(() => ($scope.reviewPanel.overview.loading = false))
|
.then(() => (ide.$scope.reviewPanel.overview.loading = false))
|
||||||
.catch(() => ($scope.reviewPanel.overview.loading = false))
|
.catch(() => (ide.$scope.reviewPanel.overview.loading = false))
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.refreshResolvedCommentsDropdown = function () {
|
ide.$scope.refreshResolvedCommentsDropdown = function () {
|
||||||
$scope.reviewPanel.dropdown.loading = true
|
ide.$scope.reviewPanel.dropdown.loading = true
|
||||||
const q = refreshRanges()
|
const q = refreshRanges()
|
||||||
q.then(() => ($scope.reviewPanel.dropdown.loading = false))
|
q.then(() => (ide.$scope.reviewPanel.dropdown.loading = false))
|
||||||
q.catch(() => ($scope.reviewPanel.dropdown.loading = false))
|
q.catch(() => (ide.$scope.reviewPanel.dropdown.loading = false))
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +510,7 @@ export default App.controller(
|
||||||
let new_comment
|
let new_comment
|
||||||
changed = true
|
changed = true
|
||||||
delete delete_changes[comment.id]
|
delete delete_changes[comment.id]
|
||||||
if ($scope.reviewPanel.resolvedThreadIds[comment.op.t]) {
|
if (ide.$scope.reviewPanel.resolvedThreadIds[comment.op.t]) {
|
||||||
new_comment =
|
new_comment =
|
||||||
resolvedComments[comment.id] != null
|
resolvedComments[comment.id] != null
|
||||||
? resolvedComments[comment.id]
|
? resolvedComments[comment.id]
|
||||||
|
@ -567,9 +573,9 @@ export default App.controller(
|
||||||
const doc_id = $scope.editor.open_doc_id
|
const doc_id = $scope.editor.open_doc_id
|
||||||
const entries = getDocEntries(doc_id)
|
const entries = getDocEntries(doc_id)
|
||||||
// All selected changes will be added to this array.
|
// All selected changes will be added to this array.
|
||||||
$scope.reviewPanel.selectedEntryIds = []
|
ide.$scope.reviewPanel.selectedEntryIds = []
|
||||||
// Count of user-visible changes, i.e. an aggregated change will count as one.
|
// Count of user-visible changes, i.e. an aggregated change will count as one.
|
||||||
$scope.reviewPanel.nVisibleSelectedChanges = 0
|
ide.$scope.reviewPanel.nVisibleSelectedChanges = 0
|
||||||
delete entries['add-comment']
|
delete entries['add-comment']
|
||||||
delete entries['bulk-actions']
|
delete entries['bulk-actions']
|
||||||
|
|
||||||
|
@ -591,7 +597,7 @@ export default App.controller(
|
||||||
let isChangeEntryAndWithinSelection = false
|
let isChangeEntryAndWithinSelection = false
|
||||||
if (
|
if (
|
||||||
entry.type === 'comment' &&
|
entry.type === 'comment' &&
|
||||||
!$scope.reviewPanel.resolvedThreadIds[entry.thread_id]
|
!ide.$scope.reviewPanel.resolvedThreadIds[entry.thread_id]
|
||||||
) {
|
) {
|
||||||
entry.focused =
|
entry.focused =
|
||||||
entry.offset <= selection_offset_start &&
|
entry.offset <= selection_offset_start &&
|
||||||
|
@ -624,9 +630,9 @@ export default App.controller(
|
||||||
|
|
||||||
if (isChangeEntryAndWithinSelection) {
|
if (isChangeEntryAndWithinSelection) {
|
||||||
for (const entry_id of Array.from(entry.entry_ids)) {
|
for (const entry_id of Array.from(entry.entry_ids)) {
|
||||||
$scope.reviewPanel.selectedEntryIds.push(entry_id)
|
ide.$scope.reviewPanel.selectedEntryIds.push(entry_id)
|
||||||
}
|
}
|
||||||
$scope.reviewPanel.nVisibleSelectedChanges++
|
ide.$scope.reviewPanel.nVisibleSelectedChanges++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,17 +644,21 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
$scope.acceptChanges = function (change_ids) {
|
ide.$scope.acceptChanges = function (change_ids) {
|
||||||
_doAcceptChanges(change_ids)
|
_doAcceptChanges(change_ids)
|
||||||
eventTracking.sendMB('rp-changes-accepted', {
|
eventTracking.sendMB('rp-changes-accepted', {
|
||||||
view: $scope.ui.reviewPanelOpen ? $scope.reviewPanel.subView : 'mini',
|
view: $scope.ui.reviewPanelOpen
|
||||||
|
? ide.$scope.reviewPanel.subView
|
||||||
|
: 'mini',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.rejectChanges = function (change_ids) {
|
ide.$scope.rejectChanges = function (change_ids) {
|
||||||
_doRejectChanges(change_ids)
|
_doRejectChanges(change_ids)
|
||||||
eventTracking.sendMB('rp-changes-rejected', {
|
eventTracking.sendMB('rp-changes-rejected', {
|
||||||
view: $scope.ui.reviewPanelOpen ? $scope.reviewPanel.subView : 'mini',
|
view: $scope.ui.reviewPanelOpen
|
||||||
|
? ide.$scope.reviewPanel.subView
|
||||||
|
: 'mini',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,11 +667,11 @@ export default App.controller(
|
||||||
// the review panel is visible when hovering over its indicator when the
|
// the review panel is visible when hovering over its indicator when the
|
||||||
// review panel is minimized. See issue #8057.
|
// review panel is minimized. See issue #8057.
|
||||||
$scope.mouseEnterIndicator = function () {
|
$scope.mouseEnterIndicator = function () {
|
||||||
$scope.reviewPanel.entryHover = true
|
ide.$scope.reviewPanel.entryHover = true
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.mouseLeaveIndicator = function () {
|
$scope.mouseLeaveIndicator = function () {
|
||||||
$scope.reviewPanel.entryHover = false
|
ide.$scope.reviewPanel.entryHover = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function _doAcceptChanges(change_ids) {
|
function _doAcceptChanges(change_ids) {
|
||||||
|
@ -679,24 +689,28 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
|
|
||||||
const bulkAccept = function () {
|
const bulkAccept = function () {
|
||||||
_doAcceptChanges($scope.reviewPanel.selectedEntryIds.slice())
|
_doAcceptChanges(ide.$scope.reviewPanel.selectedEntryIds.slice())
|
||||||
eventTracking.sendMB('rp-bulk-accept', {
|
eventTracking.sendMB('rp-bulk-accept', {
|
||||||
view: $scope.ui.reviewPanelOpen ? $scope.reviewPanel.subView : 'mini',
|
view: $scope.ui.reviewPanelOpen
|
||||||
nEntries: $scope.reviewPanel.nVisibleSelectedChanges,
|
? ide.$scope.reviewPanel.subView
|
||||||
|
: 'mini',
|
||||||
|
nEntries: ide.$scope.reviewPanel.nVisibleSelectedChanges,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const bulkReject = function () {
|
const bulkReject = function () {
|
||||||
_doRejectChanges($scope.reviewPanel.selectedEntryIds.slice())
|
_doRejectChanges(ide.$scope.reviewPanel.selectedEntryIds.slice())
|
||||||
eventTracking.sendMB('rp-bulk-reject', {
|
eventTracking.sendMB('rp-bulk-reject', {
|
||||||
view: $scope.ui.reviewPanelOpen ? $scope.reviewPanel.subView : 'mini',
|
view: $scope.ui.reviewPanelOpen
|
||||||
nEntries: $scope.reviewPanel.nVisibleSelectedChanges,
|
? ide.$scope.reviewPanel.subView
|
||||||
|
: 'mini',
|
||||||
|
nEntries: ide.$scope.reviewPanel.nVisibleSelectedChanges,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.showBulkAcceptDialog = () => showBulkActionsDialog(true)
|
ide.$scope.showBulkAcceptDialog = () => showBulkActionsDialog(true)
|
||||||
|
|
||||||
$scope.showBulkRejectDialog = () => showBulkActionsDialog(false)
|
ide.$scope.showBulkRejectDialog = () => showBulkActionsDialog(false)
|
||||||
|
|
||||||
const showBulkActionsDialog = isAccept =>
|
const showBulkActionsDialog = isAccept =>
|
||||||
$modal
|
$modal
|
||||||
|
@ -708,7 +722,7 @@ export default App.controller(
|
||||||
return isAccept
|
return isAccept
|
||||||
},
|
},
|
||||||
nChanges() {
|
nChanges() {
|
||||||
return $scope.reviewPanel.nVisibleSelectedChanges
|
return ide.$scope.reviewPanel.nVisibleSelectedChanges
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
scope: $scope.$new(),
|
scope: $scope.$new(),
|
||||||
|
@ -726,7 +740,7 @@ export default App.controller(
|
||||||
return $scope.toggleReviewPanel()
|
return $scope.toggleReviewPanel()
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.addNewComment = function (e) {
|
ide.$scope.addNewComment = function (e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
$scope.$broadcast('comment:start_adding')
|
$scope.$broadcast('comment:start_adding')
|
||||||
return $scope.toggleReviewPanel()
|
return $scope.toggleReviewPanel()
|
||||||
|
@ -754,7 +768,7 @@ export default App.controller(
|
||||||
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.submitNewComment = function (content) {
|
ide.$scope.submitNewComment = function (content) {
|
||||||
if (content == null || content === '') {
|
if (content == null || content === '') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -798,7 +812,7 @@ export default App.controller(
|
||||||
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.submitReply = function (entry, entry_id) {
|
ide.$scope.submitReply = function (entry, entry_id) {
|
||||||
const { thread_id } = entry
|
const { thread_id } = entry
|
||||||
const content = entry.replyContent
|
const content = entry.replyContent
|
||||||
$http
|
$http
|
||||||
|
@ -814,7 +828,9 @@ export default App.controller(
|
||||||
)
|
)
|
||||||
|
|
||||||
const trackingMetadata = {
|
const trackingMetadata = {
|
||||||
view: $scope.ui.reviewPanelOpen ? $scope.reviewPanel.subView : 'mini',
|
view: $scope.ui.reviewPanelOpen
|
||||||
|
? ide.$scope.reviewPanel.subView
|
||||||
|
: 'mini',
|
||||||
size: entry.replyContent.length,
|
size: entry.replyContent.length,
|
||||||
thread: thread_id,
|
thread: thread_id,
|
||||||
}
|
}
|
||||||
|
@ -833,7 +849,8 @@ export default App.controller(
|
||||||
return $scope.$broadcast('review-panel:layout')
|
return $scope.$broadcast('review-panel:layout')
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.resolveComment = function (entry, entry_id) {
|
ide.$scope.resolveComment = function (doc_id, entry_id) {
|
||||||
|
const entry = getDocEntries(doc_id)[entry_id]
|
||||||
entry.focused = false
|
entry.focused = false
|
||||||
$http.post(
|
$http.post(
|
||||||
`/project/${$scope.project_id}/thread/${entry.thread_id}/resolve`,
|
`/project/${$scope.project_id}/thread/${entry.thread_id}/resolve`,
|
||||||
|
@ -841,11 +858,13 @@ export default App.controller(
|
||||||
)
|
)
|
||||||
_onCommentResolved(entry.thread_id, ide.$scope.user)
|
_onCommentResolved(entry.thread_id, ide.$scope.user)
|
||||||
eventTracking.sendMB('rp-comment-resolve', {
|
eventTracking.sendMB('rp-comment-resolve', {
|
||||||
view: $scope.ui.reviewPanelOpen ? $scope.reviewPanel.subView : 'mini',
|
view: $scope.ui.reviewPanelOpen
|
||||||
|
? ide.$scope.reviewPanel.subView
|
||||||
|
: 'mini',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.unresolveComment = function (thread_id) {
|
ide.$scope.unresolveComment = function (thread_id) {
|
||||||
_onCommentReopened(thread_id)
|
_onCommentReopened(thread_id)
|
||||||
$http.post(`/project/${$scope.project_id}/thread/${thread_id}/reopen`, {
|
$http.post(`/project/${$scope.project_id}/thread/${thread_id}/reopen`, {
|
||||||
_csrf: window.csrfToken,
|
_csrf: window.csrfToken,
|
||||||
|
@ -861,7 +880,7 @@ export default App.controller(
|
||||||
thread.resolved = true
|
thread.resolved = true
|
||||||
thread.resolved_by_user = formatUser(user)
|
thread.resolved_by_user = formatUser(user)
|
||||||
thread.resolved_at = new Date().toISOString()
|
thread.resolved_at = new Date().toISOString()
|
||||||
$scope.reviewPanel.resolvedThreadIds[thread_id] = true
|
ide.$scope.reviewPanel.resolvedThreadIds[thread_id] = true
|
||||||
$scope.$broadcast('comment:resolve_threads', [thread_id])
|
$scope.$broadcast('comment:resolve_threads', [thread_id])
|
||||||
dispatchReviewPanelEvent('comment:resolve_threads', [thread_id])
|
dispatchReviewPanelEvent('comment:resolve_threads', [thread_id])
|
||||||
}
|
}
|
||||||
|
@ -874,14 +893,14 @@ export default App.controller(
|
||||||
delete thread.resolved
|
delete thread.resolved
|
||||||
delete thread.resolved_by_user
|
delete thread.resolved_by_user
|
||||||
delete thread.resolved_at
|
delete thread.resolved_at
|
||||||
delete $scope.reviewPanel.resolvedThreadIds[thread_id]
|
delete ide.$scope.reviewPanel.resolvedThreadIds[thread_id]
|
||||||
$scope.$broadcast('comment:unresolve_thread', thread_id)
|
$scope.$broadcast('comment:unresolve_thread', thread_id)
|
||||||
dispatchReviewPanelEvent('comment:unresolve_thread', thread_id)
|
dispatchReviewPanelEvent('comment:unresolve_thread', thread_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onThreadDeleted(thread_id) {
|
function _onThreadDeleted(thread_id) {
|
||||||
delete $scope.reviewPanel.resolvedThreadIds[thread_id]
|
delete ide.$scope.reviewPanel.resolvedThreadIds[thread_id]
|
||||||
delete $scope.reviewPanel.commentThreads[thread_id]
|
delete ide.$scope.reviewPanel.commentThreads[thread_id]
|
||||||
$scope.$broadcast('comment:remove', thread_id)
|
$scope.$broadcast('comment:remove', thread_id)
|
||||||
dispatchReviewPanelEvent('comment:remove', thread_id)
|
dispatchReviewPanelEvent('comment:remove', thread_id)
|
||||||
}
|
}
|
||||||
|
@ -908,7 +927,7 @@ export default App.controller(
|
||||||
return updateEntries()
|
return updateEntries()
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.deleteThread = function (entry_id, doc_id, thread_id) {
|
ide.$scope.deleteThread = function (entry_id, doc_id, thread_id) {
|
||||||
_onThreadDeleted(thread_id)
|
_onThreadDeleted(thread_id)
|
||||||
$http({
|
$http({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
@ -920,22 +939,22 @@ export default App.controller(
|
||||||
eventTracking.sendMB('rp-comment-delete')
|
eventTracking.sendMB('rp-comment-delete')
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.saveEdit = function (thread_id, comment) {
|
ide.$scope.saveEdit = function (thread_id, comment_id, content) {
|
||||||
$http.post(
|
$http.post(
|
||||||
`/project/${$scope.project_id}/thread/${thread_id}/messages/${comment.id}/edit`,
|
`/project/${$scope.project_id}/thread/${thread_id}/messages/${comment_id}/edit`,
|
||||||
{
|
{
|
||||||
content: comment.content,
|
content,
|
||||||
_csrf: window.csrfToken,
|
_csrf: window.csrfToken,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.deleteComment = function (thread_id, comment) {
|
ide.$scope.deleteComment = function (thread_id, comment_id) {
|
||||||
_onCommentDeleted(thread_id, comment.id)
|
_onCommentDeleted(thread_id, comment_id)
|
||||||
$http({
|
$http({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
url: `/project/${$scope.project_id}/thread/${thread_id}/messages/${comment.id}`,
|
url: `/project/${$scope.project_id}/thread/${thread_id}/messages/${comment_id}`,
|
||||||
headers: {
|
headers: {
|
||||||
'X-CSRF-Token': window.csrfToken,
|
'X-CSRF-Token': window.csrfToken,
|
||||||
},
|
},
|
||||||
|
@ -944,17 +963,17 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.setSubView = function (subView) {
|
$scope.setSubView = function (subView) {
|
||||||
$scope.reviewPanel.subView = subView
|
ide.$scope.reviewPanel.subView = subView
|
||||||
eventTracking.sendMB('rp-subview-change', { subView })
|
eventTracking.sendMB('rp-subview-change', { subView })
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.gotoEntry = (doc_id, entry) =>
|
ide.$scope.gotoEntry = (doc_id, entry_offset) =>
|
||||||
ide.editorManager.openDocId(doc_id, { gotoOffset: entry.offset })
|
ide.editorManager.openDocId(doc_id, { gotoOffset: entry_offset })
|
||||||
|
|
||||||
$scope.toggleFullTCStateCollapse = function () {
|
$scope.toggleFullTCStateCollapse = function () {
|
||||||
if ($scope.project.features.trackChanges) {
|
if ($scope.project.features.trackChanges) {
|
||||||
return ($scope.reviewPanel.fullTCStateCollapsed =
|
return (ide.$scope.reviewPanel.fullTCStateCollapsed =
|
||||||
!$scope.reviewPanel.fullTCStateCollapsed)
|
!ide.$scope.reviewPanel.fullTCStateCollapsed)
|
||||||
} else {
|
} else {
|
||||||
_sendAnalytics()
|
_sendAnalytics()
|
||||||
return $scope.openTrackChangesUpgradeModal()
|
return $scope.openTrackChangesUpgradeModal()
|
||||||
|
@ -976,10 +995,10 @@ export default App.controller(
|
||||||
if (isLocal == null) {
|
if (isLocal == null) {
|
||||||
isLocal = false
|
isLocal = false
|
||||||
}
|
}
|
||||||
if ($scope.reviewPanel.trackChangesState[userId] == null) {
|
if (ide.$scope.reviewPanel.trackChangesState[userId] == null) {
|
||||||
$scope.reviewPanel.trackChangesState[userId] = {}
|
ide.$scope.reviewPanel.trackChangesState[userId] = {}
|
||||||
}
|
}
|
||||||
const state = $scope.reviewPanel.trackChangesState[userId]
|
const state = ide.$scope.reviewPanel.trackChangesState[userId]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
state.syncState == null ||
|
state.syncState == null ||
|
||||||
|
@ -1006,7 +1025,7 @@ export default App.controller(
|
||||||
if (isLocal == null) {
|
if (isLocal == null) {
|
||||||
isLocal = false
|
isLocal = false
|
||||||
}
|
}
|
||||||
$scope.reviewPanel.trackChangesOnForEveryone = newValue
|
ide.$scope.reviewPanel.trackChangesOnForEveryone = newValue
|
||||||
const { project } = $scope
|
const { project } = $scope
|
||||||
for (const member of Array.from(project.members)) {
|
for (const member of Array.from(project.members)) {
|
||||||
_setUserTCState(member._id, newValue, isLocal)
|
_setUserTCState(member._id, newValue, isLocal)
|
||||||
|
@ -1019,7 +1038,7 @@ export default App.controller(
|
||||||
if (isLocal == null) {
|
if (isLocal == null) {
|
||||||
isLocal = false
|
isLocal = false
|
||||||
}
|
}
|
||||||
$scope.reviewPanel.trackChangesOnForGuests = newValue
|
ide.$scope.reviewPanel.trackChangesOnForGuests = newValue
|
||||||
if (
|
if (
|
||||||
currentUserType() === UserTypes.GUEST ||
|
currentUserType() === UserTypes.GUEST ||
|
||||||
currentUserType() === UserTypes.ANONYMOUS
|
currentUserType() === UserTypes.ANONYMOUS
|
||||||
|
@ -1030,15 +1049,15 @@ export default App.controller(
|
||||||
|
|
||||||
const applyClientTrackChangesStateToServer = function () {
|
const applyClientTrackChangesStateToServer = function () {
|
||||||
const data = {}
|
const data = {}
|
||||||
if ($scope.reviewPanel.trackChangesOnForEveryone) {
|
if (ide.$scope.reviewPanel.trackChangesOnForEveryone) {
|
||||||
data.on = true
|
data.on = true
|
||||||
} else {
|
} else {
|
||||||
data.on_for = {}
|
data.on_for = {}
|
||||||
for (const userId in $scope.reviewPanel.trackChangesState) {
|
for (const userId in ide.$scope.reviewPanel.trackChangesState) {
|
||||||
const userState = $scope.reviewPanel.trackChangesState[userId]
|
const userState = ide.$scope.reviewPanel.trackChangesState[userId]
|
||||||
data.on_for[userId] = userState.value
|
data.on_for[userId] = userState.value
|
||||||
}
|
}
|
||||||
if ($scope.reviewPanel.trackChangesOnForGuests) {
|
if (ide.$scope.reviewPanel.trackChangesOnForGuests) {
|
||||||
data.on_for_guests = true
|
data.on_for_guests = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1052,7 +1071,7 @@ export default App.controller(
|
||||||
return _setGuestsTCState(state)
|
return _setGuestsTCState(state)
|
||||||
} else {
|
} else {
|
||||||
const { project } = $scope
|
const { project } = $scope
|
||||||
$scope.reviewPanel.trackChangesOnForEveryone = false
|
ide.$scope.reviewPanel.trackChangesOnForEveryone = false
|
||||||
_setGuestsTCState(state.__guests__ === true)
|
_setGuestsTCState(state.__guests__ === true)
|
||||||
for (const member of Array.from(project.members)) {
|
for (const member of Array.from(project.members)) {
|
||||||
_setUserTCState(
|
_setUserTCState(
|
||||||
|
@ -1069,18 +1088,18 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.toggleTrackChangesForEveryone = function (onForEveryone) {
|
ide.$scope.toggleTrackChangesForEveryone = function (onForEveryone) {
|
||||||
_setEveryoneTCState(onForEveryone, true)
|
_setEveryoneTCState(onForEveryone, true)
|
||||||
_setGuestsTCState(onForEveryone, true)
|
_setGuestsTCState(onForEveryone, true)
|
||||||
return applyClientTrackChangesStateToServer()
|
return applyClientTrackChangesStateToServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.toggleTrackChangesForGuests = function (onForGuests) {
|
ide.$scope.toggleTrackChangesForGuests = function (onForGuests) {
|
||||||
_setGuestsTCState(onForGuests, true)
|
_setGuestsTCState(onForGuests, true)
|
||||||
return applyClientTrackChangesStateToServer()
|
return applyClientTrackChangesStateToServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.toggleTrackChangesForUser = function (onForUser, userId) {
|
ide.$scope.toggleTrackChangesForUser = function (onForUser, userId) {
|
||||||
_setUserTCState(userId, onForUser, true)
|
_setUserTCState(userId, onForUser, true)
|
||||||
return applyClientTrackChangesStateToServer()
|
return applyClientTrackChangesStateToServer()
|
||||||
}
|
}
|
||||||
|
@ -1099,13 +1118,13 @@ export default App.controller(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return $scope.toggleTrackChangesForUser(
|
return $scope.toggleTrackChangesForUser(
|
||||||
!$scope.reviewPanel.trackChangesState[ide.$scope.user.id].value,
|
!ide.$scope.reviewPanel.trackChangesState[ide.$scope.user.id].value,
|
||||||
ide.$scope.user.id
|
ide.$scope.user.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setGuestFeatureBasedOnProjectAccessLevel = projectPublicAccessLevel =>
|
const setGuestFeatureBasedOnProjectAccessLevel = projectPublicAccessLevel =>
|
||||||
($scope.reviewPanel.trackChangesForGuestsAvailable =
|
(ide.$scope.reviewPanel.trackChangesForGuestsAvailable =
|
||||||
projectPublicAccessLevel === 'tokenBased')
|
projectPublicAccessLevel === 'tokenBased')
|
||||||
|
|
||||||
const onToggleTrackChangesForGuestsAvailability = function (available) {
|
const onToggleTrackChangesForGuestsAvailability = function (available) {
|
||||||
|
@ -1113,10 +1132,10 @@ export default App.controller(
|
||||||
if (available) {
|
if (available) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!$scope.reviewPanel.trackChangesOnForGuests) {
|
if (!ide.$scope.reviewPanel.trackChangesOnForGuests) {
|
||||||
return
|
return
|
||||||
} // Already turned off
|
} // Already turned off
|
||||||
if ($scope.reviewPanel.trackChangesOnForEveryone) {
|
if (ide.$scope.reviewPanel.trackChangesOnForEveryone) {
|
||||||
return
|
return
|
||||||
} // Overrides guest setting
|
} // Overrides guest setting
|
||||||
return $scope.toggleTrackChangesForGuests(false)
|
return $scope.toggleTrackChangesForGuests(false)
|
||||||
|
@ -1153,7 +1172,6 @@ export default App.controller(
|
||||||
|
|
||||||
let _refreshingRangeUsers = false
|
let _refreshingRangeUsers = false
|
||||||
const _refreshedForUserIds = {}
|
const _refreshedForUserIds = {}
|
||||||
|
|
||||||
function refreshChangeUsers(refresh_for_user_id) {
|
function refreshChangeUsers(refresh_for_user_id) {
|
||||||
if (refresh_for_user_id != null) {
|
if (refresh_for_user_id != null) {
|
||||||
if (_refreshedForUserIds[refresh_for_user_id] != null) {
|
if (_refreshedForUserIds[refresh_for_user_id] != null) {
|
||||||
|
@ -1174,7 +1192,7 @@ export default App.controller(
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
const users = response.data
|
const users = response.data
|
||||||
_refreshingRangeUsers = false
|
_refreshingRangeUsers = false
|
||||||
$scope.users = {}
|
ide.$scope.users = $scope.users = {}
|
||||||
// Always include ourself, since if we submit an op, we might need to display info
|
// Always include ourself, since if we submit an op, we might need to display info
|
||||||
// about it locally before it has been flushed through the server
|
// about it locally before it has been flushed through the server
|
||||||
if (
|
if (
|
||||||
|
@ -1198,7 +1216,6 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
|
|
||||||
let _threadsLoaded = false
|
let _threadsLoaded = false
|
||||||
|
|
||||||
function ensureThreadsAreLoaded() {
|
function ensureThreadsAreLoaded() {
|
||||||
if (_threadsLoaded) {
|
if (_threadsLoaded) {
|
||||||
// We get any updates in real time so only need to load them once.
|
// We get any updates in real time so only need to load them once.
|
||||||
|
@ -1211,9 +1228,8 @@ export default App.controller(
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
const threads = response.data
|
const threads = response.data
|
||||||
ide.$scope.loadingThreads = false
|
ide.$scope.loadingThreads = false
|
||||||
for (const thread_id in $scope.reviewPanel.resolvedThreadIds) {
|
for (const thread_id in ide.$scope.reviewPanel.resolvedThreadIds) {
|
||||||
const _ = $scope.reviewPanel.resolvedThreadIds[thread_id]
|
delete ide.$scope.reviewPanel.resolvedThreadIds[thread_id]
|
||||||
delete $scope.reviewPanel.resolvedThreadIds[thread_id]
|
|
||||||
}
|
}
|
||||||
for (const thread_id in threads) {
|
for (const thread_id in threads) {
|
||||||
const thread = threads[thread_id]
|
const thread = threads[thread_id]
|
||||||
|
@ -1222,11 +1238,11 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
if (thread.resolved_by_user != null) {
|
if (thread.resolved_by_user != null) {
|
||||||
thread.resolved_by_user = formatUser(thread.resolved_by_user)
|
thread.resolved_by_user = formatUser(thread.resolved_by_user)
|
||||||
$scope.reviewPanel.resolvedThreadIds[thread_id] = true
|
ide.$scope.reviewPanel.resolvedThreadIds[thread_id] = true
|
||||||
$scope.$broadcast('comment:resolve_threads', [thread_id])
|
$scope.$broadcast('comment:resolve_threads', [thread_id])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$scope.reviewPanel.commentThreads = threads
|
ide.$scope.reviewPanel.commentThreads = threads
|
||||||
dispatchReviewPanelEvent('loaded_threads')
|
dispatchReviewPanelEvent('loaded_threads')
|
||||||
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
return $timeout(() => $scope.$broadcast('review-panel:layout'))
|
||||||
})
|
})
|
||||||
|
@ -1293,7 +1309,7 @@ export default App.controller(
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'line-height': {
|
case 'line-height': {
|
||||||
$scope.reviewPanel.rendererData.lineHeight = payload
|
ide.$scope.reviewPanel.rendererData.lineHeight = payload
|
||||||
$scope.$broadcast('review-panel:layout')
|
$scope.$broadcast('review-panel:layout')
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -1325,11 +1341,14 @@ export default App.controller(
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'toggle-review-panel': {
|
case 'toggle-review-panel': {
|
||||||
ide.toggleReviewPanel()
|
$scope.toggleReviewPanel()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Add methods somewhere that React can see them
|
||||||
|
$scope.reviewPanel.saveEdit = $scope.saveEdit
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1109,3 +1109,115 @@ button when (@is-overleaf-light = true) {
|
||||||
.rp-flex-block {
|
.rp-flex-block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CM6-specific review panel rules
|
||||||
|
.ol-cm-review-panel {
|
||||||
|
display: block;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.rp-size-expanded & {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: @review-panel-width;
|
||||||
|
overflow: visible;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-size-mini & {
|
||||||
|
width: @review-off-width;
|
||||||
|
z-index: 6;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
background-color: @rp-bg-blue;
|
||||||
|
border-left: solid 0 @rp-border-grey;
|
||||||
|
font-family: @font-family-base;
|
||||||
|
line-height: @line-height-base;
|
||||||
|
font-size: @rp-base-font-size;
|
||||||
|
color: @rp-type-blue;
|
||||||
|
z-index: 6;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
box-sizing: content-box;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.review-panel-toolbar {
|
||||||
|
& .review-panel-toolbar-collapse-button {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-state-current-file & {
|
||||||
|
.review-panel-tools {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-panel-toolbar {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-nav {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-panel-toggler {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-state-overview & {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.review-panel-toggler {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-nav-item {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-entry-list {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.rp-overview-file {
|
||||||
|
.rp-overview-file-entries {
|
||||||
|
//height: auto;
|
||||||
|
transition: height ease-in-out 0.15s; //, display 0.15s 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-overview-file-num-entries {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.rp-overview-file-collapse {
|
||||||
|
.rp-overview-file-num-entries {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rp-overview-file-entries {
|
||||||
|
// height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue