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}