Files
mini-openclaw-v2/src/components/xingbang/SkillPackageDialog.tsx
T

24 lines
2.5 KiB
TypeScript

'use client';
import {useEffect,useRef,useState} from 'react';
import {FolderOpen,FileText,Download,X} from 'lucide-react';
import {downloadSkill} from '@/lib/lease-library';
export default function SkillPackageDialog({card,send,onClose}:any) {
const dialog=useRef<HTMLDialogElement>(null);
const [data,setData]=useState<any>(null),[error,setError]=useState(''),[file,setFile]=useState('SKILL.md'),[busy,setBusy]=useState(false);
useEffect(()=>{dialog.current?.showModal(); let live=true;
send('GET',`/library/skills/${encodeURIComponent(card.id)}/package`).then((result:any)=>{if(live)setData(result);}).catch((e:any)=>{if(live)setError(e.message);});
return()=>{live=false;};
},[card.id]);
const entry=data?.files.find((item:any)=>item.path===file);
async function openFolder(){setBusy(true);setError('');try{await send('POST',`/library/skills/${encodeURIComponent(card.id)}/open`,{});}catch(e:any){setError(e.message);}finally{setBusy(false);}}
return <dialog ref={dialog} className="v2-dialog v2-file-dialog" onCancel={onClose} aria-labelledby="skill-folder-title">
<header><div><span className="v2-kicker">STANDARD SKILL PACKAGE</span><h2 id="skill-folder-title">{card.name}</h2><p>{data?.name || '正在读取标准文件夹…'} · v{card.version}</p></div><button className="ra-button" aria-label="关闭文件夹查看器" onClick={onClose}><X size={18}/></button></header>
{error&&<p role="alert" className="ra-alert error">{error}</p>}
{data&&<><div className="v2-package-meta"><span>{data.manifest.length} 个原始文件 · 哈希 {data.content_hash.slice(0,16)}</span><div className="xb-actions"><button className="ra-button" disabled={busy} onClick={openFolder}><FolderOpen size={15}/>在本机文件夹打开</button><button className="ra-button" onClick={()=>downloadSkill(card.id).catch(e=>setError(e.message))}><Download size={15}/>下载标准包</button></div></div>
<div className="v2-file-layout"><aside aria-label="Skills 文件树"><b><FolderOpen size={15}/>{data.name}/</b>{data.files.map((item:any)=><button key={item.path} className={file===item.path?'active':''} onClick={()=>setFile(item.path)}><FileText size={14}/>{item.path}</button>)}</aside><section><h3>{file}</h3><pre tabIndex={0}>{entry?.text ?? '此文件是二进制资源,可下载标准包查看。'}</pre></section></div>
<p className="v2-muted">卡片对应实际托管文件夹。原始文件与版本哈希保留;scripts 仅保存,不会在导入时运行。</p></>}
{!data&&!error&&<p role="status">正在读取文件清单…</p>}
</dialog>;
}