mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-26 15:34:48 -06:00
feat: auto-refresh FileNav on write_file, replace_file_content, and run_command
Backend emits terminal events for write_file, replace_file_content, and run_command. Frontend showFileNavDir subscriber uses startsWith path matching to smartly refresh only when the event is relevant: - write_file/replace_file_content: refresh if path is in current view - run_command: always refresh (uses root '/' which matches everything) - Also adds copy-to-clipboard button and code preview full-height fix
This commit is contained in:
@@ -1053,16 +1053,16 @@ async def terminal_event_handler(
|
||||
"""Emit terminal:* events for Open Terminal tools.
|
||||
|
||||
- display_file → emits 'terminal:display_file' to open the file preview.
|
||||
- write_file → emits 'terminal:write_file' to silently refresh the file browser.
|
||||
- write_file / replace_file_content → emits 'terminal:write_file' to refresh.
|
||||
- run_command → emits 'terminal:run_command' with cwd to refresh if relevant.
|
||||
"""
|
||||
if not event_emitter:
|
||||
return
|
||||
|
||||
path = tool_function_params.get("path", "")
|
||||
if not path:
|
||||
return
|
||||
|
||||
if tool_function_name == "display_file":
|
||||
path = tool_function_params.get("path", "")
|
||||
if not path:
|
||||
return
|
||||
# Only emit if the file actually exists
|
||||
parsed = tool_result
|
||||
if isinstance(parsed, str):
|
||||
@@ -1079,13 +1079,23 @@ async def terminal_event_handler(
|
||||
"data": {"path": path},
|
||||
}
|
||||
)
|
||||
elif tool_function_name == "write_file":
|
||||
elif tool_function_name in ("write_file", "replace_file_content"):
|
||||
path = tool_function_params.get("path", "")
|
||||
if not path:
|
||||
return
|
||||
await event_emitter(
|
||||
{
|
||||
"type": f"terminal:{tool_function_name}",
|
||||
"data": {"path": path},
|
||||
}
|
||||
)
|
||||
elif tool_function_name == "run_command":
|
||||
await event_emitter(
|
||||
{
|
||||
"type": "terminal:run_command",
|
||||
"data": {},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def chat_completion_tools_handler(
|
||||
|
||||
@@ -406,11 +406,14 @@
|
||||
};
|
||||
|
||||
const terminalEventHandler = (type: string, data: any) => {
|
||||
if (!data?.path) return;
|
||||
if (type === 'terminal:display_file') {
|
||||
if (!data?.path) return;
|
||||
displayFileHandler(data.path, { showControls, showFileNavPath });
|
||||
} else if (type === 'terminal:write_file') {
|
||||
} else if (type === 'terminal:write_file' || type === 'terminal:replace_file_content') {
|
||||
if (!data?.path) return;
|
||||
showFileNavDir.set(data.path);
|
||||
} else if (type === 'terminal:run_command') {
|
||||
showFileNavDir.set('/');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -511,13 +511,15 @@
|
||||
const lastSlash = filePath.lastIndexOf('/');
|
||||
const dir = lastSlash > 0 ? filePath.substring(0, lastSlash + 1) : '/';
|
||||
|
||||
if (dir === currentPath) {
|
||||
await loadDir(currentPath);
|
||||
}
|
||||
if (filePath === selectedFile) {
|
||||
const fileName = filePath.substring(lastSlash + 1);
|
||||
const entry = entries.find((e) => e.name === fileName);
|
||||
if (entry) await openEntry(entry);
|
||||
if (selectedFile) {
|
||||
if (selectedFile === filePath || currentPath.startsWith(dir)) {
|
||||
const fileName = selectedFile.split('/').pop() ?? '';
|
||||
await openEntry({ name: fileName, type: 'file', size: 0 });
|
||||
}
|
||||
} else {
|
||||
if (currentPath.startsWith(dir) || dir.startsWith(currentPath)) {
|
||||
await loadDir(currentPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -549,6 +551,8 @@
|
||||
document.addEventListener('visibilitychange', onVisibilityChange);
|
||||
|
||||
return () => {
|
||||
unsubFileNav();
|
||||
unsubFileNavDir();
|
||||
window.removeEventListener('keydown', onKeyDown);
|
||||
window.removeEventListener('keyup', onKeyUp);
|
||||
window.removeEventListener('blur', onBlur);
|
||||
|
||||
Reference in New Issue
Block a user