| // src/components/data-hub/CodeRepoPanel.tsx | |
| import { useState } from "react"; | |
| import { useCodeRepositoryIntegration } from "@/hooks/useCodeRepositoryIntegration"; | |
| import { GitBranch, Github, Plus, ExternalLink, Trash2, Star, Loader2 } from "lucide-react"; | |
| export function CodeRepoPanel() { | |
| const { repos, loading, connecting, linkRepo, unlinkRepo } = useCodeRepositoryIntegration(); | |
| const [showLink, setShowLink] = useState(false); | |
| const [provider, setProvider] = useState<"github" | "gitlab">("github"); | |
| const [owner, setOwner] = useState(""); | |
| const [name, setName] = useState(""); | |
| const handleLink = () => { | |
| if (!owner.trim() || !name.trim()) return; | |
| linkRepo(provider, owner.trim(), name.trim()); | |
| setOwner(""); setName(""); setShowLink(false); | |
| }; | |
| return ( | |
| <div className="space-y-4"> | |
| <div className="flex items-center justify-between"> | |
| <h2 className="text-xl font-bold flex items-center gap-2"><GitBranch className="w-5 h-5 text-primary"/> Linked Repositories</h2> | |
| <button onClick={() => setShowLink(true)} className="btn btn-primary btn-sm gap-1.5"><Plus className="w-4 h-4"/> Link Repo</button> | |
| </div> | |
| {showLink && ( | |
| <div className="glass rounded-xl p-4 space-y-3"> | |
| <div className="flex gap-2"> | |
| <button onClick={() => setProvider("github")} className={`px-4 py-2 rounded-lg text-sm ${provider === "github" ? "bg-primary/20 text-primary" : "bg-white/10"}`}>GitHub</button> | |
| <button onClick={() => setProvider("gitlab")} className={`px-4 py-2 rounded-lg text-sm ${provider === "gitlab" ? "bg-primary/20 text-primary" : "bg-white/10"}`}>GitLab</button> | |
| </div> | |
| <div className="flex gap-2"> | |
| <input type="text" value={owner} onChange={e => setOwner(e.target.value)} placeholder="Owner/Org" className="flex-1 input text-sm" /> | |
| <input type="text" value={name} onChange={e => setName(e.target.value)} placeholder="Repo name" className="flex-1 input text-sm" /> | |
| </div> | |
| <button onClick={handleLink} disabled={connecting} className="btn btn-primary btn-sm w-full">{connecting ? <Loader2 className="w-4 h-4 animate-spin"/> : "Link"}</button> | |
| </div> | |
| )} | |
| {loading ? ( | |
| <div className="flex justify-center py-8"><Loader2 className="w-6 h-6 animate-spin text-gray-400"/></div> | |
| ) : repos.length === 0 ? ( | |
| <div className="text-center py-8 text-gray-400"><Github className="w-8 h-8 mx-auto mb-2 opacity-30"/><p>No linked repositories</p></div> | |
| ) : ( | |
| <div className="grid grid-cols-1 md:grid-cols-2 gap-3"> | |
| {repos.map(repo => ( | |
| <div key={repo.id} className="glass rounded-xl p-4 flex items-start justify-between"> | |
| <div> | |
| <div className="flex items-center gap-2"> | |
| {repo.provider === "github" ? <Github className="w-4 h-4"/> : <GitBranch className="w-4 h-4"/>} | |
| <a href={repo.url} target="_blank" className="font-semibold text-sm hover:text-primary">{repo.owner}/{repo.name}</a> | |
| </div> | |
| <p className="text-xs text-gray-500 mt-1">{repo.description}</p> | |
| <div className="flex items-center gap-3 mt-2 text-xs text-gray-400"> | |
| <span>{repo.language}</span> | |
| <span className="flex items-center gap-1"><Star className="w-3 h-3"/> {repo.stars}</span> | |
| </div> | |
| </div> | |
| <button onClick={() => unlinkRepo(repo.id)} className="text-gray-400 hover:text-red-500"><Trash2 className="w-4 h-4"/></button> | |
| </div> | |
| ))} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } |
Xet Storage Details
- Size:
- 3.68 kB
- Xet hash:
- 2274e13392d7f863330c43ae7a2d97112282e5d0e4fc7711cb8f0fd848b43a8a
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.