Add Help menu and contextual tooltips to GUI
- Add Help menu with quick guides: Getting Started, Create Tool, Install Tools, Publish Tools, Keyboard Shortcuts, About - F1 shortcut opens Getting Started guide - Add tooltips to Tool Builder section headings (Arguments, Steps, Output Template) that appear on hover over the label text - Add tooltips to Registry page controls (search, filters, pagination) - Enhance sidebar tooltips with keyboard shortcuts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
3f259449d4
commit
9baddeef18
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -35,6 +35,18 @@ All notable changes to CmdForge will be documented in this file.
|
||||||
- Automatically clears invalid/revoked tokens
|
- Automatically clears invalid/revoked tokens
|
||||||
- Shows status bar message when connection is cleared
|
- Shows status bar message when connection is cleared
|
||||||
- Prevents confusing errors when trying to publish with stale credentials
|
- Prevents confusing errors when trying to publish with stale credentials
|
||||||
|
- **Help menu and quick guides**: Added Help menu with documentation guides
|
||||||
|
- Getting Started guide with quick start steps and keyboard shortcuts
|
||||||
|
- How to Create a Tool guide with step-by-step instructions
|
||||||
|
- How to Install Tools guide for registry browsing
|
||||||
|
- How to Publish Tools guide for sharing tools
|
||||||
|
- Keyboard Shortcuts reference
|
||||||
|
- About CmdForge dialog
|
||||||
|
- F1 shortcut opens Getting Started guide
|
||||||
|
- **Enhanced tooltips**: Added contextual tooltips throughout the GUI
|
||||||
|
- Section headings in Tool Builder (Arguments, Steps, Output Template)
|
||||||
|
- Registry page controls (search, filters, pagination, install)
|
||||||
|
- Sidebar navigation items with keyboard shortcuts
|
||||||
|
|
||||||
#### CLI Features
|
#### CLI Features
|
||||||
- `cmdforge config disconnect` - Clear registry token from local configuration
|
- `cmdforge config disconnect` - Clear registry token from local configuration
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,363 @@
|
||||||
|
"""Help dialogs for CmdForge GUI."""
|
||||||
|
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
|
||||||
|
QTextBrowser
|
||||||
|
)
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
|
||||||
|
|
||||||
|
# Help content for quick guides
|
||||||
|
HELP_CONTENT = {
|
||||||
|
"getting_started": {
|
||||||
|
"title": "Getting Started with CmdForge",
|
||||||
|
"content": """
|
||||||
|
<h3>Welcome to CmdForge!</h3>
|
||||||
|
<p>CmdForge lets you create AI-powered command-line tools that work like any Unix command.</p>
|
||||||
|
|
||||||
|
<h4>Quick Start Steps:</h4>
|
||||||
|
<ol>
|
||||||
|
<li><strong>Configure a Provider</strong> - Go to <em>Providers</em> in the sidebar and add an AI backend (like Claude or GPT). This is required before running AI tools.</li>
|
||||||
|
<li><strong>Browse the Registry</strong> - Check out the <em>Registry</em> to discover tools shared by the community.</li>
|
||||||
|
<li><strong>Install Tools</strong> - Click on any tool and hit <em>Install</em> to add it to your system.</li>
|
||||||
|
<li><strong>Create Your Own</strong> - Use the <em>Tool Builder</em> to create custom AI-powered commands.</li>
|
||||||
|
<li><strong>Use in Terminal</strong> - Run your tools like any command: <code>my-tool < input.txt</code></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h4>Key Concepts:</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Steps</strong> - Tools are made of steps: Prompt (AI call), Code (Python), or Tool (chain another tool)</li>
|
||||||
|
<li><strong>Variables</strong> - Use <code>{variable}</code> to pass data between steps</li>
|
||||||
|
<li><strong>Arguments</strong> - Add flags like <code>--format</code> that users can set when running the tool</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Keyboard Shortcuts:</h4>
|
||||||
|
<table>
|
||||||
|
<tr><td><code>Ctrl+N</code></td><td>Create new tool</td></tr>
|
||||||
|
<tr><td><code>Ctrl+S</code></td><td>Save current tool</td></tr>
|
||||||
|
<tr><td><code>Ctrl+R</code></td><td>Refresh current page</td></tr>
|
||||||
|
<tr><td><code>Ctrl+1-4</code></td><td>Navigate to pages</td></tr>
|
||||||
|
<tr><td><code>Ctrl+Q</code></td><td>Quit</td></tr>
|
||||||
|
<tr><td><code>Escape</code></td><td>Close tool builder</td></tr>
|
||||||
|
</table>
|
||||||
|
"""
|
||||||
|
},
|
||||||
|
"create_tool": {
|
||||||
|
"title": "How to Create a Tool",
|
||||||
|
"content": """
|
||||||
|
<h3>Creating a New Tool</h3>
|
||||||
|
|
||||||
|
<h4>Step 1: Start the Tool Builder</h4>
|
||||||
|
<p>Click <em>Create Tool</em> on the Welcome page, or press <code>Ctrl+N</code> from anywhere.</p>
|
||||||
|
|
||||||
|
<h4>Step 2: Fill in Basic Info</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Name</strong> - Use lowercase letters, numbers, and hyphens (e.g., <code>summarize-text</code>)</li>
|
||||||
|
<li><strong>Description</strong> - Brief explanation shown in listings</li>
|
||||||
|
<li><strong>Category</strong> - Pick from Text, Developer, Data, or add your own</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 3: Add Arguments (Optional)</h4>
|
||||||
|
<p>Arguments let users customize tool behavior:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Flag</strong> - The command-line flag (e.g., <code>--max</code>)</li>
|
||||||
|
<li><strong>Variable</strong> - Name to use in templates (e.g., <code>max</code>)</li>
|
||||||
|
<li><strong>Default</strong> - Value when flag isn't provided</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 4: Add Steps</h4>
|
||||||
|
<p>Steps define what your tool does:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Prompt Step</strong> - Calls an AI provider with your template. Use <code>{input}</code> for stdin content.</li>
|
||||||
|
<li><strong>Code Step</strong> - Runs Python code. Variables are available directly (e.g., <code>input</code>, <code>response</code>).</li>
|
||||||
|
<li><strong>Tool Step</strong> - Calls another CmdForge tool, enabling composition.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 5: Set Output Template</h4>
|
||||||
|
<p>The output template defines what your tool prints. Use <code>{variable}</code> to include step outputs.</p>
|
||||||
|
<p>Example: <code>{response}</code> prints the last AI response.</p>
|
||||||
|
|
||||||
|
<h4>Step 6: Save</h4>
|
||||||
|
<p>Press <code>Ctrl+S</code> or click <em>Save</em>. Your tool is now available as a command!</p>
|
||||||
|
|
||||||
|
<h4>Example: Simple Summarizer</h4>
|
||||||
|
<pre>
|
||||||
|
Name: summarize
|
||||||
|
Steps:
|
||||||
|
1. Prompt [claude] -> response
|
||||||
|
"Summarize this text: {input}"
|
||||||
|
Output: {response}
|
||||||
|
</pre>
|
||||||
|
<p>Run it: <code>echo "Long text..." | summarize</code></p>
|
||||||
|
"""
|
||||||
|
},
|
||||||
|
"install_tools": {
|
||||||
|
"title": "How to Install Tools",
|
||||||
|
"content": """
|
||||||
|
<h3>Installing Tools from the Registry</h3>
|
||||||
|
|
||||||
|
<h4>Step 1: Open the Registry</h4>
|
||||||
|
<p>Click <em>Registry</em> in the sidebar to browse community tools.</p>
|
||||||
|
|
||||||
|
<h4>Step 2: Find a Tool</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Search</strong> - Type keywords in the search box</li>
|
||||||
|
<li><strong>Filter by Category</strong> - Use the dropdown to narrow results</li>
|
||||||
|
<li><strong>Sort</strong> - Order by popularity, newest, or name</li>
|
||||||
|
<li><strong>Tags</strong> - Click tags on tools to filter by tag</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 3: Review Tool Details</h4>
|
||||||
|
<p>Click on a tool to see:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Description and usage information</li>
|
||||||
|
<li>Rating and download count</li>
|
||||||
|
<li>Publisher reputation</li>
|
||||||
|
<li>Available versions</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 4: Install</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Select a version (or use <em>Latest</em>)</li>
|
||||||
|
<li>Click <em>Install</em></li>
|
||||||
|
<li>Wait for confirmation</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 5: Use the Tool</h4>
|
||||||
|
<p>Installed tools are available immediately in your terminal:</p>
|
||||||
|
<pre>
|
||||||
|
echo "text" | tool-name
|
||||||
|
cat file.txt | tool-name --flag value
|
||||||
|
tool-name --help
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h4>Updates</h4>
|
||||||
|
<p>Tools with available updates show a green arrow (<span style="color: #48bb78;">↑</span>) in the list. Click <em>Update</em> to get the latest version.</p>
|
||||||
|
|
||||||
|
<h4>Managing Installed Tools</h4>
|
||||||
|
<p>Go to <em>Tools</em> in the sidebar to see all your installed tools, edit them, or delete ones you no longer need.</p>
|
||||||
|
"""
|
||||||
|
},
|
||||||
|
"publish_tools": {
|
||||||
|
"title": "How to Publish Tools",
|
||||||
|
"content": """
|
||||||
|
<h3>Publishing Your Tools</h3>
|
||||||
|
|
||||||
|
<h4>Prerequisites</h4>
|
||||||
|
<ul>
|
||||||
|
<li>A tool you've created and tested</li>
|
||||||
|
<li>A registry account (sign up at cmdforge.brrd.tech)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 1: Connect Your Account</h4>
|
||||||
|
<ol>
|
||||||
|
<li>Go to the <em>Providers</em> page</li>
|
||||||
|
<li>Click <em>Connect to Registry</em></li>
|
||||||
|
<li>Log in or register</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h4>Step 2: Prepare Your Tool</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Give it a clear, descriptive name</li>
|
||||||
|
<li>Write a helpful description</li>
|
||||||
|
<li>Choose the right category</li>
|
||||||
|
<li>Test it thoroughly</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Step 3: Publish</h4>
|
||||||
|
<ol>
|
||||||
|
<li>Go to the <em>Tools</em> page</li>
|
||||||
|
<li>Select the tool you want to publish</li>
|
||||||
|
<li>Click <em>Publish</em></li>
|
||||||
|
<li>Add tags to help users find it</li>
|
||||||
|
<li>Set the initial version number</li>
|
||||||
|
<li>Click <em>Submit</em></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h4>Versioning</h4>
|
||||||
|
<p>When you update a published tool:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Patch</strong> (1.0.0 → 1.0.1) - Bug fixes</li>
|
||||||
|
<li><strong>Minor</strong> (1.0.0 → 1.1.0) - New features, backward compatible</li>
|
||||||
|
<li><strong>Major</strong> (1.0.0 → 2.0.0) - Breaking changes</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Best Practices</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Write clear descriptions and examples</li>
|
||||||
|
<li>Use semantic versioning</li>
|
||||||
|
<li>Test before publishing updates</li>
|
||||||
|
<li>Respond to user feedback</li>
|
||||||
|
</ul>
|
||||||
|
"""
|
||||||
|
},
|
||||||
|
"keyboard_shortcuts": {
|
||||||
|
"title": "Keyboard Shortcuts",
|
||||||
|
"content": """
|
||||||
|
<h3>Keyboard Shortcuts</h3>
|
||||||
|
|
||||||
|
<h4>Global</h4>
|
||||||
|
<table style="width: 100%;">
|
||||||
|
<tr><td style="width: 40%;"><code>Ctrl+N</code></td><td>Create new tool</td></tr>
|
||||||
|
<tr><td><code>Ctrl+S</code></td><td>Save current tool</td></tr>
|
||||||
|
<tr><td><code>Ctrl+R</code></td><td>Refresh current page</td></tr>
|
||||||
|
<tr><td><code>Ctrl+Q</code></td><td>Quit application</td></tr>
|
||||||
|
<tr><td><code>F1</code></td><td>Show help</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Navigation</h4>
|
||||||
|
<table style="width: 100%;">
|
||||||
|
<tr><td style="width: 40%;"><code>Ctrl+1</code></td><td>Go to Welcome page</td></tr>
|
||||||
|
<tr><td><code>Ctrl+2</code></td><td>Go to Tools page</td></tr>
|
||||||
|
<tr><td><code>Ctrl+3</code></td><td>Go to Registry page</td></tr>
|
||||||
|
<tr><td><code>Ctrl+4</code></td><td>Go to Providers page</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Tool Builder</h4>
|
||||||
|
<table style="width: 100%;">
|
||||||
|
<tr><td style="width: 40%;"><code>Escape</code></td><td>Close builder / cancel</td></tr>
|
||||||
|
<tr><td><code>Ctrl+S</code></td><td>Save tool</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Lists and Tables</h4>
|
||||||
|
<table style="width: 100%;">
|
||||||
|
<tr><td style="width: 40%;"><code>Double-click</code></td><td>Edit selected item</td></tr>
|
||||||
|
<tr><td><code>Drag & Drop</code></td><td>Reorder steps</td></tr>
|
||||||
|
</table>
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class QuickGuideDialog(QDialog):
|
||||||
|
"""Dialog showing a quick guide on a topic."""
|
||||||
|
|
||||||
|
def __init__(self, guide_key: str, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
guide = HELP_CONTENT.get(guide_key, {})
|
||||||
|
self.setWindowTitle(guide.get("title", "Help"))
|
||||||
|
self.setMinimumSize(550, 450)
|
||||||
|
self.resize(600, 500)
|
||||||
|
self.setModal(True)
|
||||||
|
|
||||||
|
self._setup_ui(guide)
|
||||||
|
|
||||||
|
def _setup_ui(self, guide: dict):
|
||||||
|
"""Set up the dialog UI."""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(24, 24, 24, 24)
|
||||||
|
layout.setSpacing(16)
|
||||||
|
|
||||||
|
# Content browser with styled HTML
|
||||||
|
browser = QTextBrowser()
|
||||||
|
browser.setOpenExternalLinks(True)
|
||||||
|
browser.setStyleSheet("""
|
||||||
|
QTextBrowser {
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Build styled content
|
||||||
|
content = f"""
|
||||||
|
<style>
|
||||||
|
h3 {{ color: #2d3748; margin-bottom: 8px; }}
|
||||||
|
h4 {{ color: #4a5568; margin-top: 16px; margin-bottom: 8px; }}
|
||||||
|
p {{ color: #4a5568; margin-bottom: 8px; line-height: 1.5; }}
|
||||||
|
ul, ol {{ color: #4a5568; margin-bottom: 8px; }}
|
||||||
|
li {{ margin-bottom: 4px; }}
|
||||||
|
code {{ background: #edf2f7; padding: 2px 6px; border-radius: 3px; font-family: monospace; }}
|
||||||
|
pre {{ background: #edf2f7; padding: 12px; border-radius: 6px; font-family: monospace; overflow-x: auto; }}
|
||||||
|
table {{ border-collapse: collapse; margin: 8px 0; }}
|
||||||
|
td {{ padding: 6px 12px; }}
|
||||||
|
em {{ color: #667eea; }}
|
||||||
|
</style>
|
||||||
|
{guide.get("content", "")}
|
||||||
|
"""
|
||||||
|
browser.setHtml(content)
|
||||||
|
layout.addWidget(browser, 1)
|
||||||
|
|
||||||
|
# Close button
|
||||||
|
btn_layout = QHBoxLayout()
|
||||||
|
btn_layout.addStretch()
|
||||||
|
|
||||||
|
btn_close = QPushButton("Close")
|
||||||
|
btn_close.setMinimumWidth(100)
|
||||||
|
btn_close.clicked.connect(self.accept)
|
||||||
|
btn_layout.addWidget(btn_close)
|
||||||
|
|
||||||
|
layout.addLayout(btn_layout)
|
||||||
|
|
||||||
|
|
||||||
|
class AboutDialog(QDialog):
|
||||||
|
"""About CmdForge dialog."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setWindowTitle("About CmdForge")
|
||||||
|
self.setFixedSize(400, 300)
|
||||||
|
self.setModal(True)
|
||||||
|
self._setup_ui()
|
||||||
|
|
||||||
|
def _setup_ui(self):
|
||||||
|
"""Set up the dialog UI."""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(32, 32, 32, 32)
|
||||||
|
layout.setSpacing(16)
|
||||||
|
|
||||||
|
# Logo/title
|
||||||
|
title = QLabel("CmdForge")
|
||||||
|
title.setStyleSheet("""
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #667eea;
|
||||||
|
""")
|
||||||
|
title.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(title)
|
||||||
|
|
||||||
|
# Tagline
|
||||||
|
tagline = QLabel("AI-Powered CLI Tool Builder")
|
||||||
|
tagline.setStyleSheet("font-size: 14px; color: #718096;")
|
||||||
|
tagline.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(tagline)
|
||||||
|
|
||||||
|
layout.addSpacing(16)
|
||||||
|
|
||||||
|
# Version info
|
||||||
|
try:
|
||||||
|
from cmdforge import __version__
|
||||||
|
version = __version__
|
||||||
|
except ImportError:
|
||||||
|
version = "unknown"
|
||||||
|
|
||||||
|
version_label = QLabel(f"Version {version}")
|
||||||
|
version_label.setStyleSheet("color: #4a5568;")
|
||||||
|
version_label.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(version_label)
|
||||||
|
|
||||||
|
# Description
|
||||||
|
desc = QLabel(
|
||||||
|
"Create custom terminal commands that call AI providers,\n"
|
||||||
|
"chain prompts with Python code, and use them like\n"
|
||||||
|
"any Unix pipe command."
|
||||||
|
)
|
||||||
|
desc.setStyleSheet("color: #718096; font-size: 12px;")
|
||||||
|
desc.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(desc)
|
||||||
|
|
||||||
|
layout.addStretch()
|
||||||
|
|
||||||
|
# Links
|
||||||
|
links = QLabel(
|
||||||
|
'<a href="https://cmdforge.brrd.tech" style="color: #667eea;">Website</a>'
|
||||||
|
)
|
||||||
|
links.setOpenExternalLinks(True)
|
||||||
|
links.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(links)
|
||||||
|
|
||||||
|
# Close button
|
||||||
|
btn_close = QPushButton("Close")
|
||||||
|
btn_close.clicked.connect(self.accept)
|
||||||
|
layout.addWidget(btn_close)
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QMainWindow, QWidget, QHBoxLayout, QVBoxLayout,
|
QMainWindow, QWidget, QHBoxLayout, QVBoxLayout,
|
||||||
QListWidget, QListWidgetItem, QStackedWidget,
|
QListWidget, QListWidgetItem, QStackedWidget,
|
||||||
QStatusBar, QLabel, QSplitter
|
QStatusBar, QLabel, QSplitter, QMenuBar, QMenu
|
||||||
)
|
)
|
||||||
from PySide6.QtCore import Qt, QSize, QSettings, QTimer
|
from PySide6.QtCore import Qt, QSize, QSettings, QTimer
|
||||||
from PySide6.QtGui import QIcon, QFont, QShortcut, QKeySequence
|
from PySide6.QtGui import QIcon, QFont, QShortcut, QKeySequence, QAction
|
||||||
|
|
||||||
from .styles import STYLESHEET
|
from .styles import STYLESHEET
|
||||||
|
|
||||||
|
|
@ -65,6 +65,9 @@ class MainWindow(QMainWindow):
|
||||||
# Setup keyboard shortcuts
|
# Setup keyboard shortcuts
|
||||||
self._setup_shortcuts()
|
self._setup_shortcuts()
|
||||||
|
|
||||||
|
# Setup menu bar
|
||||||
|
self._setup_menu_bar()
|
||||||
|
|
||||||
# Restore window geometry
|
# Restore window geometry
|
||||||
self._restore_geometry()
|
self._restore_geometry()
|
||||||
|
|
||||||
|
|
@ -98,11 +101,11 @@ class MainWindow(QMainWindow):
|
||||||
def _setup_sidebar(self):
|
def _setup_sidebar(self):
|
||||||
"""Set up sidebar navigation items."""
|
"""Set up sidebar navigation items."""
|
||||||
items = [
|
items = [
|
||||||
("CmdForge", "Welcome to CmdForge"),
|
("CmdForge", "Welcome page - Quick actions and getting started (Ctrl+1)"),
|
||||||
("Tools", "Manage your tools"),
|
("Tools", "View, edit, delete, and test your local tools (Ctrl+2)"),
|
||||||
("Registry", "Browse and install tools"),
|
("Registry", "Browse and install tools from the community (Ctrl+3)"),
|
||||||
("Providers", "Configure AI providers"),
|
("Providers", "Configure AI backends like Claude, GPT, etc. (Ctrl+4)"),
|
||||||
("Profiles", "AI persona profiles"),
|
("Profiles", "AI persona profiles for customizing tool behavior"),
|
||||||
]
|
]
|
||||||
|
|
||||||
font = QFont()
|
font = QFont()
|
||||||
|
|
@ -228,6 +231,88 @@ class MainWindow(QMainWindow):
|
||||||
shortcut_quit = QShortcut(QKeySequence("Ctrl+Q"), self)
|
shortcut_quit = QShortcut(QKeySequence("Ctrl+Q"), self)
|
||||||
shortcut_quit.activated.connect(self.close)
|
shortcut_quit.activated.connect(self.close)
|
||||||
|
|
||||||
|
# F1: Help
|
||||||
|
shortcut_help = QShortcut(QKeySequence("F1"), self)
|
||||||
|
shortcut_help.activated.connect(self._show_getting_started)
|
||||||
|
|
||||||
|
def _setup_menu_bar(self):
|
||||||
|
"""Set up the menu bar with Help menu."""
|
||||||
|
menubar = self.menuBar()
|
||||||
|
|
||||||
|
# Help menu
|
||||||
|
help_menu = menubar.addMenu("&Help")
|
||||||
|
|
||||||
|
# Getting Started
|
||||||
|
action_getting_started = QAction("&Getting Started", self)
|
||||||
|
action_getting_started.setShortcut("F1")
|
||||||
|
action_getting_started.triggered.connect(self._show_getting_started)
|
||||||
|
help_menu.addAction(action_getting_started)
|
||||||
|
|
||||||
|
help_menu.addSeparator()
|
||||||
|
|
||||||
|
# Quick Guides
|
||||||
|
action_create_tool = QAction("How to &Create a Tool", self)
|
||||||
|
action_create_tool.triggered.connect(self._show_create_tool_guide)
|
||||||
|
help_menu.addAction(action_create_tool)
|
||||||
|
|
||||||
|
action_install_tools = QAction("How to &Install Tools", self)
|
||||||
|
action_install_tools.triggered.connect(self._show_install_tools_guide)
|
||||||
|
help_menu.addAction(action_install_tools)
|
||||||
|
|
||||||
|
action_publish = QAction("How to &Publish Tools", self)
|
||||||
|
action_publish.triggered.connect(self._show_publish_guide)
|
||||||
|
help_menu.addAction(action_publish)
|
||||||
|
|
||||||
|
help_menu.addSeparator()
|
||||||
|
|
||||||
|
# Keyboard Shortcuts
|
||||||
|
action_shortcuts = QAction("&Keyboard Shortcuts", self)
|
||||||
|
action_shortcuts.triggered.connect(self._show_keyboard_shortcuts)
|
||||||
|
help_menu.addAction(action_shortcuts)
|
||||||
|
|
||||||
|
help_menu.addSeparator()
|
||||||
|
|
||||||
|
# About
|
||||||
|
action_about = QAction("&About CmdForge", self)
|
||||||
|
action_about.triggered.connect(self._show_about)
|
||||||
|
help_menu.addAction(action_about)
|
||||||
|
|
||||||
|
def _show_getting_started(self):
|
||||||
|
"""Show Getting Started guide."""
|
||||||
|
from .dialogs.help_dialogs import QuickGuideDialog
|
||||||
|
dialog = QuickGuideDialog("getting_started", self)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
def _show_create_tool_guide(self):
|
||||||
|
"""Show Create Tool guide."""
|
||||||
|
from .dialogs.help_dialogs import QuickGuideDialog
|
||||||
|
dialog = QuickGuideDialog("create_tool", self)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
def _show_install_tools_guide(self):
|
||||||
|
"""Show Install Tools guide."""
|
||||||
|
from .dialogs.help_dialogs import QuickGuideDialog
|
||||||
|
dialog = QuickGuideDialog("install_tools", self)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
def _show_publish_guide(self):
|
||||||
|
"""Show Publish Tools guide."""
|
||||||
|
from .dialogs.help_dialogs import QuickGuideDialog
|
||||||
|
dialog = QuickGuideDialog("publish_tools", self)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
def _show_keyboard_shortcuts(self):
|
||||||
|
"""Show Keyboard Shortcuts guide."""
|
||||||
|
from .dialogs.help_dialogs import QuickGuideDialog
|
||||||
|
dialog = QuickGuideDialog("keyboard_shortcuts", self)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
def _show_about(self):
|
||||||
|
"""Show About dialog."""
|
||||||
|
from .dialogs.help_dialogs import AboutDialog
|
||||||
|
dialog = AboutDialog(self)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
def _shortcut_new_tool(self):
|
def _shortcut_new_tool(self):
|
||||||
"""Handle Ctrl+N: Create new tool."""
|
"""Handle Ctrl+N: Create new tool."""
|
||||||
self.open_tool_builder()
|
self.open_tool_builder()
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ class RegistryPage(QWidget):
|
||||||
|
|
||||||
# Browse all button
|
# Browse all button
|
||||||
self.btn_browse = QPushButton("Browse All")
|
self.btn_browse = QPushButton("Browse All")
|
||||||
|
self.btn_browse.setToolTip("Clear filters and show all available tools")
|
||||||
self.btn_browse.clicked.connect(self._browse_all)
|
self.btn_browse.clicked.connect(self._browse_all)
|
||||||
header.addWidget(self.btn_browse)
|
header.addWidget(self.btn_browse)
|
||||||
|
|
||||||
|
|
@ -143,6 +144,7 @@ class RegistryPage(QWidget):
|
||||||
# Search input
|
# Search input
|
||||||
self.search_input = QLineEdit()
|
self.search_input = QLineEdit()
|
||||||
self.search_input.setPlaceholderText("Search tools...")
|
self.search_input.setPlaceholderText("Search tools...")
|
||||||
|
self.search_input.setToolTip("Search by name, description, or keywords (press Enter)")
|
||||||
self.search_input.returnPressed.connect(self._do_search)
|
self.search_input.returnPressed.connect(self._do_search)
|
||||||
filters_layout.addWidget(self.search_input, 2)
|
filters_layout.addWidget(self.search_input, 2)
|
||||||
|
|
||||||
|
|
@ -152,6 +154,7 @@ class RegistryPage(QWidget):
|
||||||
self.category_combo = QComboBox()
|
self.category_combo = QComboBox()
|
||||||
self.category_combo.addItems(["All", "Text", "Developer", "Data", "Other"])
|
self.category_combo.addItems(["All", "Text", "Developer", "Data", "Other"])
|
||||||
self.category_combo.setMinimumWidth(100)
|
self.category_combo.setMinimumWidth(100)
|
||||||
|
self.category_combo.setToolTip("Filter by tool category")
|
||||||
self.category_combo.currentTextChanged.connect(self._on_filter_changed)
|
self.category_combo.currentTextChanged.connect(self._on_filter_changed)
|
||||||
filters_layout.addWidget(self.category_combo)
|
filters_layout.addWidget(self.category_combo)
|
||||||
|
|
||||||
|
|
@ -163,11 +166,13 @@ class RegistryPage(QWidget):
|
||||||
self.sort_combo.addItem("Newest", "published_at")
|
self.sort_combo.addItem("Newest", "published_at")
|
||||||
self.sort_combo.addItem("Name (A-Z)", "name")
|
self.sort_combo.addItem("Name (A-Z)", "name")
|
||||||
self.sort_combo.setMinimumWidth(120)
|
self.sort_combo.setMinimumWidth(120)
|
||||||
|
self.sort_combo.setToolTip("Change sort order of results")
|
||||||
self.sort_combo.currentIndexChanged.connect(self._on_filter_changed)
|
self.sort_combo.currentIndexChanged.connect(self._on_filter_changed)
|
||||||
filters_layout.addWidget(self.sort_combo)
|
filters_layout.addWidget(self.sort_combo)
|
||||||
|
|
||||||
# Search button
|
# Search button
|
||||||
self.btn_search = QPushButton("Search")
|
self.btn_search = QPushButton("Search")
|
||||||
|
self.btn_search.setToolTip("Search with current filters")
|
||||||
self.btn_search.clicked.connect(self._do_search)
|
self.btn_search.clicked.connect(self._do_search)
|
||||||
filters_layout.addWidget(self.btn_search)
|
filters_layout.addWidget(self.btn_search)
|
||||||
|
|
||||||
|
|
@ -196,6 +201,7 @@ class RegistryPage(QWidget):
|
||||||
self.results_table = QTableWidget()
|
self.results_table = QTableWidget()
|
||||||
self.results_table.setColumnCount(6)
|
self.results_table.setColumnCount(6)
|
||||||
self.results_table.setHorizontalHeaderLabels(["", "Name", "Owner", "Rating", "Downloads", "Version"])
|
self.results_table.setHorizontalHeaderLabels(["", "Name", "Owner", "Rating", "Downloads", "Version"])
|
||||||
|
self.results_table.setToolTip("Click a tool to see details. ✓ = installed, ↑ = update available")
|
||||||
self.results_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed)
|
self.results_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed)
|
||||||
self.results_table.setColumnWidth(0, 30) # Installed indicator
|
self.results_table.setColumnWidth(0, 30) # Installed indicator
|
||||||
self.results_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
|
self.results_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
|
||||||
|
|
@ -215,6 +221,7 @@ class RegistryPage(QWidget):
|
||||||
pag_layout.setContentsMargins(0, 8, 0, 0)
|
pag_layout.setContentsMargins(0, 8, 0, 0)
|
||||||
|
|
||||||
self.btn_prev = QPushButton("← Previous")
|
self.btn_prev = QPushButton("← Previous")
|
||||||
|
self.btn_prev.setToolTip("Go to previous page of results")
|
||||||
self.btn_prev.clicked.connect(self._prev_page)
|
self.btn_prev.clicked.connect(self._prev_page)
|
||||||
self.btn_prev.setEnabled(False)
|
self.btn_prev.setEnabled(False)
|
||||||
pag_layout.addWidget(self.btn_prev)
|
pag_layout.addWidget(self.btn_prev)
|
||||||
|
|
@ -228,6 +235,7 @@ class RegistryPage(QWidget):
|
||||||
pag_layout.addStretch()
|
pag_layout.addStretch()
|
||||||
|
|
||||||
self.btn_next = QPushButton("Next →")
|
self.btn_next = QPushButton("Next →")
|
||||||
|
self.btn_next.setToolTip("Go to next page of results")
|
||||||
self.btn_next.clicked.connect(self._next_page)
|
self.btn_next.clicked.connect(self._next_page)
|
||||||
self.btn_next.setEnabled(False)
|
self.btn_next.setEnabled(False)
|
||||||
pag_layout.addWidget(self.btn_next)
|
pag_layout.addWidget(self.btn_next)
|
||||||
|
|
@ -263,6 +271,7 @@ class RegistryPage(QWidget):
|
||||||
self.version_combo.setMinimumWidth(120)
|
self.version_combo.setMinimumWidth(120)
|
||||||
self.version_combo.addItem("Latest", None)
|
self.version_combo.addItem("Latest", None)
|
||||||
self.version_combo.setEnabled(False)
|
self.version_combo.setEnabled(False)
|
||||||
|
self.version_combo.setToolTip("Select which version to install")
|
||||||
version_row.addWidget(self.version_combo)
|
version_row.addWidget(self.version_combo)
|
||||||
|
|
||||||
version_row.addStretch()
|
version_row.addStretch()
|
||||||
|
|
@ -272,11 +281,13 @@ class RegistryPage(QWidget):
|
||||||
actions = QHBoxLayout()
|
actions = QHBoxLayout()
|
||||||
|
|
||||||
self.btn_install = QPushButton("Install")
|
self.btn_install = QPushButton("Install")
|
||||||
|
self.btn_install.setToolTip("Download and install this tool locally")
|
||||||
self.btn_install.clicked.connect(self._install_tool)
|
self.btn_install.clicked.connect(self._install_tool)
|
||||||
self.btn_install.setEnabled(False)
|
self.btn_install.setEnabled(False)
|
||||||
actions.addWidget(self.btn_install)
|
actions.addWidget(self.btn_install)
|
||||||
|
|
||||||
self.btn_update = QPushButton("Update Available")
|
self.btn_update = QPushButton("Update Available")
|
||||||
|
self.btn_update.setToolTip("Update to the latest version from the registry")
|
||||||
self.btn_update.clicked.connect(self._install_tool)
|
self.btn_update.clicked.connect(self._install_tool)
|
||||||
self.btn_update.setEnabled(False)
|
self.btn_update.setEnabled(False)
|
||||||
self.btn_update.setStyleSheet("background-color: #48bb78; color: white;")
|
self.btn_update.setStyleSheet("background-color: #48bb78; color: white;")
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,12 @@ class ToolBuilderPage(QWidget):
|
||||||
|
|
||||||
self.btn_cancel = QPushButton("Cancel")
|
self.btn_cancel = QPushButton("Cancel")
|
||||||
self.btn_cancel.setObjectName("secondary")
|
self.btn_cancel.setObjectName("secondary")
|
||||||
|
self.btn_cancel.setToolTip("Cancel and return to tools page (Escape)")
|
||||||
self.btn_cancel.clicked.connect(self._cancel)
|
self.btn_cancel.clicked.connect(self._cancel)
|
||||||
header_layout.addWidget(self.btn_cancel)
|
header_layout.addWidget(self.btn_cancel)
|
||||||
|
|
||||||
self.btn_save = QPushButton("Save")
|
self.btn_save = QPushButton("Save")
|
||||||
|
self.btn_save.setToolTip("Save this tool (Ctrl+S)")
|
||||||
self.btn_save.clicked.connect(self._save)
|
self.btn_save.clicked.connect(self._save)
|
||||||
header_layout.addWidget(self.btn_save)
|
header_layout.addWidget(self.btn_save)
|
||||||
|
|
||||||
|
|
@ -76,14 +78,17 @@ class ToolBuilderPage(QWidget):
|
||||||
|
|
||||||
self.name_input = QLineEdit()
|
self.name_input = QLineEdit()
|
||||||
self.name_input.setPlaceholderText("my-tool")
|
self.name_input.setPlaceholderText("my-tool")
|
||||||
|
self.name_input.setToolTip("Unique tool name using lowercase letters, numbers, and hyphens")
|
||||||
info_layout.addRow("Name:", self.name_input)
|
info_layout.addRow("Name:", self.name_input)
|
||||||
|
|
||||||
self.desc_input = QLineEdit()
|
self.desc_input = QLineEdit()
|
||||||
self.desc_input.setPlaceholderText("A brief description of what this tool does")
|
self.desc_input.setPlaceholderText("A brief description of what this tool does")
|
||||||
|
self.desc_input.setToolTip("Brief description shown in tool listings and help text")
|
||||||
info_layout.addRow("Description:", self.desc_input)
|
info_layout.addRow("Description:", self.desc_input)
|
||||||
|
|
||||||
self.category_combo = QComboBox()
|
self.category_combo = QComboBox()
|
||||||
self.category_combo.setEditable(True)
|
self.category_combo.setEditable(True)
|
||||||
|
self.category_combo.setToolTip("Category for organizing tools (select or type custom)")
|
||||||
for cat in DEFAULT_CATEGORIES:
|
for cat in DEFAULT_CATEGORIES:
|
||||||
self.category_combo.addItem(cat)
|
self.category_combo.addItem(cat)
|
||||||
info_layout.addRow("Category:", self.category_combo)
|
info_layout.addRow("Category:", self.category_combo)
|
||||||
|
|
@ -91,9 +96,19 @@ class ToolBuilderPage(QWidget):
|
||||||
left_layout.addWidget(info_box)
|
left_layout.addWidget(info_box)
|
||||||
|
|
||||||
# Arguments group
|
# Arguments group
|
||||||
args_box = QGroupBox("Arguments")
|
args_box = QGroupBox()
|
||||||
args_layout = QVBoxLayout(args_box)
|
args_layout = QVBoxLayout(args_box)
|
||||||
|
|
||||||
|
args_label = QLabel("Arguments")
|
||||||
|
args_label.setObjectName("sectionHeading")
|
||||||
|
args_label.setToolTip(
|
||||||
|
"<p>Arguments are command-line flags users can pass to your tool.</p>"
|
||||||
|
"<p>Example: Adding --max with variable 'max' lets users run:<br>"
|
||||||
|
"<code>my-tool --max 100 < input.txt</code></p>"
|
||||||
|
"<p>Use {max} in your prompts to reference the value.</p>"
|
||||||
|
)
|
||||||
|
args_layout.addWidget(args_label)
|
||||||
|
|
||||||
self.args_list = QListWidget()
|
self.args_list = QListWidget()
|
||||||
self.args_list.itemDoubleClicked.connect(self._edit_argument)
|
self.args_list.itemDoubleClicked.connect(self._edit_argument)
|
||||||
args_layout.addWidget(self.args_list)
|
args_layout.addWidget(self.args_list)
|
||||||
|
|
@ -127,21 +142,37 @@ class ToolBuilderPage(QWidget):
|
||||||
right_layout.setSpacing(16)
|
right_layout.setSpacing(16)
|
||||||
|
|
||||||
# Steps group with view toggle
|
# Steps group with view toggle
|
||||||
steps_box = QGroupBox("Steps")
|
steps_box = QGroupBox()
|
||||||
steps_layout = QVBoxLayout(steps_box)
|
steps_layout = QVBoxLayout(steps_box)
|
||||||
|
|
||||||
# View toggle header
|
# Steps header with label and view toggle
|
||||||
view_header = QHBoxLayout()
|
steps_header = QHBoxLayout()
|
||||||
|
steps_label = QLabel("Steps")
|
||||||
|
steps_label.setObjectName("sectionHeading")
|
||||||
|
steps_label.setToolTip(
|
||||||
|
"<p>Steps define what your tool does, executed in order.</p>"
|
||||||
|
"<p><b>Step types:</b><br>"
|
||||||
|
"- Prompt: Call an AI provider with a template<br>"
|
||||||
|
"- Code: Run Python code to process data<br>"
|
||||||
|
"- Tool: Call another CmdForge tool</p>"
|
||||||
|
"<p>Use {variable} syntax to pass data between steps.<br>"
|
||||||
|
"Built-in: {input} contains stdin content.</p>"
|
||||||
|
)
|
||||||
|
steps_header.addWidget(steps_label)
|
||||||
|
steps_header.addStretch()
|
||||||
|
|
||||||
|
# View toggle buttons
|
||||||
self.btn_list_view = QPushButton("List")
|
self.btn_list_view = QPushButton("List")
|
||||||
self.btn_list_view.setCheckable(True)
|
self.btn_list_view.setCheckable(True)
|
||||||
self.btn_list_view.setChecked(True)
|
self.btn_list_view.setChecked(True)
|
||||||
self.btn_list_view.setObjectName("viewToggle")
|
self.btn_list_view.setObjectName("viewToggle")
|
||||||
|
self.btn_list_view.setToolTip("View steps as a list (drag to reorder)")
|
||||||
self.btn_list_view.clicked.connect(lambda: self._set_view_mode(0))
|
self.btn_list_view.clicked.connect(lambda: self._set_view_mode(0))
|
||||||
|
|
||||||
self.btn_flow_view = QPushButton("Flow")
|
self.btn_flow_view = QPushButton("Flow")
|
||||||
self.btn_flow_view.setCheckable(True)
|
self.btn_flow_view.setCheckable(True)
|
||||||
self.btn_flow_view.setObjectName("viewToggle")
|
self.btn_flow_view.setObjectName("viewToggle")
|
||||||
|
self.btn_flow_view.setToolTip("View steps as a visual flow graph")
|
||||||
self.btn_flow_view.clicked.connect(lambda: self._set_view_mode(1))
|
self.btn_flow_view.clicked.connect(lambda: self._set_view_mode(1))
|
||||||
|
|
||||||
# Button group for mutual exclusivity
|
# Button group for mutual exclusivity
|
||||||
|
|
@ -149,10 +180,9 @@ class ToolBuilderPage(QWidget):
|
||||||
self.view_group.addButton(self.btn_list_view, 0)
|
self.view_group.addButton(self.btn_list_view, 0)
|
||||||
self.view_group.addButton(self.btn_flow_view, 1)
|
self.view_group.addButton(self.btn_flow_view, 1)
|
||||||
|
|
||||||
view_header.addWidget(self.btn_list_view)
|
steps_header.addWidget(self.btn_list_view)
|
||||||
view_header.addWidget(self.btn_flow_view)
|
steps_header.addWidget(self.btn_flow_view)
|
||||||
view_header.addStretch()
|
steps_layout.addLayout(steps_header)
|
||||||
steps_layout.addLayout(view_header)
|
|
||||||
|
|
||||||
# Stacked widget for list/flow views
|
# Stacked widget for list/flow views
|
||||||
self.steps_stack = QStackedWidget()
|
self.steps_stack = QStackedWidget()
|
||||||
|
|
@ -183,24 +213,29 @@ class ToolBuilderPage(QWidget):
|
||||||
# Step action buttons
|
# Step action buttons
|
||||||
steps_btns = QHBoxLayout()
|
steps_btns = QHBoxLayout()
|
||||||
self.btn_add_prompt = QPushButton("Add Prompt")
|
self.btn_add_prompt = QPushButton("Add Prompt")
|
||||||
|
self.btn_add_prompt.setToolTip("Add an AI prompt step - calls your provider with a template")
|
||||||
self.btn_add_prompt.clicked.connect(self._add_prompt_step)
|
self.btn_add_prompt.clicked.connect(self._add_prompt_step)
|
||||||
steps_btns.addWidget(self.btn_add_prompt)
|
steps_btns.addWidget(self.btn_add_prompt)
|
||||||
|
|
||||||
self.btn_add_code = QPushButton("Add Code")
|
self.btn_add_code = QPushButton("Add Code")
|
||||||
|
self.btn_add_code.setToolTip("Add a Python code step - process or transform data")
|
||||||
self.btn_add_code.clicked.connect(self._add_code_step)
|
self.btn_add_code.clicked.connect(self._add_code_step)
|
||||||
steps_btns.addWidget(self.btn_add_code)
|
steps_btns.addWidget(self.btn_add_code)
|
||||||
|
|
||||||
self.btn_add_tool = QPushButton("Add Tool")
|
self.btn_add_tool = QPushButton("Add Tool")
|
||||||
|
self.btn_add_tool.setToolTip("Add a tool step - chain another CmdForge tool")
|
||||||
self.btn_add_tool.clicked.connect(self._add_tool_step)
|
self.btn_add_tool.clicked.connect(self._add_tool_step)
|
||||||
steps_btns.addWidget(self.btn_add_tool)
|
steps_btns.addWidget(self.btn_add_tool)
|
||||||
|
|
||||||
self.btn_edit_step = QPushButton("Edit")
|
self.btn_edit_step = QPushButton("Edit")
|
||||||
self.btn_edit_step.setObjectName("secondary")
|
self.btn_edit_step.setObjectName("secondary")
|
||||||
|
self.btn_edit_step.setToolTip("Edit the selected step (or double-click)")
|
||||||
self.btn_edit_step.clicked.connect(self._edit_step)
|
self.btn_edit_step.clicked.connect(self._edit_step)
|
||||||
steps_btns.addWidget(self.btn_edit_step)
|
steps_btns.addWidget(self.btn_edit_step)
|
||||||
|
|
||||||
self.btn_del_step = QPushButton("Delete")
|
self.btn_del_step = QPushButton("Delete")
|
||||||
self.btn_del_step.setObjectName("danger")
|
self.btn_del_step.setObjectName("danger")
|
||||||
|
self.btn_del_step.setToolTip("Delete the selected step")
|
||||||
self.btn_del_step.clicked.connect(self._delete_step)
|
self.btn_del_step.clicked.connect(self._delete_step)
|
||||||
steps_btns.addWidget(self.btn_del_step)
|
steps_btns.addWidget(self.btn_del_step)
|
||||||
|
|
||||||
|
|
@ -210,9 +245,21 @@ class ToolBuilderPage(QWidget):
|
||||||
right_layout.addWidget(steps_box, 1) # Steps box gets stretch priority
|
right_layout.addWidget(steps_box, 1) # Steps box gets stretch priority
|
||||||
|
|
||||||
# Output group
|
# Output group
|
||||||
output_box = QGroupBox("Output Template")
|
output_box = QGroupBox()
|
||||||
output_layout = QVBoxLayout(output_box)
|
output_layout = QVBoxLayout(output_box)
|
||||||
|
|
||||||
|
output_label = QLabel("Output Template")
|
||||||
|
output_label.setObjectName("sectionHeading")
|
||||||
|
output_label.setToolTip(
|
||||||
|
"<p>The output template defines what your tool prints.</p>"
|
||||||
|
"<p><b>Use {variable} to include step outputs:</b><br>"
|
||||||
|
"- {response} - typical AI response variable<br>"
|
||||||
|
"- {result} - common code step output<br>"
|
||||||
|
"- Any output_var you defined in steps</p>"
|
||||||
|
"<p>Example: <code>{response}</code> prints just the AI response.</p>"
|
||||||
|
)
|
||||||
|
output_layout.addWidget(output_label)
|
||||||
|
|
||||||
self.output_input = QTextEdit()
|
self.output_input = QTextEdit()
|
||||||
self.output_input.setPlaceholderText("Use {variable} to reference step outputs, e.g. {response}")
|
self.output_input.setPlaceholderText("Use {variable} to reference step outputs, e.g. {response}")
|
||||||
self.output_input.setPlainText("{response}") # Default value
|
self.output_input.setPlainText("{response}") # Default value
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,12 @@ QLabel#label {
|
||||||
color: #4a5568;
|
color: #4a5568;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QLabel#sectionHeading {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #2d3748;
|
||||||
|
}
|
||||||
|
|
||||||
/* Scrollbars */
|
/* Scrollbars */
|
||||||
QScrollBar:vertical {
|
QScrollBar:vertical {
|
||||||
background-color: #f7fafc;
|
background-color: #f7fafc;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue