diff --git a/apps/webapp/app/components/billing/ConcurrentRunsChart.tsx b/apps/webapp/app/components/billing/ConcurrentRunsChart.tsx
index 0692b9931c5..5e1ef198efc 100644
--- a/apps/webapp/app/components/billing/ConcurrentRunsChart.tsx
+++ b/apps/webapp/app/components/billing/ConcurrentRunsChart.tsx
@@ -73,7 +73,13 @@ export function ConcurrentRunsChart({
>
-
+
+ {!hasDailyRunsData && (
+
+ No daily Runs to show
+
+ )}
+
+
+ {
+ if (!item.date) return "";
+ const date = new Date(item.date);
+ if (date.getDate() === 1) {
+ return dateFormatter.format(date);
+ }
+ return `${date.getDate()}`;
+ }}
+ className="text-xs"
+ >
+
+
+
+ {
+ const dateString = data.at(0)?.payload.date;
+ if (!dateString) {
+ return "";
+ }
+
+ return dateFormatter.format(new Date(dateString));
+ }}
+ />
+
+
+
+
+ );
+}
diff --git a/apps/webapp/app/presenters/OrgUsagePresenter.server.ts b/apps/webapp/app/presenters/OrgUsagePresenter.server.ts
index b77ad7b9ebe..c0fddfc3add 100644
--- a/apps/webapp/app/presenters/OrgUsagePresenter.server.ts
+++ b/apps/webapp/app/presenters/OrgUsagePresenter.server.ts
@@ -1,9 +1,7 @@
import { estimate } from "@trigger.dev/billing";
-import { formatDateTime } from "~/components/primitives/DateTime";
import { PrismaClient, prisma } from "~/db.server";
import { featuresForRequest } from "~/features.server";
import { BillingService } from "~/services/billing.server";
-import { logger } from "~/services/logger.server";
export class OrgUsagePresenter {
#prismaClient: PrismaClient;
@@ -108,7 +106,7 @@ export class OrgUsagePresenter {
const ThirtyDaysAgo = new Date();
ThirtyDaysAgo.setDate(ThirtyDaysAgo.getDate() - 30);
- ThirtyDaysAgo.setHours(0, 0, 0, 0);
+ ThirtyDaysAgo.setUTCHours(0, 0, 0, 0);
const hasConcurrencyData = concurrencyChartRawData.length > 0;
const concurrencyChartRawDataFilledIn = fillInMissingConcurrencyDays(
@@ -117,6 +115,13 @@ export class OrgUsagePresenter {
concurrencyChartRawData
);
+ const dailyRunsRawData = await this.#prismaClient.$queryRaw<
+ { day: Date; runs: BigInt }[]
+ >`SELECT date_trunc('day', "createdAt") as day, COUNT(*) as runs FROM "JobRun" WHERE "organizationId" = ${organization.id} AND "createdAt" >= NOW() - INTERVAL '30 days' AND "internal" = FALSE GROUP BY day`;
+
+ const hasDailyRunsData = dailyRunsRawData.length > 0;
+ const dailyRunsDataFilledIn = fillInMissingDailyRuns(ThirtyDaysAgo, 31, dailyRunsRawData);
+
const endOfMonth = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 1);
endOfMonth.setDate(endOfMonth.getDate() - 1);
const projectedRunsCount = Math.round(
@@ -146,12 +151,12 @@ export class OrgUsagePresenter {
const periodStart = new Date();
periodStart.setDate(1);
- periodStart.setHours(0, 0, 0, 0);
+ periodStart.setUTCHours(0, 0, 0, 0);
const periodEnd = new Date();
periodEnd.setDate(1);
periodEnd.setMonth(periodEnd.getMonth() + 1);
- periodEnd.setHours(0, 0, 0, 0);
+ periodEnd.setUTCHours(0, 0, 0, 0);
return {
id: organization.id,
@@ -161,6 +166,8 @@ export class OrgUsagePresenter {
hasMonthlyRunData,
concurrencyData: concurrencyChartRawDataFilledIn,
hasConcurrencyData,
+ dailyRunsData: dailyRunsDataFilledIn,
+ hasDailyRunsData,
runCostEstimation,
projectedRunCostEstimation,
periodStart,
@@ -224,6 +231,33 @@ function fillInMissingConcurrencyDays(
return outputData;
}
+function fillInMissingDailyRuns(
+ startDate: Date,
+ days: number,
+ data: Array<{ day: Date; runs: BigInt }>
+) {
+ const outputData: Array<{ date: Date; runs: number }> = [];
+ for (let i = 0; i < days; i++) {
+ const date = new Date(startDate);
+ date.setDate(date.getDate() + i);
+
+ const foundData = data.find((d) => d.day.toISOString() === date.toISOString());
+ if (!foundData) {
+ outputData.push({
+ date,
+ runs: 0,
+ });
+ } else {
+ outputData.push({
+ date,
+ runs: Number(foundData.runs),
+ });
+ }
+ }
+
+ return outputData;
+}
+
// Start month will be like 2023-03 and endMonth will be like 2023-10
// The result should be an array of months between these two months, including the start and end month
// So for example, if startMonth is 2023-03 and endMonth is 2023-10, the result should be:
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing._index/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing._index/route.tsx
index 1d8f8b49081..e79342c8067 100644
--- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing._index/route.tsx
+++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing._index/route.tsx
@@ -8,6 +8,7 @@ import { ConcurrentRunsChart } from "~/components/billing/ConcurrentRunsChart";
import { UsageBar } from "~/components/billing/UsageBar";
import { LinkButton } from "~/components/primitives/Buttons";
import { Callout } from "~/components/primitives/Callout";
+import { DailyRunsChart } from "~/components/billing/DailyRunsChat";
import { DateTime } from "~/components/primitives/DateTime";
import { Header2, Header3 } from "~/components/primitives/Headers";
import { Paragraph } from "~/components/primitives/Paragraph";
@@ -104,6 +105,16 @@ export default function Page() {
+
+