Merge pull request #14339 from overleaf/ii-filetree-empty-space-click-3

[web] Select project root folder improvements

GitOrigin-RevId: 48b80f26adf239215bf04d3db95a61ef35b5cf77
This commit is contained in:
ilkin-overleaf 2023-08-18 12:26:22 +03:00 committed by Copybot
parent aa2c200200
commit b05f8ad7e7
13 changed files with 164 additions and 156 deletions

View file

@ -15,7 +15,6 @@ function FileTreeContext({
reindexReferences, reindexReferences,
setRefProviderEnabled, setRefProviderEnabled,
setStartedFreeTrial, setStartedFreeTrial,
setShouldShowVisualSelection,
onSelect, onSelect,
children, children,
}) { }) {
@ -24,13 +23,9 @@ function FileTreeContext({
refProviders={refProviders} refProviders={refProviders}
setRefProviderEnabled={setRefProviderEnabled} setRefProviderEnabled={setRefProviderEnabled}
setStartedFreeTrial={setStartedFreeTrial} setStartedFreeTrial={setStartedFreeTrial}
setShouldShowVisualSelection={setShouldShowVisualSelection}
reindexReferences={reindexReferences} reindexReferences={reindexReferences}
> >
<FileTreeSelectableProvider <FileTreeSelectableProvider onSelect={onSelect}>
onSelect={onSelect}
setShouldShowVisualSelection={setShouldShowVisualSelection}
>
<FileTreeActionableProvider> <FileTreeActionableProvider>
<FileTreeDraggableProvider>{children}</FileTreeDraggableProvider> <FileTreeDraggableProvider>{children}</FileTreeDraggableProvider>
</FileTreeActionableProvider> </FileTreeActionableProvider>
@ -44,7 +39,6 @@ FileTreeContext.propTypes = {
refProviders: PropTypes.object.isRequired, refProviders: PropTypes.object.isRequired,
setRefProviderEnabled: PropTypes.func.isRequired, setRefProviderEnabled: PropTypes.func.isRequired,
setStartedFreeTrial: PropTypes.func.isRequired, setStartedFreeTrial: PropTypes.func.isRequired,
setShouldShowVisualSelection: PropTypes.func.isRequired,
onSelect: PropTypes.func.isRequired, onSelect: PropTypes.func.isRequired,
children: PropTypes.oneOfType([ children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),

View file

@ -8,16 +8,9 @@ import Icon from '../../../shared/components/icon'
import iconTypeFromName from '../util/icon-type-from-name' import iconTypeFromName from '../util/icon-type-from-name'
import classnames from 'classnames' import classnames from 'classnames'
function FileTreeDoc({ function FileTreeDoc({ name, id, isFile, isLinkedFile }) {
name,
id,
isFile,
isLinkedFile,
shouldShowVisualSelection,
}) {
const { isSelected, props: selectableEntityProps } = useSelectableEntity( const { isSelected, props: selectableEntityProps } = useSelectableEntity(
id, id,
shouldShowVisualSelection,
isFile isFile
) )
@ -45,7 +38,6 @@ FileTreeDoc.propTypes = {
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
isFile: PropTypes.bool, isFile: PropTypes.bool,
isLinkedFile: PropTypes.bool, isLinkedFile: PropTypes.bool,
shouldShowVisualSelection: PropTypes.bool,
} }
export const FileTreeIcon = ({ isLinkedFile, name }) => { export const FileTreeIcon = ({ isLinkedFile, name }) => {

View file

@ -12,7 +12,7 @@ function FileTreeFolderList({
classes = {}, classes = {},
dropRef = null, dropRef = null,
children, children,
shouldShowVisualSelection, dataTestId,
}) { }) {
files = files.map(file => ({ ...file, isFile: true })) files = files.map(file => ({ ...file, isFile: true }))
const docsAndFiles = [...docs, ...files] const docsAndFiles = [...docs, ...files]
@ -23,6 +23,7 @@ function FileTreeFolderList({
role="tree" role="tree"
ref={dropRef} ref={dropRef}
dnd-container="true" dnd-container="true"
data-testid={dataTestId}
> >
{folders.sort(compareFunction).map(folder => { {folders.sort(compareFunction).map(folder => {
return ( return (
@ -33,7 +34,6 @@ function FileTreeFolderList({
folders={folder.folders} folders={folder.folders}
docs={folder.docs} docs={folder.docs}
files={folder.fileRefs} files={folder.fileRefs}
shouldShowVisualSelection={shouldShowVisualSelection}
/> />
) )
})} })}
@ -45,7 +45,6 @@ function FileTreeFolderList({
id={doc._id} id={doc._id}
isFile={doc.isFile} isFile={doc.isFile}
isLinkedFile={doc.linkedFileData && !!doc.linkedFileData.provider} isLinkedFile={doc.linkedFileData && !!doc.linkedFileData.provider}
shouldShowVisualSelection={shouldShowVisualSelection}
/> />
) )
})} })}
@ -63,7 +62,7 @@ FileTreeFolderList.propTypes = {
}), }),
dropRef: PropTypes.func, dropRef: PropTypes.func,
children: PropTypes.node, children: PropTypes.node,
shouldShowVisualSelection: PropTypes.bool, dataTestId: PropTypes.string,
} }
function compareFunction(one, two) { function compareFunction(one, two) {

View file

@ -14,20 +14,10 @@ import FileTreeItemInner from './file-tree-item/file-tree-item-inner'
import FileTreeFolderList from './file-tree-folder-list' import FileTreeFolderList from './file-tree-folder-list'
import usePersistedState from '../../../shared/hooks/use-persisted-state' import usePersistedState from '../../../shared/hooks/use-persisted-state'
function FileTreeFolder({ function FileTreeFolder({ name, id, folders, docs, files }) {
name,
id,
folders,
docs,
files,
shouldShowVisualSelection,
}) {
const { t } = useTranslation() const { t } = useTranslation()
const { isSelected, props: selectableEntityProps } = useSelectableEntity( const { isSelected, props: selectableEntityProps } = useSelectableEntity(id)
id,
shouldShowVisualSelection
)
const { selectedEntityParentIds } = useFileTreeSelectable(id) const { selectedEntityParentIds } = useFileTreeSelectable(id)
@ -97,7 +87,6 @@ function FileTreeFolder({
docs={docs} docs={docs}
files={files} files={files}
dropRef={dropRefList} dropRef={dropRefList}
shouldShowVisualSelection={shouldShowVisualSelection}
/> />
) : null} ) : null}
</> </>
@ -110,7 +99,6 @@ FileTreeFolder.propTypes = {
folders: PropTypes.array.isRequired, folders: PropTypes.array.isRequired,
docs: PropTypes.array.isRequired, docs: PropTypes.array.isRequired,
files: PropTypes.array.isRequired, files: PropTypes.array.isRequired,
shouldShowVisualSelection: PropTypes.bool,
} }
export default FileTreeFolder export default FileTreeFolder

View file

@ -0,0 +1,26 @@
import { useFileTreeSelectable } from '../contexts/file-tree-selectable'
type FileTreeInnerProps = {
children: React.ReactNode
}
function FileTreeInner({ children }: FileTreeInnerProps) {
const { setIsRootFolderSelected } = useFileTreeSelectable()
const handleFileTreeClick = () => {
setIsRootFolderSelected(true)
}
return (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div
className="file-tree-inner"
onClick={handleFileTreeClick}
data-testid="file-tree-inner"
>
{children}
</div>
)
}
export default FileTreeInner

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react' import React, { useEffect } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import withErrorBoundary from '../../../infrastructure/error-boundary' import withErrorBoundary from '../../../infrastructure/error-boundary'
@ -18,6 +18,7 @@ import { useDroppable } from '../contexts/file-tree-draggable'
import { useFileTreeSocketListener } from '../hooks/file-tree-socket-listener' import { useFileTreeSocketListener } from '../hooks/file-tree-socket-listener'
import FileTreeModalCreateFile from './modals/file-tree-modal-create-file' import FileTreeModalCreateFile from './modals/file-tree-modal-create-file'
import FileTreeInner from './file-tree-inner'
const FileTreeRoot = React.memo(function FileTreeRoot({ const FileTreeRoot = React.memo(function FileTreeRoot({
refProviders, refProviders,
@ -31,12 +32,6 @@ const FileTreeRoot = React.memo(function FileTreeRoot({
const { _id: projectId } = useProjectContext(projectContextPropTypes) const { _id: projectId } = useProjectContext(projectContextPropTypes)
const { fileTreeData } = useFileTreeData() const { fileTreeData } = useFileTreeData()
const isReady = projectId && fileTreeData const isReady = projectId && fileTreeData
const [shouldShowVisualSelection, setShouldShowVisualSelection] =
useState(true)
const handleFileTreeClick = () => {
setShouldShowVisualSelection(false)
}
useEffect(() => { useEffect(() => {
if (isReady) onInit() if (isReady) onInit()
@ -48,23 +43,15 @@ const FileTreeRoot = React.memo(function FileTreeRoot({
refProviders={refProviders} refProviders={refProviders}
setRefProviderEnabled={setRefProviderEnabled} setRefProviderEnabled={setRefProviderEnabled}
setStartedFreeTrial={setStartedFreeTrial} setStartedFreeTrial={setStartedFreeTrial}
setShouldShowVisualSelection={setShouldShowVisualSelection}
reindexReferences={reindexReferences} reindexReferences={reindexReferences}
onSelect={onSelect} onSelect={onSelect}
> >
{isConnected ? null : <div className="disconnected-overlay" />} {isConnected ? null : <div className="disconnected-overlay" />}
<FileTreeToolbar /> <FileTreeToolbar />
<FileTreeContextMenu /> <FileTreeContextMenu />
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} <FileTreeInner>
<div <FileTreeRootFolder />
className="file-tree-inner" </FileTreeInner>
onClick={handleFileTreeClick}
data-testid="file-tree-inner"
>
<FileTreeRootFolder
shouldShowVisualSelection={shouldShowVisualSelection}
/>
</div>
<FileTreeModalDelete /> <FileTreeModalDelete />
<FileTreeModalCreateFile /> <FileTreeModalCreateFile />
<FileTreeModalCreateFolder /> <FileTreeModalCreateFolder />
@ -73,7 +60,7 @@ const FileTreeRoot = React.memo(function FileTreeRoot({
) )
}) })
function FileTreeRootFolder({ shouldShowVisualSelection }) { function FileTreeRootFolder() {
useFileTreeSocketListener() useFileTreeSocketListener()
const { fileTreeData } = useFileTreeData() const { fileTreeData } = useFileTreeData()
@ -89,7 +76,7 @@ function FileTreeRootFolder({ shouldShowVisualSelection }) {
classes={{ root: 'file-tree-list' }} classes={{ root: 'file-tree-list' }}
dropRef={dropRef} dropRef={dropRef}
isOver={isOver} isOver={isOver}
shouldShowVisualSelection={shouldShowVisualSelection} dataTestId="file-tree-list-root"
> >
<li className="bottom-buffer" /> <li className="bottom-buffer" />
</FileTreeFolderList> </FileTreeFolderList>
@ -97,10 +84,6 @@ function FileTreeRootFolder({ shouldShowVisualSelection }) {
) )
} }
FileTreeRootFolder.propTypes = {
shouldShowVisualSelection: PropTypes.bool,
}
FileTreeRoot.propTypes = { FileTreeRoot.propTypes = {
onSelect: PropTypes.func.isRequired, onSelect: PropTypes.func.isRequired,
onInit: PropTypes.func.isRequired, onInit: PropTypes.func.isRequired,

View file

@ -131,7 +131,7 @@ export function FileTreeActionableProvider({ children }) {
) )
const { fileTreeData, dispatchRename, dispatchMove } = useFileTreeData() const { fileTreeData, dispatchRename, dispatchMove } = useFileTreeData()
const { selectedEntityIds } = useFileTreeSelectable() const { selectedEntityIds, isRootFolderSelected } = useFileTreeSelectable()
const [droppedFiles, setDroppedFiles] = useState(null) const [droppedFiles, setDroppedFiles] = useState(null)
@ -263,10 +263,13 @@ export function FileTreeActionableProvider({ children }) {
dispatch({ type: ACTION_TYPES.START_CREATE_FOLDER }) dispatch({ type: ACTION_TYPES.START_CREATE_FOLDER })
}, []) }, [])
const parentFolderId = useMemo( const parentFolderId = useMemo(() => {
() => getSelectedParentFolderId(fileTreeData, selectedEntityIds), return getSelectedParentFolderId(
[fileTreeData, selectedEntityIds] fileTreeData,
) selectedEntityIds,
isRootFolderSelected
)
}, [fileTreeData, selectedEntityIds, isRootFolderSelected])
const finishCreatingEntity = useCallback( const finishCreatingEntity = useCallback(
entity => { entity => {
@ -369,8 +372,8 @@ export function FileTreeActionableProvider({ children }) {
}, [fileTreeData, projectId, selectedEntityIds]) }, [fileTreeData, projectId, selectedEntityIds])
const value = { const value = {
canDelete: selectedEntityIds.size > 0, canDelete: selectedEntityIds.size > 0 && !isRootFolderSelected,
canRename: selectedEntityIds.size === 1, canRename: selectedEntityIds.size === 1 && !isRootFolderSelected,
canCreate: selectedEntityIds.size < 2, canCreate: selectedEntityIds.size < 2,
...state, ...state,
parentFolderId, parentFolderId,
@ -427,7 +430,15 @@ export function useFileTreeActionable() {
return context return context
} }
function getSelectedParentFolderId(fileTreeData, selectedEntityIds) { function getSelectedParentFolderId(
fileTreeData,
selectedEntityIds,
isRootFolderSelected
) {
if (isRootFolderSelected) {
return fileTreeData._id
}
// we expect only one entity to be selected in that case, so we pick the first // we expect only one entity to be selected in that case, so we pick the first
const selectedEntityId = Array.from(selectedEntityIds)[0] const selectedEntityId = Array.from(selectedEntityIds)[0]
if (!selectedEntityId) { if (!selectedEntityId) {

View file

@ -75,11 +75,7 @@ function fileTreeSelectableReadOnlyReducer(selectedEntityIds, action) {
} }
} }
export function FileTreeSelectableProvider({ export function FileTreeSelectableProvider({ onSelect, children }) {
onSelect,
setShouldShowVisualSelection,
children,
}) {
const { _id: projectId, rootDocId } = useProjectContext( const { _id: projectId, rootDocId } = useProjectContext(
projectContextPropTypes projectContextPropTypes
) )
@ -92,6 +88,8 @@ export function FileTreeSelectableProvider({
const { fileTreeData, setSelectedEntities } = useFileTreeData() const { fileTreeData, setSelectedEntities } = useFileTreeData()
const [isRootFolderSelected, setIsRootFolderSelected] = useState(false)
const [selectedEntityIds, dispatch] = useReducer( const [selectedEntityIds, dispatch] = useReducer(
permissionsLevel === 'readOnly' permissionsLevel === 'readOnly'
? fileTreeSelectableReadOnlyReducer ? fileTreeSelectableReadOnlyReducer
@ -181,7 +179,8 @@ export function FileTreeSelectableProvider({
select, select,
unselect, unselect,
selectOrMultiSelectEntity, selectOrMultiSelectEntity,
setShouldShowVisualSelection, isRootFolderSelected,
setIsRootFolderSelected,
} }
return ( return (
@ -193,7 +192,6 @@ export function FileTreeSelectableProvider({
FileTreeSelectableProvider.propTypes = { FileTreeSelectableProvider.propTypes = {
onSelect: PropTypes.func.isRequired, onSelect: PropTypes.func.isRequired,
setShouldShowVisualSelection: PropTypes.func.isRequired,
children: PropTypes.oneOfType([ children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),
PropTypes.node, PropTypes.node,
@ -209,16 +207,13 @@ const editorContextPropTypes = {
permissionsLevel: PropTypes.oneOf(['readOnly', 'readAndWrite', 'owner']), permissionsLevel: PropTypes.oneOf(['readOnly', 'readAndWrite', 'owner']),
} }
export function useSelectableEntity( export function useSelectableEntity(id, isFile) {
id,
shouldShowVisualSelection = true,
isFile
) {
const { view, setView } = useLayoutContext(layoutContextPropTypes) const { view, setView } = useLayoutContext(layoutContextPropTypes)
const { const {
selectedEntityIds, selectedEntityIds,
selectOrMultiSelectEntity, selectOrMultiSelectEntity,
setShouldShowVisualSelection, isRootFolderSelected,
setIsRootFolderSelected,
} = useContext(FileTreeSelectableContext) } = useContext(FileTreeSelectableContext)
const isSelected = selectedEntityIds.has(id) const isSelected = selectedEntityIds.has(id)
@ -226,17 +221,11 @@ export function useSelectableEntity(
const handleEvent = useCallback( const handleEvent = useCallback(
ev => { ev => {
ev.stopPropagation() ev.stopPropagation()
setShouldShowVisualSelection(true) setIsRootFolderSelected(false)
selectOrMultiSelectEntity(id, ev.ctrlKey || ev.metaKey) selectOrMultiSelectEntity(id, ev.ctrlKey || ev.metaKey)
setView(isFile ? 'file' : 'editor') setView(isFile ? 'file' : 'editor')
}, },
[ [id, setIsRootFolderSelected, selectOrMultiSelectEntity, setView, isFile]
id,
setShouldShowVisualSelection,
selectOrMultiSelectEntity,
setView,
isFile,
]
) )
const handleClick = useCallback( const handleClick = useCallback(
@ -266,7 +255,7 @@ export function useSelectableEntity(
) )
const isVisuallySelected = const isVisuallySelected =
shouldShowVisualSelection && isSelected && view !== 'pdf' !isRootFolderSelected && isSelected && view !== 'pdf'
const props = useMemo( const props = useMemo(
() => ({ () => ({
className: classNames({ selected: isVisuallySelected }), className: classNames({ selected: isVisuallySelected }),

View file

@ -21,21 +21,10 @@ function HistoryFileTreeFolderList({
rootClassName, rootClassName,
children, children,
}: HistoryFileTreeFolderListProps) { }: HistoryFileTreeFolderListProps) {
const { const { selection, setSelection } = useHistoryContext()
selection,
setSelection,
shouldShowVisualSelection,
setShouldShowVisualSelection,
} = useHistoryContext()
const handleTopLevelClick = () => {
setShouldShowVisualSelection(false)
}
const handleEvent = useCallback( const handleEvent = useCallback(
(file: FileDiff, event: React.UIEvent) => { (file: FileDiff) => {
event.stopPropagation()
setShouldShowVisualSelection(true)
setSelection(prevSelection => { setSelection(prevSelection => {
if (file.pathname !== prevSelection.selectedFile?.pathname) { if (file.pathname !== prevSelection.selectedFile?.pathname) {
return { return {
@ -48,12 +37,12 @@ function HistoryFileTreeFolderList({
return prevSelection return prevSelection
}) })
}, },
[setSelection, setShouldShowVisualSelection] [setSelection]
) )
const handleClick = useCallback( const handleClick = useCallback(
(file: FileDiff, event: React.MouseEvent<HTMLLIElement>) => { (file: FileDiff) => {
handleEvent(file, event) handleEvent(file)
}, },
[handleEvent] [handleEvent]
) )
@ -61,19 +50,14 @@ function HistoryFileTreeFolderList({
const handleKeyDown = useCallback( const handleKeyDown = useCallback(
(file: FileDiff, event: React.KeyboardEvent<HTMLLIElement>) => { (file: FileDiff, event: React.KeyboardEvent<HTMLLIElement>) => {
if (event.key === 'Enter' || event.key === ' ') { if (event.key === 'Enter' || event.key === ' ') {
handleEvent(file, event) handleEvent(file)
} }
}, },
[handleEvent] [handleEvent]
) )
return ( return (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events <ul className={classNames('list-unstyled', rootClassName)} role="tree">
<ul
className={classNames('list-unstyled', rootClassName)}
role="tree"
onClick={handleTopLevelClick}
>
{folders.map(folder => ( {folders.map(folder => (
<HistoryFileTreeFolder <HistoryFileTreeFolder
key={folder.name} key={folder.name}
@ -88,7 +72,6 @@ function HistoryFileTreeFolderList({
name={doc.name} name={doc.name}
file={doc} file={doc}
selected={ selected={
shouldShowVisualSelection &&
!!selection.selectedFile && !!selection.selectedFile &&
fileFinalPathname(selection.selectedFile) === doc.pathname fileFinalPathname(selection.selectedFile) === doc.pathname
} }

View file

@ -88,8 +88,6 @@ function useHistory() {
const currentUserIsOwner = projectOwnerId === userId const currentUserIsOwner = projectOwnerId === userId
const [selection, setSelection] = useState<Selection>(selectionInitialState) const [selection, setSelection] = useState<Selection>(selectionInitialState)
const [shouldShowVisualSelection, setShouldShowVisualSelection] =
useState(true)
const [updatesInfo, setUpdatesInfo] = useState< const [updatesInfo, setUpdatesInfo] = useState<
HistoryContextValue['updatesInfo'] HistoryContextValue['updatesInfo']
@ -332,8 +330,6 @@ function useHistory() {
setSelection, setSelection,
fetchNextBatchOfUpdates, fetchNextBatchOfUpdates,
resetSelection, resetSelection,
shouldShowVisualSelection,
setShouldShowVisualSelection,
}), }),
[ [
loadingFileDiffs, loadingFileDiffs,
@ -350,8 +346,6 @@ function useHistory() {
setSelection, setSelection,
fetchNextBatchOfUpdates, fetchNextBatchOfUpdates,
resetSelection, resetSelection,
shouldShowVisualSelection,
setShouldShowVisualSelection,
] ]
) )

View file

@ -31,8 +31,4 @@ export type HistoryContextValue = {
> >
fetchNextBatchOfUpdates: () => (() => void) | void fetchNextBatchOfUpdates: () => (() => void) | void
resetSelection: () => void resetSelection: () => void
shouldShowVisualSelection: boolean
setShouldShowVisualSelection: React.Dispatch<
React.SetStateAction<HistoryContextValue['shouldShowVisualSelection']>
>
} }

View file

@ -2,6 +2,7 @@ import { expect } from 'chai'
import sinon from 'sinon' import sinon from 'sinon'
import { screen, fireEvent, waitFor } from '@testing-library/react' import { screen, fireEvent, waitFor } from '@testing-library/react'
import fetchMock from 'fetch-mock' import fetchMock from 'fetch-mock'
import MockedSocket from 'socket.io-mock'
import { import {
renderWithEditorContext, renderWithEditorContext,
@ -306,37 +307,92 @@ describe('<FileTreeRoot/>', function () {
expect(screen.queryAllByRole('button', { name: 'Menu' })).to.have.length(0) expect(screen.queryAllByRole('button', { name: 'Menu' })).to.have.length(0)
}) })
it('deselects files when clicked outside the list but inside wrapping container', function () { describe('when deselecting files', function () {
const rootFolder = [ beforeEach(function () {
{ const rootFolder = [
_id: 'root-folder-id', {
name: 'rootFolder', _id: 'root-folder-id',
docs: [{ _id: '456def', name: 'main.tex' }], name: 'rootFolder',
folders: [], docs: [{ _id: '123abc', name: 'main.tex' }],
fileRefs: [], folders: [
}, {
] _id: '789ghi',
renderWithEditorContext( name: 'thefolder',
<FileTreeRoot docs: [{ _id: '456def', name: 'sub.tex' }],
refProviders={{}} fileRefs: [],
reindexReferences={() => null} folders: [],
setRefProviderEnabled={() => null} },
setStartedFreeTrial={() => null} ],
onSelect={onSelect} fileRefs: [],
onInit={onInit} },
isConnected ]
/>, renderWithEditorContext(
{ <FileTreeRoot
rootFolder, refProviders={{}}
projectId: '123abc', reindexReferences={() => null}
rootDocId: '456def', setRefProviderEnabled={() => null}
features: {}, setStartedFreeTrial={() => null}
permissionsLevel: 'owner', onSelect={onSelect}
} onInit={onInit}
) isConnected
/>,
{
rootFolder,
projectId: '123abc',
rootDocId: '456def',
features: {},
permissionsLevel: 'owner',
socket: new MockedSocket(),
}
)
screen.getByRole('treeitem', { selected: true }) // select the sub file
fireEvent.click(screen.getByTestId('file-tree-inner')) const mainDoc = screen.getByRole('treeitem', { name: 'sub.tex' })
expect(screen.queryByRole('treeitem', { selected: true })).to.be.null fireEvent.click(mainDoc)
expect(mainDoc.getAttribute('aria-selected')).to.equal('true')
// click on empty area
fireEvent.click(screen.getByTestId('file-tree-inner'))
})
afterEach(function () {
fetchMock.reset()
})
it('removes the selected indicator', function () {
expect(screen.queryByRole('treeitem', { selected: true })).to.be.null
})
it('disables the "rename" and "delete" buttons', function () {
expect(screen.queryByRole('button', { name: 'Rename' })).to.be.null
expect(screen.queryByRole('button', { name: 'Delete' })).to.be.null
})
it('creates new file in the root folder', async function () {
fetchMock.post('express:/project/:projectId/doc', () => 200)
fireEvent.click(screen.getByRole('button', { name: /new file/i }))
fireEvent.click(screen.getByRole('button', { name: /create/i }))
const socketData = {
_id: '12345',
name: 'abcdef.tex',
docs: [],
fileRefs: [],
folders: [],
}
window._ide.socket.socketClient.emit(
'reciveNewDoc',
'root-folder-id',
socketData
)
await fetchMock.flush(true)
const newItem = screen.getByRole('treeitem', { name: socketData.name })
const rootEl = screen.getByTestId('file-tree-list-root')
expect(newItem.parentNode).to.equal(rootEl)
})
}) })
}) })

View file

@ -24,7 +24,6 @@ export default (children, options = {}) => {
setStartedFreeTrial: () => { setStartedFreeTrial: () => {
console.log('started free trial') console.log('started free trial')
}, },
setShouldShowVisualSelection: () => {},
onSelect: () => {}, onSelect: () => {},
...contextProps, ...contextProps,
} }
@ -33,7 +32,6 @@ export default (children, options = {}) => {
reindexReferences, reindexReferences,
setRefProviderEnabled, setRefProviderEnabled,
setStartedFreeTrial, setStartedFreeTrial,
setShouldShowVisualSelection,
onSelect, onSelect,
...editorContextProps ...editorContextProps
} = contextProps } = contextProps
@ -43,7 +41,6 @@ export default (children, options = {}) => {
reindexReferences={reindexReferences} reindexReferences={reindexReferences}
setRefProviderEnabled={setRefProviderEnabled} setRefProviderEnabled={setRefProviderEnabled}
setStartedFreeTrial={setStartedFreeTrial} setStartedFreeTrial={setStartedFreeTrial}
setShouldShowVisualSelection={setShouldShowVisualSelection}
onSelect={onSelect} onSelect={onSelect}
> >
{children} {children}