mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(panel): clickable Branch/PR links + branch copy button
The Branch value in the task-detail card and the Branch/PR badges in the task list were static text. Make them open the real thing on GitHub, keeping their exact look: - New repo-url helper normalizes a project git_url (https/ssh, with/without .git) into web URLs for a branch (/tree/<branch>) and PR (/pull/<n>), returning null so callers fall back to a plain label. - Task-detail Branch card: the branch is now a link to its GitHub tree URL and gains a copy button (reuses CopyButton); PR was already linked. - List-row git badge (git-status-badge): the PR badge links to task.pr_url (or the built pull URL) and the Branch badge links to the branch tree URL. The row's click handler already ignores <a> clicks, so opening a branch/PR never toggles the row. git_url is threaded via a projectGitUrls map from the tasks page, alongside the existing projectNames map. panel typecheck + eslint clean.
This commit is contained in:
@@ -1,24 +1,61 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { GitBranch, GitPullRequest, FileCheck } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Task, TaskStatus } from "@/types";
|
||||
import { branchUrl, pullUrl } from "@/lib/repo-url";
|
||||
|
||||
interface GitStatusBadgeProps {
|
||||
task: Task;
|
||||
compact?: boolean;
|
||||
/** Project git_url — used to build the clickable branch / PR links. */
|
||||
repoUrl?: string | null;
|
||||
}
|
||||
|
||||
export function GitStatusBadge({ task, compact = true }: GitStatusBadgeProps) {
|
||||
/**
|
||||
* Wrap a badge in an external link when a URL is available, otherwise render it
|
||||
* plain. The badge keeps its exact look; the link only adds the click target
|
||||
* (and a subtle hover). The parent row's click handler ignores `<a>` clicks, so
|
||||
* opening a branch/PR never also toggles the row.
|
||||
*/
|
||||
function MaybeLink({
|
||||
href,
|
||||
children,
|
||||
}: {
|
||||
href: string | null;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
if (!href) return <>{children}</>;
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="Open in GitHub"
|
||||
className="inline-flex transition-opacity hover:opacity-80"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
export function GitStatusBadge({
|
||||
task,
|
||||
compact = true,
|
||||
repoUrl,
|
||||
}: GitStatusBadgeProps) {
|
||||
// All tasks follow git workflow - show relevant status
|
||||
|
||||
// Show PR badge with status (highest priority)
|
||||
if (task.pr_number) {
|
||||
return (
|
||||
<Badge className="gap-1 text-xs bg-purple-500/10 text-purple-600 dark:text-purple-400">
|
||||
<GitPullRequest className="h-3 w-3" />
|
||||
PR #{task.pr_number}
|
||||
</Badge>
|
||||
<MaybeLink href={task.pr_url ?? pullUrl(repoUrl, task.pr_number)}>
|
||||
<Badge className="gap-1 text-xs bg-purple-500/10 text-purple-600 dark:text-purple-400">
|
||||
<GitPullRequest className="h-3 w-3" />
|
||||
PR #{task.pr_number}
|
||||
</Badge>
|
||||
</MaybeLink>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -55,10 +92,12 @@ export function GitStatusBadge({ task, compact = true }: GitStatusBadgeProps) {
|
||||
// Show branch badge (when branch exists but no PR yet)
|
||||
if (task.branch_name) {
|
||||
return (
|
||||
<Badge variant="outline" className="gap-1 text-xs">
|
||||
<GitBranch className="h-3 w-3" />
|
||||
{compact ? "Branch" : task.branch_name}
|
||||
</Badge>
|
||||
<MaybeLink href={branchUrl(repoUrl, task.branch_name)}>
|
||||
<Badge variant="outline" className="gap-1 text-xs">
|
||||
<GitBranch className="h-3 w-3" />
|
||||
{compact ? "Branch" : task.branch_name}
|
||||
</Badge>
|
||||
</MaybeLink>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user