From 5a39a3a804f0d25ba2f9d7c9b6dc3989972ae80b Mon Sep 17 00:00:00 2001 From: Augustin Date: Tue, 28 Apr 2026 15:54:38 +0200 Subject: [PATCH] fix(ui): restore Shell.jsx to v0.9.0-beta.1 state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert terminal tab to its exact state at v0.9.0-beta.1, removing split panes, file editor integration, and agent sessions added in the v0.9.0 UI overhaul. 🤗 Generated with Crush Assisted-by: GLM-5.1 via Crush --- web/src/components/Shell.jsx | 375 +++-------------------------------- 1 file changed, 27 insertions(+), 348 deletions(-) diff --git a/web/src/components/Shell.jsx b/web/src/components/Shell.jsx index 9c6462b..206dce6 100644 --- a/web/src/components/Shell.jsx +++ b/web/src/components/Shell.jsx @@ -6,21 +6,18 @@ import { WebglAddon } from '@xterm/addon-webgl' import { SearchAddon } from '@xterm/addon-search' import { Unicode11Addon } from '@xterm/addon-unicode11' import { ImageAddon } from '@xterm/addon-image' -import { Plus, X, Monitor, Globe, ChevronDown, Pencil, Trash2, Search, Copy, Send, Eye, Bot, Columns, Rows, Maximize2 } from 'lucide-react' +import { Plus, X, Monitor, Globe, ChevronDown, Pencil, Trash2, Search, Copy, Send, Eye, Bot } from 'lucide-react' import '@xterm/xterm/css/xterm.css' import { useI18n } from '../i18n' import mermaid from 'mermaid' -import FileEditor from './FileEditor' mermaid.initialize({ startOnLoad: false, theme: 'dark', securityLevel: 'loose', fontFamily: 'var(--font-mono)' }) const AI_TAB_ID = 0 const MAX_TABS = 7 -const MAX_PANES = 4 const SHELL_MAX_TOKENS = 100000 const SHELL_AI_COMMANDS = ['/clear', '/help', '/model', '/model change'] const TABS_STORAGE_KEY = 'muyue_shell_tabs' -const LAYOUT_STORAGE_KEY = 'muyue_shell_layout' const TERMINAL_BUFFER_KEY = 'muyue_terminal_buffers' function renderContent(text) { @@ -480,107 +477,6 @@ export default function Shell({ api, isSudo }) { const _streamRafRef = useRef(null) const _streamPendingRef = useRef(null) - const [splitLayout, setSplitLayout] = useState(() => { - try { - const raw = localStorage.getItem(LAYOUT_STORAGE_KEY) - if (raw) return JSON.parse(raw) - } catch {} - return null - }) - const [editingFile, setEditingFile] = useState(null) - const [agentSessions, setAgentSessions] = useState([]) - - const paneCount = useMemo(() => { - const count = (node) => { - if (!node) return 1 - if (node.type === 'leaf') return 1 - return count(node.children?.[0]) + count(node.children?.[1]) - } - return count(splitLayout) - }, [splitLayout]) - - const splitPane = useCallback((direction) => { - if (paneCount >= MAX_PANES) return - const activeId = activeTabRef.current - setSplitLayout(prev => { - if (!prev) { - return { type: 'split', direction, ratio: 0.5, activePane: activeId, children: [ - { type: 'leaf', tabId: activeId }, - { type: 'leaf', tabId: null }, - ]} - } - const clone = JSON.parse(JSON.stringify(prev)) - const findAndSplit = (node) => { - if (node.type === 'leaf' && node.tabId === activeId) { - return { type: 'split', direction, ratio: 0.5, activePane: activeId, children: [ - { type: 'leaf', tabId: activeId }, - { type: 'leaf', tabId: null }, - ]} - } - if (node.children) { - return { ...node, children: node.children.map(findAndSplit) } - } - return node - } - return findAndSplit(clone) - }) - }, [paneCount]) - - const removePane = useCallback((tabId) => { - setSplitLayout(prev => { - if (!prev) return null - if (prev.type === 'leaf') return null - const clone = JSON.parse(JSON.stringify(prev)) - const removeFromTree = (node) => { - if (node.type !== 'split') return node - const left = node.children[0] - const right = node.children[1] - const leftIsTarget = left.type === 'leaf' && left.tabId === tabId - const rightIsTarget = right.type === 'leaf' && right.tabId === tabId - if (leftIsTarget) return removeFromTree(right) - if (rightIsTarget) return removeFromTree(left) - return { ...node, children: [removeFromTree(left), removeFromTree(right)] } - } - const result = removeFromTree(clone) - if (result.type === 'leaf' && result.tabId === null) return null - if (result.type === 'split' && (!result.children || result.children.length < 2)) return result.children?.[0] || null - return result - }) - }, []) - - const assignPaneTab = useCallback((paneLeaf, tabId) => { - setSplitLayout(prev => { - if (!prev) return prev - const clone = JSON.parse(JSON.stringify(prev)) - const assign = (node) => { - if (node === paneLeaf) return { ...node, tabId } - if (node.children) return { ...node, children: node.children.map(assign) } - return node - } - return assign(clone) - }) - }, []) - - useEffect(() => { - if (splitLayout) { - localStorage.setItem(LAYOUT_STORAGE_KEY, JSON.stringify(splitLayout)) - } else { - localStorage.removeItem(LAYOUT_STORAGE_KEY) - } - }, [splitLayout]) - - useEffect(() => { - api.getAgentSessions?.().then(d => { - setAgentSessions(d?.sessions || []) - }).catch(() => {}) - const iv = setInterval(() => { - api.getAgentSessions?.().then(d => { - setAgentSessions(d?.sessions || []) - }).catch(() => {}) - }, 5000) - return () => clearInterval(iv) - }, []) - const _flushStreamUpdate = useCallback(() => { _streamRafRef.current = null const pending = _streamPendingRef.current @@ -922,22 +818,6 @@ export default function Shell({ api, isSudo }) { return } - if (ctrl && e.shiftKey && e.key === 'D') { - const shellTab = document.querySelector('.shell-layout') - if (!shellTab || shellTab.closest('.tab-hidden')) return - e.preventDefault() - splitPane('vertical') - return - } - - if (ctrl && e.shiftKey && e.key === 'H') { - const shellTab = document.querySelector('.shell-layout') - if (!shellTab || shellTab.closest('.tab-hidden')) return - e.preventDefault() - splitPane('horizontal') - return - } - if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return if (!e.altKey && !(e.key === 'Tab' && e.shiftKey)) return @@ -1438,27 +1318,6 @@ Sois concret : cite les vraies versions, les vrais chemins, les vrais nombres. L {zoomLevel > 0 ? '+' : ''}{zoomLevel > 0 ? zoomLevel * 2 : zoomLevel * 2}px )} - {paneCount < MAX_PANES && ( - <> - - - - )} - {splitLayout && ( - - )} - {agentSessions.length > 0 && ( - - - {agentSessions.length} - - )} {tabs.length < MAX_TABS && (
-
- {editingFile && ( - setEditingFile(null)} /> - )} - {!editingFile && ( - splitLayout ? ( - + {showSearch && ( +
+ + handleSearchChange(e.target.value)} + onKeyDown={e => { + if (e.key === 'Enter') { e.shiftKey ? handleSearchPrev() : handleSearchNext() } + if (e.key === 'Escape') handleCloseSearch() + e.stopPropagation() + }} + placeholder="Rechercher..." /> - ) : ( - <> - {showSearch && ( -
- - handleSearchChange(e.target.value)} - onKeyDown={e => { - if (e.key === 'Enter') { e.shiftKey ? handleSearchPrev() : handleSearchNext() } - if (e.key === 'Escape') handleCloseSearch() - e.stopPropagation() - }} - placeholder="Rechercher..." - /> - - - -
- )} - {tabs.map(tab => ( -
- ))} - - ) + + + +
)} + {tabs.map(tab => ( +
+ ))}
@@ -1941,158 +1775,3 @@ const ShellAIMessage = memo(function ShellAIMessage({ msg, sendToTerminal, termi
) }) - -function SplitPaneRenderer({ node, tabs, activeTab, setActiveTab, showSearch, searchText, searchInputRef, handleSearchChange, handleSearchNext, handleSearchPrev, handleCloseSearch, removePane, onLayoutChange }) { - if (!node) return null - - if (node.type === 'leaf') { - const tabId = node.tabId - const tab = tabId ? tabs.find(t => t.id === tabId) : null - const isActive = activeTab === tabId - - if (!tab && tabId !== null) { - const fallbackTab = tabs[0] - if (fallbackTab) { - return ( -
setActiveTab(fallbackTab.id)}> -
-
- ) - } - } - - if (!tab) { - return ( -
-
- - - Select a tab for this pane - -
- {tabs.slice(0, 4).map(t => ( - - ))} -
-
-
- ) - } - - return ( -
setActiveTab(tabId)}> -
- {tab.name} - -
-
-
-
-
- ) - } - - if (node.type === 'split') { - const dir = node.direction === 'horizontal' ? 'row' : 'column' - - return ( -
-
- -
-
{ - e.preventDefault() - const parent = e.target.parentElement - const startX = e.clientX - const startY = e.clientY - const startRatio = node.ratio || 0.5 - const isVertical = node.direction === 'vertical' - const parentSize = isVertical ? parent.offsetWidth : parent.offsetHeight - - const onMouseMove = (me) => { - const delta = isVertical ? (me.clientX - startX) : (me.clientY - startY) - const newRatio = Math.max(0.15, Math.min(0.85, startRatio + delta / parentSize)) - onLayoutChange(prev => updateSplitRatio(prev, node, newRatio)) - } - - const onMouseUp = () => { - document.removeEventListener('mousemove', onMouseMove) - document.removeEventListener('mouseup', onMouseUp) - document.body.style.cursor = '' - document.body.style.userSelect = '' - } - - document.body.style.cursor = isVertical ? 'col-resize' : 'row-resize' - document.body.style.userSelect = 'none' - document.addEventListener('mousemove', onMouseMove) - document.addEventListener('mouseup', onMouseUp) - }} - /> -
- -
-
- ) - } - - return null -} - -function assignLeafTab(layout, leaf, tabId) { - if (!layout) return layout - if (layout === leaf) return { ...layout, tabId } - if (layout.children) { - return { - ...layout, - children: layout.children.map(c => assignLeafTab(c, leaf, tabId)), - } - } - return layout -} - -function updateSplitRatio(layout, targetNode, ratio) { - if (layout === targetNode) { - return { ...layout, ratio } - } - if (layout.children) { - return { - ...layout, - children: layout.children.map(c => updateSplitRatio(c, targetNode, ratio)), - } - } - return layout -}