Merge pull request #15684 from overleaf/td-ide-page-main-doc-left-menu

Add docs to FileTreeDataContext to replace 'docs' scope value in React code

GitOrigin-RevId: 430f795eb0cd17f0f4fab9c61e46fb04ff3030b3
This commit is contained in:
Tim Down 2023-11-13 11:11:33 +00:00 committed by Copybot
parent 1c820de200
commit 6f34a84ebd
14 changed files with 90 additions and 60 deletions

View file

@ -2,16 +2,16 @@ import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import isValidTeXFile from '../../../../main/is-valid-tex-file'
import { useEditorContext } from '../../../../shared/context/editor-context'
import useScopeValue from '../../../../shared/hooks/use-scope-value'
import { useProjectSettingsContext } from '../../context/project-settings-context'
import SettingsMenuSelect from './settings-menu-select'
import type { Option } from './settings-menu-select'
import type { MainDocument } from '../../../../../../types/project-settings'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
import { MainDocument } from '../../../../../../types/project-settings'
export default function SettingsDocument() {
const { t } = useTranslation()
const { permissionsLevel } = useEditorContext()
const [docs] = useScopeValue<MainDocument[] | undefined>('docs')
const docs: MainDocument[] = useFileTreeData().docs
const { rootDocId, setRootDocId } = useProjectSettingsContext()
const validDocsOptions = useMemo(() => {

View file

@ -0,0 +1,31 @@
import { Folder } from '../../../../../types/folder'
import { DocId, MainDocument } from '../../../../../types/project-settings'
function findAllDocsInFolder(folder: Folder, path = '') {
const docs = folder.docs.map<MainDocument>(doc => ({
doc: { id: doc._id as DocId, name: doc.name },
path: path + doc.name,
}))
for (const subFolder of folder.folders) {
docs.push(...findAllDocsInFolder(subFolder, `${path}${subFolder.name}/`))
}
return docs
}
export function docsInFolder(folder: Folder) {
const docsInTree = findAllDocsInFolder(folder)
docsInTree.sort(function (a, b) {
const aDepth = (a.path.match(/\//g) || []).length
const bDepth = (b.path.match(/\//g) || []).length
if (aDepth - bDepth !== 0) {
return -(aDepth - bDepth) // Deeper path == folder first
} else if (a.path < b.path) {
return -1
} else if (a.path > b.path) {
return 1
} else {
return 0
}
})
return docsInTree
}

View file

@ -56,10 +56,6 @@ function populatePdfScope(store: ReactScopeValueStore) {
store.allowNonExistentPath('pdf', true)
}
function populateFileTreeScope(store: ReactScopeValueStore) {
store.set('docs', [])
}
function createReactScopeValueStore(projectId: string) {
const scopeStore = new ReactScopeValueStore()
@ -76,7 +72,6 @@ function createReactScopeValueStore(projectId: string) {
populateSettingsScope(scopeStore)
populateOnlineUsersScope(scopeStore)
populateReferenceScope(scopeStore)
populateFileTreeScope(scopeStore)
populateReviewPanelScope(scopeStore)
scopeStore.allowNonExistentPath('hasLintingError')

View file

@ -33,7 +33,6 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
'reviewPanel.commentThreads',
true
)
const [docs] = useScopeValue<ReviewPanel.Value<'docs'>>('docs')
const [entries] = useScopeValue<ReviewPanel.Value<'entries'>>(
'reviewPanel.entries',
true
@ -156,7 +155,6 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
() => ({
collapsed,
commentThreads,
docs,
entries,
entryHover,
isAddingComment,
@ -183,7 +181,6 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
[
collapsed,
commentThreads,
docs,
entries,
entryHover,
isAddingComment,

View file

@ -6,7 +6,6 @@ export default function populateReviewPanelScope(store: ReactScopeValueStore) {
store.set('reviewPanel.overview.loading', false)
store.set('reviewPanel.nVisibleSelectedChanges', 0)
store.set('reviewPanel.commentThreads', {})
store.set('docs', undefined)
store.set('reviewPanel.entries', {})
store.set('loadingThreads', true)
store.set('permissions', {

View file

@ -5,9 +5,12 @@ import Nav from './nav'
import Icon from '../../../../shared/components/icon'
import OverviewFile from './overview-file'
import { useReviewPanelValueContext } from '../../context/review-panel/review-panel-context'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
import { MainDocument } from '../../../../../../types/project-settings'
function OverviewContainer() {
const { loading, docs } = useReviewPanelValueContext()
const { loading } = useReviewPanelValueContext()
const docs: MainDocument[] = useFileTreeData().docs
return (
<Container>

View file

@ -13,8 +13,12 @@ import {
ThreadId,
} from '../../../../../../../types/review-panel/review-panel'
import { ReviewPanelResolvedCommentThread } from '../../../../../../../types/review-panel/comment-thread'
import { DocId } from '../../../../../../../types/project-settings'
import {
DocId,
MainDocument,
} from '../../../../../../../types/project-settings'
import { ReviewPanelEntry } from '../../../../../../../types/review-panel/entry'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
export interface FilteredResolvedComments
extends ReviewPanelResolvedCommentThread {
@ -29,8 +33,9 @@ function ResolvedCommentsDropdown() {
const { t } = useTranslation()
const [isOpen, setIsOpen] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const { docs, commentThreads, resolvedComments, permissions } =
const { commentThreads, resolvedComments, permissions } =
useReviewPanelValueContext()
const docs: MainDocument[] = useFileTreeData().docs
const { refreshResolvedCommentsDropdown } = useReviewPanelUpdaterFnsContext()

View file

@ -26,7 +26,6 @@ function useAngularReviewPanelState(): ReviewPanelState {
'reviewPanel.commentThreads',
true
)
const [docs] = useScopeValue<ReviewPanel.Value<'docs'>>('docs')
const [entries] = useScopeValue<ReviewPanel.Value<'entries'>>(
'reviewPanel.entries',
true
@ -143,7 +142,6 @@ function useAngularReviewPanelState(): ReviewPanelState {
() => ({
collapsed,
commentThreads,
docs,
entries,
entryHover,
isAddingComment,
@ -170,7 +168,6 @@ function useAngularReviewPanelState(): ReviewPanelState {
[
collapsed,
commentThreads,
docs,
entries,
entryHover,
isAddingComment,

View file

@ -7,10 +7,7 @@ import {
SubView,
ThreadId,
} from '../../../../../../../types/review-panel/review-panel'
import {
DocId,
MainDocument,
} from '../../../../../../../types/project-settings'
import { DocId } from '../../../../../../../types/project-settings'
import { dispatchReviewPanelLayout } from '../../../extensions/changes/change-manager'
/* eslint-disable no-use-before-define */
@ -18,7 +15,6 @@ export interface ReviewPanelState {
values: {
collapsed: Record<DocId, boolean>
commentThreads: ReviewPanelCommentThreads
docs: MainDocument[] | undefined
entries: ReviewPanelEntries
entryHover: boolean
isAddingComment: boolean

View file

@ -16,6 +16,7 @@ import {
} from '../../features/file-tree/util/mutate-in-tree'
import { countFiles } from '../../features/file-tree/util/count-in-tree'
import useDeepCompareEffect from '../../shared/hooks/use-deep-compare-effect'
import { docsInFolder } from '@/features/file-tree/util/docs-in-folder'
const FileTreeDataContext = createContext()
@ -147,6 +148,11 @@ export function FileTreeDataProvider({ children }) {
const [selectedEntities, setSelectedEntities] = useState([])
const docs = useMemo(
() => (fileTreeData ? docsInFolder(fileTreeData) : undefined),
[fileTreeData]
)
useDeepCompareEffect(() => {
dispatch({
type: ACTION_TYPES.RESET,
@ -210,6 +216,7 @@ export function FileTreeDataProvider({ children }) {
hasFolders: fileTreeData?.folders.length > 0,
selectedEntities,
setSelectedEntities,
docs,
}
}, [
dispatchCreateDoc,
@ -222,6 +229,7 @@ export function FileTreeDataProvider({ children }) {
fileTreeData,
selectedEntities,
setSelectedEntities,
docs,
])
return (

View file

@ -1,12 +1,13 @@
import EditorLeftMenu from '../../../../frontend/js/features/editor-left-menu/components/editor-left-menu'
import {
AllowedImageName,
MainDocument,
OverallThemeMeta,
SpellCheckLanguage,
} from '../../../../types/project-settings'
import { EditorProviders } from '../../helpers/editor-providers'
import { mockScope } from './scope'
import { Folder } from '../../../../types/folder'
import { docsInFolder } from '@/features/file-tree/util/docs-in-folder'
describe('<EditorLeftMenu />', function () {
beforeEach(function () {
@ -390,40 +391,37 @@ describe('<EditorLeftMenu />', function () {
})
it('shows document menu correctly', function () {
const docs: MainDocument[] = [
{
path: 'main.tex',
doc: {
const rootFolder: Folder = {
_id: 'root-folder-id',
name: 'rootFolder',
docs: [
{
_id: 'id1',
name: 'main.tex',
id: 'id1',
type: 'doc',
selected: false,
} as MainDocument['doc'],
},
{
path: 'folder/main2.tex',
doc: {
},
{
_id: 'id2',
name: 'main2.tex',
id: 'id2',
type: 'doc',
selected: false,
} as MainDocument['doc'],
},
]
},
],
fileRefs: [],
folders: [],
}
const scope = mockScope({
ui: {
leftMenuShown: true,
},
docs,
})
cy.mount(
<EditorProviders scope={scope}>
<EditorProviders scope={scope} rootFolder={[rootFolder as any]}>
<EditorLeftMenu />
</EditorProviders>
)
const docs = docsInFolder(rootFolder)
cy.get<HTMLOptionElement>('#settings-menu-rootDocId option').then(
options => {
const values = [...options].map(o => o.value)

View file

@ -5,21 +5,23 @@ import fetchMock from 'fetch-mock'
import SettingsDocument from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-document'
import * as isValidTeXFileModule from '../../../../../../frontend/js/main/is-valid-tex-file'
import { renderWithEditorContext } from '../../../../helpers/render-with-context'
import type { MainDocument } from '../../../../../../types/project-settings'
import { Folder } from '../../../../../../types/folder'
describe('<SettingsDocument />', function () {
let isValidTeXFileStub: sinon.SinonStub
const docs: MainDocument[] = [
{
path: 'main.tex',
doc: {
const rootFolder: Folder = {
_id: 'root-folder-id',
name: 'rootFolder',
docs: [
{
_id: '123abc',
name: 'main.tex',
id: '123abc',
type: 'doc',
selected: false,
} as MainDocument['doc'],
},
]
},
],
fileRefs: [],
folders: [],
}
beforeEach(function () {
isValidTeXFileStub = sinon
@ -34,9 +36,7 @@ describe('<SettingsDocument />', function () {
it('shows correct menu', async function () {
renderWithEditorContext(<SettingsDocument />, {
scope: {
docs,
},
rootFolder: [rootFolder],
})
const select = screen.getByLabelText('Main document')

View file

@ -22,6 +22,9 @@ describe('<ReviewPanel />', function () {
const scope = mockScope('')
scope.editor.showVisual = true
// The tests expect no documents, so remove them from the scope
scope.project.rootFolder = []
cy.wrap(scope).as('scope')
cy.mount(

View file

@ -11,8 +11,6 @@ export type MainDocument = {
doc: {
name: string
id: DocId
type: string
selected: boolean
}
path: string
}