Add startup connection validation to GUI
- Add validate_token() method to RegistryClient - Returns (is_valid, error_message) tuple - Catches 401/UNAUTHORIZED errors and connection issues - Add startup validation in MainWindow - Runs 500ms after window shows (non-blocking) - Clears invalid tokens automatically - Shows status bar message explaining what happened - Document cmdforge config disconnect command This prevents confusing errors when trying to publish with stale or revoked credentials - the GUI now auto-clears bad connections on restart. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
66fd121ee4
commit
85d1212c0d
|
|
@ -31,6 +31,13 @@ All notable changes to CmdForge will be documented in this file.
|
|||
- Auto-fetch registry version when opening publish dialog
|
||||
- Fork detection during publish workflow
|
||||
- Always refresh tools page after publish dialog closes
|
||||
- **Startup connection validation**: GUI validates registry token on startup
|
||||
- Automatically clears invalid/revoked tokens
|
||||
- Shows status bar message when connection is cleared
|
||||
- Prevents confusing errors when trying to publish with stale credentials
|
||||
|
||||
#### CLI Features
|
||||
- `cmdforge config disconnect` - Clear registry token from local configuration
|
||||
|
||||
#### Admin Features
|
||||
- Maintenance section in admin dashboard
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from PySide6.QtWidgets import (
|
|||
QListWidget, QListWidgetItem, QStackedWidget,
|
||||
QStatusBar, QLabel, QSplitter
|
||||
)
|
||||
from PySide6.QtCore import Qt, QSize, QSettings
|
||||
from PySide6.QtCore import Qt, QSize, QSettings, QTimer
|
||||
from PySide6.QtGui import QIcon, QFont, QShortcut, QKeySequence
|
||||
|
||||
from .styles import STYLESHEET
|
||||
|
|
@ -68,6 +68,33 @@ class MainWindow(QMainWindow):
|
|||
# Restore window geometry
|
||||
self._restore_geometry()
|
||||
|
||||
# Validate registry connection after window shows
|
||||
QTimer.singleShot(500, self._validate_registry_connection)
|
||||
|
||||
def _validate_registry_connection(self):
|
||||
"""Check if registry connection is valid on startup, clear if invalid."""
|
||||
try:
|
||||
from ..registry_client import RegistryClient
|
||||
from ..config import set_registry_token, load_config
|
||||
|
||||
config = load_config()
|
||||
if not config.registry.token:
|
||||
return # No connection configured, nothing to validate
|
||||
|
||||
client = RegistryClient()
|
||||
is_valid, error = client.validate_token()
|
||||
|
||||
if not is_valid:
|
||||
# Token is invalid, clear it
|
||||
set_registry_token(None)
|
||||
self.status_bar.showMessage(
|
||||
f"Registry connection cleared: {error}. Please reconnect.",
|
||||
10000 # Show for 10 seconds
|
||||
)
|
||||
except Exception as e:
|
||||
# Don't crash on validation errors, just log to status
|
||||
self.status_bar.showMessage(f"Could not validate registry connection: {e}", 5000)
|
||||
|
||||
def _setup_sidebar(self):
|
||||
"""Set up sidebar navigation items."""
|
||||
items = [
|
||||
|
|
|
|||
|
|
@ -605,6 +605,33 @@ class RegistryClient:
|
|||
|
||||
return response.json().get("data", {})
|
||||
|
||||
def validate_token(self) -> tuple[bool, str]:
|
||||
"""
|
||||
Validate that the current token is valid.
|
||||
|
||||
Returns:
|
||||
Tuple of (is_valid, error_message)
|
||||
- (True, "") if token is valid
|
||||
- (False, "reason") if token is invalid or missing
|
||||
"""
|
||||
if not self.token:
|
||||
return False, "No token configured"
|
||||
|
||||
try:
|
||||
response = self._request("GET", "/me/tools", require_auth=True)
|
||||
if response.status_code == 200:
|
||||
return True, ""
|
||||
elif response.status_code == 401:
|
||||
return False, "Token is invalid or revoked"
|
||||
else:
|
||||
return False, f"Unexpected response: {response.status_code}"
|
||||
except RegistryError as e:
|
||||
if e.http_status == 401 or e.code == "UNAUTHORIZED":
|
||||
return False, "Token is invalid or revoked"
|
||||
return False, str(e.message)
|
||||
except Exception as e:
|
||||
return False, f"Connection error: {e}"
|
||||
|
||||
def get_my_tools(self) -> List[ToolInfo]:
|
||||
"""
|
||||
Get tools published by the authenticated user.
|
||||
|
|
|
|||
Loading…
Reference in New Issue