mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: usage for databases
This commit is contained in:
@@ -10,3 +10,4 @@ export { default as Wizard } from './wizard.svelte';
|
||||
export { default as WizardStep } from './wizardStep.svelte';
|
||||
export { default as Breadcrumbs } from './breadcrumbs.svelte';
|
||||
export { default as Unauthenticated } from './unauthenticated.svelte';
|
||||
export { default as Usage, type UsagePeriods } from './usage.svelte';
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
<script context="module" lang="ts">
|
||||
export type UsagePeriods = '24h' | '30d' | '90d';
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { BarChart, LineChart } from '$lib/charts';
|
||||
import { Card, Tiles } from '$lib/components';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
type MetricMetadata = {
|
||||
title: string;
|
||||
legend: string;
|
||||
};
|
||||
|
||||
export let count: Models.Metric[];
|
||||
export let created: Models.Metric[];
|
||||
export let read: Models.Metric[];
|
||||
export let updated: Models.Metric[];
|
||||
export let deleted: Models.Metric[];
|
||||
|
||||
export let countMetadata: MetricMetadata;
|
||||
export let createdMetadata: MetricMetadata;
|
||||
export let readMetadata: MetricMetadata;
|
||||
export let updatedMetadata: MetricMetadata;
|
||||
export let deletedMetadata: MetricMetadata;
|
||||
|
||||
export let range: UsagePeriods;
|
||||
|
||||
function last(set: Models.Metric[]): Models.Metric | null {
|
||||
return set.slice(-1)[0] ?? null;
|
||||
}
|
||||
|
||||
function total(set: Models.Metric[]): number {
|
||||
return set.reduce((prev, curr) => prev + curr.value, 0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="u-flex u-main-space-between common-section">
|
||||
<h2 class="heading-level-5">Users</h2>
|
||||
<ul class="drop-tabs">
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (range = '24h')}
|
||||
disabled={range === '24h'}>
|
||||
<span class="text">24h</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (range = '30d')}
|
||||
disabled={range === '30d'}>
|
||||
<span class="text">30d</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (range = '90d')}
|
||||
disabled={range === '90d'}>
|
||||
<span class="text">90d</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Card>
|
||||
{#if count}
|
||||
<h6 class="heading-level-6">{last(count).value}</h6>
|
||||
<p>{countMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<BarChart
|
||||
series={[
|
||||
{
|
||||
name: countMetadata.legend,
|
||||
data: [...count.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Tiles>
|
||||
<Card isTile>
|
||||
{#if created}
|
||||
<h6 class="heading-level-6">{total(created)}</h6>
|
||||
<p>{createdMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: createdMetadata.legend,
|
||||
data: [...created.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if read}
|
||||
<h6 class="heading-level-6">{total(read)}</h6>
|
||||
<p>{createdMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: readMetadata.legend,
|
||||
data: [...read.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if updated}
|
||||
<h6 class="heading-level-6">{total(updated)}</h6>
|
||||
<p>{updatedMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: updatedMetadata.legend,
|
||||
data: [...updated.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if deleted}
|
||||
<h6 class="heading-level-6">{total(deleted)}</h6>
|
||||
<p>{deletedMetadata.title}</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: deletedMetadata.legend,
|
||||
data: [...deleted.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
</Tiles>
|
||||
</Container>
|
||||
@@ -1,133 +1,45 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { BarChart, LineChart } from '$lib/charts';
|
||||
import { Card, Tiles } from '$lib/components';
|
||||
import { Usage } from '$lib/layout';
|
||||
import { usersUsage } from '../store';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
import type { UsagePeriods } from '$lib/layout/usage.svelte';
|
||||
|
||||
let currentRange = '30d';
|
||||
let range: UsagePeriods = '30d';
|
||||
|
||||
$: usersUsage.load(currentRange);
|
||||
$: usersUsage.load(range);
|
||||
|
||||
// TODO: metric type is wrong
|
||||
$: usersCount = $usersUsage?.usersCount as unknown as Models.Metric[];
|
||||
$: usersCreate = $usersUsage?.usersCreate as unknown as Models.Metric[];
|
||||
$: usersRead = $usersUsage?.usersRead as unknown as Models.Metric[];
|
||||
$: usersUpdate = $usersUsage?.usersUpdate as unknown as Models.Metric[];
|
||||
$: usersDelete = $usersUsage?.usersDelete as unknown as Models.Metric[];
|
||||
|
||||
function last(set: Array<unknown>): Models.Metric | null {
|
||||
return (set as Models.Metric[]).slice(-1)[0] ?? null;
|
||||
}
|
||||
|
||||
// TODO: metric type is wrong
|
||||
function total(set: Array<unknown>): number {
|
||||
return (set as Models.Metric[]).reduce((prev, curr) => prev + curr.value, 0);
|
||||
}
|
||||
$: count = $usersUsage?.usersCount as unknown as Models.Metric[];
|
||||
$: created = $usersUsage?.usersCreate as unknown as Models.Metric[];
|
||||
$: read = $usersUsage?.usersRead as unknown as Models.Metric[];
|
||||
$: updated = $usersUsage?.usersUpdate as unknown as Models.Metric[];
|
||||
$: deleted = $usersUsage?.usersDelete as unknown as Models.Metric[];
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="u-flex u-main-space-between common-section">
|
||||
<h2 class="heading-level-5">Users</h2>
|
||||
<ul class="drop-tabs">
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '24h')}
|
||||
disabled={currentRange === '24h'}>
|
||||
<span class="text">24h</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '30d')}
|
||||
disabled={currentRange === '30d'}>
|
||||
<span class="text">30d</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '90d')}
|
||||
disabled={currentRange === '90d'}>
|
||||
<span class="text">90d</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{#if $usersUsage}
|
||||
<Card>
|
||||
{#if usersCount}
|
||||
<h6 class="heading-level-6">{last(usersCount).value}</h6>
|
||||
<p>Registered users</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<BarChart
|
||||
series={[
|
||||
{
|
||||
name: 'User',
|
||||
data: [...usersCount.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Tiles>
|
||||
<Card isTile>
|
||||
{#if usersCreate}
|
||||
<h6 class="heading-level-6">{total(usersCreate)}</h6>
|
||||
<p>Users created</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Create',
|
||||
data: [...usersCreate.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if usersRead}
|
||||
<h6 class="heading-level-6">{total(usersRead)}</h6>
|
||||
<p>Users read</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Read',
|
||||
data: [...usersRead.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if usersUpdate}
|
||||
<h6 class="heading-level-6">{total(usersUpdate)}</h6>
|
||||
<p>Users updated</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Update',
|
||||
data: [...usersUpdate.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if usersDelete}
|
||||
<h6 class="heading-level-6">{total(usersDelete)}</h6>
|
||||
<p>Users deleted</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Delete',
|
||||
data: [...usersDelete.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
</Tiles>
|
||||
{/if}
|
||||
</Container>
|
||||
<Usage
|
||||
bind:range
|
||||
{count}
|
||||
{created}
|
||||
{read}
|
||||
{updated}
|
||||
{deleted}
|
||||
countMetadata={{
|
||||
legend: 'Users',
|
||||
title: 'Registered users'
|
||||
}}
|
||||
createdMetadata={{
|
||||
legend: 'Create',
|
||||
title: 'Users created'
|
||||
}}
|
||||
readMetadata={{
|
||||
legend: 'Read',
|
||||
title: 'Users read'
|
||||
}}
|
||||
updatedMetadata={{
|
||||
legend: 'Update',
|
||||
title: 'Users updated'
|
||||
}}
|
||||
deletedMetadata={{
|
||||
legend: 'Delete',
|
||||
title: 'Users deleted'
|
||||
}} />
|
||||
|
||||
+4
@@ -46,6 +46,10 @@
|
||||
href: `${path}/indexes`,
|
||||
title: 'Indexes'
|
||||
},
|
||||
{
|
||||
href: `${path}/usage`,
|
||||
title: 'Usage'
|
||||
},
|
||||
{
|
||||
href: `${path}/settings`,
|
||||
title: 'Settings'
|
||||
|
||||
+14
@@ -116,3 +116,17 @@ export const attributeList = cachedStore<
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export const collectionUsage = cachedStore<
|
||||
Models.UsageCollection,
|
||||
{
|
||||
load: (databaseId: string, collectionId: string, range: string) => Promise<void>;
|
||||
}
|
||||
>('collectionUsage', function ({ set }) {
|
||||
return {
|
||||
load: async (databaseId, range) => {
|
||||
const usages = await sdkForProject.databases.getCollectionUsage(databaseId, range);
|
||||
set(usages);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { Usage, type UsagePeriods } from '$lib/layout';
|
||||
import { collectionUsage } from '../store';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
let range: UsagePeriods = '30d';
|
||||
|
||||
const databaseId = $page.params.database;
|
||||
const collectionId = $page.params.collection;
|
||||
|
||||
$: collectionUsage.load(databaseId, collectionId, range);
|
||||
|
||||
// TODO: metric type is wrong
|
||||
$: count = $collectionUsage?.documentsCount as unknown as Models.Metric[];
|
||||
$: created = $collectionUsage?.documentsCreate as unknown as Models.Metric[];
|
||||
$: read = $collectionUsage?.documentsRead as unknown as Models.Metric[];
|
||||
$: updated = $collectionUsage?.documentsUpdate as unknown as Models.Metric[];
|
||||
$: deleted = $collectionUsage?.documentsDelete as unknown as Models.Metric[];
|
||||
</script>
|
||||
|
||||
<Usage
|
||||
bind:range
|
||||
{count}
|
||||
{created}
|
||||
{read}
|
||||
{updated}
|
||||
{deleted}
|
||||
countMetadata={{
|
||||
legend: 'Documents',
|
||||
title: 'Total documents'
|
||||
}}
|
||||
createdMetadata={{
|
||||
legend: 'Create',
|
||||
title: 'Documents created'
|
||||
}}
|
||||
readMetadata={{
|
||||
legend: 'Read',
|
||||
title: 'Documents read'
|
||||
}}
|
||||
updatedMetadata={{
|
||||
legend: 'Update',
|
||||
title: 'Documents updated'
|
||||
}}
|
||||
deletedMetadata={{
|
||||
legend: 'Delete',
|
||||
title: 'Documents deleted'
|
||||
}} />
|
||||
@@ -38,3 +38,17 @@ export const database = cachedStore<
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export const databaseUsage = cachedStore<
|
||||
Models.UsageDatabase,
|
||||
{
|
||||
load: (databaseId: string, range: string) => Promise<void>;
|
||||
}
|
||||
>('databaseUsage', function ({ set }) {
|
||||
return {
|
||||
load: async (databaseId, range) => {
|
||||
const usages = await sdkForProject.databases.getDatabaseUsage(databaseId, range);
|
||||
set(usages);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
+45
-7
@@ -1,9 +1,47 @@
|
||||
<script>
|
||||
import { Card } from '$lib/components';
|
||||
import { Container } from '$lib/layout';
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { Usage, type UsagePeriods } from '$lib/layout';
|
||||
import { databaseUsage } from '../store';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
let range: UsagePeriods = '30d';
|
||||
|
||||
const databaseId = $page.params.database;
|
||||
|
||||
$: databaseUsage.load(databaseId, range);
|
||||
|
||||
// TODO: metric type is wrong
|
||||
$: count = $databaseUsage?.collectionsCount as unknown as Models.Metric[];
|
||||
$: created = $databaseUsage?.collectionsCreate as unknown as Models.Metric[];
|
||||
$: read = $databaseUsage?.collectionsRead as unknown as Models.Metric[];
|
||||
$: updated = $databaseUsage?.collectionsUpdate as unknown as Models.Metric[];
|
||||
$: deleted = $databaseUsage?.collectionsDelete as unknown as Models.Metric[];
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<h1>Usage</h1>
|
||||
<Card />
|
||||
</Container>
|
||||
<Usage
|
||||
bind:range
|
||||
{count}
|
||||
{created}
|
||||
{read}
|
||||
{updated}
|
||||
{deleted}
|
||||
countMetadata={{
|
||||
legend: 'Collections',
|
||||
title: 'Total collections'
|
||||
}}
|
||||
createdMetadata={{
|
||||
legend: 'Create',
|
||||
title: 'Collections created'
|
||||
}}
|
||||
readMetadata={{
|
||||
legend: 'Read',
|
||||
title: 'Collections read'
|
||||
}}
|
||||
updatedMetadata={{
|
||||
legend: 'Update',
|
||||
title: 'Collections updated'
|
||||
}}
|
||||
deletedMetadata={{
|
||||
legend: 'Delete',
|
||||
title: 'Collections deleted'
|
||||
}} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { sdkForProject } from '$lib/stores/sdk';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
import { cachedStore } from '$lib/helpers/cache';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
export const databaseList = cachedStore<
|
||||
Models.DatabaseList,
|
||||
@@ -15,3 +15,17 @@ export const databaseList = cachedStore<
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export const databasesUsage = cachedStore<
|
||||
Models.UsageDatabases,
|
||||
{
|
||||
load: (range: string) => Promise<void>;
|
||||
}
|
||||
>('databasesUsage', function ({ set }) {
|
||||
return {
|
||||
load: async (range) => {
|
||||
const usages = await sdkForProject.databases.getUsage(range);
|
||||
set(usages);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,10 +1,44 @@
|
||||
<script>
|
||||
import { Card } from '$lib/components';
|
||||
import { Container } from '$lib/layout';
|
||||
<script lang="ts">
|
||||
import { Usage, type UsagePeriods } from '$lib/layout';
|
||||
import { databasesUsage } from '../store';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
let range: UsagePeriods = '30d';
|
||||
|
||||
$: databasesUsage.load(range);
|
||||
|
||||
// TODO: metric type is wrong
|
||||
$: count = $databasesUsage?.databasesCount as unknown as Models.Metric[];
|
||||
$: created = $databasesUsage?.databasesCreate as unknown as Models.Metric[];
|
||||
$: read = $databasesUsage?.databasesRead as unknown as Models.Metric[];
|
||||
$: updated = $databasesUsage?.databasesUpdate as unknown as Models.Metric[];
|
||||
$: deleted = $databasesUsage?.databasesDelete as unknown as Models.Metric[];
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<h1>Usage</h1>
|
||||
|
||||
<Card />
|
||||
</Container>
|
||||
<Usage
|
||||
bind:range
|
||||
{count}
|
||||
{created}
|
||||
{read}
|
||||
{updated}
|
||||
{deleted}
|
||||
countMetadata={{
|
||||
legend: 'Databases',
|
||||
title: 'Total databases'
|
||||
}}
|
||||
createdMetadata={{
|
||||
legend: 'Create',
|
||||
title: 'Databases created'
|
||||
}}
|
||||
readMetadata={{
|
||||
legend: 'Read',
|
||||
title: 'Databases read'
|
||||
}}
|
||||
updatedMetadata={{
|
||||
legend: 'Update',
|
||||
title: 'Databases updated'
|
||||
}}
|
||||
deletedMetadata={{
|
||||
legend: 'Delete',
|
||||
title: 'Databases deleted'
|
||||
}} />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import { usage, type UsagePeriods } from './store';
|
||||
import { onMount } from 'svelte';
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import { DropList, DropListItem } from '$lib/components';
|
||||
import { Code, DropList, DropListItem } from '$lib/components';
|
||||
import { BarChart, LineChart } from '$lib/charts';
|
||||
import { humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@ import { sdkForConsole } from '$lib/stores/sdk';
|
||||
import { cachedStore } from '$lib/helpers/cache';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
export type UsagePeriods = '24h' | '30d' | '90d';
|
||||
export const usage = cachedStore<
|
||||
Models.UsageProject,
|
||||
{
|
||||
load: (projectId: string, range: UsagePeriods) => Promise<void>;
|
||||
load: (projectId: string, range: string) => Promise<void>;
|
||||
}
|
||||
>('projectUsage', function ({ set }) {
|
||||
return {
|
||||
|
||||
@@ -1,136 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { BarChart, LineChart } from '$lib/charts';
|
||||
import { Card, Tiles } from '$lib/components';
|
||||
import { page } from '$app/stores';
|
||||
import { Usage, type UsagePeriods } from '$lib/layout';
|
||||
import { bucketUsage } from '../store';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
let currentRange = '30d';
|
||||
let range: UsagePeriods = '30d';
|
||||
|
||||
const bucketId = $page.params.bucket;
|
||||
|
||||
$: bucketUsage.load(bucketId, currentRange);
|
||||
$: bucketUsage.load(bucketId, range);
|
||||
|
||||
// TODO: metric type is wrong
|
||||
$: filesCount = $bucketUsage?.filesCount as unknown as Models.Metric[];
|
||||
$: filesCreate = $bucketUsage?.filesCreate as unknown as Models.Metric[];
|
||||
$: filesRead = $bucketUsage?.filesRead as unknown as Models.Metric[];
|
||||
$: filesUpdate = $bucketUsage?.filesUpdate as unknown as Models.Metric[];
|
||||
$: filesDelete = $bucketUsage?.filesDelete as unknown as Models.Metric[];
|
||||
|
||||
function last(set: Array<unknown>): Models.Metric | null {
|
||||
return (set as Models.Metric[]).slice(-1)[0] ?? null;
|
||||
}
|
||||
|
||||
// TODO: metric type is wrong
|
||||
function total(set: Array<unknown>): number {
|
||||
return (set as Models.Metric[]).reduce((prev, curr) => prev + curr.value, 0);
|
||||
}
|
||||
$: count = $bucketUsage?.filesCount as unknown as Models.Metric[];
|
||||
$: created = $bucketUsage?.filesCreate as unknown as Models.Metric[];
|
||||
$: read = $bucketUsage?.filesRead as unknown as Models.Metric[];
|
||||
$: updated = $bucketUsage?.filesUpdate as unknown as Models.Metric[];
|
||||
$: deleted = $bucketUsage?.filesDelete as unknown as Models.Metric[];
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="u-flex u-main-space-between common-section">
|
||||
<h2 class="heading-level-5">Users</h2>
|
||||
<ul class="drop-tabs">
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '24h')}
|
||||
disabled={currentRange === '24h'}>
|
||||
<span class="text">24h</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '30d')}
|
||||
disabled={currentRange === '30d'}>
|
||||
<span class="text">30d</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '90d')}
|
||||
disabled={currentRange === '90d'}>
|
||||
<span class="text">90d</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{#if $bucketUsage}
|
||||
<Card>
|
||||
{#if filesCount}
|
||||
<h6 class="heading-level-6">{last(filesCount).value}</h6>
|
||||
<p>Total Files</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<BarChart
|
||||
series={[
|
||||
{
|
||||
name: 'User',
|
||||
data: [...filesCount.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Tiles>
|
||||
<Card isTile>
|
||||
{#if filesCreate}
|
||||
<h6 class="heading-level-6">{total(filesCreate)}</h6>
|
||||
<p>Files created</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Create',
|
||||
data: [...filesCreate.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if filesRead}
|
||||
<h6 class="heading-level-6">{total(filesRead)}</h6>
|
||||
<p>Files read</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Read',
|
||||
data: [...filesRead.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if filesUpdate}
|
||||
<h6 class="heading-level-6">{total(filesUpdate)}</h6>
|
||||
<p>Files updated</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Update',
|
||||
data: [...filesUpdate.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if filesDelete}
|
||||
<h6 class="heading-level-6">{total(filesDelete)}</h6>
|
||||
<p>Files deleted</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Delete',
|
||||
data: [...filesDelete.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
</Tiles>
|
||||
{/if}
|
||||
</Container>
|
||||
<Usage
|
||||
bind:range
|
||||
{count}
|
||||
{created}
|
||||
{read}
|
||||
{updated}
|
||||
{deleted}
|
||||
countMetadata={{
|
||||
legend: 'Files',
|
||||
title: 'Total files'
|
||||
}}
|
||||
createdMetadata={{
|
||||
legend: 'Create',
|
||||
title: 'Files created'
|
||||
}}
|
||||
readMetadata={{
|
||||
legend: 'Read',
|
||||
title: 'Files read'
|
||||
}}
|
||||
updatedMetadata={{
|
||||
legend: 'Update',
|
||||
title: 'Files updated'
|
||||
}}
|
||||
deletedMetadata={{
|
||||
legend: 'Delete',
|
||||
title: 'Files deleted'
|
||||
}} />
|
||||
|
||||
@@ -1,133 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { BarChart, LineChart } from '$lib/charts';
|
||||
import { Card, Tiles } from '$lib/components';
|
||||
import { Usage, type UsagePeriods } from '$lib/layout';
|
||||
import { storageUsage } from '../store';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
|
||||
let currentRange = '30d';
|
||||
let range: UsagePeriods = '30d';
|
||||
|
||||
$: storageUsage.load(currentRange);
|
||||
$: storageUsage.load(range);
|
||||
|
||||
// TODO: metric type is wrong
|
||||
$: bucketsCount = $storageUsage?.bucketsCount as unknown as Models.Metric[];
|
||||
$: bucketsCreate = $storageUsage?.bucketsCreate as unknown as Models.Metric[];
|
||||
$: bucketsRead = $storageUsage?.bucketsRead as unknown as Models.Metric[];
|
||||
$: bucketsUpdate = $storageUsage?.bucketsUpdate as unknown as Models.Metric[];
|
||||
$: bucketsDelete = $storageUsage?.bucketsDelete as unknown as Models.Metric[];
|
||||
|
||||
function last(set: Array<unknown>): Models.Metric | null {
|
||||
return (set as Models.Metric[]).slice(-1)[0] ?? null;
|
||||
}
|
||||
|
||||
// TODO: metric type is wrong
|
||||
function total(set: Array<unknown>): number {
|
||||
return (set as Models.Metric[]).reduce((prev, curr) => prev + curr.value, 0);
|
||||
}
|
||||
$: count = $storageUsage?.bucketsCount as unknown as Models.Metric[];
|
||||
$: created = $storageUsage?.bucketsCreate as unknown as Models.Metric[];
|
||||
$: read = $storageUsage?.bucketsRead as unknown as Models.Metric[];
|
||||
$: updated = $storageUsage?.bucketsUpdate as unknown as Models.Metric[];
|
||||
$: deleted = $storageUsage?.bucketsDelete as unknown as Models.Metric[];
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="u-flex u-main-space-between common-section">
|
||||
<h2 class="heading-level-5">Users</h2>
|
||||
<ul class="drop-tabs">
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '24h')}
|
||||
disabled={currentRange === '24h'}>
|
||||
<span class="text">24h</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '30d')}
|
||||
disabled={currentRange === '30d'}>
|
||||
<span class="text">30d</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="drop-tabs-item">
|
||||
<button
|
||||
class="drop-tabs-button"
|
||||
on:click={() => (currentRange = '90d')}
|
||||
disabled={currentRange === '90d'}>
|
||||
<span class="text">90d</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{#if $storageUsage}
|
||||
<Card>
|
||||
{#if bucketsCount}
|
||||
<h6 class="heading-level-6">{last(bucketsCount).value}</h6>
|
||||
<p>Total Buckets</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<BarChart
|
||||
series={[
|
||||
{
|
||||
name: 'User',
|
||||
data: [...bucketsCount.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Tiles>
|
||||
<Card isTile>
|
||||
{#if bucketsCreate}
|
||||
<h6 class="heading-level-6">{total(bucketsCreate)}</h6>
|
||||
<p>Buckets created</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Create',
|
||||
data: [...bucketsCreate.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if bucketsRead}
|
||||
<h6 class="heading-level-6">{total(bucketsRead)}</h6>
|
||||
<p>Buckets read</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Read',
|
||||
data: [...bucketsRead.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if bucketsUpdate}
|
||||
<h6 class="heading-level-6">{total(bucketsUpdate)}</h6>
|
||||
<p>Buckets updated</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Update',
|
||||
data: [...bucketsUpdate.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Card isTile>
|
||||
{#if bucketsDelete}
|
||||
<h6 class="heading-level-6">{total(bucketsDelete)}</h6>
|
||||
<p>Buckets deleted</p>
|
||||
<div class="u-margin-block-start-16" />
|
||||
<LineChart
|
||||
series={[
|
||||
{
|
||||
name: 'Delete',
|
||||
data: [...bucketsDelete.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{/if}
|
||||
</Card>
|
||||
</Tiles>
|
||||
{/if}
|
||||
</Container>
|
||||
<Usage
|
||||
bind:range
|
||||
{count}
|
||||
{created}
|
||||
{read}
|
||||
{updated}
|
||||
{deleted}
|
||||
countMetadata={{
|
||||
legend: 'Buckets',
|
||||
title: 'Total buckets'
|
||||
}}
|
||||
createdMetadata={{
|
||||
legend: 'Create',
|
||||
title: 'Buckets created'
|
||||
}}
|
||||
readMetadata={{
|
||||
legend: 'Read',
|
||||
title: 'Buckets read'
|
||||
}}
|
||||
updatedMetadata={{
|
||||
legend: 'Update',
|
||||
title: 'Buckets updated'
|
||||
}}
|
||||
deletedMetadata={{
|
||||
legend: 'Delete',
|
||||
title: 'Buckets deleted'
|
||||
}} />
|
||||
|
||||
Reference in New Issue
Block a user