Add "Set as main document" to file tree menu (#30399)

GitOrigin-RevId: e05a7d0b103226bdc34e559d0d48c12183abdf5a
This commit is contained in:
Alf Eaton
2025-12-18 09:06:19 +00:00
committed by Copybot
parent fa62723682
commit a841dbfd2c
8 changed files with 132 additions and 7 deletions
@@ -23,6 +23,8 @@ function FileTreeItemMenuItems() {
startUploadingDocOrFile,
downloadPath,
selectedFileName,
canSetRootDocId,
setRootDocId,
} = useFileTreeActionable()
const { project } = useProjectContext()
@@ -63,10 +65,23 @@ function FileTreeItemMenuItems() {
</DropdownItem>
</li>
) : null}
{canSetRootDocId ? (
<>
<DropdownDivider />
<li role="none">
<DropdownItem onClick={setRootDocId}>
{t('set_as_main_document')}
</DropdownItem>
</li>
</>
) : null}
{canDelete ? (
<li role="none">
<DropdownItem onClick={startDeleting}>{t('delete')}</DropdownItem>
</li>
<>
<DropdownDivider />
<li role="none">
<DropdownItem onClick={startDeleting}>{t('delete')}</DropdownItem>
</li>
</>
) : null}
{canCreate ? (
<>
@@ -19,6 +19,7 @@ import {
NewDocEntity,
NewLinkedFileEntity,
NewEntity,
syncRootDocId,
} from '../util/sync-mutation'
import { findInTree, findInTreeOrThrow } from '../util/find-in-tree'
import { isNameUniqueInFolder } from '../util/is-name-unique-in-folder'
@@ -39,6 +40,7 @@ import { useReferencesContext } from '@/features/ide-react/context/references-co
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
import { FileTreeEntity } from '@ol-types/file-tree-entity'
import { Doc } from '@ol-types/doc'
import { isValidTeXFile } from '@/main/is-valid-tex-file'
type DroppedFile = File & {
relativePath?: string
@@ -87,6 +89,8 @@ const FileTreeActionableContext = createContext<
droppedFiles: { files: File[]; targetFolderId: string } | null
setDroppedFiles: (value: DroppedFiles | null) => void
downloadPath?: string
canSetRootDocId: boolean
setRootDocId: () => Promise<void>
}
| undefined
>(undefined)
@@ -230,11 +234,13 @@ function fileTreeActionableReducer(state: State, action: Action) {
export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
children,
}) => {
const { projectId } = useProjectContext()
const { projectId, project, updateProject } = useProjectContext()
const { fileTreeReadOnly } = useFileTreeData()
const { indexAllReferences } = useReferencesContext()
const { write } = usePermissionsContext()
const rootDocId = project?.rootDocId
const [state, dispatch] = useReducer(
fileTreeReadOnly
? fileTreeActionableReadOnlyReducer
@@ -522,6 +528,34 @@ export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
}
}, [fileTreeData, projectId, selectedEntityIds])
const canSetRootDocId = useMemo(() => {
// must have write permission on the project
if (!write) {
return false
}
// must be only one file selected
if (!selectedFileName) {
return false
}
// must not already be the root doc
if (rootDocId && selectedEntityIds.has(rootDocId)) {
return false
}
// must have a valid root doc extension
return isValidTeXFile(selectedFileName)
}, [rootDocId, selectedEntityIds, selectedFileName, write])
const setRootDocId = useCallback(async () => {
const [selectedEntityId] = selectedEntityIds
await syncRootDocId(projectId, selectedEntityId)
updateProject({ rootDocId: selectedEntityId })
}, [projectId, selectedEntityIds, updateProject])
const value = useMemo(
() => ({
canDelete: write && selectedEntityIds.size > 0 && !isRootFolderSelected,
@@ -549,6 +583,8 @@ export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
droppedFiles,
setDroppedFiles,
downloadPath,
canSetRootDocId,
setRootDocId,
}),
[
cancel,
@@ -573,6 +609,8 @@ export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
startUploadingDocOrFile,
state,
write,
canSetRootDocId,
setRootDocId,
]
)
@@ -88,3 +88,9 @@ export function syncCreateEntity<T extends NewEntity>(
function getEntityPathName(entityType: string) {
return entityType === 'fileRef' ? 'file' : entityType
}
export function syncRootDocId(projectId: string, rootDocId: string) {
return postJSON(`/project/${projectId}/settings`, {
body: { rootDocId },
})
}
@@ -45,7 +45,7 @@ export default function RootDocumentSetting() {
<DropdownSetting
id="rootDocId"
label={t('main_document')}
description={t('the_primary_file_for_compiling_your_project')}
description={`${t('the_primary_file_for_compiling_your_project')} ${t('you_can_also_right_click_a_file_to_set_it_as_main')}`}
disabled={!write}
options={validDocsOptions}
onChange={changeRootDocId}