Tearing down of old Editor (File tree) (#31784)

* merging ide-redesign/components/file-tree into features/file-tree

* moving ide-redesign/contexts/settings-modal-context   to features/settings/contexts

* use-collapsible-file-tree.tsx → features/file-tree/hooks

* use-focus-on-setting.tsx → features/settings/hooks

* use-project-notification-preferences.ts → features/settings/hooks

* use-rail-overflow.tsx→ features/ide-react/hooks

* deleting use-switch-enable-new-editor-state.ts

* use-toolbar-menu-editor-commands.tsx → features/source-editor/hooks

* npm run extract-translations

* modifying the test to target correct buttons and removing a test for old component

* adding a test back and modifying it

* changing the test

GitOrigin-RevId: baa1e9a992c88b84313eea82161354d4958cf1ef
This commit is contained in:
Davinder Singh
2026-03-06 09:14:01 +00:00
committed by Copybot
parent 68b97f2c02
commit f27c99ea4b
41 changed files with 57 additions and 222 deletions
@@ -0,0 +1,33 @@
import OLTooltip from '@/shared/components/ol/ol-tooltip'
import MaterialIcon, {
AvailableUnfilledIcon,
} from '@/shared/components/material-icon'
import React from 'react'
export default function FileTreeActionButton({
id,
description,
onClick,
iconType,
}: {
id: string
description: string
onClick: () => void
iconType: AvailableUnfilledIcon
}) {
return (
<OLTooltip
id={id}
description={description}
overlayProps={{ placement: 'bottom' }}
>
<button className="btn file-tree-toolbar-action-button" onClick={onClick}>
<MaterialIcon
unfilled
type={iconType}
accessibilityLabel={description}
/>
</button>
</OLTooltip>
)
}
@@ -0,0 +1,123 @@
import { useTranslation } from 'react-i18next'
import * as eventTracking from '../../../infrastructure/event-tracking'
import { useFileTreeActionable } from '@/features/file-tree/contexts/file-tree-actionable'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
import React from 'react'
import { useCommandProvider } from '@/features/ide-react/hooks/use-command-provider'
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
import FileTreeActionButton from './file-tree-action-button'
import { useRailContext } from '../../ide-react/context/rail-context'
export default function FileTreeActionButtons({
fileTreeExpanded,
}: {
fileTreeExpanded: boolean
}) {
const { t } = useTranslation()
const { fileTreeReadOnly } = useFileTreeData()
const { write } = usePermissionsContext()
const { handlePaneCollapse } = useRailContext()
const {
canCreate,
canBulkDelete,
startDeleting,
startCreatingFolder,
startCreatingDocOrFile,
startUploadingDocOrFile,
} = useFileTreeActionable()
useCommandProvider(() => {
if (!canCreate || fileTreeReadOnly || !write) return
return [
{
label: t('new_file'),
id: 'new_file',
handler: ({ location }) => {
eventTracking.sendMB('new-file-click', { location })
startCreatingDocOrFile()
},
},
{
label: t('new_folder'),
id: 'new_folder',
handler: startCreatingFolder,
},
{
label: t('upload_file'),
id: 'upload_file',
handler: ({ location }) => {
eventTracking.sendMB('upload-click', { location })
startUploadingDocOrFile()
},
},
]
}, [
canCreate,
fileTreeReadOnly,
startCreatingDocOrFile,
t,
startCreatingFolder,
startUploadingDocOrFile,
write,
])
if (fileTreeReadOnly) return null
const createWithAnalytics = () => {
eventTracking.sendMB('new-file-click', { location: 'toolbar' })
startCreatingDocOrFile()
}
const uploadWithAnalytics = () => {
eventTracking.sendMB('upload-click', { location: 'toolbar' })
startUploadingDocOrFile()
}
return (
<div className="file-tree-toolbar-action-buttons">
{fileTreeExpanded && (
<>
{canCreate && (
<FileTreeActionButton
id="new-file"
description={t('new_file')}
onClick={createWithAnalytics}
iconType="note_add"
/>
)}
{canCreate && (
<FileTreeActionButton
id="new-folder"
description={t('new_folder')}
onClick={startCreatingFolder}
iconType="create_new_folder"
/>
)}
{canCreate && (
<FileTreeActionButton
id="upload"
description={t('upload')}
onClick={uploadWithAnalytics}
iconType="upload"
/>
)}
{canBulkDelete && (
<FileTreeActionButton
id="delete"
description={t('delete')}
onClick={startDeleting}
iconType="delete"
/>
)}
</>
)}
<FileTreeActionButton
id="close"
description={t('close')}
onClick={handlePaneCollapse}
iconType="close"
/>
</div>
)
}
@@ -0,0 +1,61 @@
import { Panel, PanelGroup } from 'react-resizable-panels'
import { FileTree } from '@/features/ide-react/components/file-tree'
import { OutlineContainer } from '@/features/outline/components/outline-container'
import { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
import { useOutlinePane } from '@/features/ide-react/hooks/use-outline-pane'
import useCollapsibleFileTree from '@/features/file-tree/hooks/use-collapsible-file-tree'
import classNames from 'classnames'
function FileTreeOutlinePanel() {
const { canShowOutline, outlinePanelRef, expandOutline, collapseOutline } =
useOutlinePane()
const {
fileTreeExpanded,
fileTreePanelRef,
expandFileTree,
collapseFileTree,
} = useCollapsibleFileTree()
return (
<PanelGroup
className="file-tree-outline-panel-group"
autoSaveId="ide-redesign-file-tree-outline"
direction="vertical"
>
<Panel
className={classNames('file-tree-panel', {
'file-tree-panel-collapsed': !fileTreeExpanded,
})}
defaultSize={50}
id="ide-redesign-file-tree"
order={1}
collapsible
ref={fileTreePanelRef}
onExpand={expandFileTree}
onCollapse={collapseFileTree}
minSize={10}
>
<FileTree />
</Panel>
<VerticalResizeHandle
hitAreaMargins={{ coarse: 0, fine: 0 }}
disabled={!canShowOutline}
/>
<Panel
className="file-outline-panel"
defaultSize={50}
id="ide-redesign-file-outline"
order={2}
collapsible
ref={outlinePanelRef}
onExpand={expandOutline}
onCollapse={collapseOutline}
minSize={10}
>
<OutlineContainer />
</Panel>
</PanelGroup>
)
}
export default FileTreeOutlinePanel
@@ -6,7 +6,7 @@ import FileTreeContext from './file-tree-context'
import FileTreeDraggablePreviewLayer from './file-tree-draggable-preview-layer'
import FileTreeFolderList from './file-tree-folder-list'
import FileTreeToolbar from './file-tree-toolbar'
import FileTreeToolbarNew from '@/features/ide-redesign/components/file-tree/file-tree-toolbar'
import FileTreeToolbarNew from '@/features/file-tree/components/file-tree-toolbar'
import FileTreeModalDelete from './modals/file-tree-modal-delete'
import FileTreeModalCreateFolder from './modals/file-tree-modal-create-folder'
import FileTreeModalError from './modals/file-tree-modal-error'
@@ -1,124 +1,30 @@
import { useTranslation } from 'react-i18next'
import * as eventTracking from '../../../infrastructure/event-tracking'
import { useFileTreeActionable } from '../contexts/file-tree-actionable'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
import OLTooltip from '@/shared/components/ol/ol-tooltip'
import MaterialIcon from '@/shared/components/material-icon'
import OLButtonToolbar from '@/shared/components/ol/ol-button-toolbar'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import React, { ElementType } from 'react'
const fileTreeToolbarComponents = importOverleafModules(
'fileTreeToolbarComponents'
) as { import: { default: ElementType }; path: string }[]
import React from 'react'
import useCollapsibleFileTree from '@/features/file-tree/hooks/use-collapsible-file-tree'
import FileTreeActionButtons from './file-tree-action-buttons'
function FileTreeToolbar() {
const { fileTreeReadOnly } = useFileTreeData()
const { t } = useTranslation()
if (fileTreeReadOnly) return null
const { fileTreeExpanded, toggleFileTreeExpanded } = useCollapsibleFileTree()
return (
<OLButtonToolbar
className="toolbar toolbar-filetree"
aria-label={t('project_files')}
>
<FileTreeToolbarLeft />
<FileTreeToolbarRight />
</OLButtonToolbar>
)
}
function FileTreeToolbarLeft() {
const { t } = useTranslation()
const {
canCreate,
startCreatingFolder,
startCreatingDocOrFile,
startUploadingDocOrFile,
} = useFileTreeActionable()
const createWithAnalytics = () => {
eventTracking.sendMB('new-file-click', { location: 'toolbar' })
startCreatingDocOrFile()
}
const uploadWithAnalytics = () => {
eventTracking.sendMB('upload-click', { location: 'toolbar' })
startUploadingDocOrFile()
}
if (!canCreate) return null
return (
<div className="toolbar-left">
<OLTooltip
id="new-file"
description={t('new_file')}
overlayProps={{ placement: 'bottom' }}
<div className="file-tree-toolbar">
<button
className="file-tree-expand-collapse-button"
onClick={toggleFileTreeExpanded}
aria-label={
fileTreeExpanded ? t('hide_file_tree') : t('show_file_tree')
}
>
<button className="btn" onClick={createWithAnalytics}>
<MaterialIcon type="description" accessibilityLabel={t('new_file')} />
</button>
</OLTooltip>
<OLTooltip
id="new-folder"
description={t('new_folder')}
overlayProps={{ placement: 'bottom' }}
>
<button className="btn" onClick={startCreatingFolder} tabIndex={-1}>
<MaterialIcon type="folder" accessibilityLabel={t('new_folder')} />
</button>
</OLTooltip>
<OLTooltip
id="upload"
description={t('upload')}
overlayProps={{ placement: 'bottom' }}
>
<button className="btn" onClick={uploadWithAnalytics} tabIndex={-1}>
<MaterialIcon type="upload" accessibilityLabel={t('upload')} />
</button>
</OLTooltip>
</div>
)
}
function FileTreeToolbarRight() {
const { t } = useTranslation()
const { canRename, canDelete, startRenaming, startDeleting } =
useFileTreeActionable()
return (
<div className="toolbar-right">
{fileTreeToolbarComponents.map(
({ import: { default: Component }, path }) => (
<Component key={path} />
)
)}
{canRename ? (
<OLTooltip
id="rename"
description={t('rename')}
overlayProps={{ placement: 'bottom' }}
>
<button className="btn" onClick={startRenaming} tabIndex={-1}>
<MaterialIcon type="edit" accessibilityLabel={t('rename')} />
</button>
</OLTooltip>
) : null}
{canDelete ? (
<OLTooltip
id="delete"
description={t('delete')}
overlayProps={{ placement: 'bottom' }}
>
<button className="btn" onClick={startDeleting} tabIndex={-1}>
<MaterialIcon type="delete" accessibilityLabel={t('delete')} />
</button>
</OLTooltip>
) : null}
<MaterialIcon
type={
fileTreeExpanded ? 'keyboard_arrow_down' : 'keyboard_arrow_right'
}
/>
<h4>{t('file_tree')}</h4>
</button>
<FileTreeActionButtons fileTreeExpanded={fileTreeExpanded} />
</div>
)
}
@@ -0,0 +1,24 @@
import { ImperativePanelHandle } from 'react-resizable-panels'
import { useRef } from 'react'
import useCollapsiblePanel from '@/features/ide-react/hooks/use-collapsible-panel'
import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
export default function useCollapsibleFileTree() {
const {
fileTreeExpanded,
toggleFileTreeExpanded,
expandFileTree,
collapseFileTree,
} = useFileTreeOpenContext()
const fileTreePanelRef = useRef<ImperativePanelHandle>(null)
useCollapsiblePanel(fileTreeExpanded, fileTreePanelRef)
return {
fileTreeExpanded,
fileTreePanelRef,
toggleFileTreeExpanded,
expandFileTree,
collapseFileTree,
}
}