Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions components/Admin/AdminLineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,54 @@
import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts";
import {
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@/components/ui/chart";

interface SecondLine {
data: Array<{ date: string; count: number }>;
label: string;
color?: string;
}

interface AdminLineChartProps {
title: string;
data: Array<{ date: string; count: number }>;
label?: string;
secondLine?: SecondLine;
}

export default function AdminLineChart({ title, data, label = "Count" }: AdminLineChartProps) {
export default function AdminLineChart({
title,
data,
label = "Count",
secondLine,
}: AdminLineChartProps) {
if (data.length === 0) return null;

const chartConfig = {
count: {
label,
color: "#345A5D",
},
count: { label, color: "#345A5D" },
...(secondLine
? { count2: { label: secondLine.label, color: secondLine.color ?? "#6B8E93" } }
: {}),
} satisfies ChartConfig;

// Merge primary and secondary data by date
const secondMap = new Map(secondLine?.data.map((d) => [d.date, d.count]) ?? []);
const mergedData = data.map((d) => ({
date: d.date,
count: d.count,
...(secondLine ? { count2: secondMap.get(d.date) ?? 0 } : {}),
}));

return (
<div className="mb-6 rounded-lg border p-4">
<h2 className="mb-4 text-sm font-medium text-gray-700 dark:text-gray-300">{title}</h2>
<ChartContainer config={chartConfig} className="h-[250px] w-full">
<LineChart data={data} accessibilityLayer>
<LineChart data={mergedData} accessibilityLayer>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
Expand All @@ -55,13 +77,23 @@ export default function AdminLineChart({ title, data, label = "Count" }: AdminLi
/>
}
/>
{secondLine && <ChartLegend content={<ChartLegendContent />} />}
<Line
dataKey="count"
type="monotone"
stroke="var(--color-count)"
strokeWidth={2}
dot={{ fill: "var(--color-count)", r: 4 }}
/>
{secondLine && (
<Line
dataKey="count2"
type="monotone"
stroke="var(--color-count2)"
strokeWidth={2}
dot={{ fill: "var(--color-count2)", r: 4 }}
/>
)}
</LineChart>
</ChartContainer>
</div>
Expand Down
31 changes: 26 additions & 5 deletions components/CodingAgentSlackTags/CodingAgentSlackTagsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,27 @@ export default function CodingAgentSlackTagsPage() {
<div className="mb-6 flex items-center gap-4">
<PeriodSelector period={period} onPeriodChange={setPeriod} />
{data && (
<div className="text-sm text-gray-600 dark:text-gray-400">
<span className="font-semibold text-gray-900 dark:text-gray-100">{data.total}</span>{" "}
{data.total === 1 ? "tag" : "tags"} found
<div className="flex gap-4 text-sm text-gray-600 dark:text-gray-400">
<span>
<span className="font-semibold text-gray-900 dark:text-gray-100">{data.total}</span>{" "}
{data.total === 1 ? "tag" : "tags"}
</span>
<span>
<span className="font-semibold text-gray-900 dark:text-gray-100">{data.tags_with_pull_requests}</span>{" "}
with PRs
</span>
<span>
<span className="font-semibold text-gray-900 dark:text-gray-100">{data.total_pull_requests}</span>{" "}
total PRs
</span>
</div>
)}
</div>

{isLoading && (
<>
<ChartSkeleton />
<TableSkeleton columns={["Tagged By", "Prompt", "Channel", "Timestamp"]} />
<TableSkeleton columns={["Tagged By", "Prompt", "Channel", "Pull Requests", "Timestamp"]} />
</>
)}

Expand All @@ -62,7 +72,18 @@ export default function CodingAgentSlackTagsPage() {

{!isLoading && !error && data && data.tags.length > 0 && (
<>
<AdminLineChart title="Tags Over Time" data={getTagsByDate(data.tags)} label="Tags" />
<AdminLineChart
title="Tags & Pull Requests Over Time"
data={getTagsByDate(data.tags).map((d) => ({ date: d.date, count: d.count }))}
label="Tags"
secondLine={{
data: getTagsByDate(data.tags).map((d) => ({
date: d.date,
count: d.pull_request_count,
})),
label: "Tags with PRs",
}}
/>
<SlackTagsTable tags={data.tags} />
</>
)}
Expand Down
24 changes: 24 additions & 0 deletions components/CodingAgentSlackTags/SlackTagsColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
return (
<div className="flex items-center gap-2">
{tag.user_avatar && (
<img

Check warning on line 15 in components/CodingAgentSlackTags/SlackTagsColumns.tsx

View workflow job for this annotation

GitHub Actions / ESLint

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={tag.user_avatar}
alt={tag.user_name}
className="h-6 w-6 rounded-full"
Expand Down Expand Up @@ -41,6 +41,30 @@
<span className="text-sm text-gray-500 dark:text-gray-400">#{getValue<string>()}</span>
),
},
{
id: "pull_requests",
accessorKey: "pull_requests",
header: "Pull Requests",
cell: ({ getValue }) => {
const prs = getValue<string[]>();
if (!prs?.length) return <span className="text-sm text-gray-400">—</span>;
return (
<div className="flex flex-col gap-1">
{prs.map((url) => (
<a
key={url}
href={url}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-blue-600 hover:underline dark:text-blue-400"
>
{url.match(/github\.com\/[^/]+\/([^/]+)\/pull\/(\d+)/)?.slice(1).join("#")}
</a>
))}
</div>
);
},
},
{
id: "timestamp",
accessorKey: "timestamp",
Expand Down
15 changes: 9 additions & 6 deletions lib/coding-agent/getTagsByDate.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import type { SlackTag } from "@/types/coding-agent";

interface TagsByDateEntry {
export interface TagsByDateEntry {
date: string;
count: number;
pull_request_count: number;
}

/**
* Aggregates Slack tags by UTC date (YYYY-MM-DD) for charting.
* Aggregates Slack tags and their associated pull requests by UTC date (YYYY-MM-DD) for charting.
*
* @param tags - Array of SlackTag objects
* @returns Array of { date, count } sorted ascending by date
* @returns Array of { date, count, pull_request_count } sorted ascending by date
*/
export function getTagsByDate(tags: SlackTag[]): TagsByDateEntry[] {
const counts: Record<string, number> = {};
const counts: Record<string, { count: number; pull_request_count: number }> = {};

for (const tag of tags) {
const date = tag.timestamp.slice(0, 10); // "YYYY-MM-DD"
counts[date] = (counts[date] ?? 0) + 1;
if (!counts[date]) counts[date] = { count: 0, pull_request_count: 0 };
counts[date].count += 1;
counts[date].pull_request_count += (tag.pull_requests?.length ?? 0) > 0 ? 1 : 0;
}
Comment on lines +20 to 23
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

pull_request_count is currently counting tags, not pull requests.

At Line 22, this adds 1 per tagged message with any PR. That undercounts days where a message includes multiple PR links and conflicts with “pull requests over time” semantics.

🔧 Proposed fix
-    counts[date].pull_request_count += (tag.pull_requests?.length ?? 0) > 0 ? 1 : 0;
+    counts[date].pull_request_count += tag.pull_requests?.length ?? 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!counts[date]) counts[date] = { count: 0, pull_request_count: 0 };
counts[date].count += 1;
counts[date].pull_request_count += (tag.pull_requests?.length ?? 0) > 0 ? 1 : 0;
}
if (!counts[date]) counts[date] = { count: 0, pull_request_count: 0 };
counts[date].count += 1;
counts[date].pull_request_count += tag.pull_requests?.length ?? 0;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/coding-agent/getTagsByDate.ts` around lines 20 - 23, The
pull_request_count currently increments by 1 per tag regardless of how many PRs
are referenced; change the increment in the block that updates counts (where
counts[date] is initialized and modified) to add the actual number of PRs
referenced by the tag (use tag.pull_requests?.length or 0) instead of always
adding 1 so pull_request_count reflects total PR links for that date.


return Object.entries(counts)
.map(([date, count]) => ({ date, count }))
.map(([date, { count, pull_request_count }]) => ({ date, count, pull_request_count }))
.sort((a, b) => a.date.localeCompare(b.date));
}
3 changes: 3 additions & 0 deletions types/coding-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ export interface SlackTag {
timestamp: string;
channel_id: string;
channel_name: string;
pull_requests: string[];
}

export type { AdminPeriod as SlackTagsPeriod } from "./admin";

export interface SlackTagsResponse {
status: "success";
total: number;
total_pull_requests: number;
tags_with_pull_requests: number;
tags: SlackTag[];
}
Loading