From 13a7e752d5264d63bb73c73c94eb05c7446c09b7 Mon Sep 17 00:00:00 2001
From: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com>
Date: Mon, 10 Jul 2023 15:12:22 +0300
Subject: [PATCH] Merge pull request #13710 from
overleaf/ii-review-panel-migration-bulk-actions-entry
[web] Create bulk actions entry and bulk actions modal
GitOrigin-RevId: c88ce6213304a110ee7410529813310b863178c1
---
.../web/frontend/extracted-translations.json | 4 +
.../review-panel/current-file-container.tsx | 11 ++-
.../entries/bulk-actions-entry.tsx | 7 --
.../bulk-actions-entry/bulk-actions-entry.tsx | 66 ++++++++++++++
.../bulk-actions-entry/bulk-actions.tsx | 24 +++++
.../entries/bulk-actions-entry/modal.tsx | 87 +++++++++++++++++++
.../hooks/use-angular-review-panel-state.ts | 13 +++
.../review-panel/types/review-panel-state.ts | 3 +
.../controllers/ReviewPanelController.js | 8 +-
.../review-panel/review-panel.spec.tsx | 11 +++
services/web/types/review-panel/entry.ts | 3 +-
11 files changed, 223 insertions(+), 14 deletions(-)
delete mode 100644 services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry.tsx
create mode 100644 services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions-entry.tsx
create mode 100644 services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions.tsx
create mode 100644 services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/modal.tsx
diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index 8410af827e..88ca9f218f 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -14,6 +14,7 @@
"about_to_leave_projects": "",
"about_to_trash_projects": "",
"accept": "",
+ "accept_all": "",
"accept_invitation": "",
"accepted_invite": "",
"access_denied": "",
@@ -87,6 +88,8 @@
"blank_project": "",
"blocked_filename": "",
"browser": "",
+ "bulk_accept_confirm": "",
+ "bulk_reject_confirm": "",
"by_subscribing_you_agree_to_our_terms_of_service": "",
"can_edit": "",
"can_link_institution_email_acct_to_institution_acct": "",
@@ -809,6 +812,7 @@
"refreshing": "",
"regards": "",
"reject": "",
+ "reject_all": "",
"relink_your_account": "",
"remote_service_error": "",
"remove": "",
diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx
index da4fbd0aee..d7373fdd02 100644
--- a/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx
+++ b/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx
@@ -7,7 +7,7 @@ import ChangeEntry from './entries/change-entry'
import AggregateChangeEntry from './entries/aggregate-change-entry'
import CommentEntry from './entries/comment-entry'
import AddCommentEntry from './entries/add-comment-entry'
-import BulkActionsEntry from './entries/bulk-actions-entry'
+import BulkActionsEntry from './entries/bulk-actions-entry/bulk-actions-entry'
import {
useReviewPanelUpdaterFnsContext,
useReviewPanelValueContext,
@@ -24,6 +24,7 @@ function CurrentFileContainer() {
permissions,
loadingThreads,
users,
+ nVisibleSelectedChanges: nChanges,
toggleReviewPanel,
} = useReviewPanelValueContext()
const { setEntryHover } = useReviewPanelUpdaterFnsContext()
@@ -114,7 +115,13 @@ function CurrentFileContainer() {
}
if (entry.type === 'bulk-actions') {
- return
+ return (
+
+ )
}
return null
diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry.tsx
deleted file mode 100644
index bb9fc52b90..0000000000
--- a/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import EntryContainer from './entry-container'
-
-function BulkActionsEntry() {
- return Bulk actions entry
-}
-
-export default BulkActionsEntry
diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions-entry.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions-entry.tsx
new file mode 100644
index 0000000000..71261bba8b
--- /dev/null
+++ b/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions-entry.tsx
@@ -0,0 +1,66 @@
+import { useTranslation } from 'react-i18next'
+import EntryContainer from '../entry-container'
+import EntryCallout from '../entry-callout'
+import Icon from '../../../../../../shared/components/icon'
+import BulkActions from './bulk-actions'
+import Modal, { useBulkActionsModal } from './modal'
+import { ReviewPanelBulkActionsEntry } from '../../../../../../../../types/review-panel/entry'
+
+type BulkActionsEntryProps = {
+ entry: ReviewPanelBulkActionsEntry
+ nChanges: number
+}
+
+function BulkActionsEntry({ entry, nChanges }: BulkActionsEntryProps) {
+ const { t } = useTranslation()
+ const {
+ show,
+ setShow,
+ isAccept,
+ handleShowBulkAcceptDialog,
+ handleShowBulkRejectDialog,
+ handleConfirmDialog,
+ } = useBulkActionsModal()
+
+ return (
+ <>
+
+ {nChanges > 1 && (
+ <>
+
+
+
+ {t('reject_all')} ({nChanges})
+
+
+ {t('accept_all')} ({nChanges})
+
+
+ >
+ )}
+
+
+ >
+ )
+}
+
+export default BulkActionsEntry
diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions.tsx
new file mode 100644
index 0000000000..f8201e479e
--- /dev/null
+++ b/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/bulk-actions.tsx
@@ -0,0 +1,24 @@
+import classnames from 'classnames'
+
+function BulkActions({
+ className,
+ ...rest
+}: React.ComponentPropsWithoutRef<'div'>) {
+ return (
+
+ )
+}
+
+BulkActions.Button = function BulkActionsButton({
+ className,
+ ...rest
+}: React.ComponentPropsWithoutRef<'button'>) {
+ return (
+
+ )
+}
+
+export default BulkActions
diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/modal.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/modal.tsx
new file mode 100644
index 0000000000..325259a38b
--- /dev/null
+++ b/services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry/modal.tsx
@@ -0,0 +1,87 @@
+import { useState, useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { Button, Modal as BootstrapModal } from 'react-bootstrap'
+import AccessibleModal from '../../../../../../shared/components/accessible-modal'
+import { useReviewPanelValueContext } from '../../../../context/review-panel/review-panel-context'
+
+type BulkActionsModalProps = {
+ show: boolean
+ setShow: React.Dispatch>
+ isAccept: boolean
+ nChanges: number
+ onConfirm: () => void
+}
+
+function Modal({
+ show,
+ setShow,
+ isAccept,
+ nChanges,
+ onConfirm,
+}: BulkActionsModalProps) {
+ const { t } = useTranslation()
+
+ return (
+ setShow(false)}>
+
+ {isAccept ? t('accept_all') : t('reject_all')}
+
+
+
+ {isAccept
+ ? t('bulk_accept_confirm', { nChanges })
+ : t('bulk_reject_confirm', { nChanges })}
+
+
+
+
+
+
+
+ )
+}
+
+export function useBulkActionsModal() {
+ const [show, setShow] = useState(false)
+ const [isAccept, setIsAccept] = useState(false)
+ const { bulkAcceptActions, bulkRejectActions } = useReviewPanelValueContext()
+
+ const handleShowBulkAcceptDialog = useCallback(() => {
+ setIsAccept(true)
+ setShow(true)
+ }, [])
+
+ const handleShowBulkRejectDialog = useCallback(() => {
+ setIsAccept(false)
+ setShow(true)
+ }, [])
+
+ const handleConfirmDialog = useCallback(() => {
+ if (isAccept) {
+ bulkAcceptActions()
+ } else {
+ bulkRejectActions()
+ }
+
+ setShow(false)
+ }, [bulkAcceptActions, bulkRejectActions, isAccept])
+
+ return {
+ show,
+ setShow,
+ isAccept,
+ handleShowBulkAcceptDialog,
+ handleShowBulkRejectDialog,
+ handleConfirmDialog,
+ }
+}
+
+export default Modal
diff --git a/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts b/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts
index 849c99d6af..a7414f9b61 100644
--- a/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts
+++ b/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts
@@ -16,6 +16,9 @@ function useAngularReviewPanelState(): ReviewPanelState {
const [loading] = useScopeValue>(
'reviewPanel.overview.loading'
)
+ const [nVisibleSelectedChanges] = useScopeValue<
+ ReviewPanel.Value<'nVisibleSelectedChanges'>
+ >('reviewPanel.nVisibleSelectedChanges')
const [collapsed, setCollapsed] = useScopeValue<
ReviewPanel.Value<'collapsed'>
>('reviewPanel.overview.docsCollapsedState')
@@ -97,6 +100,10 @@ function useAngularReviewPanelState(): ReviewPanelState {
useScopeValue>('acceptChanges')
const [rejectChanges] =
useScopeValue>('rejectChanges')
+ const [bulkAcceptActions] =
+ useScopeValue>('bulkAcceptActions')
+ const [bulkRejectActions] =
+ useScopeValue>('bulkRejectActions')
const handleSetSubview = useCallback(
(subView: SubView) => {
@@ -132,6 +139,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
gotoEntry,
handleLayoutChange,
loadingThreads,
+ nVisibleSelectedChanges,
permissions,
users,
resolveComment,
@@ -152,6 +160,8 @@ function useAngularReviewPanelState(): ReviewPanelState {
trackChangesForGuestsAvailable,
formattedProjectMembers,
toggleReviewPanel,
+ bulkAcceptActions,
+ bulkRejectActions,
unresolveComment,
deleteThread,
refreshResolvedCommentsDropdown,
@@ -169,6 +179,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
gotoEntry,
handleLayoutChange,
loadingThreads,
+ nVisibleSelectedChanges,
permissions,
users,
resolveComment,
@@ -189,6 +200,8 @@ function useAngularReviewPanelState(): ReviewPanelState {
trackChangesForGuestsAvailable,
formattedProjectMembers,
toggleReviewPanel,
+ bulkAcceptActions,
+ bulkRejectActions,
unresolveComment,
deleteThread,
refreshResolvedCommentsDropdown,
diff --git a/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts b/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts
index 9c8bf61deb..4bd1698538 100644
--- a/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts
+++ b/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts
@@ -24,6 +24,7 @@ export interface ReviewPanelState {
gotoEntry: (docId: DocId, entryOffset: number) => void
handleLayoutChange: () => void
loadingThreads: boolean
+ nVisibleSelectedChanges: number
permissions: ReviewPanelPermissions
users: ReviewPanelUsers
resolveComment: (docId: DocId, entryId: ThreadId) => void
@@ -54,6 +55,8 @@ export interface ReviewPanelState {
}
>
toggleReviewPanel: () => void
+ bulkAcceptActions: () => void
+ bulkRejectActions: () => void
unresolveComment: (threadId: ThreadId) => void
deleteThread: (_entryId: unknown, docId: DocId, threadId: ThreadId) => void
refreshResolvedCommentsDropdown: () => Promise
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 3b6e402e93..b0ebbdbabe 100644
--- a/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js
+++ b/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js
@@ -688,7 +688,7 @@ export default App.controller(
dispatchReviewPanelEvent('changes:reject', change_ids)
}
- const bulkAccept = function () {
+ ide.$scope.bulkAcceptActions = function () {
_doAcceptChanges(ide.$scope.reviewPanel.selectedEntryIds.slice())
eventTracking.sendMB('rp-bulk-accept', {
view: $scope.ui.reviewPanelOpen
@@ -698,7 +698,7 @@ export default App.controller(
})
}
- const bulkReject = function () {
+ ide.$scope.bulkRejectActions = function () {
_doRejectChanges(ide.$scope.reviewPanel.selectedEntryIds.slice())
eventTracking.sendMB('rp-bulk-reject', {
view: $scope.ui.reviewPanelOpen
@@ -729,9 +729,9 @@ export default App.controller(
})
.result.then(function (isAccept) {
if (isAccept) {
- return bulkAccept()
+ return ide.$scope.bulkAcceptActions()
} else {
- return bulkReject()
+ return ide.$scope.bulkRejectActions()
}
})
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 257867acf6..273c25be18 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
@@ -232,6 +232,17 @@ describe('', function () {
it.skip('adds comment', function () {})
})
+ describe('bulk actions entry', function () {
+ // eslint-disable-next-line mocha/no-skipped-tests
+ it.skip('renders the reject and accept all buttons`', 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 () {})
+ })
+
describe('overview mode', function () {
// eslint-disable-next-line mocha/no-skipped-tests
it.skip('shows list of files changed', function () {})
diff --git a/services/web/types/review-panel/entry.ts b/services/web/types/review-panel/entry.ts
index faf78a308d..fb430d41a5 100644
--- a/services/web/types/review-panel/entry.ts
+++ b/services/web/types/review-panel/entry.ts
@@ -57,8 +57,9 @@ export interface ReviewPanelAddCommentEntry extends ReviewPanelBaseEntry {
type: 'add-comment'
}
-interface ReviewPanelBulkActionsEntry extends ReviewPanelBaseEntry {
+export interface ReviewPanelBulkActionsEntry extends ReviewPanelBaseEntry {
type: 'bulk-actions'
+ length: number
}
export type ReviewPanelEntry =