misc: improve timeout handling and warnings in skills (#211)

This commit is contained in:
Felix
2026-02-28 10:16:36 +08:00
committed by GitHub
Unverified
parent 538d285c71
commit d4f77a442c
6 changed files with 79 additions and 13 deletions

View File

@@ -637,6 +637,14 @@ export function Skills() {
}
}, [t]);
const [skillsDirPath, setSkillsDirPath] = useState('~/.openclaw/skills');
useEffect(() => {
window.electron.ipcRenderer.invoke('openclaw:getSkillsDir')
.then((dir) => setSkillsDirPath(dir as string))
.catch(console.error);
}, []);
// Handle marketplace search
const handleMarketplaceSearch = useCallback((e: React.FormEvent) => {
e.preventDefault();
@@ -659,9 +667,14 @@ export function Skills() {
await enableSkill(slug);
toast.success(t('toast.installed'));
} catch (err) {
toast.error(t('toast.failedInstall') + ': ' + String(err));
const errorMessage = err instanceof Error ? err.message : String(err);
if (['installTimeoutError', 'installRateLimitError'].includes(errorMessage)) {
toast.error(t(`toast.${errorMessage}`, { path: skillsDirPath }), { duration: 10000 });
} else {
toast.error(t('toast.failedInstall') + ': ' + errorMessage);
}
}
}, [installSkill, enableSkill, t]);
}, [installSkill, enableSkill, t, skillsDirPath]);
// Initial marketplace load (Discovery)
useEffect(() => {
@@ -798,8 +811,12 @@ export function Skills() {
{error && (
<Card className="border-destructive">
<CardContent className="py-4 text-destructive flex items-center gap-2">
<AlertCircle className="h-5 w-5" />
{error}
<AlertCircle className="h-5 w-5 shrink-0" />
<span>
{['fetchTimeoutError', 'fetchRateLimitError', 'timeoutError', 'rateLimitError'].includes(error)
? t(`toast.${error}`, { path: skillsDirPath })
: error}
</span>
</CardContent>
</Card>
)}
@@ -905,6 +922,12 @@ export function Skills() {
</div>
</CardContent>
</Card>
<Card className="border-info/30 bg-info/5">
<CardContent className="py-3 text-sm flex items-start gap-2 text-muted-foreground">
<Download className="h-4 w-4 mt-0.5 shrink-0" />
<span>{t('marketplace.manualInstallHint', { path: skillsDirPath })}</span>
</CardContent>
</Card>
<div className="flex gap-4">
<form onSubmit={handleMarketplaceSearch} className="flex-1 flex gap-2">
<div className="relative flex-1">
@@ -970,9 +993,13 @@ export function Skills() {
{searchError && (
<Card className="border-destructive/50 bg-destructive/5">
<CardContent className="py-3 text-sm text-destructive flex items-center gap-2">
<AlertCircle className="h-4 w-4" />
<span>{t('marketplace.searchError')}</span>
<CardContent className="py-3 text-sm text-destructive flex items-start gap-2">
<AlertCircle className="h-4 w-4 mt-0.5 shrink-0" />
<span>
{['searchTimeoutError', 'searchRateLimitError', 'timeoutError', 'rateLimitError'].includes(searchError.replace('Error: ', ''))
? t(`toast.${searchError.replace('Error: ', '')}`, { path: skillsDirPath })
: t('marketplace.searchError')}
</span>
</CardContent>
</Card>
)}