diff --git a/src/cmdforge/gui/pages/tools_page.py b/src/cmdforge/gui/pages/tools_page.py
index 4d9738e..6f21912 100644
--- a/src/cmdforge/gui/pages/tools_page.py
+++ b/src/cmdforge/gui/pages/tools_page.py
@@ -363,6 +363,29 @@ class ToolsPage(QWidget):
self.info_text.setPlaceholderText("Select a tool to view details")
info_layout.addWidget(self.info_text)
+ # Rating bar at bottom of details panel
+ self.rating_bar = QWidget()
+ rating_bar_layout = QHBoxLayout(self.rating_bar)
+ rating_bar_layout.setContentsMargins(4, 4, 4, 4)
+ rating_bar_layout.setSpacing(12)
+
+ self.rating_label = QLabel("")
+ self.rating_label.setTextFormat(Qt.RichText)
+ self.rating_label.setStyleSheet("color: #4a5568; font-size: 12px;")
+ rating_bar_layout.addWidget(self.rating_label)
+
+ rating_bar_layout.addStretch()
+
+ self.btn_rate = QPushButton("Rate Tool")
+ self.btn_rate.setObjectName("secondary")
+ self.btn_rate.clicked.connect(self._rate_tool)
+ self.btn_rate.setEnabled(False)
+ self.btn_rate.setToolTip("Local tools can't be rated")
+ rating_bar_layout.addWidget(self.btn_rate)
+
+ self.rating_bar.setVisible(False)
+ info_layout.addWidget(self.rating_bar)
+
right_layout.addWidget(info_box, 1)
splitter.addWidget(right)
@@ -401,13 +424,6 @@ class ToolsPage(QWidget):
self.btn_delete.setEnabled(False)
btn_layout.addWidget(self.btn_delete)
- self.btn_rate = QPushButton("Rate Tool")
- self.btn_rate.setObjectName("secondary")
- self.btn_rate.clicked.connect(self._rate_tool)
- self.btn_rate.setEnabled(False)
- self.btn_rate.setToolTip("Local tools can't be rated")
- btn_layout.addWidget(self.btn_rate)
-
btn_layout.addStretch()
# Connect/Publish button
@@ -442,6 +458,7 @@ class ToolsPage(QWidget):
self.tool_tree.clear()
self._current_tool = None
self.info_text.clear()
+ self.rating_bar.setVisible(False)
self._has_pending_tools = False # Reset, will be set during tree building
tools = list_tools()
@@ -628,6 +645,7 @@ class ToolsPage(QWidget):
if not items:
self._current_tool = None
self.info_text.clear()
+ self.rating_bar.setVisible(False)
self._update_buttons()
return
@@ -636,6 +654,7 @@ class ToolsPage(QWidget):
if not tool_name:
self._current_tool = None
self.info_text.clear()
+ self.rating_bar.setVisible(False)
self._update_buttons()
return
@@ -737,43 +756,6 @@ class ToolsPage(QWidget):
f"Reason:
{feedback_escaped}"
)
- # Rating section (for registry-sourced tools)
- registry_info = get_tool_registry_info(qname)
- if registry_info:
- cached = self._rating_cache.get(qname)
- if cached:
- rating_data = cached.get("rating")
- my_review = cached.get("my_review")
- if rating_data:
- avg = rating_data.get("average_rating", 0)
- count = rating_data.get("rating_count", 0)
- if count > 0:
- filled = round(avg)
- stars_html = "".join(
- "★" if i < filled else "☆" for i in range(5)
- )
- lines.append(
- f"
" - f"{stars_html} " - f"{avg:.1f}/5 from {count} review{'s' if count != 1 else ''}
" - ) - else: - lines.append( - "" - "No ratings yet
" - ) - if my_review: - my_stars = "★" * my_review["rating"] + "☆" * (5 - my_review["rating"]) - lines.append( - f"" - f"Your rating: {my_stars}
" - ) - elif registry_info: - lines.append( - "" - "Loading ratings...
" - ) - # Source info if tool.source: source_type = tool.source.type @@ -817,6 +799,40 @@ class ToolsPage(QWidget): self.info_text.setHtml("\n".join(lines)) + # Update rating bar below the detail text + self._update_rating_bar(qname) + + def _update_rating_bar(self, qname: str): + """Update the rating bar widget at the bottom of the detail panel.""" + registry_info = get_tool_registry_info(qname) + if not registry_info: + self.rating_bar.setVisible(False) + return + + self.rating_bar.setVisible(True) + cached = self._rating_cache.get(qname) + + if cached: + rating_data = cached.get("rating") + my_review = cached.get("my_review") + parts = [] + if rating_data: + avg = rating_data.get("average_rating", 0) + count = rating_data.get("rating_count", 0) + if count > 0: + filled = round(avg) + stars = "".join("★" if i < filled else "☆" for i in range(5)) + parts.append(f"{stars}" + f" {avg:.1f}/5 from {count} review{'s' if count != 1 else ''}") + else: + parts.append("No ratings yet") + if my_review: + my_stars = "★" * my_review["rating"] + "☆" * (5 - my_review["rating"]) + parts.append(f"Your rating: {my_stars}") + self.rating_label.setText(" · ".join(parts) if parts else "") + else: + self.rating_label.setText("Loading ratings...") + def _has_settings(self, tool: Tool) -> bool: """Check if a tool has configurable settings.""" if not tool or not tool.path: