Просмотр исходного кода

Open selected file on project restore (#28145)

* Open selected file on project restore

* check if restorationState is "restoring" before opening a file

GitOrigin-RevId: c6f4cf69ecbe55b1d1949e4524fe7e39737c5487
Domagoj Kriskovic 1 год назад
Родитель
Сommit
c984134142

+ 6 - 2
services/web/app/src/Features/History/HistoryController.js

@@ -204,9 +204,13 @@ async function revertProject(req, res, next) {
   const { version } = req.body
   const userId = SessionManager.getLoggedInUserId(req.session)
 
-  await RestoreManager.promises.revertProject(userId, projectId, version)
+  const reverted = await RestoreManager.promises.revertProject(
+    userId,
+    projectId,
+    version
+  )
 
-  res.sendStatus(200)
+  res.json(reverted)
 }
 
 async function getLabels(req, res, next) {

+ 9 - 1
services/web/app/src/Features/History/RestoreManager.js

@@ -359,8 +359,9 @@ const RestoreManager = {
     }
     const threadIds = await getCommentThreadIds(projectId)
 
+    const reverted = []
     for (const pathname of pathsAtPastVersion) {
-      await RestoreManager._revertSingleFile(
+      const res = await RestoreManager._revertSingleFile(
         userId,
         projectId,
         version,
@@ -368,6 +369,11 @@ const RestoreManager = {
         threadIds,
         { origin }
       )
+      reverted.push({
+        id: res._id,
+        type: res.type,
+        path: pathname,
+      })
     }
 
     const entitiesAtLiveVersion =
@@ -391,6 +397,8 @@ const RestoreManager = {
         )
       }
     }
+
+    return reverted
   },
 
   async _writeFileVersionToDisk(projectId, version, pathname) {

+ 45 - 5
services/web/frontend/js/features/history/context/hooks/use-restore-project.ts

@@ -1,7 +1,12 @@
-import { useCallback, useState } from 'react'
+import { useCallback, useState, useEffect } from 'react'
 import { useErrorBoundary } from 'react-error-boundary'
 import { restoreProjectToVersion } from '../../services/api'
 import { useLayoutContext } from '@/shared/context/layout-context'
+import { useHistoryContext } from '../history-context'
+import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
+import { useFileTreeData } from '@/shared/context/file-tree-data-context'
+import { findInTree } from '@/features/file-tree/util/find-in-tree'
+import { RestoreProjectResponse } from '../../services/types/restore-file'
 
 type RestorationState = 'initial' | 'restoring' | 'restored' | 'error'
 
@@ -11,21 +16,56 @@ export const useRestoreProject = () => {
 
   const [restorationState, setRestorationState] =
     useState<RestorationState>('initial')
+  const { selection } = useHistoryContext()
+  const { openDocWithId, openFileWithId } = useEditorManagerContext()
+  const { fileTreeData } = useFileTreeData()
+  const [restoredEntities, setRestoredEntities] =
+    useState<RestoreProjectResponse | null>(null)
+
+  useEffect(() => {
+    if (restorationState === 'restoring' && restoredEntities) {
+      const entity =
+        restoredEntities.find(
+          item => item.path === selection.selectedFile?.pathname
+        ) || restoredEntities[0]
+
+      if (entity) {
+        const result = findInTree(fileTreeData, entity.id)
+        if (result) {
+          if (entity.type === 'doc') {
+            openDocWithId(entity.id)
+          } else if (entity.type === 'file') {
+            openFileWithId(entity.id)
+          }
+        }
+      }
+
+      setRestorationState('restored')
+      restoreView()
+    }
+  }, [
+    fileTreeData,
+    restoredEntities,
+    openDocWithId,
+    openFileWithId,
+    restoreView,
+    restorationState,
+    selection.selectedFile?.pathname,
+  ])
 
   const restoreProject = useCallback(
     (projectId: string, version: number) => {
       setRestorationState('restoring')
       restoreProjectToVersion(projectId, version)
-        .then(() => {
-          setRestorationState('restored')
-          restoreView()
+        .then((res: RestoreProjectResponse) => {
+          setRestoredEntities(res)
         })
         .catch(err => {
           setRestorationState('error')
           showBoundary(err)
         })
     },
-    [showBoundary, restoreView]
+    [showBoundary]
   )
 
   return {

+ 6 - 0
services/web/frontend/js/features/history/services/types/restore-file.ts

@@ -2,3 +2,9 @@ export type RestoreFileResponse = {
   id: string
   type: 'doc' | 'file'
 }
+
+export type RestoreProjectResponse = Array<{
+  id: string
+  path: string
+  type: 'doc' | 'file'
+}>

+ 4 - 1
services/web/test/unit/src/History/RestoreManagerTests.js

@@ -993,7 +993,10 @@ describe('RestoreManager', function () {
       this.ProjectGetter.promises.getProject
         .withArgs(this.project_id)
         .resolves({ overleaf: { history: { rangesSupportEnabled: true } } })
-      this.RestoreManager.promises._revertSingleFile = sinon.stub().resolves()
+      this.RestoreManager.promises._revertSingleFile = sinon.stub().resolves({
+        _id: 'mock-doc-id',
+        type: 'doc',
+      })
       this.RestoreManager.promises._getProjectPathsAtVersion = sinon
         .stub()
         .resolves([])