"use client"; import { IconTrash, IconRefresh, IconPlayerPlay, IconPlayerPause, IconRestore, } from "@tabler/icons-react"; import { Button } from "@kandev/ui/button"; import { Badge } from "@kandev/ui/badge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@kandev/ui/table"; import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip"; import { useAppStore } from "@/components/state-provider"; import type { SentryIssueWatch, SentrySearchFilter } from "@/lib/types/sentry"; type SentryIssueWatchTableProps = { watches: SentryIssueWatch[]; // showWorkspace renders a Workspace column when the table aggregates rows // from every workspace (install-wide settings page). showWorkspace?: boolean; onEdit: (watch: SentryIssueWatch) => void; onDelete: (id: string, workspaceId: string) => void; onTrigger: (id: string, workspaceId: string) => void; onReset: (id: string, workspaceId: string) => void; onToggleEnabled: (watch: SentryIssueWatch) => void; }; function formatLastPolled(dateStr?: string | null): string { if (!dateStr) return "Never"; const ts = new Date(dateStr).getTime(); if (Number.isNaN(ts)) return "Never"; const diff = Date.now() - ts; const minutes = Math.floor(diff / 60000); if (minutes < 1) return "Just now"; if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); if (hours < 24) return `${hours}h ago`; return `${Math.floor(hours / 24)}d ago`; } // summarizeFilter renders the structured filter as a short tag-style label // the user can scan at a glance. function summarizeFilter(filter: SentrySearchFilter | undefined): string { if (!filter) return "(any)"; const parts: string[] = []; if (filter.orgSlug) parts.push(`org:${filter.orgSlug}`); if (filter.projectSlug) parts.push(`project:${filter.projectSlug}`); if (filter.environment) parts.push(`env:${filter.environment}`); if (filter.levels && filter.levels.length > 0) { parts.push(`level:${filter.levels.join(",")}`); } if (filter.statuses && filter.statuses.length > 0) { parts.push(`status:${filter.statuses.join(",")}`); } if (filter.statsPeriod) parts.push(`period:${filter.statsPeriod}`); if (filter.query) parts.push(`q:"${filter.query}"`); return parts.length === 0 ? "(any)" : parts.join(" ยท "); } function WatchActions({ watch, onToggleEnabled, onTrigger, onReset, onDelete, }: { watch: SentryIssueWatch; onToggleEnabled: (watch: SentryIssueWatch) => void; onTrigger: (id: string, workspaceId: string) => void; onReset: (id: string, workspaceId: string) => void; onDelete: (id: string, workspaceId: string) => void; }) { return (
{watch.enabled ? "Pause" : "Enable"} Check now Reset Delete
); } export function SentryIssueWatchTable({ watches, showWorkspace, onEdit, onDelete, onTrigger, onReset, onToggleEnabled, }: SentryIssueWatchTableProps) { const workspaces = useAppStore((s) => s.workspaces.items); const workspaceName = (id: string) => workspaces.find((w) => w.id === id)?.name ?? id; if (watches.length === 0) { return (

No Sentry watchers configured. Create one to auto-create tasks from filtered issues.

); } return ( {showWorkspace && Workspace} Filter Interval Last Polled Status Actions {watches.map((watch) => ( onEdit(watch)}> {showWorkspace && ( {workspaceName(watch.workspaceId)} )} {summarizeFilter(watch.filter)} {Math.round(watch.pollIntervalSeconds / 60)}m {formatLastPolled(watch.lastPolledAt)} {watch.enabled ? "Active" : "Paused"} ))}
); }