mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #3550 from overleaf/ta-disconected-overlay
Add Disconnected Overlay Over File Tree GitOrigin-RevId: bdcd4f58effe841eb223abbb852e0b0f574efefd
This commit is contained in:
parent
e1ffeef06a
commit
dc48ba1d61
10 changed files with 83 additions and 4 deletions
|
@ -18,6 +18,7 @@ aside.editor-sidebar.full-size(
|
|||
has-write-permissions="hasWritePermissions"
|
||||
on-select="onSelect"
|
||||
on-init="onInit"
|
||||
is-connected="isConnected"
|
||||
)
|
||||
|
||||
div(ng-controller="FileTreeController")
|
||||
|
|
|
@ -24,7 +24,8 @@ function FileTreeRoot({
|
|||
rootDocId,
|
||||
hasWritePermissions,
|
||||
onSelect,
|
||||
onInit
|
||||
onInit,
|
||||
isConnected
|
||||
}) {
|
||||
const isReady = projectId && rootFolder
|
||||
|
||||
|
@ -41,6 +42,7 @@ function FileTreeRoot({
|
|||
rootDocId={rootDocId}
|
||||
onSelect={onSelect}
|
||||
>
|
||||
{isConnected ? null : <div className="disconnected-overlay" />}
|
||||
<FileTreeToolbar />
|
||||
<FileTreeContextMenu />
|
||||
<div className="file-tree-inner">
|
||||
|
@ -83,7 +85,8 @@ FileTreeRoot.propTypes = {
|
|||
rootDocId: PropTypes.string,
|
||||
hasWritePermissions: PropTypes.bool.isRequired,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
onInit: PropTypes.func.isRequired
|
||||
onInit: PropTypes.func.isRequired,
|
||||
isConnected: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
export default withErrorBoundary(FileTreeRoot, FileTreeError)
|
||||
|
|
|
@ -13,6 +13,7 @@ App.controller('ReactFileTreeController', function(
|
|||
$scope.rootFolder = null
|
||||
$scope.rootDocId = null
|
||||
$scope.hasWritePermissions = false
|
||||
$scope.isConnected = true
|
||||
|
||||
$scope.$on('project:joined', () => {
|
||||
$scope.rootFolder = $scope.project.rootFolder
|
||||
|
@ -30,6 +31,23 @@ App.controller('ReactFileTreeController', function(
|
|||
)
|
||||
})
|
||||
|
||||
// Set isConnected to true if:
|
||||
// - connection state is 'ready', OR
|
||||
// - connection state is 'waitingCountdown' and reconnection_countdown is null
|
||||
// The added complexity is needed because in Firefox on page reload the
|
||||
// connection state goes into 'waitingCountdown' before being hidden and we
|
||||
// don't want to show a disconnect UI.
|
||||
function updateIsConnected() {
|
||||
const isReady = $scope.connection.state === 'ready'
|
||||
const willStartCountdown =
|
||||
$scope.connection.state === 'waitingCountdown' &&
|
||||
$scope.connection.reconnection_countdown === null
|
||||
$scope.isConnected = isReady || willStartCountdown
|
||||
}
|
||||
|
||||
$scope.$watch('connection.state', updateIsConnected)
|
||||
$scope.$watch('connection.reconnection_countdown', updateIsConnected)
|
||||
|
||||
$scope.onInit = () => {
|
||||
// HACK: resize the vertical pane on init after a 0ms timeout. We do not
|
||||
// understand why this is necessary but without this the resized handle is
|
||||
|
|
|
@ -86,6 +86,9 @@ FullTree.parameters = { setupMocks: defaultSetupMocks }
|
|||
export const ReadOnly = args => <FileTreeRoot {...args} />
|
||||
ReadOnly.args = { hasWritePermissions: false }
|
||||
|
||||
export const Disconnected = args => <FileTreeRoot {...args} />
|
||||
Disconnected.args = { isConnected: false }
|
||||
|
||||
export const NetworkErrors = args => <FileTreeRoot {...args} />
|
||||
NetworkErrors.parameters = {
|
||||
setupMocks: () => {
|
||||
|
@ -116,7 +119,8 @@ export default {
|
|||
rootFolder: rootFolderBase,
|
||||
hasWritePermissions: true,
|
||||
projectId: '123abc',
|
||||
rootDocId: '5e74f1a7ce17ae0041dfd056'
|
||||
rootDocId: '5e74f1a7ce17ae0041dfd056',
|
||||
isConnected: true
|
||||
},
|
||||
argTypes: {
|
||||
onInit: { action: 'onInit' },
|
||||
|
|
|
@ -347,6 +347,18 @@
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.disconnected-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
background: @file-tree-bg;
|
||||
opacity: 0.5;
|
||||
cursor: wait;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-new-file {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { expect } from 'chai'
|
||||
import React from 'react'
|
||||
import sinon from 'sinon'
|
||||
import { screen, render, fireEvent, waitFor } from '@testing-library/react'
|
||||
|
@ -30,7 +31,7 @@ describe('<FileTreeRoot/>', function() {
|
|||
fileRefs: []
|
||||
}
|
||||
]
|
||||
render(
|
||||
const { container } = render(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
|
@ -38,12 +39,14 @@ describe('<FileTreeRoot/>', function() {
|
|||
rootDocId="456def"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
screen.queryByRole('tree')
|
||||
screen.getByRole('treeitem')
|
||||
screen.getByRole('treeitem', { name: 'main.tex', selected: true })
|
||||
expect(container.querySelector('.disconnected-overlay')).to.not.exist
|
||||
})
|
||||
|
||||
it('renders with invalid selected doc in local storage', async function() {
|
||||
|
@ -67,6 +70,7 @@ describe('<FileTreeRoot/>', function() {
|
|||
rootDocId="456def"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -80,6 +84,31 @@ describe('<FileTreeRoot/>', function() {
|
|||
await waitFor(() => screen.getByRole('button', { name: 'Cancel' }))
|
||||
})
|
||||
|
||||
it('renders disconnected overlay', function() {
|
||||
const rootFolder = [
|
||||
{
|
||||
_id: 'root-folder-id',
|
||||
docs: [{ _id: '456def', name: 'main.tex' }],
|
||||
folders: [],
|
||||
fileRefs: []
|
||||
}
|
||||
]
|
||||
|
||||
const { container } = render(
|
||||
<FileTreeRoot
|
||||
rootFolder={rootFolder}
|
||||
projectId="123abc"
|
||||
hasWritePermissions={false}
|
||||
rootDocId="456def"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected={false}
|
||||
/>
|
||||
)
|
||||
|
||||
expect(container.querySelector('.disconnected-overlay')).to.exist
|
||||
})
|
||||
|
||||
it('fire onSelect', function() {
|
||||
const rootFolder = [
|
||||
{
|
||||
|
@ -100,6 +129,7 @@ describe('<FileTreeRoot/>', function() {
|
|||
hasWritePermissions={false}
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
sinon.assert.calledOnce(onSelect)
|
||||
|
@ -147,6 +177,7 @@ describe('<FileTreeRoot/>', function() {
|
|||
hasWritePermissions={false}
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ describe('FileTree Context Menu Flow', function() {
|
|||
rootDocId="456def"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
const treeitem = screen.getByRole('button', { name: 'main.tex' })
|
||||
|
@ -54,6 +55,7 @@ describe('FileTree Context Menu Flow', function() {
|
|||
rootDocId="456def"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
const treeitem = screen.getByRole('button', { name: 'main.tex' })
|
||||
|
|
|
@ -42,6 +42,7 @@ describe('FileTree Create Folder Flow', function() {
|
|||
hasWritePermissions
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -97,6 +98,7 @@ describe('FileTree Create Folder Flow', function() {
|
|||
rootDocId="789ghi"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -161,6 +163,7 @@ describe('FileTree Create Folder Flow', function() {
|
|||
rootDocId="456def"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -214,6 +217,7 @@ describe('FileTree Create Folder Flow', function() {
|
|||
rootDocId="456def"
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ describe('FileTree Delete Entity Flow', function() {
|
|||
hasWritePermissions
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -139,6 +140,7 @@ describe('FileTree Delete Entity Flow', function() {
|
|||
hasWritePermissions
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -187,6 +189,7 @@ describe('FileTree Delete Entity Flow', function() {
|
|||
hasWritePermissions
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ describe('FileTree Rename Entity Flow', function() {
|
|||
hasWritePermissions
|
||||
onSelect={onSelect}
|
||||
onInit={onInit}
|
||||
isConnected
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue