Freqtrade UI Not Installed
The web interface files are missing from your installation.
@@ -130,6 +211,12 @@Once installed, refresh this page to access the dashboard.
+diff --git a/.Jules/palette.md b/.Jules/palette.md index 5cd7c63db..63eb67c61 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -5,3 +5,11 @@ ## 2026-01-29 - CLI Feedback **Learning:** Silent long-running operations (like UI download) cause user uncertainty ("Did it hang?"). **Action:** Always implement a progress bar (e.g., via `rich`) for network operations > 2 seconds. + +## 2026-01-30 - Dead-end Fallback UX +**Learning:** Static error pages (like "UI not installed") act as dead ends, forcing users to manually refresh. This breaks the flow during setup. +**Action:** Always provide a "Check Again" or "Retry" action on state-dependent error pages to keep the user in the flow. + +## 2026-01-30 - Text-based Card UI +**Learning:** In constraint-heavy text interfaces (Telegram), dense Key:Value lists are hard to scan. Grouping related data (Header with ID, PnL with Emoji, Details below) mimics a "Card" UI pattern effectively. +**Action:** Use whitespace and grouping to create visual "cards" in text messages instead of flat lists. diff --git a/freqtrade/commands/deploy_ui.py b/freqtrade/commands/deploy_ui.py index a5afe06be..ca4252aae 100644 --- a/freqtrade/commands/deploy_ui.py +++ b/freqtrade/commands/deploy_ui.py @@ -80,6 +80,16 @@ def download_and_install_ui(dest_folder: Path, dl_url: str, version: str): with (dest_folder / ".uiversion").open("w") as f: f.write(version) + from freqtrade.loggers.rich_console import get_rich_console + + console = get_rich_console() + console.print() + console.print(f"[bold green]â FreqUI {version} installed successfully![/bold green]") + console.print(f"Installed to: [bold]{dest_folder}[/bold]") + console.print("\n[bold]Next steps:[/bold]") + console.print("1. Restart your bot to load the new UI.") + console.print("2. Access the dashboard in your browser.") + def get_ui_download_url(version: str | None, prerelease: bool) -> tuple[str, str]: base_url = "https://api.github.com/repos/freqtrade/frequi/" diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index 8fc592381..fb3a8ce69 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -39,7 +39,7 @@ def start_list_exchanges(args: dict[str, Any]) -> None: available_exchanges = [e for e in available_exchanges if e["valid"] is not False] title = f"Exchanges available for Freqtrade ({len(available_exchanges)} exchanges):" show_fut_reasons = args.get("list_exchanges_futures_options", False) - table = Table(title=title) + table = Table(title=title, row_styles=["", "dim"]) table.add_column("Exchange Name") table.add_column("Class Name") @@ -62,7 +62,7 @@ def start_list_exchanges(args: dict[str, Any]) -> None: continue name = Text(exchange["name"]) if exchange["supported"]: - name.append(" (Supported)", style="italic") + name.append(" â ", style="italic") name.stylize("green bold") classname = Text(exchange["classname"]) if exchange["is_alias"]: diff --git a/freqtrade/exchange/exchange_ws.py b/freqtrade/exchange/exchange_ws.py index cbc9772a3..b2611bc33 100644 --- a/freqtrade/exchange/exchange_ws.py +++ b/freqtrade/exchange/exchange_ws.py @@ -44,8 +44,26 @@ class ExchangeWS: def cleanup(self) -> None: logger.debug("Cleanup called - stopping") self._klines_watching.clear() - for task in self._background_tasks: - task.cancel() + # Cancel all tasks + for _ in range(3): + try: + tasks = list(self._background_tasks) + for task in tasks: + if hasattr(self, "_loop") and not self._loop.is_closed(): + self._loop.call_soon_threadsafe(task.cancel) + break + except RuntimeError: + # Set changed size during iteration + continue + + # Wait for tasks to cleanup + start = time.time() + while self._background_tasks: + time.sleep(0.01) + if time.time() - start > 5: + logger.warning("Timeout waiting for background tasks to cancel") + break + if hasattr(self, "_loop") and not self._loop.is_closed(): self.reset_connections() diff --git a/freqtrade/rpc/api_server/ui/fallback_file.html b/freqtrade/rpc/api_server/ui/fallback_file.html index 28b34f554..13bb122a5 100644 --- a/freqtrade/rpc/api_server/ui/fallback_file.html +++ b/freqtrade/rpc/api_server/ui/fallback_file.html @@ -15,6 +15,21 @@ --code-bg: #2d2d2d; --border-color: #333; --success-color: #4caf50; + --btn-bg: #2d2d2d; + --btn-hover: #3d3d3d; + } + [data-theme="light"] { + --bg-color: #f5f5f5; + --card-bg: #ffffff; + --text-color: #333333; + --text-muted: #666666; + --accent-color: #2196f3; + --accent-hover: #1976d2; + --code-bg: #f0f0f0; + --border-color: #ddd; + --success-color: #43a047; + --btn-bg: #e0e0e0; + --btn-hover: #d0d0d0; } * { box-sizing: border-box; @@ -44,7 +59,7 @@ h1 { font-size: 2rem; margin-bottom: 1rem; - color: #fff; + color: var(--text-color); font-weight: 700; } .subtitle { @@ -69,7 +84,7 @@ display: block; padding: 1.5rem; padding-right: 4rem; - color: #fff; + color: var(--text-color); overflow-x: auto; } .copy-btn { @@ -88,7 +103,7 @@ } .copy-btn:hover { background-color: rgba(255, 255, 255, 0.1); - color: #fff; + color: var(--text-color); } .copy-btn.copied { color: var(--success-color); @@ -114,9 +129,75 @@ .icon { margin-right: 0.4rem; } + + /* New Elements */ + .theme-toggle { + position: absolute; + top: 1rem; + right: 1rem; + background: var(--btn-bg); + border: 1px solid var(--border-color); + color: var(--text-color); + padding: 0.5rem; + border-radius: 50%; + cursor: pointer; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; + } + .theme-toggle:hover { + background: var(--btn-hover); + transform: scale(1.05); + } + .theme-toggle .icon { + margin-right: 0; + font-size: 1.2rem; + } + + .actions { + margin-top: 1.5rem; + } + + .refresh-btn { + background-color: var(--accent-color); + color: #fff; + border: none; + padding: 0.8rem 1.5rem; + font-size: 1rem; + border-radius: 6px; + cursor: pointer; + font-weight: 600; + transition: background-color 0.2s, transform 0.1s; + display: inline-flex; + align-items: center; + gap: 0.5rem; + } + .refresh-btn:hover { + background-color: var(--accent-hover); + transform: translateY(-1px); + } + .refresh-btn:active { + transform: translateY(0); + } + .refresh-btn:disabled { + opacity: 0.7; + cursor: wait; + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + }
+ +The web interface files are missing from your installation.
@@ -130,6 +211,12 @@Once installed, refresh this page to access the dashboard.
+