Merge branch 'main' of https://github.com/appwrite/appwrite-console-poc into feat-trim-text-tooltip

This commit is contained in:
Torsten Dittmann
2022-10-11 13:23:57 +02:00
30 changed files with 982 additions and 1238 deletions
+301 -997
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -28,8 +28,8 @@
},
"devDependencies": {
"@playwright/test": "^1.26.1",
"@sveltejs/adapter-auto": "1.0.0-next.80",
"@sveltejs/kit": "1.0.0-next.509",
"@sveltejs/adapter-static": "1.0.0-next.44",
"@sveltejs/kit": "1.0.0-next.512",
"@sveltejs/vite-plugin-svelte": "^1.0.8",
"@testing-library/dom": "^8.18.1",
"@testing-library/jest-dom": "^5.16.5",
+5 -1
View File
@@ -1,3 +1,7 @@
<article class="card common-section">
<script lang="ts">
export let isTile = false;
</script>
<article class="card" class:common-section={!isTile}>
<slot />
</article>
+2
View File
@@ -34,3 +34,5 @@ export { default as Json } from './json.svelte';
export { default as CustomId } from './customId.svelte';
export { default as Secret } from './secret.svelte';
export { default as Trim } from './trim.svelte';
export { default as Tabs } from './tabs.svelte';
export { default as Tab } from './tab.svelte';
+16
View File
@@ -0,0 +1,16 @@
<script lang="ts">
export let selected = false;
export let href: string = null;
</script>
<li class="tabs-item">
{#if href}
<a class="tabs-button" {href} class:is-selected={selected}>
<span class="text"><slot /></span>
</a>
{:else}
<button class="tabs-button" on:click|preventDefault class:is-selected={selected}>
<span class="text"><slot /></span>
</button>
{/if}
</li>
+70
View File
@@ -0,0 +1,70 @@
<script lang="ts">
let showLeft = false;
let showRight = false;
let tabsList: HTMLUListElement;
const slide = (direction: 'left' | 'right') => {
let scrollCompleted = 0;
let slideVar = setInterval(() => {
if (direction == 'left') {
tabsList.scrollLeft -= 10;
} else {
tabsList.scrollLeft += 10;
}
scrollCompleted += 10;
if (scrollCompleted >= 100) {
clearInterval(slideVar);
}
}, 10);
};
//TODO: implement this directly into onScroll
const throttle = (fn: () => void, delay: number) => {
let timeout = false;
return () => {
if (!timeout) {
timeout = true;
fn.apply(this);
setTimeout(() => {
timeout = false;
}, delay);
}
};
};
const onScroll = () => {
if (!tabsList) {
return;
}
const { offsetWidth, scrollLeft, scrollWidth } = tabsList;
showLeft = scrollLeft > 10;
showRight = scrollLeft < scrollWidth - offsetWidth - 10;
};
</script>
<svelte:window on:resize={throttle(onScroll, 25)} />
<div class="tabs">
{#if showLeft}
<button
class="tabs-button-scroll is-start"
aria-label="Show items in start side"
on:click={() => slide('left')}>
<span class="icon-cheveron-left" aria-hidden="true" />
</button>
{/if}
{#if showRight}
<button
class="tabs-button-scroll is-end"
aria-label="Show items in end side"
on:click={() => slide('right')}>
<span class="icon-cheveron-right" aria-hidden="true" />
</button>
{/if}
<ul
class="tabs-list scroll-shadow-horizontal"
bind:this={tabsList}
on:scroll={throttle(onScroll, 25)}>
<slot />
</ul>
</div>
+1 -1
View File
@@ -1,3 +1,3 @@
<ul class="grid-box common-section">
<ul class="grid-box common-section" style="--grid-item-size:25rem;">
<slot />
</ul>
+1
View File
@@ -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';
+17 -75
View File
@@ -2,7 +2,15 @@
import { navigating, page } from '$app/stores';
import { tabs, title, backButton, copyData, titleDropdown } from '$lib/stores/layout';
import { Cover } from '.';
import { Copy, DropList, DropListItem, DropListLink, AvatarGroup } from '$lib/components';
import {
Copy,
DropList,
DropListItem,
DropListLink,
AvatarGroup,
Tabs,
Tab
} from '$lib/components';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import {
@@ -22,29 +30,12 @@
export let showSideNavigation = false;
let y: number;
let tabsList: HTMLUListElement;
let showLeft = false;
let showRight = false;
let showDropdown = false;
navigating.subscribe(() => {
if (isOpen) isOpen = false;
});
const slide = (direction: 'left' | 'right') => {
let scrollCompleted = 0;
let slideVar = setInterval(() => {
if (direction == 'left') {
tabsList.scrollLeft -= 10;
} else {
tabsList.scrollLeft += 10;
}
scrollCompleted += 10;
if (scrollCompleted >= 100) {
clearInterval(slideVar);
}
}, 10);
};
let avatars = [];
let avatarsTotal = 0;
@@ -65,29 +56,6 @@
await goto(`${base}/login`);
};
const onScroll = () => {
if (!tabsList) {
return;
}
const { offsetWidth, scrollLeft, scrollWidth } = tabsList;
showLeft = scrollLeft > 10;
showRight = scrollLeft < scrollWidth - offsetWidth - 10;
};
//TODO: implement this directly into onScroll
const throttle = (fn: () => void, delay: number) => {
let timeout = false;
return () => {
if (!timeout) {
timeout = true;
fn.apply(this);
setTimeout(() => {
timeout = false;
}, delay);
}
};
};
const toggleMenu = () => {
y = 0;
isOpen = !isOpen;
@@ -101,7 +69,7 @@
};
</script>
<svelte:window bind:scrollY={y} on:resize={throttle(onScroll, 25)} />
<svelte:window bind:scrollY={y} />
<main
class:grid-with-side={showSideNavigation}
@@ -200,39 +168,13 @@
</svelte:fragment>
{#if $tabs.length}
<div class="tabs">
{#if showLeft}
<button
class="tabs-button-scroll is-start"
aria-label="Show items in start side"
on:click={() => slide('left')}>
<span class="icon-cheveron-left" aria-hidden="true" />
</button>
{/if}
{#if showRight}
<button
class="tabs-button-scroll is-end"
aria-label="Show items in end side"
on:click={() => slide('right')}>
<span class="icon-cheveron-right" aria-hidden="true" />
</button>
{/if}
<ul
class="tabs-list scroll-shadow-horizontal"
bind:this={tabsList}
on:scroll={throttle(onScroll, 25)}>
{#each $tabs as tab}
<li class="tabs-item">
<a
class="tabs-button"
href={tab.href}
class:is-selected={$page.url.pathname === tab.href}>
<span class="text">{tab.title}</span>
</a>
</li>
{/each}
</ul>
</div>
<Tabs>
{#each $tabs as tab}
<Tab href={tab.href} selected={$page.url.pathname === tab.href}>
{tab.title}
</Tab>
{/each}
</Tabs>
{/if}
</Cover>
<slot />
+126
View File
@@ -0,0 +1,126 @@
<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, DropTabs, DropTabsItem, 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>
<DropTabs>
<DropTabsItem on:click={() => (range = '24h')} disabled={range === '24h'}>
24h
</DropTabsItem>
<DropTabsItem on:click={() => (range = '30d')} disabled={range === '30d'}>
30d
</DropTabsItem>
<DropTabsItem on:click={() => (range = '90d')} disabled={range === '90d'}>
90d
</DropTabsItem>
</DropTabs>
</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>
+13
View File
@@ -0,0 +1,13 @@
<script>
import { Tabs, Tab } from '../components';
export let tabs = [];
</script>
<Tabs>
{#each tabs as tab}
<Tab href={tab.href}>
{tab.title}
</Tab>
{/each}
</Tabs>
@@ -1,101 +1,45 @@
<script>
import { Container } from '$lib/layout';
import { BarChart } from '$lib/charts';
import { Card } from '$lib/components';
<script lang="ts">
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);
$: data = $usersUsage;
$: usersUsage.load(range);
//TODO: add types once they are fixed
// TODO: metric type is wrong
$: 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>
{#if data}
<div class="u-flex u-main-end common-section">
<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>
<Card>
<h6 class="heading-level-6">Users</h6>
<p>Count of users over time</p>
<BarChart
series={[
{
name: 'User',
data: [...data.usersCount.map((e) => [e.date, e.value])]
}
]} />
</Card>
<Card>
<h6 class="heading-level-6">Operations</h6>
<p>Count of users create, read, update and delete operations over time</p>
<BarChart
series={[
{
name: 'Create',
data: [...data.usersCreate.map((e) => [e.date, e.value])]
}
]} />
</Card>
<Card>
<h6 class="heading-level-6">Operations</h6>
<p>Count of users create, read, update and delete operations over time</p>
<BarChart
series={[
{
name: 'Read',
data: [...data.usersRead.map((e) => [e.date, e.value])]
}
]} />
</Card>
<Card>
<h6 class="heading-level-6">Operations</h6>
<p>Count of users create, read, update and delete operations over time</p>
<BarChart
series={[
{
name: 'Update',
data: [...data.usersUpdate.map((e) => [e.date, e.value])]
}
]} />
</Card>
<Card>
<h6 class="heading-level-6">Operations</h6>
<p>Count of users create, read, update and delete operations over time</p>
<BarChart
series={[
{
name: 'Delete',
data: [...data.usersDelete.map((e) => [e.date, e.value])]
}
]} />
</Card>
{/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'
}} />
@@ -46,6 +46,10 @@
href: `${path}/indexes`,
title: 'Indexes'
},
{
href: `${path}/usage`,
title: 'Usage'
},
{
href: `${path}/settings`,
title: 'Settings'
@@ -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);
}
};
});
@@ -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);
}
};
});
@@ -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'
}} />
@@ -1,12 +1,12 @@
<script lang="ts">
import type { Models } from '@aw-labs/appwrite-console';
import { Container } from '$lib/layout';
import { Container, type UsagePeriods } from '$lib/layout';
import { page } from '$app/stores';
import { browser } from '$app/environment';
import { tabs, title, backButton, copyData } from '$lib/stores/layout';
import { sdkForConsole } from '$lib/stores/sdk';
import { project } from '../store';
import { usage, type UsagePeriods } from './store';
import { usage } from './store';
import { onMount } from 'svelte';
import { afterNavigate } from '$app/navigation';
import { DropList, DropListItem } from '$lib/components';
@@ -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,42 +1,45 @@
import { sdkForProject } from '$lib/stores/sdk';
import type { Models } from '@aw-labs/appwrite-console';
import { writable } from 'svelte/store';
import { browser } from '$app/environment';
function createBucketStore() {
const { subscribe, set } = writable<Models.Bucket>(
browser ? JSON.parse(sessionStorage.getItem('bucket')) : null
);
import { cachedStore } from '$lib/helpers/cache';
export const bucket = cachedStore<
Models.Bucket,
{
load: (bucketId: string) => Promise<void>;
}
>('bucket', function ({ set }) {
return {
subscribe,
set,
load: async (bucketId: string) => {
load: async (bucketId) => {
const response = await sdkForProject.storage.getBucket(bucketId);
set(response);
}
};
}
function createFilesStore() {
const { subscribe, set } = writable<Models.FileList>(
browser ? JSON.parse(sessionStorage.getItem('files')) : null
);
});
export const files = cachedStore<
Models.FileList,
{
load: (bucketId: string, queries: string[], search: string) => Promise<void>;
}
>('files', function ({ set }) {
return {
subscribe,
set,
load: async (bucketId: string, queries?: string[], search?: string) => {
load: async (bucketId, queries, search) => {
const response = await sdkForProject.storage.listFiles(bucketId, queries, search);
set(response);
}
};
}
});
export const bucket = createBucketStore();
export const files = createFilesStore();
if (browser) {
bucket.subscribe((n) => sessionStorage?.setItem('bucket', JSON.stringify(n ?? '')));
files.subscribe((n) => sessionStorage?.setItem('files', JSON.stringify(n ?? '')));
}
export const bucketUsage = cachedStore<
Models.UsageBuckets,
{
load: (bucketId: string, range: string) => Promise<void>;
}
>('bucketsUsage', function ({ set }) {
return {
load: async (bucketId, range) => {
const response = await sdkForProject.storage.getBucketUsage(bucketId, range);
set(response);
}
};
});
@@ -1,10 +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 { bucketUsage } from '../store';
import type { Models } from '@aw-labs/appwrite-console';
let range: UsagePeriods = '30d';
const bucketId = $page.params.bucket;
$: bucketUsage.load(bucketId, range);
// TODO: metric type is wrong
$: 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>
<h1>Usage</h1>
<Card />
</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'
}} />
@@ -15,3 +15,17 @@ export const bucketList = cachedStore<
}
};
});
export const storageUsage = cachedStore<
Models.UsageStorage,
{
load: (range: string) => Promise<void>;
}
>('storageUsage', function ({ set }) {
return {
load: async (range) => {
const response = await sdkForProject.storage.getUsage(range);
set(response);
}
};
});
@@ -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 { storageUsage } from '../store';
import type { Models } from '@aw-labs/appwrite-console';
let range: UsagePeriods = '30d';
$: storageUsage.load(range);
// TODO: metric type is wrong
$: 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>
<h1>Usage</h1>
<Card />
</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'
}} />
+4 -2
View File
@@ -1,4 +1,4 @@
import adapter from '@sveltejs/adapter-auto';
import adapter from '@sveltejs/adapter-static';
import preprocess from 'svelte-preprocess';
/** @type {import('@sveltejs/kit').Config} */
@@ -10,7 +10,9 @@ const config = {
accessors: process.env.VITEST
},
kit: {
adapter: adapter(),
adapter: adapter({
fallback: 'index.html'
}),
paths: {
base: ''
}
+32
View File
@@ -0,0 +1,32 @@
import '@testing-library/jest-dom';
import { vi } from 'vitest';
import { render, fireEvent } from '@testing-library/svelte';
import { Tab } from '../../../src/lib/components';
test('shows tab', () => {
const { getByRole } = render(Tab);
expect(getByRole('button')).toBeInTheDocument();
});
test('shows tab - is selected', () => {
const { getByRole } = render(Tab, { selected: true });
expect(getByRole('button')).toHaveClass('is-selected');
});
test('shows tab - is link', () => {
render(Tab, { href: 'https://appwrite.io' });
const link = document.querySelector('a');
expect(link).toHaveAttribute('href', 'https://appwrite.io');
});
test('shows tab - on:click', async () => {
const { getByRole, component } = render(Tab);
const tab = getByRole('button');
const callback = vi.fn();
component.$on('click', callback);
await fireEvent.click(tab);
expect(callback).toHaveBeenCalled();
});
+27
View File
@@ -0,0 +1,27 @@
import '@testing-library/jest-dom';
import { render } from '@testing-library/svelte';
import Tabs from '../../../src/lib/mock/tabs.test.svelte';
const list = [
{
title: 'Tab 1',
href: '#tab-1'
},
{
title: 'Tab 2',
href: '#tab-2'
},
{
title: 'Tab 3',
href: '#tab-3'
}
];
test('shows Tabs component', () => {
const { container } = render(Tabs, { tabs: list });
const tabs = container.querySelector('div.tabs');
const children = tabs.childNodes;
expect(tabs).toBeInTheDocument();
expect(children.length).toBe(list.length);
});
+8
View File
@@ -0,0 +1,8 @@
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/"
}
]
}
+2 -2
View File
@@ -4,10 +4,10 @@ import { sveltekit } from '@sveltejs/kit/vite';
const config = {
plugins: [sveltekit()],
optimizeDeps: {
include: ['echarts']
include: ['echarts', 'prismjs']
},
ssr: {
noExternal: ['echarts']
noExternal: ['echarts', 'prismjs']
},
define: {
'import.meta.env.VERCEL_ANALYTICS_ID': JSON.stringify(process.env.VERCEL_ANALYTICS_ID)