mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
add: database read, writes in org. usage screen.
This commit is contained in:
@@ -193,6 +193,65 @@
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Databases reads and writes</Heading>
|
||||
|
||||
<p class="text">
|
||||
The total number of database reads and writes across all projects in your organization.
|
||||
</p>
|
||||
<svelte:fragment slot="aside">
|
||||
<!-- types need to be added to console sdk -->
|
||||
{#if data.organizationUsage.databasesReadsTotal || data.organizationUsage.databasesWritesTotal}
|
||||
<div style:margin-top="-1.5em">
|
||||
<BarChart
|
||||
options={{
|
||||
yAxis: {
|
||||
axisLabel: {
|
||||
formatter: formatNum
|
||||
}
|
||||
}
|
||||
}}
|
||||
series={[
|
||||
{
|
||||
name: 'Reads',
|
||||
data: [
|
||||
...data.organizationUsage.databasesReads.map((e) => [
|
||||
e.date,
|
||||
e.value
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Writes',
|
||||
data: [
|
||||
...data.organizationUsage.databasesWrites.map((e) => [
|
||||
e.date,
|
||||
e.value
|
||||
])
|
||||
]
|
||||
}
|
||||
]} />
|
||||
</div>
|
||||
{#if project?.length > 0}
|
||||
<ProjectBreakdown
|
||||
{data}
|
||||
projects={project}
|
||||
databaseOperationMetric={['databasesReads', 'databasesWrites']} />
|
||||
{/if}
|
||||
{:else}
|
||||
<Card isDashed>
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
<span
|
||||
class="icon-chart-square-bar text-large"
|
||||
aria-hidden="true"
|
||||
style="font-size: 32px;" />
|
||||
<p class="u-bold">No data to show</p>
|
||||
</div>
|
||||
</Card>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Executions</Heading>
|
||||
|
||||
@@ -318,6 +377,7 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">GB hours</Heading>
|
||||
|
||||
@@ -378,6 +438,7 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Phone OTP</Heading>
|
||||
<p class="text">
|
||||
@@ -430,6 +491,7 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<TotalMembers members={data?.organizationMembers} />
|
||||
|
||||
<p class="text common-section u-color-text-gray">
|
||||
|
||||
+98
-23
@@ -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<Metric, 'databasesReads' | 'databasesWrites'>;
|
||||
|
||||
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`);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<Collapsible>
|
||||
@@ -76,7 +117,13 @@
|
||||
<TableScroll dense noStyles noMargin style="table-layout: auto">
|
||||
<TableHeader>
|
||||
<TableCellHead>Project</TableCellHead>
|
||||
<TableCellHead>{getMetricTitle(metric)}</TableCellHead>
|
||||
{#if databaseOperationMetric}
|
||||
<TableCellHead>Reads</TableCellHead>
|
||||
<TableCellHead>Writes</TableCellHead>
|
||||
{:else}
|
||||
<TableCellHead>{getMetricTitle(metric)}</TableCellHead>
|
||||
{/if}
|
||||
|
||||
{#if estimate}
|
||||
<TableCellHead>Estimated cost</TableCellHead>
|
||||
{/if}
|
||||
@@ -85,17 +132,33 @@
|
||||
{/if}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#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}
|
||||
<TableRow>
|
||||
<TableCell title="Project">
|
||||
{data.projectNames[project.projectId]?.name ?? 'Unknown'}
|
||||
</TableCell>
|
||||
<TableCell title={getMetricTitle(metric)}
|
||||
>{format(project.usage)}</TableCell>
|
||||
{#if databaseOperationMetric}
|
||||
<TableCell title="Reads">
|
||||
{format(project.databasesReads ?? 0)}
|
||||
</TableCell>
|
||||
<TableCell title="Writes">
|
||||
{format(project.databasesWrites ?? 0)}
|
||||
</TableCell>
|
||||
{:else}
|
||||
<TableCell>
|
||||
{format(project.usage)}
|
||||
</TableCell>
|
||||
{/if}
|
||||
|
||||
{#if project.estimate}
|
||||
<TableCell title="Estimated cost"
|
||||
>{formatCurrency(project.estimate)}</TableCell>
|
||||
<TableCell title="Estimated cost">
|
||||
{formatCurrency(project.estimate)}
|
||||
</TableCell>
|
||||
{/if}
|
||||
</TableRow>
|
||||
{:else}
|
||||
@@ -103,11 +166,23 @@
|
||||
<TableCell title="Project">
|
||||
{data.projectNames[project.projectId]?.name ?? 'Unknown'}
|
||||
</TableCell>
|
||||
<TableCell title={getMetricTitle(metric)}
|
||||
>{format(project.usage)}</TableCell>
|
||||
{#if databaseOperationMetric}
|
||||
<TableCell title="Reads">
|
||||
{format(project.databasesReads ?? 0)}
|
||||
</TableCell>
|
||||
<TableCell title="Writes">
|
||||
{format(project.databasesWrites ?? 0)}
|
||||
</TableCell>
|
||||
{:else}
|
||||
<TableCell>
|
||||
{format(project.usage)}
|
||||
</TableCell>
|
||||
{/if}
|
||||
|
||||
{#if project.estimate}
|
||||
<TableCell title="Estimated cost"
|
||||
>{formatCurrency(project.estimate)}</TableCell>
|
||||
<TableCell title="Estimated cost">
|
||||
{formatCurrency(project.estimate)}
|
||||
</TableCell>
|
||||
{/if}
|
||||
<TableCell right={true}>
|
||||
<span
|
||||
|
||||
Reference in New Issue
Block a user