table rows as links

This commit is contained in:
Oliver Bryan
2026-01-21 13:09:04 +00:00
parent 4c01fa229d
commit 5f8d049de3

View File

@@ -3,7 +3,7 @@ import Avatar from "@/components/avatar";
import { useSelection } from "@/components/selection-provider"; import { useSelection } from "@/components/selection-provider";
import StatusTag from "@/components/status-tag"; import StatusTag from "@/components/status-tag";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { useIssues, useSelectedOrganisation } from "@/lib/query/hooks"; import { useIssues, useSelectedOrganisation, useSelectedProject } from "@/lib/query/hooks";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
export function IssuesTable({ export function IssuesTable({
@@ -16,10 +16,28 @@ export function IssuesTable({
const { selectedProjectId, selectedIssueId, selectIssue } = useSelection(); const { selectedProjectId, selectedIssueId, selectIssue } = useSelection();
const { data: issuesData = [] } = useIssues(selectedProjectId); const { data: issuesData = [] } = useIssues(selectedProjectId);
const selectedOrganisation = useSelectedOrganisation(); const selectedOrganisation = useSelectedOrganisation();
const selectedProject = useSelectedProject();
const statuses = selectedOrganisation?.Organisation.statuses ?? {}; const statuses = selectedOrganisation?.Organisation.statuses ?? {};
const issues = useMemo(() => [...issuesData].reverse(), [issuesData]); const issues = useMemo(() => [...issuesData].reverse(), [issuesData]);
const getIssueUrl = (issueNumber: number) => {
if (!selectedOrganisation || !selectedProject) return "#";
const params = new URLSearchParams();
params.set("o", selectedOrganisation.Organisation.slug.toLowerCase());
params.set("p", selectedProject.Project.key.toLowerCase());
params.set("i", issueNumber.toString());
return `/app?${params.toString()}`;
};
const handleLinkClick = (e: React.MouseEvent) => {
if (e.metaKey || e.ctrlKey || e.shiftKey) {
e.stopPropagation();
return;
}
e.preventDefault();
};
return ( return (
<Table className={cn("table-fixed", className)}> <Table className={cn("table-fixed", className)}>
<TableHeader> <TableHeader>
@@ -51,13 +69,23 @@ export function IssuesTable({
}} }}
> >
{(columns.id == null || columns.id === true) && ( {(columns.id == null || columns.id === true) && (
<TableCell className="font-medium border-r text-right"> <TableCell className="font-medium border-r text-right p-0">
<a
href={getIssueUrl(issueData.Issue.number)}
onClick={handleLinkClick}
className="block w-full h-full px-2 py-1 text-inherit hover:underline decoration-transparent"
>
{issueData.Issue.number.toString().padStart(3, "0")} {issueData.Issue.number.toString().padStart(3, "0")}
</a>
</TableCell> </TableCell>
)} )}
{(columns.title == null || columns.title === true) && ( {(columns.title == null || columns.title === true) && (
<TableCell className="min-w-0"> <TableCell className="min-w-0 p-0">
<div className="flex items-center gap-2 min-w-0"> <a
href={getIssueUrl(issueData.Issue.number)}
onClick={handleLinkClick}
className="flex items-center gap-2 min-w-0 w-full h-full px-2 py-1 text-inherit hover:underline decoration-transparent"
>
{(columns.status == null || columns.status === true) && ( {(columns.status == null || columns.status === true) && (
<StatusTag <StatusTag
status={issueData.Issue.status} status={issueData.Issue.status}
@@ -65,14 +93,27 @@ export function IssuesTable({
/> />
)} )}
<span className="truncate">{issueData.Issue.title}</span> <span className="truncate">{issueData.Issue.title}</span>
</div> </a>
</TableCell> </TableCell>
)} )}
{(columns.description == null || columns.description === true) && ( {(columns.description == null || columns.description === true) && (
<TableCell className="overflow-hidden">{issueData.Issue.description}</TableCell> <TableCell className="overflow-hidden p-0">
<a
href={getIssueUrl(issueData.Issue.number)}
onClick={handleLinkClick}
className="block w-full h-full px-2 py-1 text-inherit hover:underline decoration-transparent"
>
{issueData.Issue.description}
</a>
</TableCell>
)} )}
{(columns.assignee == null || columns.assignee === true) && ( {(columns.assignee == null || columns.assignee === true) && (
<TableCell className={"flex items-center justify-end py-0 h-[32px]"}> <TableCell className="h-[32px] p-0">
<a
href={getIssueUrl(issueData.Issue.number)}
onClick={handleLinkClick}
className="flex items-center justify-end w-full h-full px-2"
>
{issueData.Assignees && issueData.Assignees.length > 0 && ( {issueData.Assignees && issueData.Assignees.length > 0 && (
<div className="flex items-center -space-x-2 pr-1.5"> <div className="flex items-center -space-x-2 pr-1.5">
{issueData.Assignees.slice(0, 3).map((assignee) => ( {issueData.Assignees.slice(0, 3).map((assignee) => (
@@ -92,6 +133,7 @@ export function IssuesTable({
)} )}
</div> </div>
)} )}
</a>
</TableCell> </TableCell>
)} )}
</TableRow> </TableRow>