From 884c454c55c72dcbbcba6c6982bc81dca40a7e2c Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 24 Jan 2025 13:01:08 +0530 Subject: [PATCH] add: database read, writes in org. usage screen. --- .../usage/[[invoice]]/+page.svelte | 62 +++++++++ .../usage/[[invoice]]/ProjectBreakdown.svelte | 121 ++++++++++++++---- 2 files changed, 160 insertions(+), 23 deletions(-) diff --git a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte index 3cebea75e..77096eb10 100644 --- a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte +++ b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte @@ -193,6 +193,65 @@ + + Databases reads and writes + +

+ The total number of database reads and writes across all projects in your organization. +

+ + + {#if data.organizationUsage.databasesReadsTotal || data.organizationUsage.databasesWritesTotal} +
+ [ + e.date, + e.value + ]) + ] + }, + { + name: 'Writes', + data: [ + ...data.organizationUsage.databasesWrites.map((e) => [ + e.date, + e.value + ]) + ] + } + ]} /> +
+ {#if project?.length > 0} + + {/if} + {:else} + +
+
+
+ {/if} +
+
+ Executions @@ -318,6 +377,7 @@ {/if} + GB hours @@ -378,6 +438,7 @@ {/if} + Phone OTP

@@ -430,6 +491,7 @@ {/if} +

diff --git a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/ProjectBreakdown.svelte b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/ProjectBreakdown.svelte index 8542fe75c..7bd50227c 100644 --- a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/ProjectBreakdown.svelte +++ b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/ProjectBreakdown.svelte @@ -15,14 +15,26 @@ import type { OrganizationUsage } from '$lib/sdk/billing'; import { base } from '$app/paths'; import { canSeeProjects } from '$lib/stores/roles'; + import { onMount } from 'svelte'; + + type Metric = + | 'users' + | 'storage' + | 'bandwidth' + | 'executions' + | 'authPhoneTotal' + | 'databasesReads' + | 'databasesWrites'; - type Metric = 'users' | 'storage' | 'bandwidth' | 'executions' | 'authPhoneTotal'; type Estimate = 'authPhoneEstimate'; + type DatabaseOperationMetric = Extract; + export let data: PageData; export let projects: OrganizationUsage['projects']; - export let metric: Metric; + export let metric: Metric | undefined = undefined; export let estimate: Estimate | undefined = undefined; + export let databaseOperationMetric: DatabaseOperationMetric[] | undefined = undefined; function getMetricTitle(metric: Metric): string { switch (metric) { @@ -38,25 +50,48 @@ } function groupByProject( - metric: Metric, - estimate?: Estimate - ): Array<{ projectId: string; usage: number; estimate?: number }> { + metric: Metric | undefined, + estimate?: Estimate, + databaseOps?: DatabaseOperationMetric[] + ): Array<{ + projectId: string; + databasesReads?: number; + databasesWrites?: number; + usage?: number; + estimate?: number; + }> { const data = []; for (const project of projects) { - const usage = project[metric]; - if (!usage) { - continue; + if (metric) { + const usage = project[metric]; + if (!usage) continue; + + data.push({ + projectId: project.projectId, + usage: usage ?? 0, + estimate: estimate ? project[estimate] : undefined + }); + } else if (databaseOps) { + const reads = project['databasesReads'] ?? 0; + const writes = project['databasesWrites'] ?? 0; + + if (reads || writes) { + data.push({ + projectId: project.projectId, + databasesReads: reads, + databasesWrites: writes + }); + } } - data.push({ - projectId: project.projectId, - usage: usage ?? 0, - estimate: estimate ? project[estimate] : undefined - }); } return data; } function format(value: number): string { + if (databaseOperationMetric) { + return abbreviateNumber(value); + } + switch (metric) { case 'authPhoneTotal': return formatNumberWithCommas(value); @@ -68,6 +103,12 @@ return humanFileSize(value).value + humanFileSize(value).unit; } } + + onMount(() => { + if (metric === undefined && databaseOperationMetric === undefined) { + throw new Error(`metric or database operations must be defined`); + } + }); @@ -76,7 +117,13 @@ Project - {getMetricTitle(metric)} + {#if databaseOperationMetric} + Reads + Writes + {:else} + {getMetricTitle(metric)} + {/if} + {#if estimate} Estimated cost {/if} @@ -85,17 +132,33 @@ {/if} - {#each groupByProject(metric, estimate).sort((a, b) => b.usage - a.usage) as project} + {#each groupByProject(metric, estimate, databaseOperationMetric).sort((a, b) => { + const aValue = a.usage ?? a.databasesReads ?? 0; + const bValue = b.usage ?? b.databasesReads ?? 0; + return bValue - aValue; + }) as project} {#if !$canSeeProjects} {data.projectNames[project.projectId]?.name ?? 'Unknown'} - {format(project.usage)} + {#if databaseOperationMetric} + + {format(project.databasesReads ?? 0)} + + + {format(project.databasesWrites ?? 0)} + + {:else} + + {format(project.usage)} + + {/if} + {#if project.estimate} - {formatCurrency(project.estimate)} + + {formatCurrency(project.estimate)} + {/if} {:else} @@ -103,11 +166,23 @@ {data.projectNames[project.projectId]?.name ?? 'Unknown'} - {format(project.usage)} + {#if databaseOperationMetric} + + {format(project.databasesReads ?? 0)} + + + {format(project.databasesWrites ?? 0)} + + {:else} + + {format(project.usage)} + + {/if} + {#if project.estimate} - {formatCurrency(project.estimate)} + + {formatCurrency(project.estimate)} + {/if}