diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index e22484be68..c7bbef0fd4 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -525,6 +525,7 @@
"file_or_folder_name_already_exists": "",
"file_outline": "",
"file_size": "",
+ "file_tree": "",
"files_cannot_include_invalid_characters": "",
"files_selected": "",
"fill_in_our_quick_survey": "",
@@ -668,6 +669,7 @@
"hide_configuration": "",
"hide_deleted_user": "",
"hide_document_preamble": "",
+ "hide_file_tree": "",
"hide_local_file_contents": "",
"hide_outline": "",
"history": "",
@@ -1462,6 +1464,7 @@
"show_all": "",
"show_all_projects": "",
"show_document_preamble": "",
+ "show_file_tree": "",
"show_hotkeys": "",
"show_in_code": "",
"show_in_pdf": "",
diff --git a/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2 b/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2
index b0b89fa332..fb158e5ea1 100644
Binary files a/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2 and b/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2 differ
diff --git a/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs b/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs
index 7ed8321b44..1c551ebdbd 100644
--- a/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs
+++ b/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs
@@ -1,20 +1,24 @@
// @ts-check
// Make sure to run the build-unfilled.mjs script after updating this list
// to update the font file with the latest icons.
+// You may need to hard reload your browser window to see the changes.
export default /** @type {const} */ ([
'book_5',
'code',
+ 'create_new_folder',
'description',
'forum',
'help',
'image',
'info',
'integration_instructions',
+ 'note_add',
'picture_as_pdf',
'rate_review',
'report',
'settings',
'table_chart',
+ 'upload_file',
'web_asset',
])
diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx
index 9377faad7f..24db6255f9 100644
--- a/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx
+++ b/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx
@@ -6,6 +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-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'
@@ -18,6 +19,7 @@ import FileTreeInner from './file-tree-inner'
import { useDragLayer } from 'react-dnd'
import classnames from 'classnames'
import { pathInFolder } from '@/features/file-tree/util/path'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
const FileTreeRoot = React.memo<{
onSelect: () => void
@@ -41,6 +43,7 @@ const FileTreeRoot = React.memo<{
const { _id: projectId } = useProjectContext()
const { fileTreeData } = useFileTreeData()
const isReady = Boolean(projectId && fileTreeData)
+ const newEditor = useFeatureFlag('editor-redesign')
useEffect(() => {
if (fileTreeContainer) {
@@ -97,7 +100,7 @@ const FileTreeRoot = React.memo<{
fileTreeContainer={fileTreeContainer}
>
{isConnected ? null :
}
-
+ {newEditor ? : }
diff --git a/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx b/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx
index b72a061b67..eec94f5d99 100644
--- a/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx
+++ b/services/web/frontend/js/features/ide-react/context/file-tree-open-context.tsx
@@ -30,6 +30,8 @@ const FileTreeOpenContext = createContext<
handleFileTreeInit: () => void
handleFileTreeSelect: (selectedEntities: FileTreeFindResult[]) => void
handleFileTreeDelete: (entity: FileTreeFindResult) => void
+ fileTreeExpanded: boolean
+ toggleFileTreeExpanded: () => void
}
| undefined
>(undefined)
@@ -46,6 +48,13 @@ export const FileTreeOpenProvider: FC = ({ children }) => {
const [selectedEntityCount, setSelectedEntityCount] = useState(0)
const [fileTreeReady, setFileTreeReady] = useState(false)
+ // NOTE: Only used in editor redesign
+ const [fileTreeExpanded, setFileTreeExpanded] = useState(true)
+
+ const toggleFileTreeExpanded = useCallback(() => {
+ setFileTreeExpanded(prev => !prev)
+ }, [])
+
const handleFileTreeInit = useCallback(() => {
setFileTreeReady(true)
}, [])
@@ -129,6 +138,8 @@ export const FileTreeOpenProvider: FC = ({ children }) => {
handleFileTreeInit,
handleFileTreeSelect,
handleFileTreeDelete,
+ fileTreeExpanded,
+ toggleFileTreeExpanded,
}
}, [
handleFileTreeDelete,
@@ -136,6 +147,8 @@ export const FileTreeOpenProvider: FC = ({ children }) => {
handleFileTreeSelect,
openEntity,
selectedEntityCount,
+ fileTreeExpanded,
+ toggleFileTreeExpanded,
])
return (
diff --git a/services/web/frontend/js/features/ide-redesign/components/file-tree-outline-panel.tsx b/services/web/frontend/js/features/ide-redesign/components/file-tree-outline-panel.tsx
index f67619bc3c..bf69d40e59 100644
--- a/services/web/frontend/js/features/ide-redesign/components/file-tree-outline-panel.tsx
+++ b/services/web/frontend/js/features/ide-redesign/components/file-tree-outline-panel.tsx
@@ -3,35 +3,42 @@ 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 '../hooks/use-collapsible-file-tree'
+import classNames from 'classnames'
function FileTreeOutlinePanel() {
const { outlineEnabled, outlinePanelRef } = useOutlinePane()
+ const { fileTreeExpanded, fileTreePanelRef } = useCollapsibleFileTree()
return (
diff --git a/services/web/frontend/js/features/ide-redesign/components/file-tree-toolbar.tsx b/services/web/frontend/js/features/ide-redesign/components/file-tree-toolbar.tsx
new file mode 100644
index 0000000000..cdc28ef4b7
--- /dev/null
+++ b/services/web/frontend/js/features/ide-redesign/components/file-tree-toolbar.tsx
@@ -0,0 +1,112 @@
+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 OLTooltip from '@/features/ui/components/ol/ol-tooltip'
+import MaterialIcon, {
+ AvailableUnfilledIcon,
+} from '@/shared/components/material-icon'
+import React from 'react'
+import useCollapsibleFileTree from '../hooks/use-collapsible-file-tree'
+
+function FileTreeToolbar() {
+ const { t } = useTranslation()
+ const { fileTreeExpanded, toggleFileTreeExpanded } = useCollapsibleFileTree()
+
+ return (
+
+
+
+
+ )
+}
+
+function FileTreeActionButtons() {
+ const { t } = useTranslation()
+ const { fileTreeReadOnly } = useFileTreeData()
+
+ const {
+ canCreate,
+ startCreatingFolder,
+ startCreatingDocOrFile,
+ startUploadingDocOrFile,
+ } = useFileTreeActionable()
+
+ if (!canCreate || fileTreeReadOnly) return null
+
+ const createWithAnalytics = () => {
+ eventTracking.sendMB('new-file-click', { location: 'toolbar' })
+ startCreatingDocOrFile()
+ }
+
+ const uploadWithAnalytics = () => {
+ eventTracking.sendMB('upload-click', { location: 'toolbar' })
+ startUploadingDocOrFile()
+ }
+
+ return (
+
+
+
+
+
+ )
+}
+
+function FileTreeActionButton({
+ id,
+ description,
+ onClick,
+ iconType,
+}: {
+ id: string
+ description: string
+ onClick: () => void
+ iconType: AvailableUnfilledIcon
+}) {
+ return (
+
+
+
+ )
+}
+
+export default FileTreeToolbar
diff --git a/services/web/frontend/js/features/ide-redesign/hooks/use-collapsible-file-tree.tsx b/services/web/frontend/js/features/ide-redesign/hooks/use-collapsible-file-tree.tsx
new file mode 100644
index 0000000000..89b4d252a1
--- /dev/null
+++ b/services/web/frontend/js/features/ide-redesign/hooks/use-collapsible-file-tree.tsx
@@ -0,0 +1,12 @@
+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 } = useFileTreeOpenContext()
+ const fileTreePanelRef = useRef(null)
+ useCollapsiblePanel(fileTreeExpanded, fileTreePanelRef)
+
+ return { fileTreeExpanded, fileTreePanelRef, toggleFileTreeExpanded }
+}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/file-tree.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/file-tree.scss
index 5368b69dc8..a0d0ab8c83 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/file-tree.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/file-tree.scss
@@ -35,6 +35,63 @@
--file-tree-item-dragging-preview-bg: #{rgb($bg-light-secondary, 0.6)};
--file-tree-item-dragging-preview-colour: #{rgb($content-primary, 0.6)};
+ .file-tree-outline-panel-group {
+ background-color: var(--file-tree-bg);
+ }
+
+ .file-tree-toolbar {
+ display: flex;
+ justify-content: space-between;
+ height: 28px;
+ margin: var(--spacing-02);
+ }
+
+ .file-tree-panel {
+ min-height: 36px;
+ }
+
+ .file-tree-panel-collapsed {
+ max-height: 36px;
+ }
+
+ .file-tree-expand-collapse-button {
+ border-radius: var(--border-radius-base);
+ color: var(--outline-content-color);
+ display: flex;
+ align-items: center;
+ background-color: transparent;
+ border: 0;
+ padding: 0 var(--spacing-02);
+ flex-grow: 1;
+
+ &:hover {
+ background-color: var(--file-tree-item-hover-bg);
+ }
+
+ h4 {
+ font-size: var(--font-size-02);
+ margin: 0;
+ font-weight: normal;
+ }
+ }
+
+ .file-tree-toolbar-action-buttons {
+ display: flex;
+ }
+
+ .file-tree-toolbar-action-button {
+ padding: var(--spacing-02);
+ border-radius: var(--border-radius-full);
+
+ &:hover {
+ background-color: var(--file-tree-item-hover-bg);
+ }
+
+ .material-symbols {
+ font-size: 16px;
+ }
+ }
+
.file-tree {
background-color: var(--file-tree-bg);
}
@@ -47,6 +104,7 @@
border-left: 1px solid
color-mix(in srgb, var(--border-primary) 24%, transparent);
margin-left: 14px !important;
+ margin-top: 0;
&.file-tree-list {
border-left: none;
diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/outline.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/outline.scss
index c716cd426e..5e240cb19c 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/outline.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/outline.scss
@@ -37,6 +37,10 @@
);
--outline-container-color-bg: var(--bg-light-primary);
+ .file-outline-panel {
+ min-height: 36px;
+ }
+
.outline-pane {
padding: 4px;
}
diff --git a/services/web/locales/en.json b/services/web/locales/en.json
index 9fc78cdb23..ed609bc70b 100644
--- a/services/web/locales/en.json
+++ b/services/web/locales/en.json
@@ -701,6 +701,7 @@
"file_outline": "File outline",
"file_size": "File size",
"file_too_large": "File too large",
+ "file_tree": "File tree",
"files_cannot_include_invalid_characters": "File name is empty or contains invalid characters",
"files_selected": "files selected.",
"fill_in_our_quick_survey": "Fill in our quick survey.",
@@ -892,6 +893,7 @@
"hide_configuration": "Hide configuration",
"hide_deleted_user": "Hide deleted users",
"hide_document_preamble": "Hide document preamble",
+ "hide_file_tree": "Hide file tree",
"hide_local_file_contents": "Hide Local File Contents",
"hide_outline": "Hide File outline",
"history": "History",
@@ -1933,6 +1935,7 @@
"show_all": "show all",
"show_all_projects": "Show all projects",
"show_document_preamble": "Show document preamble",
+ "show_file_tree": "Show file tree",
"show_hotkeys": "Show Hotkeys",
"show_in_code": "Show in code",
"show_in_pdf": "Show in PDF",