Add collapsible README viewer to tool details panel and owner override for publish
- Add collapsible README section to tools page detail panel with lazy loading - README loads from disk only when user clicks the toggle bar - Section collapses to a single header bar, expands to show content - Add --owner flag to registry publish command for admin use - Simplify dependency gathering in publish to use unified code path Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
94e33c0763
commit
f2cb9c0057
|
|
@ -187,6 +187,7 @@ def main():
|
||||||
p_reg_publish.add_argument("path", nargs="?", help="Path to tool directory (default: current dir)")
|
p_reg_publish.add_argument("path", nargs="?", help="Path to tool directory (default: current dir)")
|
||||||
p_reg_publish.add_argument("--dry-run", action="store_true", help="Validate without publishing")
|
p_reg_publish.add_argument("--dry-run", action="store_true", help="Validate without publishing")
|
||||||
p_reg_publish.add_argument("-f", "--force", action="store_true", help="Skip confirmation prompts")
|
p_reg_publish.add_argument("-f", "--force", action="store_true", help="Skip confirmation prompts")
|
||||||
|
p_reg_publish.add_argument("--owner", default="", help="Owner override (admin only, e.g. 'official')")
|
||||||
p_reg_publish.set_defaults(func=cmd_registry)
|
p_reg_publish.set_defaults(func=cmd_registry)
|
||||||
|
|
||||||
# registry my-tools
|
# registry my-tools
|
||||||
|
|
|
||||||
|
|
@ -456,21 +456,20 @@ def _cmd_registry_publish(args):
|
||||||
my_owner = None
|
my_owner = None
|
||||||
|
|
||||||
tool = load_tool(name)
|
tool = load_tool(name)
|
||||||
if tool:
|
if not tool:
|
||||||
dep_result = gather_local_unpublished_deps([name], client, my_owner)
|
# Tool isn't installed locally; derive from config.yaml
|
||||||
else:
|
tool = Tool.from_dict(data)
|
||||||
# Tool isn't installed locally; derive deps from config.yaml
|
|
||||||
temp_tool = Tool.from_dict(data)
|
dep_names = []
|
||||||
dep_names = []
|
for dep in tool.dependencies:
|
||||||
for dep in temp_tool.dependencies:
|
if '/' not in dep:
|
||||||
if '/' not in dep:
|
dep_names.append(dep)
|
||||||
dep_names.append(dep)
|
for step in tool.steps:
|
||||||
for step in temp_tool.steps:
|
if isinstance(step, ToolStep) and '/' not in step.tool:
|
||||||
if isinstance(step, ToolStep) and '/' not in step.tool:
|
dep_names.append(step.tool)
|
||||||
dep_names.append(step.tool)
|
dep_names = sorted(set(dep_names) - {name})
|
||||||
dep_names = sorted(set(dep_names))
|
if dep_names:
|
||||||
if dep_names:
|
dep_result = gather_local_unpublished_deps(dep_names, client, my_owner)
|
||||||
dep_result = gather_local_unpublished_deps(dep_names, client, my_owner)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Warning: Could not check dependencies: {e}", file=sys.stderr)
|
print(f"Warning: Could not check dependencies: {e}", file=sys.stderr)
|
||||||
dep_result = None
|
dep_result = None
|
||||||
|
|
@ -560,7 +559,8 @@ def _cmd_registry_publish(args):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client = get_client()
|
client = get_client()
|
||||||
result = client.publish_tool(config_yaml, readme, defaults)
|
owner = getattr(args, "owner", "")
|
||||||
|
result = client.publish_tool(config_yaml, readme, defaults, owner=owner)
|
||||||
|
|
||||||
pr_url = result.get("pr_url", "")
|
pr_url = result.get("pr_url", "")
|
||||||
status = result.get("status", "")
|
status = result.get("status", "")
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,7 @@ class ToolsPage(QWidget):
|
||||||
self._issue_worker = None
|
self._issue_worker = None
|
||||||
self._my_slug: Optional[str] = None # Cached current user slug
|
self._my_slug: Optional[str] = None # Cached current user slug
|
||||||
self._my_slug_fetched = False
|
self._my_slug_fetched = False
|
||||||
|
self._readme_loaded_for: Optional[str] = None # Track which tool's README is loaded
|
||||||
self._setup_ui()
|
self._setup_ui()
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
|
|
@ -452,6 +453,37 @@ class ToolsPage(QWidget):
|
||||||
rating_bar_layout.addWidget(self.btn_report_issue)
|
rating_bar_layout.addWidget(self.btn_report_issue)
|
||||||
|
|
||||||
self.rating_bar.setVisible(False)
|
self.rating_bar.setVisible(False)
|
||||||
|
|
||||||
|
# Collapsible README section
|
||||||
|
self.readme_container = QWidget()
|
||||||
|
readme_container_layout = QVBoxLayout(self.readme_container)
|
||||||
|
readme_container_layout.setContentsMargins(0, 8, 0, 0)
|
||||||
|
readme_container_layout.setSpacing(0)
|
||||||
|
|
||||||
|
self.readme_toggle = QPushButton("▶ README")
|
||||||
|
self.readme_toggle.setStyleSheet(
|
||||||
|
"QPushButton { text-align: left; padding: 6px 10px; "
|
||||||
|
"background: #edf2f7; border: 1px solid #e2e8f0; border-radius: 4px; "
|
||||||
|
"color: #4a5568; font-weight: 600; font-size: 12px; }"
|
||||||
|
"QPushButton:hover { background: #e2e8f0; }"
|
||||||
|
)
|
||||||
|
self.readme_toggle.setCursor(Qt.PointingHandCursor)
|
||||||
|
self.readme_toggle.clicked.connect(self._on_readme_toggled)
|
||||||
|
readme_container_layout.addWidget(self.readme_toggle)
|
||||||
|
|
||||||
|
self.readme_text = QTextEdit()
|
||||||
|
self.readme_text.setReadOnly(True)
|
||||||
|
self.readme_text.setMinimumHeight(200)
|
||||||
|
self.readme_text.setStyleSheet(
|
||||||
|
"QTextEdit { font-family: monospace; font-size: 12px; "
|
||||||
|
"border: 1px solid #e2e8f0; border-top: none; border-radius: 0 0 4px 4px; }"
|
||||||
|
)
|
||||||
|
self.readme_text.setVisible(False)
|
||||||
|
readme_container_layout.addWidget(self.readme_text)
|
||||||
|
|
||||||
|
self.readme_container.setVisible(False)
|
||||||
|
info_layout.addWidget(self.readme_container)
|
||||||
|
|
||||||
info_layout.addWidget(self.rating_bar)
|
info_layout.addWidget(self.rating_bar)
|
||||||
|
|
||||||
right_layout.addWidget(info_box, 1)
|
right_layout.addWidget(info_box, 1)
|
||||||
|
|
@ -527,6 +559,7 @@ class ToolsPage(QWidget):
|
||||||
self._current_tool = None
|
self._current_tool = None
|
||||||
self.info_text.clear()
|
self.info_text.clear()
|
||||||
self.rating_bar.setVisible(False)
|
self.rating_bar.setVisible(False)
|
||||||
|
self.readme_container.setVisible(False)
|
||||||
self._has_pending_tools = False # Reset, will be set during tree building
|
self._has_pending_tools = False # Reset, will be set during tree building
|
||||||
|
|
||||||
tools = list_tools()
|
tools = list_tools()
|
||||||
|
|
@ -724,6 +757,7 @@ class ToolsPage(QWidget):
|
||||||
self._current_tool = None
|
self._current_tool = None
|
||||||
self.info_text.clear()
|
self.info_text.clear()
|
||||||
self.rating_bar.setVisible(False)
|
self.rating_bar.setVisible(False)
|
||||||
|
self.readme_container.setVisible(False)
|
||||||
self._update_buttons()
|
self._update_buttons()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -871,6 +905,49 @@ class ToolsPage(QWidget):
|
||||||
# Update rating bar below the detail text
|
# Update rating bar below the detail text
|
||||||
self._update_rating_bar(qname)
|
self._update_rating_bar(qname)
|
||||||
|
|
||||||
|
# Reset README section (collapsed, visible, lazy-loaded on expand)
|
||||||
|
self._current_tool = tool
|
||||||
|
self._readme_loaded_for = None
|
||||||
|
self.readme_text.clear()
|
||||||
|
self.readme_text.setVisible(False)
|
||||||
|
self.readme_toggle.setText("▶ README")
|
||||||
|
self.readme_container.setVisible(tool.path is not None)
|
||||||
|
|
||||||
|
def _on_readme_toggled(self):
|
||||||
|
"""Toggle README section visibility and lazy-load content on first expand."""
|
||||||
|
expanding = not self.readme_text.isVisible()
|
||||||
|
self.readme_text.setVisible(expanding)
|
||||||
|
self.readme_toggle.setText("▼ README" if expanding else "▶ README")
|
||||||
|
|
||||||
|
if not expanding:
|
||||||
|
return
|
||||||
|
|
||||||
|
tool = self._current_tool
|
||||||
|
if not tool or not tool.path:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Avoid reloading if already loaded for this tool
|
||||||
|
if self._readme_loaded_for == tool.name:
|
||||||
|
return
|
||||||
|
|
||||||
|
readme_path = tool.path.parent / "README.md"
|
||||||
|
if readme_path.exists():
|
||||||
|
try:
|
||||||
|
content = readme_path.read_text()
|
||||||
|
escaped = content.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||||
|
self.readme_text.setHtml(
|
||||||
|
f"<pre style='white-space: pre-wrap; font-family: monospace; "
|
||||||
|
f"font-size: 12px; color: #2d3748;'>{escaped}</pre>"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.readme_text.setPlainText(f"Error reading README: {e}")
|
||||||
|
else:
|
||||||
|
self.readme_text.setHtml(
|
||||||
|
"<p style='color: #718096; font-style: italic;'>No README.md found for this tool.</p>"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._readme_loaded_for = tool.name
|
||||||
|
|
||||||
def _update_rating_bar(self, qname: str):
|
def _update_rating_bar(self, qname: str):
|
||||||
"""Update the rating bar widget at the bottom of the detail panel."""
|
"""Update the rating bar widget at the bottom of the detail panel."""
|
||||||
registry_info = get_tool_registry_info(qname, self._my_slug)
|
registry_info = get_tool_registry_info(qname, self._my_slug)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue