Fix publish state tracking and add sync status feature
- Track moderation status (pending/approved/rejected) in local tool config - Add new "pending" state indicator (◐ yellow) distinct from "published" (✓ green) - Add "Sync Status" button to check registry for updated moderation status - Add /me/tools/<name>/status API endpoint for checking tool status - Improve admin panel error handling with better error messages Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
@@ -183,14 +183,16 @@ class PublishDialog(QDialog):
|
||||
self.status_label.setText("Published successfully!")
|
||||
self.status_label.setStyleSheet("color: #38a169; font-weight: 600;")
|
||||
|
||||
# Save registry_hash to local config for publish state tracking
|
||||
# Save registry_hash and moderation status to local config for publish state tracking
|
||||
config_hash = result.get("config_hash")
|
||||
moderation_status = result.get("status", "pending")
|
||||
if config_hash and hasattr(self._tool, 'path') and self._tool.path:
|
||||
try:
|
||||
config_path = self._tool.path
|
||||
if config_path.exists():
|
||||
config_data = yaml.safe_load(config_path.read_text()) or {}
|
||||
config_data["registry_hash"] = config_hash
|
||||
config_data["registry_status"] = moderation_status
|
||||
config_path.write_text(yaml.dump(config_data, default_flow_style=False, sort_keys=False))
|
||||
except Exception:
|
||||
pass # Non-critical - just won't show publish state
|
||||
|
||||
@@ -29,7 +29,8 @@ def get_tool_publish_state(tool_name: str) -> Tuple[str, Optional[str]]:
|
||||
|
||||
Returns:
|
||||
Tuple of (state, registry_hash) where state is:
|
||||
- "published" - has registry_hash and current hash matches
|
||||
- "published" - approved in registry and current hash matches
|
||||
- "pending" - submitted but awaiting moderation
|
||||
- "modified" - has registry_hash but current hash differs
|
||||
- "local" - no registry_hash (never published/downloaded)
|
||||
"""
|
||||
@@ -40,6 +41,7 @@ def get_tool_publish_state(tool_name: str) -> Tuple[str, Optional[str]]:
|
||||
try:
|
||||
config = yaml.safe_load(config_path.read_text())
|
||||
registry_hash = config.get("registry_hash")
|
||||
registry_status = config.get("registry_status", "pending")
|
||||
|
||||
if not registry_hash:
|
||||
return ("local", None)
|
||||
@@ -47,10 +49,15 @@ def get_tool_publish_state(tool_name: str) -> Tuple[str, Optional[str]]:
|
||||
# Compute current hash (excluding hash fields)
|
||||
current_hash = compute_config_hash(config)
|
||||
|
||||
if current_hash == registry_hash:
|
||||
if current_hash != registry_hash:
|
||||
return ("modified", registry_hash)
|
||||
|
||||
# Hash matches - check moderation status
|
||||
if registry_status == "approved":
|
||||
return ("published", registry_hash)
|
||||
else:
|
||||
return ("modified", registry_hash)
|
||||
# pending, rejected, or unknown
|
||||
return ("pending", registry_hash)
|
||||
except Exception:
|
||||
return ("local", None)
|
||||
|
||||
@@ -156,6 +163,14 @@ class ToolsPage(QWidget):
|
||||
|
||||
btn_layout.addStretch()
|
||||
|
||||
# Sync status button (only when connected)
|
||||
self.btn_sync = QPushButton("Sync Status")
|
||||
self.btn_sync.setObjectName("secondary")
|
||||
self.btn_sync.clicked.connect(self._sync_tool_status)
|
||||
self.btn_sync.setEnabled(False)
|
||||
self.btn_sync.setToolTip("Check registry for updated moderation status")
|
||||
btn_layout.addWidget(self.btn_sync)
|
||||
|
||||
# Connect/Publish button
|
||||
config = load_config()
|
||||
if config.registry.token:
|
||||
@@ -219,8 +234,12 @@ class ToolsPage(QWidget):
|
||||
# Show state indicator in display name
|
||||
if state == "published":
|
||||
display_name = f"{name} ✓"
|
||||
tooltip = "Published to registry - up to date"
|
||||
tooltip = "Published to registry - approved"
|
||||
color = QColor(56, 161, 105) # Green
|
||||
elif state == "pending":
|
||||
display_name = f"{name} ◐"
|
||||
tooltip = "Submitted to registry - pending review"
|
||||
color = QColor(214, 158, 46) # Yellow/amber
|
||||
elif state == "modified":
|
||||
display_name = f"{name} ●"
|
||||
tooltip = "Published to registry - local modifications"
|
||||
@@ -298,7 +317,13 @@ class ToolsPage(QWidget):
|
||||
lines.append(
|
||||
"<p style='background: #c6f6d5; color: #276749; padding: 6px 10px; "
|
||||
"border-radius: 4px; margin-bottom: 12px; font-size: 12px;'>"
|
||||
"✓ Published to registry - up to date</p>"
|
||||
"✓ Published to registry - approved</p>"
|
||||
)
|
||||
elif state == "pending":
|
||||
lines.append(
|
||||
"<p style='background: #fef3c7; color: #92400e; padding: 6px 10px; "
|
||||
"border-radius: 4px; margin-bottom: 12px; font-size: 12px;'>"
|
||||
"◐ Submitted to registry - pending review</p>"
|
||||
)
|
||||
elif state == "modified":
|
||||
lines.append(
|
||||
@@ -360,9 +385,16 @@ class ToolsPage(QWidget):
|
||||
if config.registry.token:
|
||||
# Connected - enable Publish when tool selected
|
||||
self.btn_publish.setEnabled(has_selection)
|
||||
# Enable Sync when tool selected and has registry_hash
|
||||
if has_selection:
|
||||
state, registry_hash = get_tool_publish_state(self._current_tool.name)
|
||||
self.btn_sync.setEnabled(registry_hash is not None)
|
||||
else:
|
||||
self.btn_sync.setEnabled(False)
|
||||
else:
|
||||
# Not connected - Connect button is always enabled
|
||||
self.btn_publish.setEnabled(True)
|
||||
self.btn_sync.setEnabled(False)
|
||||
|
||||
def _create_tool(self):
|
||||
"""Create a new tool."""
|
||||
@@ -413,8 +445,54 @@ class ToolsPage(QWidget):
|
||||
if not self._current_tool:
|
||||
return
|
||||
|
||||
tool_name = self._current_tool.name # Save before refresh clears it
|
||||
from ..dialogs.publish_dialog import PublishDialog
|
||||
dialog = PublishDialog(self, self._current_tool)
|
||||
if dialog.exec():
|
||||
self.refresh() # Refresh to show updated publish state indicator
|
||||
self.main_window.show_status(f"Published '{self._current_tool.name}'")
|
||||
self.main_window.show_status(f"Published '{tool_name}'")
|
||||
|
||||
def _sync_tool_status(self):
|
||||
"""Sync the moderation status of the selected tool from the registry."""
|
||||
if not self._current_tool:
|
||||
return
|
||||
|
||||
tool_name = self._current_tool.name
|
||||
config_path = get_tools_dir() / tool_name / "config.yaml"
|
||||
|
||||
if not config_path.exists():
|
||||
return
|
||||
|
||||
try:
|
||||
from ...registry_client import RegistryClient, RegistryError
|
||||
|
||||
config = load_config()
|
||||
client = RegistryClient()
|
||||
client.token = config.registry.token
|
||||
|
||||
# Get status from registry
|
||||
status_data = client.get_my_tool_status(tool_name)
|
||||
new_status = status_data.get("status", "pending")
|
||||
|
||||
# Update local config
|
||||
config_data = yaml.safe_load(config_path.read_text()) or {}
|
||||
old_status = config_data.get("registry_status", "pending")
|
||||
|
||||
if old_status != new_status:
|
||||
config_data["registry_status"] = new_status
|
||||
config_path.write_text(yaml.dump(config_data, default_flow_style=False, sort_keys=False))
|
||||
|
||||
self.refresh()
|
||||
if new_status == "approved":
|
||||
self.main_window.show_status(f"Tool '{tool_name}' has been approved!")
|
||||
elif new_status == "rejected":
|
||||
self.main_window.show_status(f"Tool '{tool_name}' was rejected")
|
||||
else:
|
||||
self.main_window.show_status(f"Status updated: {new_status}")
|
||||
else:
|
||||
self.main_window.show_status(f"Status unchanged: {new_status}")
|
||||
|
||||
except RegistryError as e:
|
||||
QMessageBox.warning(self, "Sync Error", f"Could not sync status:\n{e.message}")
|
||||
except Exception as e:
|
||||
QMessageBox.warning(self, "Sync Error", f"Could not sync status:\n{e}")
|
||||
|
||||
Reference in New Issue
Block a user