Ver código fonte

Merge pull request #13528 from overleaf/ii-review-panel-migration-current-file-view

[web] Create initial current file container

GitOrigin-RevId: 81635922bb10b97637af296d987f28d43cf61262
ilkin-overleaf 3 anos atrás
pai
commit
b61ee4c4d3
23 arquivos alterados com 266 adições e 128 exclusões
  1. 1 1
      services/web/frontend/js/features/project-list/util/sort-projects.ts
  2. 4 2
      services/web/frontend/js/features/source-editor/components/review-panel/container.tsx
  3. 47 36
      services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx
  4. 7 0
      services/web/frontend/js/features/source-editor/components/review-panel/entries/add-comment-entry.tsx
  5. 7 0
      services/web/frontend/js/features/source-editor/components/review-panel/entries/aggregate-change-entry.tsx
  6. 7 0
      services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry.tsx
  7. 7 0
      services/web/frontend/js/features/source-editor/components/review-panel/entries/change-entry.tsx
  8. 7 0
      services/web/frontend/js/features/source-editor/components/review-panel/entries/comment-entry.tsx
  9. 9 0
      services/web/frontend/js/features/source-editor/components/review-panel/entries/entry-container.tsx
  10. 0 0
      services/web/frontend/js/features/source-editor/components/review-panel/entries/resolved-comment-entry.tsx
  11. 36 27
      services/web/frontend/js/features/source-editor/components/review-panel/overview-container.tsx
  12. 9 4
      services/web/frontend/js/features/source-editor/components/review-panel/review-panel.tsx
  13. 1 1
      services/web/frontend/js/features/source-editor/components/review-panel/toolbar/resolved-comments-scroller.tsx
  14. 13 3
      services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts
  15. 7 3
      services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts
  16. 1 1
      services/web/frontend/js/features/source-editor/utils/sub-view.ts
  17. 36 42
      services/web/frontend/stylesheets/app/editor/review-panel.less
  18. 1 0
      services/web/test/frontend/features/source-editor/helpers/mock-scope.ts
  19. 0 0
      services/web/types/helpers/array/sort.ts
  20. 3 0
      services/web/types/helpers/brand.ts
  21. 0 8
      services/web/types/review-panel.ts
  22. 47 0
      services/web/types/review-panel/entry.ts
  23. 16 0
      services/web/types/review-panel/review-panel.ts

+ 1 - 1
services/web/frontend/js/features/project-list/util/sort-projects.ts

@@ -1,7 +1,7 @@
 import { Project, Sort } from '../../../../../types/project/dashboard/api'
 import { SortingOrder } from '../../../../../types/sorting-order'
 import { getOwnerName } from './project'
-import { Compare } from '../../../../../types/array/sort'
+import { Compare } from '../../../../../types/helpers/array/sort'
 
 const order = (order: SortingOrder, projects: Project[]) => {
   return order === 'asc' ? [...projects] : projects.reverse()

+ 4 - 2
services/web/frontend/js/features/source-editor/components/review-panel/container.tsx

@@ -18,10 +18,12 @@ function Container({ children, classNames, ...rest }: ContainerProps) {
       {...rest}
       data-testid="review-panel"
     >
+      <div className="review-panel-tools">
+        <Toolbar />
+        <Nav />
+      </div>
       <Toggler />
-      <Toolbar />
       {children}
-      <Nav />
     </div>
   )
 }

+ 47 - 36
services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx

@@ -1,50 +1,61 @@
-import Container from './container'
+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 { useReviewPanelValueContext } from '../../context/review-panel/review-panel-context'
 import useCodeMirrorContentHeight from '../../hooks/use-codemirror-content-height'
 
 function CurrentFileContainer() {
+  const { entries, openDocId, permissions } = useReviewPanelValueContext()
   const contentHeight = useCodeMirrorContentHeight()
 
   console.log('Review panel got content height', contentHeight)
 
+  const currentDocEntries =
+    openDocId && openDocId in entries ? entries[openDocId] : undefined
+
   return (
-    <Container>
+    <div
+      id="review-panel-current-file"
+      role="tabpanel"
+      tabIndex={0}
+      aria-labelledby="review-panel-tab-current-file"
+    >
       <div
-        id="review-panel-current-file"
-        role="tabpanel"
-        tabIndex={0}
-        aria-labelledby="review-panel-tab-current-file"
+        className="rp-entry-list-inner"
+        style={{ height: `${contentHeight}px` }}
       >
-        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
-        tempor incididunt ut labore et dolore magna aliqua. Et malesuada fames
-        ac turpis egestas integer eget aliquet nibh. Et leo duis ut diam quam
-        nulla porttitor massa id. Risus quis varius quam quisque id diam vel
-        quam elementum. Nibh venenatis cras sed felis. Sit amet commodo nulla
-        facilisi nullam vehicula ipsum a arcu. Dui ut ornare lectus sit amet est
-        placerat in. Aliquam ultrices sagittis orci a. Leo a diam sollicitudin
-        tempor id eu nisl nunc mi. Quis ipsum suspendisse ultrices gravida
-        dictum fusce. Ut etiam sit amet nisl purus in mollis nunc sed. Rhoncus
-        est pellentesque elit ullamcorper dignissim cras. Faucibus turpis in eu
-        mi bibendum. Proin libero nunc consequat interdum. Ac placerat
-        vestibulum lectus mauris ultrices eros in cursus turpis. Ac felis donec
-        et odio. Nullam ac tortor vitae purus faucibus. Consectetur lorem donec
-        massa sapien faucibus et molestie. Praesent elementum facilisis leo vel
-        fringilla est ullamcorper eget nulla. Adipiscing vitae proin sagittis
-        nisl rhoncus mattis rhoncus urna. Cursus metus aliquam eleifend mi in
-        nulla posuere sollicitudin aliquam. Eget nullam non nisi est sit amet
-        facilisis magna. Donec adipiscing tristique risus nec feugiat in
-        fermentum posuere. Gravida rutrum quisque non tellus orci ac auctor
-        augue. Euismod in pellentesque massa placerat duis ultricies lacus.
-        Pellentesque diam volutpat commodo sed egestas. Tempus iaculis urna id
-        volutpat lacus laoreet. Lorem ipsum dolor sit amet consectetur.
-        Tincidunt id aliquet risus feugiat in ante metus. Risus ultricies
-        tristique nulla aliquet enim tortor at auctor urna. Purus in mollis nunc
-        sed. In ante metus dictum at. Magna eget est lorem ipsum dolor sit.
-        Fusce id velit ut tortor pretium viverra. Augue neque gravida in
-        fermentum et sollicitudin ac. Et malesuada fames ac turpis. Felis
-        bibendum ut tristique et egestas quis ipsum suspendisse ultrices. Varius
-        vel pharetra vel turpis nunc eget.
+        {currentDocEntries &&
+          Object.entries(currentDocEntries).map(([id, entry]) => {
+            if (!entry.visible) {
+              return null
+            }
+
+            if (entry.type === 'insert' || entry.type === 'delete') {
+              return <ChangeEntry key={id} />
+            }
+
+            if (entry.type === 'aggregate-change') {
+              return <AggregateChangeEntry key={id} />
+            }
+
+            if (entry.type === 'comment') {
+              return <CommentEntry key={id} />
+            }
+
+            if (entry.type === 'add-comment' && permissions.comment) {
+              return <AddCommentEntry key={id} />
+            }
+
+            if (entry.type === 'bulk-actions') {
+              return <BulkActionsEntry key={id} />
+            }
+
+            return null
+          })}
       </div>
-    </Container>
+    </div>
   )
 }
 

+ 7 - 0
services/web/frontend/js/features/source-editor/components/review-panel/entries/add-comment-entry.tsx

@@ -0,0 +1,7 @@
+import EntryContainer from './entry-container'
+
+function AddCommentEntry() {
+  return <EntryContainer>Add comment entry</EntryContainer>
+}
+
+export default AddCommentEntry

+ 7 - 0
services/web/frontend/js/features/source-editor/components/review-panel/entries/aggregate-change-entry.tsx

@@ -0,0 +1,7 @@
+import EntryContainer from './entry-container'
+
+function AggregateChangeEntry() {
+  return <EntryContainer>Aggregate change entry</EntryContainer>
+}
+
+export default AggregateChangeEntry

+ 7 - 0
services/web/frontend/js/features/source-editor/components/review-panel/entries/bulk-actions-entry.tsx

@@ -0,0 +1,7 @@
+import EntryContainer from './entry-container'
+
+function BulkActionsEntry() {
+  return <EntryContainer>Bulk actions entry</EntryContainer>
+}
+
+export default BulkActionsEntry

+ 7 - 0
services/web/frontend/js/features/source-editor/components/review-panel/entries/change-entry.tsx

@@ -0,0 +1,7 @@
+import EntryContainer from './entry-container'
+
+function ChangeEntry() {
+  return <EntryContainer>Change entry</EntryContainer>
+}
+
+export default ChangeEntry

+ 7 - 0
services/web/frontend/js/features/source-editor/components/review-panel/entries/comment-entry.tsx

@@ -0,0 +1,7 @@
+import EntryContainer from './entry-container'
+
+function CommentEntry() {
+  return <EntryContainer>Comment entry</EntryContainer>
+}
+
+export default CommentEntry

+ 9 - 0
services/web/frontend/js/features/source-editor/components/review-panel/entries/entry-container.tsx

@@ -0,0 +1,9 @@
+type EntryContainerProps = {
+  children: React.ReactNode
+}
+
+function EntryContainer({ children }: EntryContainerProps) {
+  return <div className="rp-entry-wrapper">{children}</div>
+}
+
+export default EntryContainer

+ 0 - 0
services/web/frontend/js/features/source-editor/components/review-panel/toolbar/resolved-comment-entry.tsx → services/web/frontend/js/features/source-editor/components/review-panel/entries/resolved-comment-entry.tsx


+ 36 - 27
services/web/frontend/js/features/source-editor/components/review-panel/overview-container.tsx

@@ -1,32 +1,41 @@
-import Container from './container'
-
 function OverviewContainer() {
   return (
-    <Container>
-      <div
-        id="review-panel-overview"
-        role="tabpanel"
-        tabIndex={0}
-        aria-labelledby="review-panel-tab-overview"
-      >
-        Faucibus turpis in eu mi bibendum. Proin libero nunc consequat interdum.
-        Ac placerat vestibulum lectus mauris ultrices eros in cursus turpis. Ac
-        felis donec et odio. Nullam ac tortor vitae purus faucibus. Consectetur
-        lorem donec massa sapien faucibus et molestie. Praesent elementum
-        facilisis leo vel fringilla est ullamcorper eget nulla. Adipiscing vitae
-        proin sagittis nisl rhoncus mattis rhoncus urna. Cursus metus aliquam
-        eleifend mi in nulla posuere sollicitudin aliquam. Eget nullam non nisi
-        est sit amet facilisis magna. Donec adipiscing tristique risus nec
-        feugiat in fermentum posuere. Gravida rutrum quisque non tellus orci ac
-        auctor augue. Euismod in pellentesque massa placerat duis ultricies
-        lacus. Pellentesque diam volutpat commodo sed egestas. Tempus iaculis
-        urna id volutpat lacus laoreet. Lorem ipsum dolor sit amet consectetur.
-        Tincidunt id aliquet risus feugiat in ante metus. Risus ultricies
-        tristique nulla aliquet enim tortor at auctor urna. Purus in mollis nunc
-        sed. In ante metus dictum at. Magna eget est lorem ipsum dolor sit.
-        Fusce id velit ut tortor pretium viverra.
-      </div>
-    </Container>
+    <div
+      className="rp-entry-list"
+      id="review-panel-overview"
+      role="tabpanel"
+      tabIndex={0}
+      aria-labelledby="review-panel-tab-overview"
+    >
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+      tempor incididunt ut labore et dolore magna aliqua. Et malesuada fames ac
+      turpis egestas integer eget aliquet nibh. Et leo duis ut diam quam nulla
+      porttitor massa id. Risus quis varius quam quisque id diam vel quam
+      elementum. Nibh venenatis cras sed felis. Sit amet commodo nulla facilisi
+      nullam vehicula ipsum a arcu. Dui ut ornare lectus sit amet est placerat
+      in. Aliquam ultrices sagittis orci a. Leo a diam sollicitudin tempor id eu
+      nisl nunc mi. Quis ipsum suspendisse ultrices gravida dictum fusce. Ut
+      etiam sit amet nisl purus in mollis nunc sed. Rhoncus est pellentesque
+      elit ullamcorper dignissim cras. Faucibus turpis in eu mi bibendum. Proin
+      libero nunc consequat interdum. Ac placerat vestibulum lectus mauris
+      ultrices eros in cursus turpis. Ac felis donec et odio. Nullam ac tortor
+      vitae purus faucibus. Consectetur lorem donec massa sapien faucibus et
+      molestie. Praesent elementum facilisis leo vel fringilla est ullamcorper
+      eget nulla. Adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus
+      urna. Cursus metus aliquam eleifend mi in nulla posuere sollicitudin
+      aliquam. Eget nullam non nisi est sit amet facilisis magna. Donec
+      adipiscing tristique risus nec feugiat in fermentum posuere. Gravida
+      rutrum quisque non tellus orci ac auctor augue. Euismod in pellentesque
+      massa placerat duis ultricies lacus. Pellentesque diam volutpat commodo
+      sed egestas. Tempus iaculis urna id volutpat lacus laoreet. Lorem ipsum
+      dolor sit amet consectetur. Tincidunt id aliquet risus feugiat in ante
+      metus. Risus ultricies tristique nulla aliquet enim tortor at auctor urna.
+      Purus in mollis nunc sed. In ante metus dictum at. Magna eget est lorem
+      ipsum dolor sit. Fusce id velit ut tortor pretium viverra. Augue neque
+      gravida in fermentum et sollicitudin ac. Et malesuada fames ac turpis.
+      Felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices.
+      Varius vel pharetra vel turpis nunc eget.
+    </div>
   )
 }
 

+ 9 - 4
services/web/frontend/js/features/source-editor/components/review-panel/review-panel.tsx

@@ -1,11 +1,12 @@
 import ReactDOM from 'react-dom'
+import Container from './container'
+import CurrentFileContainer from './current-file-container'
+import OverviewContainer from './overview-container'
 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'
 import { isCurrentFileView } from '../../utils/sub-view'
 
 type ReviewPanelViewProps = {
@@ -18,9 +19,13 @@ function ReviewPanelView({ parentDomNode }: ReviewPanelViewProps) {
   return ReactDOM.createPortal(
     <>
       {isCurrentFileView(subView) ? (
-        <CurrentFileContainer />
+        <Container>
+          <CurrentFileContainer />
+        </Container>
       ) : (
-        <OverviewContainer />
+        <Container>
+          <OverviewContainer />
+        </Container>
       )}
     </>,
     parentDomNode

+ 1 - 1
services/web/frontend/js/features/source-editor/components/review-panel/toolbar/resolved-comments-scroller.tsx

@@ -1,6 +1,6 @@
 import { useTranslation } from 'react-i18next'
 import { useMemo } from 'react'
-import ResolvedCommentEntry from './resolved-comment-entry'
+import ResolvedCommentEntry from '../entries/resolved-comment-entry'
 import moment from 'moment'
 
 type ResolvedCommentsScrollerProps = {

+ 13 - 3
services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts

@@ -3,7 +3,7 @@ import useScopeValue from '../../../../../shared/hooks/use-scope-value'
 import { ReviewPanelState } from '../types/review-panel-state'
 import { sendMB } from '../../../../../infrastructure/event-tracking'
 import * as ReviewPanel from '../types/review-panel-state'
-import { SubView } from '../../../../../../../types/review-panel'
+import { SubView } from '../../../../../../../types/review-panel/review-panel'
 
 function useAngularReviewPanelState(): ReviewPanelState {
   const [subView, setSubView] = useScopeValue<ReviewPanel.Value<'subView'>>(
@@ -12,12 +12,18 @@ function useAngularReviewPanelState(): ReviewPanelState {
   const [collapsed, setCollapsed] = useScopeValue<
     ReviewPanel.Value<'collapsed'>
   >('reviewPanel.overview.docsCollapsedState')
+  const [entries] = useScopeValue<ReviewPanel.Value<'entries'>>(
+    'reviewPanel.entries'
+  )
+
   const [permissions] =
     useScopeValue<ReviewPanel.Value<'permissions'>>('permissions')
 
   const [wantTrackChanges] = useScopeValue<
     ReviewPanel.Value<'wantTrackChanges'>
   >('editor.wantTrackChanges')
+  const [openDocId] =
+    useScopeValue<ReviewPanel.Value<'openDocId'>>('editor.open_doc_id')
   const [shouldCollapse, setShouldCollapse] = useScopeValue<
     ReviewPanel.Value<'shouldCollapse'>
   >('reviewPanel.fullTCStateCollapsed')
@@ -63,10 +69,12 @@ function useAngularReviewPanelState(): ReviewPanelState {
   const values = useMemo<ReviewPanelState['values']>(
     () => ({
       collapsed,
+      entries,
       permissions,
-      subView,
       shouldCollapse,
+      subView,
       wantTrackChanges,
+      openDocId,
       toggleTrackChangesForEveryone,
       toggleTrackChangesForUser,
       toggleTrackChangesForGuests,
@@ -79,10 +87,12 @@ function useAngularReviewPanelState(): ReviewPanelState {
     }),
     [
       collapsed,
+      entries,
       permissions,
-      subView,
       shouldCollapse,
+      subView,
       wantTrackChanges,
+      openDocId,
       toggleTrackChangesForEveryone,
       toggleTrackChangesForUser,
       toggleTrackChangesForGuests,

+ 7 - 3
services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts

@@ -1,15 +1,19 @@
 import {
-  SubView,
+  DocId,
+  ReviewPanelEntries,
   ReviewPanelPermissions,
-} from '../../../../../../../types/review-panel'
+  SubView,
+} from '../../../../../../../types/review-panel/review-panel'
 
 export interface ReviewPanelState {
   values: {
     collapsed: Record<string, boolean>
-    subView: SubView
+    entries: ReviewPanelEntries
     permissions: ReviewPanelPermissions
     shouldCollapse: boolean
+    subView: SubView
     wantTrackChanges: boolean
+    openDocId: DocId | null
     toggleTrackChangesForEveryone: (isOn: boolean) => unknown
     toggleTrackChangesForUser: (isOn: boolean, memberId: string) => unknown
     toggleTrackChangesForGuests: (isOn: boolean) => unknown

+ 1 - 1
services/web/frontend/js/features/source-editor/utils/sub-view.ts

@@ -1,4 +1,4 @@
-import { SubView } from '../../../../../types/review-panel'
+import { SubView } from '../../../../../types/review-panel/review-panel'
 
 export const isCurrentFileView = (view: SubView) => view === 'cur_file'
 export const isOverviewView = (view: SubView) => view === 'overview'

+ 36 - 42
services/web/frontend/stylesheets/app/editor/review-panel.less

@@ -1185,8 +1185,19 @@ button when (@is-overleaf-light = true) {
 
 // CM6-specific review panel rules
 .ol-cm-review-panel {
+  position: relative;
+  z-index: 6;
   display: block;
   flex-shrink: 0;
+  flex-direction: column;
+
+  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;
+  box-sizing: content-box;
 
   .rp-size-expanded & {
     display: flex;
@@ -1202,18 +1213,6 @@ button when (@is-overleaf-light = true) {
     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-toggler {
     display: flex;
     flex-direction: column;
@@ -1227,15 +1226,15 @@ button when (@is-overleaf-light = true) {
     }
   }
 
+  .review-panel-toolbar-collapse-button {
+    border: none;
+    background: none;
+    padding: 0;
+  }
+
   .review-panel-toolbar {
     position: sticky;
     top: 0;
-
-    .review-panel-toolbar-collapse-button {
-      border: none;
-      background: none;
-      padding: 0;
-    }
   }
 
   .rp-nav {
@@ -1263,39 +1262,34 @@ button when (@is-overleaf-light = true) {
     flex-direction: column;
   }
 
-  .rp-nav-item {
-    border-right: 0;
-    border-bottom: 0;
-    border-left: 0;
-    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 {
-      .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: none;
+        display: inline;
       }
 
-      &.rp-overview-file-collapse {
-        .rp-overview-file-num-entries {
-          display: inline;
-        }
-
-        .rp-overview-file-entries {
-          // height: 0;
-        }
+      .rp-overview-file-entries {
+        // height: 0;
       }
     }
   }
 
+  .rp-nav-item {
+    border-right: 0;
+    border-bottom: 0;
+    border-left: 0;
+    background: none;
+  }
+
   .rp-tc-state {
     height: 0;
     transition: height 150ms;

+ 1 - 0
services/web/test/frontend/features/source-editor/helpers/mock-scope.ts

@@ -78,6 +78,7 @@ export const mockScope = (content?: string) => {
       subView: 'cur_file',
       formattedProjectMembers: {},
       fullTCStateCollapsed: true,
+      entries: {},
     },
     ui: {
       reviewPanelOpen: true,

+ 0 - 0
services/web/types/array/sort.ts → services/web/types/helpers/array/sort.ts


+ 3 - 0
services/web/types/helpers/brand.ts

@@ -0,0 +1,3 @@
+declare const brand: unique symbol
+
+export type Brand<T, TBrand> = T & { [brand]: TBrand }

+ 0 - 8
services/web/types/review-panel.ts

@@ -1,8 +0,0 @@
-export type SubView = 'cur_file' | 'overview'
-
-export interface ReviewPanelPermissions {
-  read: boolean
-  write: boolean
-  admin: boolean
-  comment: boolean
-}

+ 47 - 0
services/web/types/review-panel/entry.ts

@@ -0,0 +1,47 @@
+interface ReviewPanelEntryScreenPos {
+  y: number
+  height: number
+  editorPaddingTop: number
+}
+
+interface ReviewPanelBaseEntry {
+  visible: boolean
+}
+
+interface ReviewPanelCommentEntry extends ReviewPanelBaseEntry {
+  type: 'comment'
+  content: string
+  entry_ids: string[]
+  focused: boolean
+  offset: number
+  screenPos: ReviewPanelEntryScreenPos
+  thread_id: string
+}
+
+interface ReviewPanelInsertEntry extends ReviewPanelBaseEntry {
+  type: 'insert'
+}
+
+interface ReviewPanelDeleteEntry extends ReviewPanelBaseEntry {
+  type: 'delete'
+}
+
+interface ReviewPanelAggregateChangeEntry extends ReviewPanelBaseEntry {
+  type: 'aggregate-change'
+}
+
+interface ReviewPanelAddCommentEntry extends ReviewPanelBaseEntry {
+  type: 'add-comment'
+}
+
+interface ReviewPanelBulkActionsEntry extends ReviewPanelBaseEntry {
+  type: 'bulk-actions'
+}
+
+export type ReviewPanelEntry =
+  | ReviewPanelCommentEntry
+  | ReviewPanelInsertEntry
+  | ReviewPanelDeleteEntry
+  | ReviewPanelAggregateChangeEntry
+  | ReviewPanelAddCommentEntry
+  | ReviewPanelBulkActionsEntry

+ 16 - 0
services/web/types/review-panel/review-panel.ts

@@ -0,0 +1,16 @@
+import { Brand } from '../helpers/brand'
+import { ReviewPanelEntry } from './entry'
+
+export type SubView = 'cur_file' | 'overview'
+
+export interface ReviewPanelPermissions {
+  read: boolean
+  write: boolean
+  admin: boolean
+  comment: boolean
+}
+
+export type ReviewPanelDocEntries = Record<string, ReviewPanelEntry>
+
+export type DocId = Brand<string, 'DocId'>
+export type ReviewPanelEntries = Record<DocId, ReviewPanelDocEntries>