Skip to content

Commit

Permalink
fix: Show different statuses on graph (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
adityachoudhari26 authored Oct 22, 2024
1 parent e6e9666 commit de9f31f
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 35 deletions.
107 changes: 76 additions & 31 deletions apps/webservice/src/app/[workspaceSlug]/systems/JobHistoryChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,75 @@ import type { Workspace } from "@ctrlplane/db/schema";
import { isSameDay, startOfDay, sub } from "date-fns";
import _ from "lodash";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
import colors from "tailwindcss/colors";

import {
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@ctrlplane/ui/card";
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@ctrlplane/ui/chart";
import { ChartContainer, ChartTooltip } from "@ctrlplane/ui/chart";
import { JobStatus } from "@ctrlplane/validators/jobs";

import { api } from "~/trpc/react";
import { dateRange } from "~/utils/date/range";

const statusColors = {
[JobStatus.ActionRequired]: colors.yellow[500],
[JobStatus.ExternalRunNotFound]: colors.red[700],
[JobStatus.InvalidIntegration]: colors.amber[700],
[JobStatus.InvalidJobAgent]: colors.amber[400],
[JobStatus.Failure]: colors.red[500],
[JobStatus.Cancelled]: colors.neutral[600],
[JobStatus.Skipped]: colors.neutral[500],
[JobStatus.Pending]: colors.neutral[400],
[JobStatus.InProgress]: colors.blue[500],
[JobStatus.Completed]: colors.green[500],
};

const statusLabels = {
[JobStatus.ActionRequired]: "Action Required",
[JobStatus.ExternalRunNotFound]: "External Run Not Found",
[JobStatus.InvalidIntegration]: "Invalid Integration",
[JobStatus.InvalidJobAgent]: "Invalid Job Agent",
[JobStatus.Failure]: "Failure",
[JobStatus.Cancelled]: "Cancelled",
[JobStatus.Skipped]: "Skipped",
[JobStatus.Pending]: "Pending",
[JobStatus.InProgress]: "In Progress",
[JobStatus.Completed]: "Completed",
};

export const JobHistoryChart: React.FC<{
workspace: Workspace;
className?: string;
}> = ({ className, workspace }) => {
const releaseJobTriggers = api.job.config.byWorkspaceId.list.useQuery(
workspace.id,
{ refetchInterval: 60_000 },
);

const dailyCounts = api.job.config.byWorkspaceId.dailyCount.useQuery({
workspaceId: workspace.id,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
});

const now = startOfDay(new Date());
const chartData = dateRange(sub(now, { weeks: 6 }), now, 1, "days").map(
(d) => ({
date: new Date(d).toISOString(),
jobs: dailyCounts.data?.find((c) => isSameDay(c.date, d))?.count ?? 0,
}),
(d) => {
const dayData =
dailyCounts.data?.find((c) => isSameDay(c.date, d))?.statusCounts ?? {};
const date = new Date(d).toISOString();
return { date, ...dayData };
},
);

const targets = api.target.byWorkspaceId.list.useQuery({
workspaceId: workspace.id,
});
const deployments = api.deployment.byWorkspaceId.useQuery(workspace.id, {});

const totalJobs = dailyCounts.data?.reduce(
(acc, c) => acc + Number(c.totalCount),
0,
);

return (
<div className={className}>
<CardHeader className="flex flex-col items-stretch space-y-0 border-b p-0 sm:flex-row">
Expand All @@ -61,9 +86,7 @@ export const JobHistoryChart: React.FC<{
<div className="relative z-30 flex flex-1 flex-col justify-center gap-1 border-t px-6 py-4 text-left even:border-l data-[active=true]:bg-muted/50 sm:border-l sm:border-t-0 sm:px-8 sm:py-6">
<span className="text-xs text-muted-foreground">Jobs</span>
<span className="text-lg font-bold leading-none sm:text-3xl">
{releaseJobTriggers.data?.filter(
(t) => t.job.status !== JobStatus.Pending,
).length ?? "-"}
{totalJobs ?? "-"}
</span>
</div>

Expand Down Expand Up @@ -114,21 +137,43 @@ export const JobHistoryChart: React.FC<{
}}
/>
<ChartTooltip
content={
<ChartTooltipContent
className="w-[150px]"
nameKey="views"
labelFormatter={(value) => {
return new Date(value).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
});
}}
/>
}
content={({ active, payload, label }) => {
if (active && payload?.length)
return (
<div className="rounded-lg border bg-background p-2 shadow-sm">
<div className="font-semibold">
{new Date(label).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})}
</div>
{payload.reverse().map((entry, index) => (
<div
key={`item-${index}`}
className="flex items-center gap-2"
>
<div
className="h-3 w-3 rounded-full"
style={{ backgroundColor: entry.color }}
/>
<span>{statusLabels[entry.name as JobStatus]}: </span>
<span className="font-semibold">{entry.value}</span>
</div>
))}
</div>
);
return null;
}}
/>
<Bar dataKey="jobs" fill={`hsl(var(--chart-1))`} />
{Object.entries(statusColors).map(([status, color]) => (
<Bar
key={status}
dataKey={status.toLowerCase()}
stackId="jobs"
fill={color}
/>
))}
</BarChart>
</ChartContainer>
</CardContent>
Expand Down
25 changes: 21 additions & 4 deletions packages/api/src/router/job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,37 @@ const releaseJobTriggerRouter = createTRPCRouter({
})
.query(async ({ ctx, input }) => {
const dateTruncExpr = sql<Date>`date_trunc('day', ${releaseJobTrigger.createdAt} AT TIME ZONE 'UTC' AT TIME ZONE '${sql.raw(input.timezone)}')`;
return ctx.db

const subquery = ctx.db
.select({
date: dateTruncExpr.as("date"),
count: sql<number>`COUNT(*)`.as("count"),
status: job.status,
countPerStatus: sql<number>`COUNT(*)`.as("countPerStatus"),
})
.from(releaseJobTrigger)
.innerJoin(job, eq(releaseJobTrigger.jobId, job.id))
.innerJoin(
environment,
eq(releaseJobTrigger.environmentId, environment.id),
)
.innerJoin(system, eq(environment.systemId, system.id))
.where(eq(system.workspaceId, input.workspaceId))
.groupBy(dateTruncExpr)
.orderBy(dateTruncExpr);
.groupBy(dateTruncExpr, job.status)
.as("sub");

return ctx.db
.select({
date: subquery.date,
totalCount: sql<number>`SUM(${subquery.countPerStatus})`.as(
"totalCount",
),
statusCounts: sql<Record<JobStatus, number>>`
jsonb_object_agg(${subquery.status}, ${subquery.countPerStatus})
`.as("statusCounts"),
})
.from(subquery)
.groupBy(subquery.date)
.orderBy(subquery.date);
}),
}),

Expand Down

0 comments on commit de9f31f

Please sign in to comment.