From 3c5d2fc4e03656fdeb649f74bc9ae474a2bf0e80 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Sat, 4 Apr 2026 16:19:10 +0200 Subject: [PATCH] feat: configurable path replacements for ComfyUI Docker mount differences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added 'Path Replacements' section in the Projects tab. Each entry is a from→to string substitution applied to project_path output, fixing casing mismatches between Docker containers (e.g. Davinci → davinci). Stored in .editor_config.json under 'path_replacements'. Co-Authored-By: Claude Sonnet 4.6 --- api_routes.py | 6 ++++++ tab_projects_ng.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/api_routes.py b/api_routes.py index ad3da21..71a9916 100644 --- a/api_routes.py +++ b/api_routes.py @@ -62,6 +62,12 @@ def _get_project(name: str) -> dict[str, Any]: resolved = resolve_path_case_insensitive(folder_path) if resolved: folder_path = str(resolved) + # Apply configured path replacements (e.g. Docker mount casing differences) + config = load_config() + for rep in config.get("path_replacements", []): + src, dst = rep.get("from", ""), rep.get("to", "") + if src: + folder_path = folder_path.replace(src, dst) return {"name": proj["name"], "folder_path": folder_path, "description": proj.get("description", "")} diff --git a/tab_projects_ng.py b/tab_projects_ng.py index eca356f..38e8078 100644 --- a/tab_projects_ng.py +++ b/tab_projects_ng.py @@ -59,6 +59,48 @@ def render_projects_tab(state: AppState): ui.button('Create Project', icon='add', on_click=create_project).classes('w-full') + # --- Path replacements (for ComfyUI Docker path differences) --- + with ui.card().classes('w-full q-pa-md q-mb-md'): + ui.label('ComfyUI Path Replacements').classes('section-header') + ui.label('Applied to project_path output — use to fix Docker mount casing differences.' + ).classes('text-caption q-mb-sm') + + replacements: list[dict] = state.config.get('path_replacements', []) + + @ui.refreshable + def render_replacements(): + for idx, rep in enumerate(replacements): + with ui.row().classes('w-full items-center no-wrap q-gutter-xs'): + ui.input('From', value=rep.get('from', '')).classes('col').props( + 'outlined dense').on('update:model-value', + lambda e, i=idx: _update_replacement(i, 'from', e.args)) + ui.label('→').classes('text-caption') + ui.input('To', value=rep.get('to', '')).classes('col').props( + 'outlined dense').on('update:model-value', + lambda e, i=idx: _update_replacement(i, 'to', e.args)) + ui.button(icon='delete', on_click=lambda i=idx: _remove_replacement(i) + ).props('flat dense color=negative') + + def _update_replacement(idx, field, value): + replacements[idx][field] = value + state.config['path_replacements'] = replacements + save_config(state.current_dir, state.config.get('favorites', []), state.config) + + def _remove_replacement(idx): + replacements.pop(idx) + state.config['path_replacements'] = replacements + save_config(state.current_dir, state.config.get('favorites', []), state.config) + render_replacements.refresh() + + def _add_replacement(): + replacements.append({'from': '', 'to': ''}) + state.config['path_replacements'] = replacements + save_config(state.current_dir, state.config.get('favorites', []), state.config) + render_replacements.refresh() + + render_replacements() + ui.button('Add Replacement', icon='add', on_click=_add_replacement).props('flat dense') + # --- Active project indicator --- # Fetch once with file counts and reuse in render_project_list _cached_projects = state.db.list_projects_with_file_counts()