mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-04 23:27:13 +00:00
Merge pull request #3977 from overleaf/as-file-tree-application-context
Pull user id from ApplicationContext instead of window in file tree GitOrigin-RevId: e6c037b4a46ecdca066bcb5c67f6eeb8834f11fd
This commit is contained in:
parent
0026e9d246
commit
7d3b989d74
8 changed files with 88 additions and 47 deletions
|
@ -3,6 +3,7 @@ import { react2angular } from 'react2angular'
|
|||
import { cloneDeep } from 'lodash'
|
||||
|
||||
import FileTreeRoot from '../components/file-tree-root'
|
||||
import { rootContext } from '../../../shared/context/root-context'
|
||||
|
||||
App.controller('ReactFileTreeController', function (
|
||||
$scope,
|
||||
|
@ -115,4 +116,10 @@ App.controller('ReactFileTreeController', function (
|
|||
}
|
||||
})
|
||||
|
||||
App.component('fileTreeRoot', react2angular(FileTreeRoot))
|
||||
App.component(
|
||||
'fileTreeRoot',
|
||||
react2angular(
|
||||
rootContext.use(FileTreeRoot),
|
||||
Object.keys(FileTreeRoot.propTypes)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import { useCallback, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { useApplicationContext } from '../../../shared/context/application-context'
|
||||
import { useFileTreeMutable } from '../contexts/file-tree-mutable'
|
||||
import { useFileTreeSelectable } from '../contexts/file-tree-selectable'
|
||||
import { findInTreeOrThrow } from '../util/find-in-tree'
|
||||
|
||||
export function useFileTreeSocketListener() {
|
||||
const { user } = useApplicationContext({
|
||||
user: PropTypes.shape({ id: PropTypes.string.isRequired }),
|
||||
})
|
||||
const {
|
||||
dispatchRename,
|
||||
dispatchDelete,
|
||||
|
@ -25,14 +30,17 @@ export function useFileTreeSocketListener() {
|
|||
const selectEntityIfCreatedByUser = useCallback(
|
||||
// hack to automatically re-open refreshed linked files
|
||||
(entityId, entityName, userId) => {
|
||||
if (window.user && window.user.id && window.user.id === userId) {
|
||||
// If the created entity's user exists and is the current user
|
||||
if (userId && user?.id === userId) {
|
||||
// And we're expecting a refreshed socket for this entity
|
||||
if (window.expectingLinkedFileRefreshedSocketFor === entityName) {
|
||||
// Then select it
|
||||
select(entityId)
|
||||
window.expectingLinkedFileRefreshedSocketFor = null
|
||||
}
|
||||
}
|
||||
},
|
||||
[select]
|
||||
[user, select]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import MockedSocket from 'socket.io-mock'
|
||||
|
||||
import { ContextRoot } from '../js/shared/context/root-context'
|
||||
import { rootFolderBase } from './fixtures/file-tree-base'
|
||||
import { rootFolderLimit } from './fixtures/file-tree-limit'
|
||||
import FileTreeRoot from '../js/features/file-tree/components/file-tree-root'
|
||||
|
@ -149,7 +150,9 @@ export default {
|
|||
<style>{'html, body, .file-tree { height: 100%; width: 100%; }'}</style>
|
||||
<div className="editor-sidebar full-size">
|
||||
<div className="file-tree">
|
||||
<Story />
|
||||
<ContextRoot ide={window._ide} settings={{}}>
|
||||
<Story />
|
||||
</ContextRoot>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import { expect } from 'chai'
|
||||
import React from 'react'
|
||||
import sinon from 'sinon'
|
||||
import { screen, render, fireEvent, waitFor } from '@testing-library/react'
|
||||
import { screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
|
||||
import {
|
||||
renderWithEditorContext,
|
||||
cleanUpContext,
|
||||
} from '../../../helpers/render-with-context'
|
||||
import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
|
||||
|
||||
describe('<FileTreeRoot/>', function () {
|
||||
|
@ -19,6 +23,7 @@ describe('<FileTreeRoot/>', function () {
|
|||
fetchMock.restore()
|
||||
onSelect.reset()
|
||||
onInit.reset()
|
||||
cleanUpContext()
|
||||
global.localStorage.clear()
|
||||
})
|
||||
|
||||
|
@ -31,7 +36,7 @@ describe('<FileTreeRoot/>', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
const { container } = render(
|
||||
const { container } = renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -67,7 +72,7 @@ describe('<FileTreeRoot/>', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -106,7 +111,7 @@ describe('<FileTreeRoot/>', function () {
|
|||
},
|
||||
]
|
||||
|
||||
const { container } = render(
|
||||
const { container } = renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -138,7 +143,7 @@ describe('<FileTreeRoot/>', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -191,7 +196,7 @@ describe('<FileTreeRoot/>', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
import { expect } from 'chai'
|
||||
import React from 'react'
|
||||
import sinon from 'sinon'
|
||||
import { screen, render, fireEvent } from '@testing-library/react'
|
||||
import { screen, fireEvent } from '@testing-library/react'
|
||||
|
||||
import {
|
||||
renderWithEditorContext,
|
||||
cleanUpContext,
|
||||
} from '../../../helpers/render-with-context'
|
||||
import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
|
||||
|
||||
describe('FileTree Context Menu Flow', function () {
|
||||
const onSelect = sinon.stub()
|
||||
const onInit = sinon.stub()
|
||||
|
||||
afterEach(function () {
|
||||
onSelect.reset()
|
||||
onInit.reset()
|
||||
cleanUpContext()
|
||||
})
|
||||
|
||||
it('opens on contextMenu event', async function () {
|
||||
const rootFolder = [
|
||||
{
|
||||
|
@ -18,7 +28,7 @@ describe('FileTree Context Menu Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -52,7 +62,7 @@ describe('FileTree Context Menu Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import { expect } from 'chai'
|
||||
import React from 'react'
|
||||
import sinon from 'sinon'
|
||||
import { screen, render, fireEvent, waitFor } from '@testing-library/react'
|
||||
import { screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
import MockedSocket from 'socket.io-mock'
|
||||
|
||||
import {
|
||||
renderWithEditorContext,
|
||||
cleanUpContext,
|
||||
} from '../../../helpers/render-with-context'
|
||||
import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
|
||||
|
||||
describe('FileTree Create Folder Flow', function () {
|
||||
|
@ -13,9 +17,6 @@ describe('FileTree Create Folder Flow', function () {
|
|||
|
||||
beforeEach(function () {
|
||||
global.requestAnimationFrame = sinon.stub()
|
||||
window._ide = {
|
||||
socket: new MockedSocket(),
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
|
@ -23,7 +24,7 @@ describe('FileTree Create Folder Flow', function () {
|
|||
fetchMock.restore()
|
||||
onSelect.reset()
|
||||
onInit.reset()
|
||||
delete window._ide
|
||||
cleanUpContext()
|
||||
})
|
||||
|
||||
it('add to root when no files are selected', async function () {
|
||||
|
@ -35,7 +36,7 @@ describe('FileTree Create Folder Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -48,7 +49,8 @@ describe('FileTree Create Folder Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
|
||||
const newFolderName = 'Foo Bar In Root'
|
||||
|
@ -95,7 +97,7 @@ describe('FileTree Create Folder Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -109,7 +111,8 @@ describe('FileTree Create Folder Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
|
||||
const expandButton = screen.getByRole('button', { name: 'Expand' })
|
||||
|
@ -165,7 +168,7 @@ describe('FileTree Create Folder Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -179,7 +182,8 @@ describe('FileTree Create Folder Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
|
||||
const newFolderName = 'Foo Bar In thefolder'
|
||||
|
@ -224,7 +228,7 @@ describe('FileTree Create Folder Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -238,7 +242,8 @@ describe('FileTree Create Folder Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
|
||||
var newFolderName = 'existingFile'
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
import { expect } from 'chai'
|
||||
import React from 'react'
|
||||
import sinon from 'sinon'
|
||||
import { screen, render, fireEvent, waitFor } from '@testing-library/react'
|
||||
import { screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
import MockedSocket from 'socket.io-mock'
|
||||
|
||||
import {
|
||||
renderWithEditorContext,
|
||||
cleanUpContext,
|
||||
} from '../../../helpers/render-with-context'
|
||||
import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
|
||||
|
||||
describe('FileTree Delete Entity Flow', function () {
|
||||
const onSelect = sinon.stub()
|
||||
const onInit = sinon.stub()
|
||||
|
||||
beforeEach(function () {
|
||||
window._ide = {
|
||||
socket: new MockedSocket(),
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
fetchMock.restore()
|
||||
onSelect.reset()
|
||||
onInit.reset()
|
||||
delete window._ide
|
||||
cleanUpContext()
|
||||
})
|
||||
|
||||
describe('single entity', function () {
|
||||
|
@ -34,7 +32,7 @@ describe('FileTree Delete Entity Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -47,7 +45,8 @@ describe('FileTree Delete Entity Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
|
||||
const treeitem = screen.getByRole('treeitem', { name: 'main.tex' })
|
||||
|
@ -151,7 +150,7 @@ describe('FileTree Delete Entity Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -164,7 +163,8 @@ describe('FileTree Delete Entity Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
|
||||
const expandButton = screen.queryByRole('button', { name: 'Expand' })
|
||||
|
@ -208,7 +208,7 @@ describe('FileTree Delete Entity Flow', function () {
|
|||
},
|
||||
]
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -221,7 +221,8 @@ describe('FileTree Delete Entity Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
|
||||
// select two files
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import { expect } from 'chai'
|
||||
import React from 'react'
|
||||
import sinon from 'sinon'
|
||||
import { screen, render, fireEvent } from '@testing-library/react'
|
||||
import { screen, fireEvent } from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
import MockedSocket from 'socket.io-mock'
|
||||
|
||||
import {
|
||||
renderWithEditorContext,
|
||||
cleanUpContext,
|
||||
} from '../../../helpers/render-with-context'
|
||||
import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
|
||||
|
||||
describe('FileTree Rename Entity Flow', function () {
|
||||
|
@ -12,9 +16,6 @@ describe('FileTree Rename Entity Flow', function () {
|
|||
const onInit = sinon.stub()
|
||||
|
||||
beforeEach(function () {
|
||||
window._ide = {
|
||||
socket: new MockedSocket(),
|
||||
}
|
||||
global.requestAnimationFrame = sinon.stub()
|
||||
})
|
||||
|
||||
|
@ -23,7 +24,7 @@ describe('FileTree Rename Entity Flow', function () {
|
|||
fetchMock.restore()
|
||||
onSelect.reset()
|
||||
onInit.reset()
|
||||
delete window._ide
|
||||
cleanUpContext()
|
||||
})
|
||||
|
||||
beforeEach(function () {
|
||||
|
@ -46,7 +47,7 @@ describe('FileTree Rename Entity Flow', function () {
|
|||
fileRefs: [],
|
||||
},
|
||||
]
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -59,7 +60,8 @@ describe('FileTree Rename Entity Flow', function () {
|
|||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
/>,
|
||||
{ socket: new MockedSocket() }
|
||||
)
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue