1
0
Fork 0
mirror of https://github.com/overleaf/overleaf.git synced 2025-04-23 01:46:22 +00:00

Merge pull request from overleaf/ii-review-panel-migration-in-editor-widgets

[web] Create in editor widgets

GitOrigin-RevId: 53dfb9935ee59bbdedc353aad5e5b19f389a513c
This commit is contained in:
ilkin-overleaf 2023-07-12 16:52:29 +03:00 committed by Copybot
parent 3297506021
commit 84bbdf9772
12 changed files with 211 additions and 21 deletions
services/web
app
src/Features/Project
views/project/editor
frontend
test/frontend/features/review-panel

View file

@ -953,6 +953,7 @@ const ProjectController = {
historyViewReact: historyViewAssignment.variant === 'react',
isReviewPanelReact: reviewPanelAssignment.variant === 'react',
showPersonalAccessToken,
hasTrackChangesFeature: Features.hasFeature('track-changes'),
})
timer.done()
}

View file

@ -41,6 +41,7 @@ meta(name="ol-showCM6SwitchAwaySurvey", data-type="boolean" content=showCM6Switc
meta(name="ol-richTextVariant" content=richTextVariant)
meta(name="ol-showPersonalAccessToken", data-type="boolean" content=showPersonalAccessToken)
meta(name="ol-isReviewPanelReact", data-type="boolean" content=isReviewPanelReact)
meta(name="ol-hasTrackChangesFeature", data-type="boolean" content=hasTrackChangesFeature)
if (richTextVariant === 'cm6')
meta(name="ol-mathJax3Path" content=mathJax3Path)

View file

@ -0,0 +1,5 @@
function AddCommentButton(props: React.ComponentPropsWithoutRef<'button'>) {
return <button className="rp-add-comment-btn" {...props} />
}
export default AddCommentButton

View file

@ -24,14 +24,13 @@ function CurrentFileContainer() {
permissions,
loadingThreads,
users,
entryHover,
nVisibleSelectedChanges: nChanges,
toggleReviewPanel,
} = useReviewPanelValueContext()
const { setEntryHover } = useReviewPanelUpdaterFnsContext()
const contentHeight = useCodeMirrorContentHeight()
console.log('Review panel got content height', contentHeight)
const currentDocEntries =
openDocId && openDocId in entries ? entries[openDocId] : undefined
@ -42,7 +41,7 @@ function CurrentFileContainer() {
}, [currentDocEntries])
return (
<Container>
<Container classNames={{ 'rp-collapsed-displaying-entry': entryHover }}>
<div className="review-panel-tools">
<Toolbar />
<Nav />

View file

@ -0,0 +1,110 @@
import ReactDOM from 'react-dom'
import { useTranslation } from 'react-i18next'
import ToggleWidget from './toggle-widget'
import BulkActions from '../entries/bulk-actions-entry/bulk-actions'
import AddCommentButton from '../add-comment-button'
import Icon from '../../../../../shared/components/icon'
import {
useReviewPanelUpdaterFnsContext,
useReviewPanelValueContext,
} from '../../../context/review-panel/review-panel-context'
import { useCodeMirrorViewContext } from '../../codemirror-editor'
import Modal, { useBulkActionsModal } from '../entries/bulk-actions-entry/modal'
import getMeta from '../../../../../utils/meta'
import useScopeValue from '../../../../../shared/hooks/use-scope-value'
import { MergeAndOverride } from '../../../../../../../types/utils'
import { ReviewPanelBulkActionsEntry } from '../../../../../../../types/review-panel/entry'
function EditorWidgets() {
const { t } = useTranslation()
const {
show,
setShow,
isAccept,
handleShowBulkAcceptDialog,
handleShowBulkRejectDialog,
handleConfirmDialog,
} = useBulkActionsModal()
const { setIsAddingComment } = useReviewPanelUpdaterFnsContext()
const [addNewComment] =
useScopeValue<(e: React.MouseEvent<HTMLButtonElement>) => void>(
'addNewComment'
)
const view = useCodeMirrorViewContext()
type UseReviewPanelValueContextReturnType = ReturnType<
typeof useReviewPanelValueContext
>
const {
entries,
openDocId,
nVisibleSelectedChanges: nChanges,
wantTrackChanges,
permissions,
// Remapping entries as they may contain `add-comment` and `bulk-actions` props along with DocIds
// Ideally the `add-comment` and `bulk-actions` objects should not be within the entries object
// as the doc data, but this is what currently angular returns.
} = useReviewPanelValueContext() as MergeAndOverride<
UseReviewPanelValueContextReturnType,
{
entries: {
// eslint-disable-next-line no-use-before-define
[Entry in UseReviewPanelValueContextReturnType['entries'] as keyof Entry]: Entry & {
'add-comment': ReviewPanelBulkActionsEntry
'bulk-actions': ReviewPanelBulkActionsEntry
}
}
}
>
const hasTrackChangesFeature = getMeta('ol-hasTrackChangesFeature')
const currentDocEntries =
openDocId && openDocId in entries ? entries[openDocId] : undefined
const handleAddNewCommentClick = (e: React.MouseEvent<HTMLButtonElement>) => {
addNewComment(e)
setTimeout(() => {
// Re-render the comment box in order to add autofocus every time
setIsAddingComment(false)
setIsAddingComment(true)
}, 0)
}
return ReactDOM.createPortal(
<>
<div className="rp-in-editor-widgets react-rp-in-editor-widgets">
<div className="rp-in-editor-widgets-inner">
{wantTrackChanges && <ToggleWidget />}
{nChanges > 1 && (
<>
<BulkActions.Button onClick={handleShowBulkAcceptDialog}>
<Icon type="check" /> {t('accept_all')} ({nChanges})
</BulkActions.Button>
<BulkActions.Button onClick={handleShowBulkRejectDialog}>
<Icon type="times" /> {t('reject_all')} ({nChanges})
</BulkActions.Button>
</>
)}
{hasTrackChangesFeature &&
permissions.comment &&
currentDocEntries?.['add-comment'] && (
<AddCommentButton onClick={handleAddNewCommentClick}>
<Icon type="comment" /> {t('add_comment')}
</AddCommentButton>
)}
</div>
</div>
<Modal
show={show}
setShow={setShow}
isAccept={isAccept}
nChanges={nChanges}
onConfirm={handleConfirmDialog}
/>
</>,
view.scrollDOM
)
}
export default EditorWidgets

View file

@ -0,0 +1,25 @@
import { Trans } from 'react-i18next'
import { useReviewPanelValueContext } from '../../../context/review-panel/review-panel-context'
import { useCodeMirrorStateContext } from '../../codemirror-editor'
import { EditorView } from '@codemirror/view'
import classnames from 'classnames'
function ToggleWidget() {
const { toggleReviewPanel } = useReviewPanelValueContext()
const state = useCodeMirrorStateContext()
const darkTheme = state.facet(EditorView.darkTheme)
return (
<button
className={classnames('rp-track-changes-indicator', {
'rp-track-changes-indicator-on-dark': darkTheme,
})}
onClick={toggleReviewPanel}
>
{/* eslint-disable-next-line react/jsx-key */}
<Trans i18nKey="track_changes_is_on" components={[<strong />]} />
</button>
)
}
export default ToggleWidget

View file

@ -4,8 +4,12 @@ import EntryContainer from './entry-container'
import EntryCallout from './entry-callout'
import EntryActions from './entry-actions'
import AutoExpandingTextArea from '../../../../../shared/components/auto-expanding-text-area'
import AddCommentButton from '../add-comment-button'
import Icon from '../../../../../shared/components/icon'
import { useReviewPanelValueContext } from '../../../context/review-panel/review-panel-context'
import {
useReviewPanelUpdaterFnsContext,
useReviewPanelValueContext,
} from '../../../context/review-panel/review-panel-context'
import classnames from 'classnames'
import { ReviewPanelAddCommentEntry } from '../../../../../../../types/review-panel/entry'
@ -15,24 +19,25 @@ type AddCommentEntryProps = {
function AddCommentEntry({ entry }: AddCommentEntryProps) {
const { t } = useTranslation()
const { submitNewComment, handleLayoutChange } = useReviewPanelValueContext()
const { isAddingComment, submitNewComment, handleLayoutChange } =
useReviewPanelValueContext()
const { setIsAddingComment } = useReviewPanelUpdaterFnsContext()
const [content, setContent] = useState('')
const [isAdding, setIsAdding] = useState(false)
const handleStartNewComment = () => {
setIsAdding(true)
setIsAddingComment(true)
handleLayoutChange()
}
const handleSubmitNewComment = () => {
submitNewComment(content)
setIsAdding(false)
setIsAddingComment(false)
setContent('')
}
const handleCancelNewComment = () => {
setIsAdding(false)
setIsAddingComment(false)
setContent('')
handleLayoutChange()
}
@ -61,14 +66,14 @@ function AddCommentEntry({ entry }: AddCommentEntryProps) {
<EntryCallout className="rp-entry-callout-add-comment" />
<div
className={classnames('rp-entry', 'rp-entry-add-comment', {
'rp-entry-adding-comment': isAdding,
'rp-entry-adding-comment': isAddingComment,
})}
style={{
top: entry.screenPos.y + 'px',
visibility: entry.visible ? 'visible' : 'hidden',
}}
>
{isAdding ? (
{isAddingComment ? (
<>
<div className="rp-new-comment">
<AutoExpandingTextArea
@ -97,12 +102,9 @@ function AddCommentEntry({ entry }: AddCommentEntryProps) {
</EntryActions>
</>
) : (
<button
className="rp-add-comment-btn"
onClick={handleStartNewComment}
>
<AddCommentButton onClick={handleStartNewComment}>
<Icon type="comment" /> {t('add_comment')}
</button>
</AddCommentButton>
)}
</div>
</EntryContainer>

View file

@ -1,4 +1,5 @@
import ReactDOM from 'react-dom'
import EditorWidgets from './editor-widgets/editor-widgets'
import CurrentFileContainer from './current-file-container'
import OverviewContainer from './overview-container'
import { useCodeMirrorViewContext } from '../codemirror-editor'
@ -17,6 +18,7 @@ function ReviewPanelView({ parentDomNode }: ReviewPanelViewProps) {
return ReactDOM.createPortal(
<>
<EditorWidgets />
{isCurrentFileView(subView) ? (
<CurrentFileContainer />
) : (

View file

@ -127,6 +127,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
)
const [entryHover, setEntryHover] = useState(false)
const [isAddingComment, setIsAddingComment] = useState(false)
const values = useMemo<ReviewPanelState['values']>(
() => ({
@ -136,6 +137,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
docs,
entries,
entryHover,
isAddingComment,
gotoEntry,
handleLayoutChange,
loadingThreads,
@ -176,6 +178,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
docs,
entries,
entryHover,
isAddingComment,
gotoEntry,
handleLayoutChange,
loadingThreads,
@ -217,8 +220,15 @@ function useAngularReviewPanelState(): ReviewPanelState {
setEntryHover,
setCollapsed,
setShouldCollapse,
setIsAddingComment,
}),
[handleSetSubview, setCollapsed, setEntryHover, setShouldCollapse]
[
handleSetSubview,
setCollapsed,
setEntryHover,
setShouldCollapse,
setIsAddingComment,
]
)
return { values, updaterFns }

View file

@ -13,6 +13,7 @@ import {
MainDocument,
} from '../../../../../../../types/project-settings'
/* eslint-disable no-use-before-define */
export interface ReviewPanelState {
values: {
collapsed: Record<DocId, boolean>
@ -21,6 +22,7 @@ export interface ReviewPanelState {
docs: MainDocument[] | undefined
entries: ReviewPanelEntries
entryHover: boolean
isAddingComment: boolean
gotoEntry: (docId: DocId, entryOffset: number) => void
handleLayoutChange: () => void
loadingThreads: boolean
@ -66,15 +68,17 @@ export interface ReviewPanelState {
}
updaterFns: {
handleSetSubview: (subView: SubView) => void
setEntryHover: React.Dispatch<React.SetStateAction<boolean>>
setCollapsed: React.Dispatch<
React.SetStateAction<ReviewPanelState['values']['collapsed']>
setEntryHover: React.Dispatch<React.SetStateAction<Value<'entryHover'>>>
setIsAddingComment: React.Dispatch<
React.SetStateAction<Value<'isAddingComment'>>
>
setCollapsed: React.Dispatch<React.SetStateAction<Value<'collapsed'>>>
setShouldCollapse: React.Dispatch<
React.SetStateAction<ReviewPanelState['values']['shouldCollapse']>
React.SetStateAction<Value<'shouldCollapse'>>
>
}
}
/* eslint-enable no-use-before-define */
// Getter for values
export type Value<T extends keyof ReviewPanelState['values']> =

View file

@ -1304,3 +1304,20 @@ button when (@is-overleaf-light = true) {
}
}
}
.react-rp-in-editor-widgets {
position: sticky;
font-family: @font-family-sans-serif;
.rp-in-editor-widgets-inner {
position: absolute;
top: 0;
right: 0;
display: flex;
flex-direction: column;
}
.rp-track-changes-indicator {
border: 0;
}
}

View file

@ -250,4 +250,18 @@ describe('<ReviewPanel />', function () {
// eslint-disable-next-line mocha/no-skipped-tests
it.skip('renders comments', function () {})
})
describe('in editor widgets', function () {
// eslint-disable-next-line mocha/no-skipped-tests
it.skip('toggle review panel', function () {})
// eslint-disable-next-line mocha/no-skipped-tests
it.skip('accepts all changes', function () {})
// eslint-disable-next-line mocha/no-skipped-tests
it.skip('rejects all changes', function () {})
// eslint-disable-next-line mocha/no-skipped-tests
it.skip('add comment', function () {})
})
})