Refactor SkillManagementPanel to conditionally show action buttons based on connection status

- Added offline and setup-required states with informative messages
- Updated SkillSetupModal to use connection status for setup vs. manage mode
- Simplified mode logic for better UX and error handling in setup scenarios
This commit is contained in:
cyrus
2026-02-02 16:39:44 +05:30
parent bf9bb66d38
commit e3f46680ec
2 changed files with 65 additions and 48 deletions
+49 -40
View File
@@ -145,50 +145,59 @@ export default function SkillManagementPanel({
</div>
)}
{/* Action buttons — single row */}
<div className="pt-1">
{!confirmDisconnect ? (
<div className="flex space-x-2">
<button
onClick={handleRestart}
disabled={restarting}
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-stone-700/60 border border-stone-600/50 rounded-xl hover:bg-stone-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{restarting ? "Restarting..." : "Restart"}
</button>
{onReconfigure && (
{/* Action buttons — only show if skill is actually running */}
{connectionStatus !== "offline" && connectionStatus !== "setup_required" ? (
<div className="pt-1">
{!confirmDisconnect ? (
<div className="flex space-x-2">
<button
onClick={onReconfigure}
className="flex-1 px-3 py-2 text-xs font-medium text-primary-300 bg-primary-500/10 border border-primary-500/30 rounded-xl hover:bg-primary-500/20 transition-colors"
onClick={handleRestart}
disabled={restarting}
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-stone-700/60 border border-stone-600/50 rounded-xl hover:bg-stone-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
Re-run Setup
{restarting ? "Restarting..." : "Restart"}
</button>
)}
<button
onClick={() => setConfirmDisconnect(true)}
className="flex-1 px-3 py-2 text-xs font-medium text-coral-400 bg-coral-500/10 border border-coral-500/30 rounded-xl hover:bg-coral-500/20 transition-colors"
>
Disconnect
</button>
{onReconfigure && (
<button
onClick={onReconfigure}
className="flex-1 px-3 py-2 text-xs font-medium text-primary-300 bg-primary-500/10 border border-primary-500/30 rounded-xl hover:bg-primary-500/20 transition-colors"
>
Re-run Setup
</button>
)}
<button
onClick={() => setConfirmDisconnect(true)}
className="flex-1 px-3 py-2 text-xs font-medium text-coral-400 bg-coral-500/10 border border-coral-500/30 rounded-xl hover:bg-coral-500/20 transition-colors"
>
Disconnect
</button>
</div>
) : (
<div className="flex space-x-2">
<button
onClick={() => setConfirmDisconnect(false)}
className="flex-1 px-3 py-2 text-xs font-medium text-stone-400 bg-stone-800/50 border border-stone-700 rounded-xl hover:bg-stone-800 transition-colors"
>
Cancel
</button>
<button
onClick={handleDisconnect}
disabled={disconnecting}
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-coral-500 rounded-xl hover:bg-coral-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{disconnecting ? "Disconnecting..." : "Confirm Disconnect"}
</button>
</div>
)}
</div>
) : (
// Show message for offline skills
<div className="pt-1">
<div className="text-xs text-stone-500 text-center py-2 px-3 bg-stone-800/30 rounded-xl border border-stone-700/30">
Skill is offline. Use "Re-run Setup" to reconnect.
</div>
) : (
<div className="flex space-x-2">
<button
onClick={() => setConfirmDisconnect(false)}
className="flex-1 px-3 py-2 text-xs font-medium text-stone-400 bg-stone-800/50 border border-stone-700 rounded-xl hover:bg-stone-800 transition-colors"
>
Cancel
</button>
<button
onClick={handleDisconnect}
disabled={disconnecting}
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-coral-500 rounded-xl hover:bg-coral-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{disconnecting ? "Disconnecting..." : "Confirm Disconnect"}
</button>
</div>
)}
</div>
</div>
)}
</div>
);
}
+16 -8
View File
@@ -7,6 +7,7 @@
import { useState, useEffect, useRef } from "react";
import { createPortal } from "react-dom";
import { useAppSelector } from "../../store/hooks";
import { useSkillConnectionStatus } from "../../lib/skills/hooks";
import SkillSetupWizard from "./SkillSetupWizard";
import SkillManagementPanel from "./SkillManagementPanel";
@@ -27,13 +28,20 @@ export default function SkillSetupModal({
onClose,
}: SkillSetupModalProps) {
const modalRef = useRef<HTMLDivElement>(null);
const setupComplete = useAppSelector(
(state) => state.skills.skills[skillId]?.setupComplete,
);
// Skills without setup hooks always go straight to manage mode.
const [mode, setMode] = useState<"manage" | "setup">(
!hasSetup || setupComplete ? "manage" : "setup",
);
const skill = useAppSelector((state) => state.skills.skills[skillId]);
const connectionStatus = useSkillConnectionStatus(skillId);
// Simplified mode logic: Only show manage mode when skill is actually working
// Everything else (offline, errors, never connected, etc.) goes to setup mode
const [mode, setMode] = useState<"manage" | "setup">(() => {
// Only show manage mode when the skill is actually working
const isWorking = connectionStatus === "connected" || connectionStatus === "connecting";
// For skills without setup hooks, still need to check if they're working
// Show manage mode only if skill is currently working
// Everything else goes to setup mode (first-time setup, errors, offline, disconnected)
return isWorking ? "manage" : "setup";
});
// Handle escape key
useEffect(() => {
@@ -137,7 +145,7 @@ export default function SkillSetupModal({
<SkillSetupWizard
skillId={skillId}
onComplete={onClose}
onCancel={setupComplete ? () => setMode("manage") : onClose}
onCancel={skill?.setupComplete ? () => setMode("manage") : onClose}
/>
)}
</div>