Merge branch 'main' of github.com:appwrite/console into feat-databases-v2

This commit is contained in:
Arman
2023-03-23 16:59:45 +01:00
97 changed files with 1375 additions and 1101 deletions
+4 -5
View File
@@ -6,10 +6,9 @@
"packages": {
"": {
"name": "@appwrite/console",
"version": "0.0.1",
"dependencies": {
"@analytics/google-analytics": "^1.0.5",
"@appwrite.io/pink": "^0.0.6-rc.3",
"@appwrite.io/pink": "^0.0.6-rc.4",
"@appwrite.io/pink-icons": "^0.0.6-rc.3",
"@aw-labs/appwrite-console": "^13.1.0",
"@popperjs/core": "^2.11.6",
@@ -149,9 +148,9 @@
"integrity": "sha512-1Yw7u/COtxx06BfwlI+kVhsa/upKYzmCNrT4c8QDeCY2KMYlnijkUjtHiPU08HxyTIVB5j6d75O0YWVIHwQS8g=="
},
"node_modules/@appwrite.io/pink": {
"version": "0.0.6-rc.3",
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.0.6-rc.3.tgz",
"integrity": "sha512-oeRwchmRdHjspYJFipc6k/oWOOdaD7TKFwJ1weZMJMF2/GmQ44zCYo2qJhN2tPRb73Wje2dTvnkV6MH/Rxg7vw==",
"version": "0.0.6-rc.4",
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.0.6-rc.4.tgz",
"integrity": "sha512-vSBq0wB4lQMM8vRPCh0B2M8aWIdrFQSf14X58y8DVjj0djg/gwQ51pwxLojXAol7rwFNhh73NSqTuRC4y+BpxA==",
"dependencies": {
"@appwrite.io/pink-icons": "*",
"normalize.css": "^8.0.1",
+1 -2
View File
@@ -1,6 +1,5 @@
{
"name": "@appwrite/console",
"version": "0.0.1",
"engines": {
"node": ">=16"
},
@@ -20,8 +19,8 @@
},
"dependencies": {
"@analytics/google-analytics": "^1.0.5",
"@appwrite.io/pink": "^0.0.6-rc.3",
"@appwrite.io/pink-icons": "^0.0.6-rc.3",
"@appwrite.io/pink": "^0.0.6-rc.4",
"@aw-labs/appwrite-console": "^13.1.0",
"@popperjs/core": "^2.11.6",
"@sentry/svelte": "^7.44.2",
+1
View File
@@ -43,6 +43,7 @@
class:common-section={!isTile}
class:is-border-dashed={isDashed}
class:is-danger={danger}
class:is-allowed-focus={href}
on:click
on:keyup={clickOnEnter}
{href}>
+1
View File
@@ -49,3 +49,4 @@ export { default as Output } from './output.svelte';
export { default as ViewSelector } from './viewSelector.svelte';
export { default as LabelCard } from './labelCard.svelte';
export { default as CustomPagination } from './customPagination.svelte';
export { default as Limit } from './limit.svelte';
+44
View File
@@ -0,0 +1,44 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page as pageStore } from '$app/stores';
import { InputSelect } from '$lib/elements/forms';
import { preferences } from '$lib/stores/preferences';
export let sum: number;
export let limit: number;
export let name: string;
const options = [
{ label: '6', value: 6 },
{ label: '12', value: 12 },
{ label: '24', value: 24 },
{ label: '48', value: 48 },
{ label: '96', value: 96 }
];
async function limitChange() {
const url = new URL($pageStore.url);
const previousLimit = Number(url.searchParams.get('limit'));
url.searchParams.set('limit', limit.toString());
preferences.setLimit(limit);
if (url.searchParams.has('page')) {
const page = Number(url.searchParams.get('page'));
const newPage = Math.floor(((page - 1) * previousLimit) / limit);
url.searchParams.set('page', newPage.toString());
}
await goto(url.toString());
}
</script>
<div class="u-flex u-gap-12 u-cross-center">
<InputSelect
id="rows"
label="Rows per page"
showLabel={false}
{options}
bind:value={limit}
on:change={limitChange} />
<p class="text">{name} per page. Total results: {sum}</p>
</div>
+68 -49
View File
@@ -1,10 +1,10 @@
<script lang="ts">
import { page } from '$app/stores';
import { page as pageStore } from '$app/stores';
import { Button } from '$lib/elements/forms';
export let sum: number;
export let limit: number;
export let offset: number;
export let path: string;
export let hidePages = false;
$: totalPages = Math.ceil(sum / limit);
@@ -27,68 +27,87 @@
...(end < total - 1 ? ['...', total] : end < total ? [total] : [])
];
}
function getLink(page: number): string {
const url = new URL($pageStore.url);
if (page === 1) {
url.searchParams.delete('page');
} else {
url.searchParams.set('page', page.toString());
}
return url.toString();
}
</script>
{#if totalPages > 1}
{@const search = $page.url.search}
<nav class="pagination">
<a
class:is-disabled={currentPage <= 1}
class="button is-text"
aria-label="prev page"
href={`${path}/${currentPage - 1}${search}`}>
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="text">Prev</span>
</a>
{#if !hidePages}
<ol class="pagination-list is-only-desktop">
{#each pages as page}
{#if typeof page === 'number'}
<li class="pagination-item">
<a
href={`${path}/${page}${search}`}
class="button"
class:is-disabled={currentPage === page}
class:is-text={currentPage !== page}
aria-label="page">
<span class="text">{page}</span>
</a>
</li>
{:else}
<li class="li is-text">
<span class="icon">...</span>
</li>
{/if}
{/each}
</ol>
{/if}
<a
class:is-disabled={currentPage === totalPages}
class="button is-text"
href={`${path}/${currentPage + 1}${search}`}
aria-label="next page">
<span class="text">Next</span>
<span class="icon-cheveron-right" aria-hidden="true" />
</a>
</nav>
{#key $pageStore.url}
<nav class="pagination">
{#if currentPage <= 1}
<Button disabled text ariaLabel="prev page">
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="text">Prev</span>
</Button>
{:else}
<Button text ariaLabel="prev page" href={getLink(currentPage - 1)}>
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="text">Prev</span>
</Button>
{/if}
{#if !hidePages}
<ol class="pagination-list is-only-desktop">
{#each pages as page}
{#if typeof page === 'number'}
<li class="pagination-item">
{#if currentPage === page}
<Button ariaLabel="page" disabled>
<span class="text">{page}</span>
</Button>
{:else}
<Button text ariaLabel="page" href={getLink(page)}>
<span class="text">{page}</span>
</Button>
{/if}
</li>
{:else}
<li class="li is-text">
<span class="icon">...</span>
</li>
{/if}
{/each}
</ol>
{/if}
{#if currentPage >= totalPages}
<Button disabled text ariaLabel="next page">
<span class="text">Next</span>
<span class="icon-cheveron-right" aria-hidden="true" />
</Button>
{:else}
<Button text ariaLabel="next page" href={getLink(currentPage + 1)}>
<span class="text">Next</span>
<span class="icon-cheveron-right" aria-hidden="true" />
</Button>
{/if}
</nav>
{/key}
{:else}
<nav class="pagination">
<button type="button" class="button is-text is-disabled" aria-label="prev page">
<Button text disabled ariaLabel="prev page">
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="text">Prev</span>
</button>
</Button>
{#if !hidePages}
<ol class="pagination-list is-only-desktop">
<li class="pagination-item">
<button type="button" class="button is-disabled" aria-label="page">
<Button disabled ariaLabel="page">
<span class="text">1</span>
</button>
</Button>
</li>
</ol>
{/if}
<button type="button" class="button is-text is-disabled" aria-label="next page">
<Button text disabled ariaLabel="next page">
<span class="text">Next</span>
<span class="icon-cheveron-right" aria-hidden="true" />
</button>
</Button>
</nav>
{/if}
+13 -8
View File
@@ -29,23 +29,28 @@
}
});
$: valueChange(search);
$: valueChange(search ?? '');
function valueChange(value: string) {
clearTimeout(timer);
timer = setTimeout(async () => {
timer = setTimeout(() => {
const url = new URL($page.url);
if (url.search === value) {
const previous = url.searchParams.get('search') ?? '';
if (previous === value) {
return;
}
/**
* Reset to first page if search changes.
*/
if ($page.data.page > 1) {
url.pathname = url.pathname.replace(new RegExp(`/${$page.data.page}*$`), '/');
url.searchParams.delete('page');
}
if (value === '') {
url.searchParams.delete('search');
} else {
url.searchParams.set('search', value);
}
url.search = value;
trackEvent('search');
goto(url, { keepFocus: true });
}, debounce);
+83 -50
View File
@@ -1,34 +1,68 @@
<script lang="ts">
import { Button, InputChoice } from '$lib/elements/forms';
import { DropList } from '.';
import { prefs } from '$lib/stores/user';
import { page } from '$app/stores';
import { onMount } from 'svelte';
import type { Writable } from 'svelte/store';
type Column = {
<script context="module" lang="ts">
export type Column = {
id: string;
title: string;
show: boolean;
width?: number;
};
</script>
<script lang="ts">
import { Button, InputChoice } from '$lib/elements/forms';
import { DropList } from '.';
import { page } from '$app/stores';
import type { Writable } from 'svelte/store';
import { preferences } from '$lib/stores/preferences';
import { onMount } from 'svelte';
import { View } from '$lib/helpers/load';
export let columns: Writable<Column[]>;
export let showToggle = true;
const pathname = $page.url.pathname;
export let view: View;
export let isCustomCollection = false;
export let hideView = false;
export let hideColumns = false;
let showSelectColumns = false;
onMount(() => {
updateColumns();
onMount(async () => {
if (isCustomCollection) {
const prefs = preferences.getCustomCollectionColumns($page.params.collection);
columns.set(
$columns.map((column) => {
column.show = prefs?.includes(column.id) ?? true;
return column;
})
);
} else {
const prefs = preferences.get($page.route);
columns.set(
$columns.map((column) => {
column.show = prefs.columns?.includes(column.id) ?? true;
return column;
})
);
}
return columns.subscribe((ctx) => {
const columns = ctx.filter((n) => n.show).map((n) => n.id);
if (isCustomCollection) {
preferences.setCustomCollectionColumns(columns);
} else {
preferences.setColumns(columns);
}
});
});
function updateColumns() {
if ($prefs?.[pathname]) {
$columns.forEach((column, i) => {
column.show = $prefs[pathname][i];
});
$columns = $columns;
}
function getViewLink(view: View): string {
const url = new URL($page.url);
url.searchParams.set('view', view);
return url.toString();
}
function updateViewPreferences(view: View) {
preferences.setView(view);
}
$: selectedColumnsNumber = $columns.reduce((acc, column) => {
@@ -37,19 +71,14 @@
}
return acc;
}, 0);
columns.subscribe((columns) => {
const columnsArray = columns.map((column) => column.show);
prefs.updatePrefs({ ...$prefs, [pathname]: columnsArray });
});
</script>
{#if $columns?.length}
{#if $prefs?.preferredView === 'list'}
{#if !hideColumns && view === View.Table}
{#if $columns?.length}
<DropList bind:show={showSelectColumns} scrollable={true}>
<Button secondary on:click={() => (showSelectColumns = true)}>
<Button secondary on:click={() => (showSelectColumns = !showSelectColumns)}>
<span
class="icon-view-boards u-opacity-50 "
class="icon-view-boards u-opacity-50"
aria-hidden="true"
aria-label="columns" />
<span class="text">Columns</span>
@@ -68,29 +97,33 @@
{/if}
{/if}
{#if showToggle}
{#if !hideView}
<div class="toggle-button">
<ul class="toggle-button-list">
<li class="toggle-button-item">
<button
class="toggle-button-element"
aria-label="List View"
type="button"
class:is-selected={$prefs.preferredView === 'list'}
on:click={() => prefs.updatePrefs({ ...$prefs, preferredView: 'list' })}>
<span class="icon-view-list" aria-hidden="true" />
</button>
</li>
<li class="toggle-button-item">
<button
class="toggle-button-element"
aria-label="Grid View"
type="button"
class:is-selected={$prefs.preferredView === 'grid'}
on:click={() => prefs.updatePrefs({ ...$prefs, preferredView: 'grid' })}>
<span class="icon-view-grid" aria-hidden="true" />
</button>
</li>
{#key $page.url}
<li class="toggle-button-item">
<a
href={getViewLink(View.Table)}
on:click={() => updateViewPreferences(View.Table)}
class="toggle-button-element"
aria-label="List View"
type="button"
class:is-selected={view === View.Table}>
<span class="icon-view-list" aria-hidden="true" />
</a>
</li>
<li class="toggle-button-item">
<a
href={getViewLink(View.Grid)}
on:click={() => updateViewPreferences(View.Grid)}
class="toggle-button-element"
aria-label="Grid View"
type="button"
class:is-selected={view === View.Grid}>
<span class="icon-view-grid" aria-hidden="true" />
</a>
</li>
{/key}
</ul>
</div>
{/if}
+27 -16
View File
@@ -1,24 +1,35 @@
import { goto } from '$app/navigation';
import { preferences } from '$lib/stores/preferences';
import type { Page } from '@sveltejs/kit';
export function pageToOffset(page: number, limit: number): number {
return page ? page * limit - limit : 0;
}
export async function redirectOnOffsetOverflow(
offset: number,
page: number,
total: number,
project: string,
path: string,
search: string
) {
if (offset > total) {
if (page <= 2) {
await goto(`/console/project-${project}/${path}?${search}`);
} else {
await goto(`/console/project-${project}/${path}/${page - 1}?${search}`);
}
}
export function getPage(url: URL): number {
return Number(url.searchParams.get('page'));
}
export function getLimit(url: URL, route: Page['route'], fallback: number): number {
return Number(url.searchParams.get('limit') ?? preferences.get(route).limit ?? fallback);
}
export enum View {
Table = 'table',
Grid = 'grid'
}
export function getView(url: URL, route: Page['route'], fallback: View): View {
return (url.searchParams.get('view') ?? preferences.get(route).view) === View.Grid
? View.Grid
: View.Table ?? fallback;
}
export function getColumns(route: Page['route'], fallback: string[]): string[] {
return preferences.get(route).columns ?? fallback;
}
export function getSearch(url: URL): string | undefined {
return url.searchParams.get('search') ?? undefined;
}
type TabElement = { href: string; title: string; hasChildren?: boolean };
+4 -5
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { AvatarInitials, EmptySearch, Pagination, Trim } from '$lib/components';
import { AvatarInitials, EmptySearch, Limit, Pagination, Trim } from '$lib/components';
import {
TableBody,
TableHeader,
@@ -11,12 +11,11 @@
} from '$lib/elements/table';
import { Container } from '$lib/layout';
import { toLocaleDateTime } from '$lib/helpers/date';
import { PAGE_LIMIT } from '$lib/constants';
import type { Models } from '@aw-labs/appwrite-console';
export let logs: Models.LogList;
export let path: string;
export let offset = 0;
export let limit = 0;
</script>
<Container>
@@ -66,8 +65,8 @@
</TableBody>
</TableScroll>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {logs.total}</p>
<Pagination limit={PAGE_LIMIT} {path} {offset} sum={logs.total} />
<Limit {limit} sum={logs.total} name="Logs" />
<Pagination {limit} {offset} sum={logs.total} />
</div>
{:else}
<EmptySearch>
+111
View File
@@ -0,0 +1,111 @@
import { browser } from '$app/environment';
import { page } from '$app/stores';
import type { View } from '$lib/helpers/load';
import type { Page } from '@sveltejs/kit';
import { get, writable } from 'svelte/store';
import { sdk } from './sdk';
type Preferences = {
limit?: number;
view?: View;
columns?: string[];
};
type PreferencesStore = {
[key: string]: {
[key: string]: Preferences;
collections?: {
[key: string]: Preferences['columns'];
};
};
};
function createPreferences() {
const { subscribe, set, update } = writable<PreferencesStore>({});
if (browser) {
set(JSON.parse(globalThis.localStorage.getItem('preferences') ?? '{}'));
}
return {
subscribe,
get: (route: Page['route']): Preferences => {
let preferences: PreferencesStore;
subscribe((n) => (preferences = n))();
return (
preferences[sdk.forProject.client.config.project]?.[route.id] ?? {
limit: null,
view: null,
columns: null
}
);
},
getCustomCollectionColumns: (collectionId: string): Preferences['columns'] => {
let preferences: PreferencesStore;
subscribe((n) => (preferences = n))();
return (
preferences[sdk.forProject.client.config.project]?.collections?.[collectionId] ??
null
);
},
setLimit: (limit: Preferences['limit']) =>
update((n) => {
const path = get(page).route.id;
const project = sdk.forProject.client.config.project;
if (!n[project]?.[path]) {
n[project] ??= {};
n[project][path] ??= {};
}
n[project][path].limit = limit;
return n;
}),
setView: (view: Preferences['view']) =>
update((n) => {
const path = get(page).route.id;
const project = sdk.forProject.client.config.project;
if (!n[project]?.[path]) {
n[project] ??= {};
n[project][path] ??= {};
}
n[project][path].view = view;
return n;
}),
setColumns: (columns: Preferences['columns']) =>
update((n) => {
const path = get(page).route.id;
const project = sdk.forProject.client.config.project;
if (!n[project]?.[path]) {
n[project] ??= {};
n[project][path] ??= {};
}
n[project][path].columns = columns;
return n;
}),
setCustomCollectionColumns: (columns: Preferences['columns']) =>
update((n) => {
const current = get(page);
const project = sdk.forProject.client.config.project;
const collection = current.params.collection;
if (!n[project]?.collections?.[collection]) {
n[project] ??= {};
n[project].collections ??= {};
}
n[project].collections[collection] = columns;
return n;
})
};
}
export const preferences = createPreferences();
if (browser) {
preferences.subscribe((n) => globalThis.localStorage.setItem('preferences', JSON.stringify(n)));
}
@@ -3,7 +3,6 @@
import type { PageData } from './$types';
export let data: PageData;
const path = '/console/account/activity';
</script>
<Activity {path} logs={data.logs} offset={data.offset} />
<Activity {...data} />
@@ -0,0 +1,17 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
logs: await sdk.forConsole.account.listLogs([Query.offset(offset), Query.limit(limit)])
};
};
@@ -1,15 +0,0 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
return {
offset,
logs: await sdk.forConsole.account.listLogs([Query.offset(offset), Query.limit(PAGE_LIMIT)])
};
};
@@ -6,13 +6,13 @@
Pagination,
AvatarGroup,
CardContainer,
Heading
Heading,
Limit
} from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import CreateOrganization from '../../../createOrganization.svelte';
import CreateOrganization from '../../createOrganization.svelte';
import { sdk } from '$lib/stores/sdk';
import { CARD_LIMIT } from '$lib/constants';
import type { PageData } from './$types';
export let data: PageData;
@@ -67,12 +67,8 @@
</Empty>
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.organizations.total}</p>
<Pagination
limit={CARD_LIMIT}
path="/console/account/organizations"
offset={data.offset}
sum={data.organizations.total} />
<Limit limit={data.limit} sum={data.organizations.total} name="Organizations" />
<Pagination limit={data.limit} offset={data.offset} sum={data.organizations.total} />
</div>
</Container>
@@ -1,18 +1,20 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { CARD_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, CARD_LIMIT);
export const load: PageLoad = async ({ url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
organizations: await sdk.forConsole.teams.list([
Query.offset(offset),
Query.limit(CARD_LIMIT),
Query.limit(limit),
Query.orderDesc('$createdAt')
])
};
@@ -124,6 +124,5 @@
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.sessions.total}</p>
<!-- <Pagination limit={PAGE_LIMIT} offset={data.offset} sum={data.sessions.total} /> -->
</div>
</Container>
@@ -1,13 +1,12 @@
<script lang="ts">
import { base } from '$app/paths';
import { Pill } from '$lib/elements';
import { GridItem1, Heading, Empty, CardContainer, Pagination } from '$lib/components';
import { GridItem1, Heading, Empty, CardContainer, Pagination, Limit } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import CreateProject from '../createProject.svelte';
import CreateOrganization from '../../createOrganization.svelte';
import CreateProject from './createProject.svelte';
import CreateOrganization from '../createOrganization.svelte';
import type { PageData } from './$types';
import { CARD_LIMIT } from '$lib/constants';
import { page } from '$app/stores';
export let data: PageData;
@@ -96,12 +95,8 @@
</Empty>
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.projects.total}</p>
<Pagination
path={`/console/organization-${$page.params.organization}`}
limit={CARD_LIMIT}
offset={data.offset}
sum={data.projects.total} />
<Limit limit={data.limit} sum={data.projects.total} name="Projects" />
<Pagination limit={data.limit} offset={data.offset} sum={data.projects.total} />
</div>
</Container>
@@ -1,18 +1,20 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { CARD_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, CARD_LIMIT);
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
projects: await sdk.forConsole.projects.list([
Query.offset(offset),
Query.limit(CARD_LIMIT),
Query.limit(limit),
Query.equal('teamId', params.organization),
Query.orderDesc('$createdAt')
])
@@ -2,8 +2,8 @@
import { invalidate } from '$app/navigation';
import { page } from '$app/stores';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { AvatarInitials, Heading, Pagination } from '$lib/components';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { AvatarInitials, Heading, Limit, Pagination } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import {
@@ -21,7 +21,7 @@
import { sdk } from '$lib/stores/sdk';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
import Delete from '../../deleteMember.svelte';
import Delete from '../deleteMember.svelte';
export let data: PageData;
@@ -111,12 +111,8 @@
</TableBody>
</TableScroll>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.organizationMembers.total}</p>
<Pagination
offset={data.offset}
limit={PAGE_LIMIT}
path={`/console/organization-${$page.params.organization}/members`}
sum={data.members.total} />
<Limit limit={data.limit} sum={data.members.total} name="Members" />
<Pagination limit={data.limit} offset={data.offset} sum={data.members.total} />
</div>
{/if}
</Container>
@@ -1,17 +1,19 @@
import { PAGE_LIMIT } from '$lib/constants';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@aw-labs/appwrite-console';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
export const load: PageLoad = async ({ url, params, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
organizationMembers: await sdk.forConsole.teams.listMemberships(params.organization, [
Query.limit(PAGE_LIMIT),
Query.limit(limit),
Query.offset(offset)
])
};
@@ -6,5 +6,5 @@
<Container>
<Heading size="1" tag="h3">{$page.status}</Heading>
<Heading size="3" tag="h4">{$page.error.message}</Heading>
<p class="body-text-2 u-margin-block-start-4">{$page.error.message}</p>
</Container>
@@ -6,7 +6,8 @@
Pagination,
Copy,
SearchQuery,
AvatarInitials
AvatarInitials,
Limit
} from '$lib/components';
import { Button } from '$lib/elements/forms';
import {
@@ -23,8 +24,7 @@
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import { goto } from '$app/navigation';
import { PAGE_LIMIT } from '$lib/constants';
import Create from '../createUser.svelte';
import Create from './createUser.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
@@ -32,9 +32,9 @@
let showCreate = false;
const projectId = $page.params.project;
const userCreated = async (event: CustomEvent<Models.User<Record<string, unknown>>>) => {
async function userCreated(event: CustomEvent<Models.User<Record<string, unknown>>>) {
await goto(`${base}/console/project-${projectId}/auth/user-${event.detail.$id}`);
};
}
</script>
<Container>
@@ -111,12 +111,8 @@
</TableBody>
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.users.total}</p>
<Pagination
offset={data.offset}
limit={PAGE_LIMIT}
sum={data.users.total}
path={`/console/project-${projectId}/auth`} />
<Limit limit={data.limit} sum={data.users.total} name="Users" />
<Pagination limit={data.limit} offset={data.offset} sum={data.users.total} />
</div>
{:else if data.search}
<EmptySearch>
@@ -0,0 +1,23 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getSearch, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ url, route }) => {
const page = getPage(url);
const search = getSearch(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
search,
page,
users: await sdk.forProject.users.list(
[Query.limit(limit), Query.offset(offset), Query.orderDesc('$createdAt')],
search
)
};
};
@@ -1,21 +0,0 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, url }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
const search = url.search.slice(1) ?? undefined;
return {
offset,
search,
page,
users: await sdk.forProject.users.list(
[Query.limit(PAGE_LIMIT), Query.offset(offset), Query.orderDesc('$createdAt')],
search
)
};
};
@@ -1,14 +1,13 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal, CopyInput, Alert } from '$lib/components';
import { Button, InputText, InputTextarea, InputSwitch, FormList } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { Alert, CopyInput, Modal } from '$lib/components';
import { Button, FormList, InputSwitch, InputText, InputTextarea } from '$lib/elements/forms';
import type { Provider } from '$lib/stores/oauth-providers';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { updateOAuth } from './updateOAuth';
const projectId = $page.params.project;
export let provider: Provider;
@@ -17,6 +16,7 @@
let keyID: string = null;
let teamID: string = null;
let p8: string = null;
let error: string;
onMount(() => {
appId ??= provider.appId;
@@ -24,33 +24,13 @@
if (provider.secret) ({ keyID, teamID, p8 } = JSON.parse(provider.secret));
});
let error: string;
const projectId = $page.params.project;
const update = async () => {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been ${
provider.enabled ? 'enabled' : 'disabled'
}`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
const result = await updateOAuth({ projectId, provider, secret, appId, enabled });
if (result.status === 'error') {
error = result.message;
} else {
provider = null;
invalidate(Dependencies.PROJECT);
} catch (e) {
error = e.message;
trackError(e, Submit.ProviderUpdate);
}
};
@@ -1,14 +1,11 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal, CopyInput, Alert } from '$lib/components';
import { Button, InputPassword, InputText, InputSwitch, FormList } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { Alert, CopyInput, Modal } from '$lib/components';
import { Button, FormList, InputPassword, InputSwitch, InputText } from '$lib/elements/forms';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { updateOAuth } from './updateOAuth';
export let provider: Provider;
@@ -26,29 +23,12 @@
const projectId = $page.params.project;
const update = async () => {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been ${
provider.enabled ? 'enabled' : 'disabled'
}`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
const result = await updateOAuth({ projectId, provider, secret, appId, enabled });
if (result.status === 'error') {
error = result.message;
} else {
provider = null;
invalidate(Dependencies.PROJECT);
} catch (e) {
error = e.message;
trackError(e, Submit.ProviderUpdate);
}
};
@@ -1,14 +1,11 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal, CopyInput, Alert } from '$lib/components';
import { Button, InputPassword, InputText, InputSwitch, FormList } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { Alert, CopyInput, Modal } from '$lib/components';
import { Button, FormList, InputPassword, InputSwitch, InputText } from '$lib/elements/forms';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { updateOAuth } from './updateOAuth';
export let provider: Provider;
@@ -26,29 +23,12 @@
const projectId = $page.params.project;
const update = async () => {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been ${
provider.enabled ? 'enabled' : 'disabled'
}`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
const result = await updateOAuth({ projectId, provider, secret, appId, enabled });
if (result.status === 'error') {
error = result.message;
} else {
provider = null;
invalidate(Dependencies.PROJECT);
} catch (e) {
error = e.message;
trackError(e, Submit.ProviderUpdate);
}
};
@@ -1,14 +1,11 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal, CopyInput, Alert } from '$lib/components';
import { Button, InputPassword, InputText, InputSwitch, FormList } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { Alert, CopyInput, Modal } from '$lib/components';
import { Button, FormList, InputPassword, InputSwitch, InputText } from '$lib/elements/forms';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { updateOAuth } from './updateOAuth';
export let provider: Provider;
@@ -26,29 +23,12 @@
const projectId = $page.params.project;
const update = async () => {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been ${
provider.enabled ? 'enabled' : 'disabled'
}`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
const result = await updateOAuth({ projectId, provider, secret, appId, enabled });
if (result.status === 'error') {
error = result.message;
} else {
provider = null;
invalidate(Dependencies.PROJECT);
} catch (e) {
error = e.message;
trackError(e, Submit.ProviderUpdate);
}
};
@@ -1,14 +1,11 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal, CopyInput, Alert } from '$lib/components';
import { Button, InputPassword, InputText, InputSwitch, FormList } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { Alert, CopyInput, Modal } from '$lib/components';
import { Button, FormList, InputPassword, InputSwitch, InputText } from '$lib/elements/forms';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { updateOAuth } from './updateOAuth';
export let provider: Provider;
@@ -27,29 +24,12 @@
let error: string;
const update = async () => {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been ${
provider.enabled ? 'enabled' : 'disabled'
}`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
const result = await updateOAuth({ projectId, provider, secret, appId, enabled });
if (result.status === 'error') {
error = result.message;
} else {
provider = null;
invalidate(Dependencies.PROJECT);
} catch (e) {
error = e.message;
trackError(e, Submit.ProviderUpdate);
}
};
</script>
@@ -1,14 +1,11 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal, CopyInput, Alert } from '$lib/components';
import { Button, InputPassword, InputText, InputSwitch, FormList } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { Alert, CopyInput, Modal } from '$lib/components';
import { Button, FormList, InputPassword, InputSwitch, InputText } from '$lib/elements/forms';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { updateOAuth } from './updateOAuth';
export let provider: Provider;
@@ -27,29 +24,12 @@
const projectId = $page.params.project;
const update = async () => {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been ${
provider.enabled ? 'enabled' : 'disabled'
}`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
const result = await updateOAuth({ projectId, provider, secret, appId, enabled });
if (result.status === 'error') {
error = result.message;
} else {
provider = null;
invalidate(Dependencies.PROJECT);
} catch (e) {
error = e.message;
trackError(e, Submit.ProviderUpdate);
}
};
@@ -1,14 +1,13 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal, CopyInput, Alert } from '$lib/components';
import { Button, InputPassword, InputText, InputSwitch, FormList } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { Alert, CopyInput, Modal } from '$lib/components';
import { Button, FormList, InputPassword, InputSwitch, InputText } from '$lib/elements/forms';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { updateOAuth } from './updateOAuth';
const projectId = $page.params.project;
export let provider: Provider;
@@ -17,42 +16,23 @@
let clientSecret: string = null;
let oktaDomain: string = null;
let authorizationServerId: string = null;
let error: string;
onMount(() => {
appId ??= provider.appId;
enabled ??= provider.enabled;
if (provider.secret)
if (provider.secret) {
({ clientSecret, oktaDomain, authorizationServerId } = JSON.parse(provider.secret));
}
});
let error: string;
const projectId = $page.params.project;
const update = async () => {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been ${
provider.enabled ? 'enabled' : 'disabled'
}`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
const result = await updateOAuth({ projectId, provider, secret, appId, enabled });
if (result.status === 'error') {
error = result.message;
} else {
provider = null;
invalidate(Dependencies.PROJECT);
} catch (e) {
error = e.message;
trackError(e, Submit.ProviderUpdate);
}
};
@@ -25,9 +25,7 @@
await sdk.forConsole.projects.updateAuthStatus(projectId, box.method, box.value);
addNotification({
type: 'success',
message: `${box.label} authentication has been ${
box.value ? 'enabled' : 'disabled'
}`
message: `${box.label} authentication has been updated`
});
trackEvent(Submit.AuthStatusUpdate, {
method: box.method,
@@ -10,15 +10,21 @@
TableCell
} from '$lib/elements/table';
import { Button } from '$lib/elements/forms';
import { Empty, EmptySearch, AvatarInitials, Pagination, SearchQuery } from '$lib/components';
import Create from '../../createTeam.svelte';
import {
Empty,
EmptySearch,
AvatarInitials,
Pagination,
SearchQuery,
Limit
} from '$lib/components';
import Create from '../createTeam.svelte';
import { goto } from '$app/navigation';
import { toLocaleDateTime } from '$lib/helpers/date';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
import { PAGE_LIMIT } from '$lib/constants';
export let data: PageData;
@@ -63,12 +69,8 @@
</TableBody>
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.teams.total}</p>
<Pagination
limit={PAGE_LIMIT}
path={`/console/project-${$page.params.project}/auth/teams`}
offset={data.offset}
sum={data.teams.total} />
<Limit limit={data.limit} sum={data.teams.total} name="Teams" />
<Pagination limit={data.limit} offset={data.offset} sum={data.teams.total} />
</div>
{:else if data.search}
<EmptySearch>
@@ -0,0 +1,23 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getSearch, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ url, route }) => {
const page = getPage(url);
const search = getSearch(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
search,
page,
teams: await sdk.forProject.teams.list(
[Query.limit(limit), Query.offset(offset), Query.orderDesc('$createdAt')],
search
)
};
};
@@ -1,21 +0,0 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, url }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
const search = url.search.slice(1) ?? undefined;
return {
offset,
search,
page,
teams: await sdk.forProject.teams.list(
[Query.limit(PAGE_LIMIT), Query.offset(offset), Query.orderDesc('$createdAt')],
search
)
};
};
@@ -0,0 +1,8 @@
<script lang="ts">
import type { PageData } from './$types';
import { Activity } from '$lib/layout';
export let data: PageData;
</script>
<Activity {...data} />
@@ -1,17 +1,19 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
logs: await sdk.forProject.teams.listLogs(params.team, [
Query.limit(PAGE_LIMIT),
Query.limit(limit),
Query.offset(offset)
])
};
@@ -1,10 +0,0 @@
<script lang="ts">
import type { PageData } from './$types';
import { page } from '$app/stores';
import { Activity } from '$lib/layout';
export let data: PageData;
const path = `/console/project-${$page.params.project}/auth/teams/team-${$page.params.team}/activity`;
</script>
<Activity {path} logs={data.logs} offset={data.offset} />
@@ -1,6 +1,13 @@
<script lang="ts">
import { page } from '$app/stores';
import { Empty, EmptySearch, AvatarInitials, Pagination, SearchQuery } from '$lib/components';
import {
Empty,
EmptySearch,
AvatarInitials,
Pagination,
SearchQuery,
Limit
} from '$lib/components';
import {
Table,
TableHeader,
@@ -17,9 +24,9 @@
import { base } from '$app/paths';
import { toLocaleDateTime } from '$lib/helpers/date';
import type { PageData } from './$types';
import CreateMember from '../../createMembership.svelte';
import DeleteMembership from '../../deleteMembership.svelte';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import CreateMember from '../createMembership.svelte';
import DeleteMembership from '../deleteMembership.svelte';
import { Dependencies } from '$lib/constants';
import { trackEvent } from '$lib/actions/analytics';
export let data: PageData;
@@ -81,12 +88,8 @@
</TableBody>
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.memberships.total}</p>
<Pagination
limit={PAGE_LIMIT}
path={`/console/project-${$page.params.project}/auth/teams/team-${$page.params.team}/members`}
offset={data.offset}
sum={data.memberships.total} />
<Limit limit={data.limit} sum={data.memberships.total} name="Memberships" />
<Pagination limit={data.limit} offset={data.offset} sum={data.memberships.total} />
</div>
{:else if data.search}
<EmptySearch>
@@ -1,22 +1,24 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, getSearch, pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends, url }) => {
export const load: PageLoad = async ({ params, depends, url, route }) => {
depends(Dependencies.MEMBERSHIPS);
const teamId = params.team;
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
const search = url.search.slice(1) ?? undefined;
const page = getPage(url);
const search = getSearch(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
search,
limit,
memberships: await sdk.forProject.teams.listMemberships(
teamId,
[Query.limit(PAGE_LIMIT), Query.offset(offset), Query.orderDesc('$createdAt')],
[Query.limit(limit), Query.offset(offset), Query.orderDesc('$createdAt')],
search
)
};
@@ -0,0 +1,51 @@
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import type { Provider } from '$lib/stores/oauth-providers';
import { sdk } from '$lib/stores/sdk';
type Args = {
projectId: string;
provider: Provider;
appId: string;
secret: string;
enabled: boolean;
};
type Return = {
status: 'success' | 'error';
message?: string;
};
export async function updateOAuth({
projectId,
provider,
appId,
secret,
enabled
}: Args): Promise<Return> {
try {
await sdk.forConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
appId,
secret,
enabled
);
addNotification({
type: 'success',
message: `${provider.name} authentication has been updated`
});
trackEvent(Submit.ProviderUpdate, {
provider,
enabled
});
invalidate(Dependencies.PROJECT);
return { status: 'success' };
} catch (e) {
trackError(e, Submit.ProviderUpdate);
return { status: 'error', message: e.message };
}
}
@@ -1,15 +1,20 @@
import type { Models } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
export const load: PageLoad = async ({ params }) => {
const { period } = params;
const response = await sdk.forProject.users.getUsage(period ?? '30d');
return {
count: response.usersCount as unknown as Models.Metric[],
created: response.usersCreate as unknown as Models.Metric[],
read: response.usersRead as unknown as Models.Metric[],
updated: response.usersUpdate as unknown as Models.Metric[],
deleted: response.usersDelete as unknown as Models.Metric[]
};
try {
const response = await sdk.forProject.users.getUsage(period ?? '30d');
return {
count: response.usersCount as unknown as Models.Metric[],
created: response.usersCreate as unknown as Models.Metric[],
read: response.usersRead as unknown as Models.Metric[],
updated: response.usersUpdate as unknown as Models.Metric[],
deleted: response.usersDelete as unknown as Models.Metric[]
};
} catch (e) {
throw error(e.code, e.message);
}
};
@@ -0,0 +1,8 @@
<script lang="ts">
import type { PageData } from './$types';
import { Activity } from '$lib/layout';
export let data: PageData;
</script>
<Activity logs={data.logs} offset={data.offset} />
@@ -1,17 +1,18 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
logs: await sdk.forProject.users.listLogs(params.user, [
Query.limit(PAGE_LIMIT),
Query.limit(limit),
Query.offset(offset)
])
};
@@ -1,10 +0,0 @@
<script lang="ts">
import type { PageData } from './$types';
import { page } from '$app/stores';
import { Activity } from '$lib/layout';
export let data: PageData;
const path = `/console/project-${$page.params.project}/auth/user-${$page.params.user}/activity`;
</script>
<Activity {path} logs={data.logs} offset={data.offset} />
@@ -13,7 +13,7 @@
} from '$lib/elements/table';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import DeleteMembership from '../../deleteMembership.svelte';
import DeleteMembership from '../deleteMembership.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
import { trackEvent } from '$lib/actions/analytics';
@@ -13,8 +13,8 @@
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { sdk } from '$lib/stores/sdk';
import DeleteAllSessions from '../../deleteAllSessions.svelte';
import DeleteSessions from '../../deleteSession.svelte';
import DeleteAllSessions from '../deleteAllSessions.svelte';
import DeleteSessions from '../deleteSession.svelte';
import type { PageData } from './$types';
export let data: PageData;
@@ -4,6 +4,7 @@ import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends }) => {
depends(Dependencies.SESSIONS);
return {
sessions: await sdk.forProject.users.listSessions(params.user)
};
@@ -1,42 +1,34 @@
<script lang="ts">
import { page } from '$app/stores';
import { goto, invalidate } from '$app/navigation';
import { goto } from '$app/navigation';
import { Button } from '$lib/elements/forms';
import { Empty, Heading, ViewSelector } from '$lib/components';
import { Empty, Heading, Pagination, Limit, ViewSelector } from '$lib/components';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import Create from '../create.svelte';
import Create from './create.svelte';
import Grid from './grid.svelte';
import Table from './table.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
import GridView from './gridView.svelte';
import TableView from './tableView.svelte';
import { prefs } from '$lib/stores/user';
import { Dependencies } from '$lib/constants';
import { columns } from './store';
export let data: PageData;
const project = $page.params.project;
let showCreate = false;
const project = $page.params.project;
async function handleCreate(event: CustomEvent<Models.Database>) {
showCreate = false;
await goto(`${base}/console/project-${project}/databases/database-${event.detail.$id}`);
}
prefs.subscribe((prefs) => {
if (prefs?.preferredView) {
invalidate(Dependencies.DATABASES);
}
});
</script>
<Container>
<div class="u-flex common-section u-main-space-between">
<div class="u-flex u-gap-12 common-section u-main-space-between">
<Heading tag="h2" size="5">Databases</Heading>
<div class="u-flex u-gap-16">
<ViewSelector {columns} />
<ViewSelector view={data.view} {columns} />
<Button on:click={() => (showCreate = true)} event="create_database">
<span class="icon-plus" aria-hidden="true" />
@@ -46,11 +38,16 @@
</div>
{#if data.databases.total}
{#if $prefs?.preferredView === 'list'}
<TableView {data} {columns} />
{#if data.view === 'grid'}
<Grid {data} />
{:else}
<GridView {data} bind:showCreate />
<Table {data} />
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<Limit limit={data.limit} sum={data.databases.total} name="Databases" />
<Pagination limit={data.limit} offset={data.offset} sum={data.databases.total} />
</div>
{:else}
<Empty
single
@@ -0,0 +1,23 @@
import { CARD_LIMIT } from '$lib/constants';
import { getLimit, getPage, getView, pageToOffset, View } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@aw-labs/appwrite-console';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const view = getView(url, route, View.Grid);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
view,
databases: await sdk.forProject.databases.list([
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
])
};
};
@@ -1,41 +0,0 @@
import { Query } from '@aw-labs/appwrite-console';
import { pageToOffset, redirectOnOffsetOverflow } from '$lib/helpers/load';
import { CARD_LIMIT, Dependencies, PAGE_LIMIT } from '$lib/constants';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { get } from 'svelte/store';
import { prefs } from '$lib/stores/user';
export const load: PageLoad = async ({ params, depends, url }) => {
depends(Dependencies.DATABASES);
const customPrefs = get(prefs);
const page = Number(params.page);
const limit = customPrefs?.pageLimit
? customPrefs.pageLimit
: customPrefs?.preferredView === 'list'
? PAGE_LIMIT
: CARD_LIMIT;
const offset = pageToOffset(page, limit);
const databases = await sdk.forProject.databases.list([
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
]);
await redirectOnOffsetOverflow(
offset,
page,
databases.total,
params.project,
'databases',
url.search
);
return {
offset,
databases
};
};
@@ -0,0 +1,44 @@
<script lang="ts">
import { Empty, Heading, Limit, Pagination, ViewSelector } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { columns, showCreate } from './store';
import Table from './table.svelte';
import Grid from './grid.svelte';
import type { PageData } from './$types';
export let data: PageData;
</script>
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<Heading tag="h2" size="5">Collections</Heading>
<div class="u-flex u-gap-16">
<ViewSelector view={data.view} {columns} />
<Button on:click={() => ($showCreate = true)} event="create_collection">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create collection</span>
</Button>
</div>
</div>
{#if data.collections.total}
{#if data.view === 'grid'}
<Grid {data} />
{:else}
<Table {data} />
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<Limit limit={data.limit} sum={data.collections.total} name="Collections" />
<Pagination limit={data.limit} offset={data.offset} sum={data.collections.total} />
</div>
{:else}
<Empty
single
href="https://appwrite.io/docs/databases#collection"
target="collection"
on:click={() => ($showCreate = true)} />
{/if}
</Container>
@@ -0,0 +1,23 @@
import { Query } from '@aw-labs/appwrite-console';
import { CARD_LIMIT } from '$lib/constants';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getView, pageToOffset, View } from '$lib/helpers/load';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const view = getView(url, route, View.Grid);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
view,
collections: await sdk.forProject.databases.listCollections(params.database, [
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
])
};
};
@@ -1,59 +0,0 @@
<script lang="ts">
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { Button } from '$lib/elements/forms';
import { Empty, Heading, ViewSelector } from '$lib/components';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import type { PageData } from './$types';
import type { Models } from '@aw-labs/appwrite-console';
import Create from '../createCollection.svelte';
import GridView from './gridView.svelte';
import TableView from './tableView.svelte';
import { prefs } from '$lib/stores/user';
import { columns } from './store';
export let data: PageData;
let showCreate = false;
const project = $page.params.project;
const databaseId = $page.params.database;
async function handleCreate(event: CustomEvent<Models.Collection>) {
showCreate = false;
await goto(
`${base}/console/project-${project}/databases/database-${databaseId}/collection-${event.detail.$id}`
);
}
</script>
<Container>
<div class="u-flex common-section u-main-space-between">
<Heading tag="h2" size="5">Collections</Heading>
<div class="u-flex u-gap-16">
<ViewSelector {columns} />
<Button on:click={() => (showCreate = true)} event="create_collection">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create collection</span>
</Button>
</div>
</div>
{#if data.collections.total}
{#if $prefs?.preferredView === 'list'}
<TableView {data} {columns} />
{:else}
<GridView {data} bind:showCreate />
{/if}
{:else}
<Empty
single
href="https://appwrite.io/docs/databases#collection"
target="collection"
on:click={() => (showCreate = true)} />
{/if}
</Container>
<Create bind:showCreate on:created={handleCreate} />
@@ -1,41 +0,0 @@
import { Query } from '@aw-labs/appwrite-console';
import { pageToOffset, redirectOnOffsetOverflow } from '$lib/helpers/load';
import { CARD_LIMIT, Dependencies, PAGE_LIMIT } from '$lib/constants';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { get } from 'svelte/store';
import { prefs } from '$lib/stores/user';
export const load: PageLoad = async ({ params, depends, url }) => {
depends(Dependencies.DATABASE);
const page = Number(params.page);
const customPrefs = get(prefs);
const limit = customPrefs?.pageLimit
? customPrefs.pageLimit
: customPrefs?.preferredView === 'list'
? PAGE_LIMIT
: CARD_LIMIT;
const offset = pageToOffset(page, limit);
const collections = await sdk.forProject.databases.listCollections(params.database, [
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
]);
await redirectOnOffsetOverflow(
offset,
page,
collections.total,
params.project,
`databases/database-${params.database}`,
url.search
);
return {
offset,
collections
};
};
@@ -0,0 +1,72 @@
<script lang="ts">
import { Empty, Heading, Pagination, Limit, ViewSelector } from '$lib/components';
import { Container } from '$lib/layout';
import { Button } from '$lib/elements/forms';
import { wizard } from '$lib/stores/wizard';
import Create from './createDocument.svelte';
import type { PageData } from './$types';
import { collection, columns } from './store';
import CreateAttribute from './createAttribute.svelte';
import Table from './table.svelte';
import { preferences } from '$lib/stores/preferences';
import { page } from '$app/stores';
export let data: PageData;
let showCreateAttribute = false;
$: selected = preferences.getCustomCollectionColumns($page.params.collection);
$: columns.set(
$collection.attributes.map((attribute) => ({
id: attribute.key,
title: attribute.key,
type: attribute.type,
show: selected?.includes(attribute.key) ?? true
}))
);
function openWizard() {
wizard.start(Create);
}
</script>
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<Heading tag="h2" size="5">Documents</Heading>
<div class="u-flex u-gap-16">
<ViewSelector view={data.view} {columns} hideView isCustomCollection />
<Button
disabled={!$collection?.attributes?.length}
on:click={openWizard}
event="create_document">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create document</span>
</Button>
</div>
</div>
{#if $collection?.attributes?.length}
{#if data.documents.total}
<Table {data} />
<div class="u-flex common-section u-main-space-between">
<Limit limit={data.limit} sum={data.documents.total} name="Documents" />
<Pagination limit={data.limit} offset={data.offset} sum={data.documents.total} />
</div>
{:else}
<Empty
single
href="https://appwrite.io/docs/databases#create-documents"
target="document"
on:click={openWizard} />
{/if}
{:else}
<Empty
single
href="https://appwrite.io/docs/databases#attributes"
target="attribute"
on:click={() => (showCreateAttribute = true)} />
{/if}
</Container>
<CreateAttribute bind:showCreate={showCreateAttribute} />
@@ -0,0 +1,24 @@
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { getLimit, getPage, getView, pageToOffset, View } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@aw-labs/appwrite-console';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends, url, route }) => {
depends(Dependencies.DOCUMENTS);
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const view = getView(url, route, View.Grid);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
view,
documents: await sdk.forProject.databases.listDocuments(
params.database,
params.collection,
[Query.limit(limit), Query.offset(offset), Query.orderDesc('$createdAt')]
)
};
};
@@ -1,217 +0,0 @@
<script lang="ts">
import {
TableScroll,
TableRowLink,
TableBody,
TableHeader,
TableCellHead,
TableCell
} from '$lib/elements/table';
import { Empty, Copy, Heading, ViewSelector, CustomPagination } from '$lib/components';
import { Pill } from '$lib/elements';
import { Container } from '$lib/layout';
import { Button } from '$lib/elements/forms';
import { base } from '$app/paths';
import { wizard } from '$lib/stores/wizard';
import Create from '../createDocument.svelte';
import type { PageData } from './$types';
import { collection } from '../store';
import { page } from '$app/stores';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import CreateAttribute from '../createAttribute.svelte';
import { tooltip } from '$lib/actions/tooltip';
import { columns } from './store';
import { onMount } from 'svelte';
import RelationshipsModal from './relationshipsModal.svelte';
import CreateAttributeDropdown from '../attributes/createAttributeDropdown.svelte';
export let data: PageData;
const projectId = $page.params.project;
const databaseId = $page.params.database;
let showCreateAttribute = false;
let showRelationships = false;
let selectedRelationship: string[] = null;
let showCreateDropdown = false;
let selectedAttribute: string = null;
function openWizard() {
wizard.start(Create);
}
onMount(() => {
columns.set([
...$collection.attributes.map((attribute) => ({
id: attribute.key,
title: attribute.key,
type: attribute.type,
show: true
}))
]);
});
function formatArray(array: unknown[]) {
if (array.length === 0) return '[ ]';
let formattedFields: string[] = [];
for (const item of array) {
if (typeof item === 'string') {
formattedFields.push(`"${item}"`);
} else {
formattedFields.push(`${item}`);
}
}
return `[${formattedFields.join(', ')}]`;
}
function formatColumn(column: unknown) {
let formattedColumn: string;
if (typeof column === 'string') {
formattedColumn = column;
} else if (Array.isArray(column)) {
formattedColumn = formatArray(column);
} else if (column === null) {
formattedColumn = 'n/a';
} else {
formattedColumn = `${column}`;
}
return {
value:
formattedColumn.length > 20
? `${formattedColumn.slice(0, 20)}...`
: formattedColumn,
truncated: formattedColumn.length > 20,
whole: formattedColumn
};
}
</script>
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<Heading tag="h2" size="5">Documents</Heading>
<div class="u-flex u-gap-16">
<ViewSelector showToggle={false} {columns} />
<Button
disabled={!$collection?.attributes?.length}
on:click={openWizard}
event="create_document">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create document</span>
</Button>
</div>
</div>
{#if $collection?.attributes?.length}
{#if data.documents.total}
<TableScroll isSticky>
<TableHeader>
<TableCellHead width={200} eyebrow={false}>Document ID</TableCellHead>
{#each $columns as column}
{#if column.show}
<TableCellHead eyebrow={false}>{column.title}</TableCellHead>
{/if}
{/each}
</TableHeader>
<TableBody>
{#each data.documents.documents as document}
<TableRowLink
href={`${base}/console/project-${projectId}/databases/database-${databaseId}/collection-${$collection.$id}/document-${document.$id}`}>
<TableCell width={230}>
<Copy value={document.$id}>
<Pill button trim>
<span class="icon-duplicate" aria-hidden="true" />
<span class="text">{document.$id}</span>
</Pill>
</Copy>
</TableCell>
{#each $columns as column}
{#if column.show}
{#if column.type === 'relationship'}
{#if column.direction === 'one'}
<TableCell title={column.title}>
{document[column.id]}
</TableCell>
{:else}
<TableCell>
{@const itemsNum = column?.data?.lenght}
<Button
on:click={() => {
showRelationships = true;
selectedRelationship = document;
}}
disabled={!itemsNum}>
Items <span class="inline-tag">{itemsNum}</span>
</Button>
</TableCell>
{/if}
{:else}
{@const formatted = formatColumn(document[column.id])}
<TableCell>
<div
use:tooltip={{
content: formatted.whole,
disabled: !formatted.truncated
}}>
{formatted.value}
</div>
</TableCell>
{/if}
{/if}
{/each}
</TableRowLink>
{/each}
</TableBody>
</TableScroll>
<CustomPagination
limit={PAGE_LIMIT}
name="Documents"
path={`/console/project-${$page.params.project}/databases/database-${$page.params.database}/collection-${$page.params.collection}`}
offset={data.offset}
total={data.documents.total}
dependencies={[Dependencies.DOCUMENTS]} />
{:else}
<Empty
single
href="https://appwrite.io/docs/databases#create-documents"
target="document"
on:click={openWizard} />
{/if}
{:else}
<Empty single target="attribute" on:click={() => (showCreateDropdown = true)}>
<div class="u-text-center">
<Heading size="7" tag="h2">Create your first attribute to get started.</Heading>
<p class="body-text-2 u-margin-block-start-4">
Need a hand? Check out our documentation.
</p>
</div>
<div class="u-flex u-gap-16 u-main-center">
<Button
external
href="https://appwrite.io/docs/databases#attributes"
text
event="empty_documentation"
ariaLabel={`create {target}`}>Documentation</Button>
<CreateAttributeDropdown
bind:showCreateDropdown
bind:showCreate={showCreateAttribute}
bind:selectedOption={selectedAttribute}>
<Button
secondary
event="create_attribute"
on:click={() => {
showCreateDropdown = !showCreateDropdown;
}}>
Create attribute
</Button>
</CreateAttributeDropdown>
</div>
</Empty>
{/if}
</Container>
<CreateAttribute bind:showCreate={showCreateAttribute} bind:selectedOption={selectedAttribute} />
<RelationshipsModal bind:show={showRelationships} {selectedRelationship} />
@@ -1,20 +0,0 @@
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { pageToOffset } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@aw-labs/appwrite-console';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends }) => {
depends(Dependencies.DOCUMENTS);
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
return {
offset,
documents: await sdk.forProject.databases.listDocuments(
params.database,
params.collection,
[Query.limit(PAGE_LIMIT), Query.offset(offset), Query.orderDesc('$createdAt')]
)
};
};
@@ -0,0 +1,8 @@
<script lang="ts">
import { Activity } from '$lib/layout';
import type { PageData } from './$types';
export let data: PageData;
</script>
<Activity {...data} />
@@ -1,19 +1,21 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
logs: await sdk.forProject.databases.listCollectionLogs(
params.database,
params.collection,
[Query.limit(PAGE_LIMIT), Query.offset(offset)]
[Query.limit(limit), Query.offset(offset)]
)
};
};
@@ -1,11 +0,0 @@
<script lang="ts">
import { page } from '$app/stores';
import { Activity } from '$lib/layout';
import type { PageData } from './$types';
export let data: PageData;
const path = `/console/project-${$page.params.project}/databases/database-${$page.params.database}/collection-${$page.params.collection}/activity`;
</script>
<Activity {path} logs={data.logs} offset={data.offset} />
@@ -0,0 +1,8 @@
<script lang="ts">
import type { PageData } from './$types';
import { Activity } from '$lib/layout';
export let data: PageData;
</script>
<Activity {...data} />
@@ -1,20 +1,22 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
logs: await sdk.forProject.databases.listDocumentLogs(
params.database,
params.collection,
params.document,
[Query.limit(PAGE_LIMIT), Query.offset(offset)]
[Query.limit(limit), Query.offset(offset)]
)
};
};
@@ -1,10 +0,0 @@
<script lang="ts">
import type { PageData } from './$types';
import { page } from '$app/stores';
import { Activity } from '$lib/layout';
export let data: PageData;
const path = `/console/project-${$page.params.project}/databases/database-${$page.params.database}/collection-${$page.params.collection}/document-${$page.params.document}/activity`;
</script>
<Activity {path} logs={data.logs} offset={data.offset} />
@@ -1,6 +1,7 @@
import { page } from '$app/stores';
import type { Column } from '$lib/components/viewSelector.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import { derived } from 'svelte/store';
import { derived, writable } from 'svelte/store';
export type Attributes =
| Models.AttributeBoolean
@@ -22,3 +23,4 @@ export const attributes = derived(
($page) => $page.data.collection.attributes as Attributes[]
);
export const indexes = derived(page, ($page) => $page.data.collection.indexes as Models.Index[]);
export const columns = writable<Column[]>([]);
@@ -2,7 +2,7 @@
import { base } from '$app/paths';
import { page } from '$app/stores';
import { showCreate } from '../store';
import type { PageData } from './[[page]]/$types';
import type { PageData } from './$types';
$: data = $page.data as PageData;
$: project = $page.params.project;
@@ -31,7 +31,7 @@
{#if data?.allCollections?.total}
<ul class="drop-list">
{#each sortedCollections as collection}
{@const href = `${base}/console/project-${project}/databases/database-${databaseId}/collection-${collection.$id}/documents`}
{@const href = `${base}/console/project-${project}/databases/database-${databaseId}/collection-${collection.$id}`}
{@const isSelected = collectionId === collection.$id}
<li class="drop-list-item">
<a class="drop-button" class:is-selected={isSelected} {href}>
@@ -0,0 +1,98 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { tooltip } from '$lib/actions/tooltip';
import { Copy } from '$lib/components';
import { Pill } from '$lib/elements';
import {
TableBody,
TableCell,
TableCellHead,
TableHeader,
TableRowLink,
TableScroll
} from '$lib/elements/table';
import type { PageData } from './$types';
import { collection, columns } from './store';
export let data: PageData;
const projectId = $page.params.project;
const databaseId = $page.params.database;
function formatArray(array: unknown[]) {
if (array.length === 0) return '[ ]';
let formattedFields: string[] = [];
for (const item of array) {
if (typeof item === 'string') {
formattedFields.push(`"${item}"`);
} else {
formattedFields.push(`${item}`);
}
}
return `[${formattedFields.join(', ')}]`;
}
function formatColumn(column: unknown) {
let formattedColumn: string;
if (typeof column === 'string') {
formattedColumn = column;
} else if (Array.isArray(column)) {
formattedColumn = formatArray(column);
} else if (column === null) {
formattedColumn = 'n/a';
} else {
formattedColumn = `${column}`;
}
return {
value:
formattedColumn.length > 20
? `${formattedColumn.slice(0, 20)}...`
: formattedColumn,
truncated: formattedColumn.length > 20,
whole: formattedColumn
};
}
</script>
<TableScroll isSticky>
<TableHeader>
<TableCellHead width={100} eyebrow={false}>Document ID</TableCellHead>
{#each $columns.filter((n) => n.show) as column}
{#if column.show}
<TableCellHead eyebrow={false}>{column.title}</TableCellHead>
{/if}
{/each}
</TableHeader>
<TableBody>
{#each data.documents.documents as document}
<TableRowLink
href={`${base}/console/project-${projectId}/databases/database-${databaseId}/collection-${$collection.$id}/document-${document.$id}`}>
<TableCell>
<Copy value={document.$id}>
<Pill button trim>
<span class="icon-duplicate" aria-hidden="true" />
<span class="text">{document.$id}</span>
</Pill>
</Copy>
</TableCell>
{#each $columns.filter((n) => n.show) as column}
{@const formatted = formatColumn(document[column.id])}
<TableCell>
<div
use:tooltip={{
content: formatted.whole,
disabled: !formatted.truncated
}}>
{formatted.value}
</div>
</TableCell>
{/each}
</TableRowLink>
{/each}
</TableBody>
</TableScroll>
@@ -0,0 +1,31 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { CardContainer, Copy, GridItem1 } from '$lib/components';
import { Pill } from '$lib/elements';
import type { PageData } from './$types';
export let data: PageData;
export let showCreate = false;
const projectId = $page.params.project;
const databaseId = $page.params.database;
</script>
<CardContainer
total={data.collections.total}
on:click={() => (showCreate = true)}
event="collection">
{#each data.collections.collections as collection}
<GridItem1
href={`${base}/console/project-${projectId}/databases/database-${databaseId}/collection-${collection.$id}`}>
<svelte:fragment slot="title">{collection.name}</svelte:fragment>
<svelte:fragment slot="status">
{#if !collection.enabled}
<Pill>disabled</Pill>
{/if}</svelte:fragment>
<Copy value={collection.$id}>
<Pill button><i class="icon-duplicate" />Collection ID</Pill>
</Copy>
</GridItem1>
{/each}
</CardContainer>
@@ -1,6 +1,14 @@
import { page } from '$app/stores';
import type { Column } from '$lib/components/viewSelector.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import { derived, writable } from 'svelte/store';
export const database = derived(page, ($page) => $page.data.database as Models.Database);
export const showCreate = writable(false);
export const columns = writable<Column[]>([
{ id: '$id', title: 'Database ID', show: true, width: 50 },
{ id: 'name', title: 'Name', show: true, width: 120 },
{ id: '$createdAt', title: 'Created', show: true, width: 120 },
{ id: '$updatedAt', title: 'Updated', show: true, width: 120 }
]);
@@ -0,0 +1,63 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Copy } from '$lib/components';
import { Pill } from '$lib/elements';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRowLink
} from '$lib/elements/table';
import { toLocaleDateTime } from '$lib/helpers/date';
import type { PageData } from './$types';
import { columns } from './store';
export let data: PageData;
const projectId = $page.params.project;
const databaseId = $page.params.database;
</script>
<Table>
<TableHeader>
{#each $columns as column}
{#if column.show}
<TableCellHead width={column.width}>{column.title}</TableCellHead>
{/if}
{/each}
</TableHeader>
<TableBody>
{#each data.collections.collections as collection}
<TableRowLink
href={`${base}/console/project-${projectId}/databases/database-${databaseId}/collection-${collection.$id}`}>
{#each $columns as column}
{#if column.show}
{#if column.id === '$id'}
{#key $columns}
<TableCell title={column.title}>
<Copy value={collection.$id}>
<Pill button trim>
<span class="icon-duplicate" aria-hidden="true" />
<span class="text u-trim">{collection.$id}</span>
</Pill>
</Copy>
</TableCell>
{/key}
{:else if column.id === 'name'}
<TableCellText title={column.title}>
{collection.name}
</TableCellText>
{:else}
<TableCellText title={column.title}>
{toLocaleDateTime(collection[column.id])}
</TableCellText>
{/if}
{/if}
{/each}
</TableRowLink>
{/each}
</TableBody>
</Table>
@@ -0,0 +1,25 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { CardContainer, Copy, GridItem1 } from '$lib/components';
import { Pill } from '$lib/elements';
import type { PageData } from './$types';
export let data: PageData;
export let showCreate = false;
const project = $page.params.project;
</script>
<CardContainer total={data.databases.total} on:click={() => (showCreate = true)} event="database">
{#each data.databases.databases as database}
<GridItem1 href={`${base}/console/project-${project}/databases/database-${database.$id}`}>
<svelte:fragment slot="title">{database.name}</svelte:fragment>
<Copy value={database.$id}>
<Pill button><i class="icon-duplicate" />Database ID</Pill>
</Copy>
</GridItem1>
{/each}
<svelte:fragment slot="empty">
<p>Create a new database</p>
</svelte:fragment>
</CardContainer>
@@ -0,0 +1,9 @@
import type { Column } from '$lib/components/viewSelector.svelte';
import { writable } from 'svelte/store';
export const columns = writable<Column[]>([
{ id: '$id', title: 'Database ID', show: true, width: 50 },
{ id: 'name', title: 'Name', show: true, width: 120 },
{ id: '$createdAt', title: 'Created', show: true, width: 120 },
{ id: '$updatedAt', title: 'Updated', show: true, width: 120 }
]);
@@ -0,0 +1,62 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Copy } from '$lib/components';
import { Pill } from '$lib/elements';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRowLink
} from '$lib/elements/table';
import { toLocaleDateTime } from '$lib/helpers/date';
import type { PageData } from './$types';
import { columns } from './store';
export let data: PageData;
const projectId = $page.params.project;
</script>
<Table>
<TableHeader>
{#each $columns as column}
{#if column.show}
<TableCellHead width={column.width}>{column.title}</TableCellHead>
{/if}
{/each}
</TableHeader>
<TableBody>
{#each data.databases.databases as database}
<TableRowLink
href={`${base}/console/project-${projectId}/databases/database-${database.$id}`}>
{#each $columns as column}
{#if column.show}
{#if column.id === '$id'}
{#key $columns}
<TableCell title={column.title}>
<Copy value={database.$id}>
<Pill button trim>
<span class="icon-duplicate" aria-hidden="true" />
<span class="text u-trim">{database.$id}</span>
</Pill>
</Copy>
</TableCell>
{/key}
{:else if column.id === 'name'}
<TableCellText title={column.title}>
{database.name}
</TableCellText>
{:else}
<TableCellText title={column.title}>
{toLocaleDateTime(database[column.id])}
</TableCellText>
{/if}
{/if}
{/each}
</TableRowLink>
{/each}
</TableBody>
</Table>
@@ -1,16 +1,20 @@
import type { Models } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
export const load: PageLoad = async ({ params }) => {
const { period } = params;
const response = await sdk.forProject.databases.getUsage(period ?? '30d');
return {
count: response.databasesCount as unknown as Models.Metric[],
created: response.databasesCreate as unknown as Models.Metric[],
read: response.databasesRead as unknown as Models.Metric[],
updated: response.databasesUpdate as unknown as Models.Metric[],
deleted: response.databasesDelete as unknown as Models.Metric[]
};
try {
const response = await sdk.forProject.databases.getUsage(period ?? '30d');
return {
count: response.databasesCount as unknown as Models.Metric[],
created: response.databasesCreate as unknown as Models.Metric[],
read: response.databasesRead as unknown as Models.Metric[],
updated: response.databasesUpdate as unknown as Models.Metric[],
deleted: response.databasesDelete as unknown as Models.Metric[]
};
} catch (e) {
throw error(e.code, e.message);
}
};
@@ -1,7 +1,15 @@
<script lang="ts">
import { page } from '$app/stores';
import { Button } from '$lib/elements/forms';
import { Empty, CardContainer, Copy, GridItem1, Heading, Pagination } from '$lib/components';
import {
Empty,
CardContainer,
Copy,
GridItem1,
Heading,
Pagination,
Limit
} from '$lib/components';
import { Pill } from '$lib/elements';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
@@ -10,9 +18,8 @@
import { wizard } from '$lib/stores/wizard';
import { beforeNavigate } from '$app/navigation';
import { toLocaleDateTime } from '$lib/helpers/date';
import Create from '../createFunction.svelte';
import Create from './createFunction.svelte';
import type { PageData } from './$types';
import { CARD_LIMIT } from '$lib/constants';
export let data: PageData;
@@ -82,12 +89,8 @@
</svelte:fragment>
</CardContainer>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.functions.total}</p>
<Pagination
limit={CARD_LIMIT}
path={`/console/project-${$page.params.project}/functions`}
offset={data.offset}
sum={data.functions.total} />
<Limit limit={data.limit} sum={data.functions.total} name="Functions" />
<Pagination limit={data.limit} offset={data.offset} sum={data.functions.total} />
</div>
{:else}
<Empty
@@ -1,18 +1,20 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { CARD_LIMIT, Dependencies } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends }) => {
export const load: PageLoad = async ({ url, depends, route }) => {
depends(Dependencies.FUNCTIONS);
const page = Number(params.page);
const offset = pageToOffset(page, CARD_LIMIT);
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
functions: await sdk.forProject.functions.list([
Query.limit(CARD_LIMIT),
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
])
@@ -9,7 +9,8 @@
Empty,
Status,
Heading,
Pagination
Pagination,
Limit
} from '$lib/components';
import {
TableHeader,
@@ -20,7 +21,7 @@
TableCellText,
TableScroll
} from '$lib/elements/table';
import { execute, func } from '../store';
import { execute, func } from './store';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import { app } from '$lib/stores/app';
@@ -28,15 +29,14 @@
import { toLocaleDateTime } from '$lib/helpers/date';
import { log } from '$lib/stores/logs';
import { invalidate } from '$app/navigation';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
import Delete from '../delete.svelte';
import Create from '../create.svelte';
import Activate from '../activate.svelte';
import Delete from './delete.svelte';
import Create from './create.svelte';
import Activate from './activate.svelte';
import { browser } from '$app/environment';
import { sdk } from '$lib/stores/sdk';
import { page } from '$app/stores';
import Output from '$lib/components/output.svelte';
import { calculateTime } from '$lib/helpers/timeConversion';
import { timer } from '$lib/actions/timer';
@@ -279,13 +279,10 @@
href="https://appwrite.io/docs/functions#createFunction"
on:click={() => (showCreate = true)} />
{/if}
{@const sum = data.deployments.total ? data.deployments.total - 1 : 0}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.deployments.total ? data.deployments.total - 1 : 0}</p>
<Pagination
limit={PAGE_LIMIT}
path={`/console/project-${$page.params.project}/functions/function-${$page.params.function}`}
offset={data.offset}
sum={data.deployments.total ? data.deployments.total - 1 : 0} />
<Limit limit={data.limit} {sum} name="Deployments" />
<Pagination limit={data.limit} offset={data.offset} {sum} />
</div>
</Container>
@@ -1,18 +1,20 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends }) => {
export const load: PageLoad = async ({ params, depends, url, route }) => {
depends(Dependencies.DEPLOYMENTS);
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
deployments: await sdk.forProject.functions.listDeployments(params.function, [
Query.limit(PAGE_LIMIT),
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
])
@@ -1,8 +1,7 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { page } from '$app/stores';
import { Copy, EmptySearch, Heading, Pagination, Status } from '$lib/components';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { Copy, EmptySearch, Heading, Limit, Pagination, Status } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import {
@@ -20,8 +19,8 @@
import { log } from '$lib/stores/logs';
import { sdk } from '$lib/stores/sdk';
import { onDestroy, onMount } from 'svelte';
import { func } from '../../store';
import CreateDeployment from '../../create.svelte';
import { func } from '../store';
import CreateDeployment from '../create.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
@@ -105,12 +104,8 @@
</TableBody>
</TableScroll>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.executions.total}</p>
<Pagination
limit={PAGE_LIMIT}
path={`/console/project-${$page.params.project}/functions/function-${$page.params.function}/executions`}
offset={data.offset}
sum={data.executions.total} />
<Limit limit={data.limit} sum={data.executions.total} name="Executions" />
<Pagination limit={data.limit} offset={data.offset} sum={data.executions.total} />
</div>
{:else}
<EmptySearch>
@@ -1,18 +1,20 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends }) => {
export const load: PageLoad = async ({ params, depends, url, route }) => {
depends(Dependencies.EXECUTIONS);
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
executions: await sdk.forProject.functions.listExecutions(params.function, [
Query.limit(PAGE_LIMIT),
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
])
@@ -1,15 +1,20 @@
import type { Models } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
export const load: PageLoad = async ({ params }) => {
const response = await sdk.forProject.functions.getFunctionUsage(
params.function,
params.period ?? '30d'
);
try {
const response = await sdk.forProject.functions.getFunctionUsage(
params.function,
params.period ?? '30d'
);
return {
count: response.executionsTotal as unknown as Models.Metric[],
errors: response.executionsFailure as unknown as Models.Metric[]
};
return {
count: response.executionsTotal as unknown as Models.Metric[],
errors: response.buildsFailure as unknown as Models.Metric[]
};
} catch (e) {
throw error(e.code, e.message);
}
};
@@ -1,6 +1,7 @@
<script lang="ts">
import { Alert, Code } from '$lib/components';
import { WizardStep } from '$lib/layout';
import { Mode, MODE } from '$lib/system';
import { sdk } from '$lib/stores/sdk';
const { endpoint, project } = sdk.forProject.client.config;
@@ -10,6 +11,8 @@ let client = Client()
.setEndpoint("${endpoint}")
.setProject("${project}")
.setSelfSigned(status: true) // For self signed certificates, only use for development`;
let showAlert = true;
</script>
<WizardStep>
@@ -25,13 +28,18 @@ let client = Client()
Before sending any API calls to your new Appwrite project, make sure your device or emulator
has network access to your Appwrite project's hostname or IP address.
</p>
<div class="common-section">
<Alert type="info">
<svelte:fragment slot="title">For self-hosted solutions</svelte:fragment>
When connecting to a locally hosted Appwrite project from an emulator or a mobile device,
you should use the private IP of the device running your Appwrite project as the hostname
of the endpoint instead of localhost. You can also use a service like ngrok to proxy the
Appwrite server.
</Alert>
</div>
{#if showAlert}
<div class="common-section">
<Alert
type="info"
dismissible={MODE === Mode.CLOUD}
on:dismiss={() => (showAlert = false)}>
<svelte:fragment slot="title">For self-hosted solutions</svelte:fragment>
When connecting to a locally hosted Appwrite project from an emulator or a mobile device,
you should use the private IP of the device running your Appwrite project as the hostname
of the endpoint instead of localhost. You can also use a service like ngrok to proxy
the Appwrite server.
</Alert>
</div>
{/if}
</WizardStep>
@@ -1,6 +1,7 @@
<script lang="ts">
import { Alert, Code } from '$lib/components';
import { WizardStep } from '$lib/layout';
import { Mode, MODE } from '$lib/system';
import { sdk } from '$lib/stores/sdk';
const { endpoint, project } = sdk.forProject.client.config;
@@ -11,6 +12,8 @@ client
.setEndpoint('${endpoint}')
.setProject('${project}')
.setSelfSigned(status: true); // For self signed certificates, only use for development`;
let showAlert = true;
</script>
<WizardStep>
@@ -26,13 +29,18 @@ client
Before sending any API calls to your new Appwrite project, make sure your device or emulator
has network access to your Appwrite project's hostname or IP address.
</p>
<div class="common-section">
<Alert type="info">
<svelte:fragment slot="title">For self-hosted solutions</svelte:fragment>
When connecting to a locally hosted Appwrite project from an emulator or a mobile device,
you should use the private IP of the device running your Appwrite project as the hostname
of the endpoint instead of localhost. You can also use a service like ngrok to proxy the
Appwrite server.
</Alert>
</div>
{#if showAlert}
<div class="common-section">
<Alert
type="info"
dismissible={MODE === Mode.CLOUD}
on:dismiss={() => (showAlert = false)}>
<svelte:fragment slot="title">For self-hosted solutions</svelte:fragment>
When connecting to a locally hosted Appwrite project from an emulator or a mobile device,
you should use the private IP of the device running your Appwrite project as the hostname
of the endpoint instead of localhost. You can also use a service like ngrok to proxy
the Appwrite server.
</Alert>
</div>
{/if}
</WizardStep>
@@ -20,8 +20,8 @@
import { Dependencies } from '$lib/constants';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
import Create from '../create.svelte';
import Delete from '../delete.svelte';
import Create from './create.svelte';
import Delete from './delete.svelte';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
export let data: PageData;
@@ -2,17 +2,25 @@
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { Button } from '$lib/elements/forms';
import { Empty, Pagination, Copy, GridItem1, CardContainer, Heading } from '$lib/components';
import {
Empty,
Pagination,
Copy,
GridItem1,
CardContainer,
Heading,
Limit
} from '$lib/components';
import { Pill } from '$lib/elements';
import Create from '../create.svelte';
import Create from './create.svelte';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import { tooltip } from '$lib/actions/tooltip';
import type { Models } from '@aw-labs/appwrite-console';
import type { PageData } from './$types';
import { CARD_LIMIT } from '$lib/constants';
export let data: PageData;
let showCreate = false;
const project = $page.params.project;
@@ -83,12 +91,8 @@
</CardContainer>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.buckets.total}</p>
<Pagination
limit={CARD_LIMIT}
path={`/console/project-${$page.params.project}/storage`}
offset={data.offset}
sum={data.buckets.total} />
<Limit limit={data.limit} sum={data.buckets.total} name="Buckets" />
<Pagination limit={data.limit} offset={data.offset} sum={data.buckets.total} />
</div>
{:else}
<Empty
@@ -1,17 +1,19 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { CARD_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const page = Number(params.page);
const offset = pageToOffset(page, CARD_LIMIT);
export const load: PageLoad = async ({ url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
buckets: await sdk.forProject.storage.listBuckets([
Query.limit(CARD_LIMIT),
Query.limit(limit),
Query.offset(offset),
Query.orderDesc('$createdAt')
])
@@ -11,10 +11,11 @@
DropList,
DropListItem,
DropListLink,
SearchQuery
SearchQuery,
Limit
} from '$lib/components';
import Create from '../create.svelte';
import Delete from '../deleteFile.svelte';
import Create from './create.svelte';
import Delete from './deleteFile.svelte';
import {
Table,
TableHeader,
@@ -34,7 +35,7 @@
import { addNotification } from '$lib/stores/notifications';
import type { PageData } from './$types';
import { invalidate } from '$app/navigation';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
export let data: PageData;
@@ -184,12 +185,8 @@
</TableBody>
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {data.files.total}</p>
<Pagination
limit={PAGE_LIMIT}
path={`/console/project-${$page.params.project}/storage/bucket-${$page.params.bucket}`}
offset={data.offset}
sum={data.files.total} />
<Limit limit={data.limit} sum={data.files.total} name="Files" />
<Pagination limit={data.limit} offset={data.offset} sum={data.files.total} />
</div>
{:else if data.search}
<EmptySearch>
@@ -0,0 +1,24 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getSearch, pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends, url, route }) => {
depends(Dependencies.FILES);
const page = getPage(url);
const search = getSearch(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
return {
offset,
limit,
search,
files: await sdk.forProject.storage.listFiles(
params.bucket,
[Query.limit(limit), Query.offset(offset), Query.orderDesc('$createdAt')],
search
)
};
};
@@ -1,22 +0,0 @@
import { Query } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import { pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends, url }) => {
depends(Dependencies.FILES);
const page = Number(params.page);
const offset = pageToOffset(page, PAGE_LIMIT);
const search = url.search.slice(1) ?? undefined;
return {
offset,
search,
files: await sdk.forProject.storage.listFiles(
params.bucket,
[Query.limit(PAGE_LIMIT), Query.offset(offset), Query.orderDesc('$createdAt')],
search
)
};
};
@@ -1,15 +1,20 @@
import type { Models } from '@aw-labs/appwrite-console';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
export const load: PageLoad = async ({ params }) => {
const response = await sdk.forProject.storage.getUsage(params.period ?? '30d');
try {
const response = await sdk.forProject.storage.getUsage(params.period ?? '30d');
return {
count: response.bucketsCount as unknown as Models.Metric[],
created: response.bucketsCreate as unknown as Models.Metric[],
read: response.bucketsRead as unknown as Models.Metric[],
updated: response.bucketsUpdate as unknown as Models.Metric[],
deleted: response.bucketsDelete as unknown as Models.Metric[]
};
return {
count: response.bucketsCount as unknown as Models.Metric[],
created: response.bucketsCreate as unknown as Models.Metric[],
read: response.bucketsRead as unknown as Models.Metric[],
updated: response.bucketsUpdate as unknown as Models.Metric[],
deleted: response.bucketsDelete as unknown as Models.Metric[]
};
} catch (e) {
throw error(e.code, e.message);
}
};