Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/lib/server/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ export const getOrganizationSizes = async () => {
orgId: organization.id,
name: organization.name,
memberCount: count(membership.userId),
totalSecrets: sql<number>`coalesce(sum(${stats.totalSecrets}), 0)`
totalSecrets: sql<number>`coalesce(sum(${stats.totalSecrets}), 0)`,
totalSecretRequests: sql<number>`coalesce(sum(${stats.totalSecretRequests}), 0)`
})
.from(organization)
.innerJoin(membership, eq(membership.organizationId, organization.id))
Expand All @@ -156,6 +157,17 @@ export const getOrganizationSizes = async () => {
return result;
};

export const getOrganizationsByTier = async () => {
const result = await db
.select({
tier: organization.subscriptionTier,
count: count()
})
.from(organization)
.groupBy(organization.subscriptionTier);
return result;
};

// ── Subscriptions & Revenue ────────────────────────────

export const getActiveSubscriptions = async () => {
Expand Down
4 changes: 4 additions & 0 deletions src/routes/(app)/(default)/account/admin/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getAdoptionRates,
getApiKeyStats,
getGlobalStats,
getOrganizationsByTier,
getOrganizationSizes,
getRecentSignups,
getSecretCounts,
Expand Down Expand Up @@ -30,6 +31,7 @@ export const load: PageServerLoad = async () => {
secretRequestStats,
totalOrganizations,
organizationSizes,
organizationsByTier,
activeSubscriptions,
apiKeyStats,
whiteLabelStats
Expand All @@ -45,6 +47,7 @@ export const load: PageServerLoad = async () => {
getSecretRequestStats(),
getTotalOrganizations(),
getOrganizationSizes(),
getOrganizationsByTier(),
getActiveSubscriptions(),
getApiKeyStats(),
getWhiteLabelStats()
Expand All @@ -63,6 +66,7 @@ export const load: PageServerLoad = async () => {
secretRequestStats,
totalOrganizations,
organizationSizes,
organizationsByTier,
activeSubscriptions,
apiKeyStats,
whiteLabelStats
Expand Down
30 changes: 30 additions & 0 deletions src/routes/(app)/(default)/account/admin/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@
<span class="text-muted-foreground">Expired:</span>
<span class="font-medium">{data.secretRequestStats.expired}</span>
</div>
<div>
<span class="text-muted-foreground">Total (all-time):</span>
<span class="font-medium">{data.globalStats?.totalSecretRequests ?? 0}</span>
</div>
{#if data.secretRequestStats.total > 0}
<div>
<span class="text-muted-foreground">Response rate:</span>
Expand Down Expand Up @@ -219,6 +223,30 @@

<!-- Organizations Section -->
<Card title="Organizations" class="mb-6">
<h3 class="mb-2 text-lg font-semibold">Subscription Tiers</h3>
<Table.Root>
<Table.Header>
<Table.Row>
<Table.Head>Tier</Table.Head>
<Table.Head class="text-right">Organizations</Table.Head>
<Table.Head class="text-right">%</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#each data.organizationsByTier as tier, i (i)}
<Table.Row>
<Table.Cell>{tier.tier}</Table.Cell>
<Table.Cell class="text-right">{tier.count}</Table.Cell>
<Table.Cell class="text-right"
>{formatPercent(tier.count / data.totalOrganizations)}</Table.Cell
>
</Table.Row>
{/each}
</Table.Body>
</Table.Root>

<Separator class="my-6" />

{#if data.organizationSizes.length === 0}
<p class="text-muted-foreground">No organizations yet.</p>
{:else}
Expand All @@ -228,6 +256,7 @@
<Table.Head>Name</Table.Head>
<Table.Head class="text-right">Members</Table.Head>
<Table.Head class="text-right">Secrets</Table.Head>
<Table.Head class="text-right">Secret Requests</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
Expand All @@ -236,6 +265,7 @@
<Table.Cell>{org.name}</Table.Cell>
<Table.Cell class="text-right">{org.memberCount}</Table.Cell>
<Table.Cell class="text-right">{org.totalSecrets}</Table.Cell>
<Table.Cell class="text-right">{org.totalSecretRequests}</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
Expand Down
Loading