mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: collection grid view, caching
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { DropList } from '.';
|
||||
|
||||
export let view = 'grid';
|
||||
import { preferredView } from '$lib/stores/layout';
|
||||
|
||||
let showSelectColumns = false;
|
||||
</script>
|
||||
@@ -19,12 +18,18 @@
|
||||
|
||||
<ul class="buttons-list">
|
||||
<li class="buttons-list-item">
|
||||
<Button text disabled={view === 'list'} on:click={() => (view = 'list')}>
|
||||
<Button
|
||||
text
|
||||
disabled={$preferredView === 'list'}
|
||||
on:click={() => ($preferredView = 'list')}>
|
||||
<span class="icon-view-list" />
|
||||
</Button>
|
||||
</li>
|
||||
<li class="buttons-list-item">
|
||||
<Button text disabled={view === 'grid'} on:click={() => (view = 'grid')}>
|
||||
<Button
|
||||
text
|
||||
disabled={$preferredView === 'grid'}
|
||||
on:click={() => ($preferredView = 'grid')}>
|
||||
<span class="icon-view-grid" />
|
||||
</Button>
|
||||
</li>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { writable, readable } from 'svelte/store';
|
||||
import type { SvelteComponent } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export type Tab = {
|
||||
href: string;
|
||||
@@ -11,6 +12,8 @@ export type Breadcrumb = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type View = 'list' | 'grid';
|
||||
|
||||
export type updateLayoutArguments = {
|
||||
header?: typeof SvelteComponent;
|
||||
breadcrumb?: typeof SvelteComponent;
|
||||
@@ -26,3 +29,11 @@ export function updateLayout(args: updateLayoutArguments) {
|
||||
|
||||
export const pageLimit = readable(12); // default page limit
|
||||
export const cardLimit = readable(6); // default card limit
|
||||
|
||||
export const preferredView = writable<View>(
|
||||
browser ? (sessionStorage.getItem('prefferedView') as View) : 'grid'
|
||||
);
|
||||
|
||||
if (browser) {
|
||||
preferredView.subscribe((u) => sessionStorage.setItem('prefferedView', u ?? 'grid'));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { goto, invalidate } from '$app/navigation';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Empty, Heading, ViewSelector } from '$lib/components';
|
||||
import { Container } from '$lib/layout';
|
||||
@@ -10,17 +10,22 @@
|
||||
import type { PageData } from './$types';
|
||||
import GridView from './gridView.svelte';
|
||||
import TableView from './tableView.svelte';
|
||||
import { preferredView } from '$lib/stores/layout';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
let showCreate = false;
|
||||
let view = 'grid';
|
||||
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}`);
|
||||
}
|
||||
|
||||
$: preferredView.subscribe(() => {
|
||||
invalidate(Dependencies.COLLECTION);
|
||||
});
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
@@ -28,7 +33,7 @@
|
||||
<Heading tag="h2" size="5">Databases</Heading>
|
||||
|
||||
<div class="u-flex u-gap-16">
|
||||
<ViewSelector bind:view>test</ViewSelector>
|
||||
<ViewSelector>test</ViewSelector>
|
||||
|
||||
<Button on:click={() => (showCreate = true)} event="create_database">
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
@@ -38,7 +43,7 @@
|
||||
</div>
|
||||
|
||||
{#if data.databases.total}
|
||||
{#if view === 'list'}
|
||||
{#if $preferredView === 'list'}
|
||||
<TableView {data} />
|
||||
{:else}
|
||||
<GridView {data} bind:showCreate />
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { Query } from '@aw-labs/appwrite-console';
|
||||
import { sdkForProject } from '$lib/stores/sdk';
|
||||
import { pageToOffset } from '$lib/helpers/load';
|
||||
import { CARD_LIMIT } from '$lib/constants';
|
||||
import { CARD_LIMIT, PAGE_LIMIT } from '$lib/constants';
|
||||
import type { PageLoad } from './$types';
|
||||
import { preferredView } from '$lib/stores/layout';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
export const load: PageLoad = async ({ params, parent }) => {
|
||||
await parent();
|
||||
const page = Number(params.page);
|
||||
const offset = pageToOffset(page, CARD_LIMIT);
|
||||
const limit = get(preferredView) === 'list' ? PAGE_LIMIT : CARD_LIMIT;
|
||||
console.log(get(preferredView));
|
||||
|
||||
const offset = pageToOffset(page, limit);
|
||||
|
||||
return {
|
||||
offset,
|
||||
databases: await sdkForProject.databases.list([
|
||||
Query.limit(CARD_LIMIT),
|
||||
Query.limit(limit),
|
||||
Query.offset(offset),
|
||||
Query.orderDesc('$createdAt')
|
||||
])
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<svelte:fragment slot="title">{database.name}</svelte:fragment>
|
||||
|
||||
<Copy value={database.$id}>
|
||||
<Pill button><i class="icon-duplicate" />Database ID</Pill>
|
||||
<Pill button><span class="icon-duplicate" />Database ID</Pill>
|
||||
</Copy>
|
||||
</GridItem1>
|
||||
{/each}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { Copy, Pagination } from '$lib/components';
|
||||
import { PAGE_LIMIT } from '$lib/constants';
|
||||
@@ -9,25 +10,27 @@
|
||||
TableCellHead,
|
||||
TableCellText,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableRowLink,
|
||||
TableScroll
|
||||
} from '$lib/elements/table';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
const project = $page.params.project;
|
||||
</script>
|
||||
|
||||
<TableScroll>
|
||||
<TableHeader>
|
||||
<TableCellHead width={50}>Collection ID</TableCellHead>
|
||||
<TableCellHead width={45}>Database ID</TableCellHead>
|
||||
<TableCellHead width={100}>Name</TableCellHead>
|
||||
<TableCellHead width={100}>Updated At</TableCellHead>
|
||||
<TableCellHead width={100}>Created At</TableCellHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each data.databases.databases as database}
|
||||
<TableRow>
|
||||
<TableRowLink
|
||||
href={`${base}/console/project-${project}/databases/database-${database.$id}`}>
|
||||
<TableCell title="Deployment ID">
|
||||
<Copy value={database.$id}>
|
||||
<Pill button trim>
|
||||
@@ -45,7 +48,7 @@
|
||||
<TableCellText title="Created">
|
||||
{toLocaleDateTime(database.$createdAt)}
|
||||
</TableCellText>
|
||||
</TableRow>
|
||||
</TableRowLink>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</TableScroll>
|
||||
|
||||
+24
-44
@@ -1,24 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { goto, invalidate } from '$app/navigation';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Empty, Copy, GridItem1, CardContainer, Heading, Pagination } from '$lib/components';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { Empty, Heading, ViewSelector } from '$lib/components';
|
||||
import { Container } from '$lib/layout';
|
||||
import { base } from '$app/paths';
|
||||
import { cardLimit } from '$lib/stores/layout';
|
||||
import { createPersistentPagination } from '$lib/stores/pagination';
|
||||
import type { PageData } from './$types';
|
||||
import type { Models } from '@aw-labs/appwrite-console';
|
||||
import Create from '../create.svelte';
|
||||
import { CARD_LIMIT } from '$lib/constants';
|
||||
import GridView from './gridView.svelte';
|
||||
import TableView from './tableView.svelte';
|
||||
import { preferredView } from '$lib/stores/layout';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
|
||||
export let data: PageData;
|
||||
let showCreate = false;
|
||||
|
||||
const project = $page.params.project;
|
||||
const databaseId = $page.params.database;
|
||||
const offset = createPersistentPagination($cardLimit);
|
||||
|
||||
async function handleCreate(event: CustomEvent<Models.Collection>) {
|
||||
showCreate = false;
|
||||
@@ -26,51 +25,32 @@
|
||||
`${base}/console/project-${project}/databases/database-${databaseId}/collection-${event.detail.$id}`
|
||||
);
|
||||
}
|
||||
|
||||
$: preferredView.subscribe(() => {
|
||||
invalidate(Dependencies.DOCUMENT);
|
||||
});
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="u-flex u-gap-12 common-section u-main-space-between">
|
||||
<div class="u-flex common-section u-main-space-between">
|
||||
<Heading tag="h2" size="5">Collections</Heading>
|
||||
|
||||
<Button on:click={() => (showCreate = true)} event="create_collection">
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Create collection</span>
|
||||
</Button>
|
||||
<div class="u-flex u-gap-16">
|
||||
<ViewSelector>test</ViewSelector>
|
||||
|
||||
<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}
|
||||
<CardContainer
|
||||
event="collection"
|
||||
total={data.collections.total}
|
||||
offset={$offset}
|
||||
on:click={() => (showCreate = true)}>
|
||||
{#each data.collections.collections as collection}
|
||||
<GridItem1
|
||||
href={`${base}/console/project-${project}/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}
|
||||
<svelte:fragment slot="empty">
|
||||
<p>Create a new collection</p>
|
||||
</svelte:fragment>
|
||||
</CardContainer>
|
||||
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {data.collections.total}</p>
|
||||
<Pagination
|
||||
limit={CARD_LIMIT}
|
||||
path={`/console/project-${$page.params.project}/databases/database-${$page.params.database}`}
|
||||
offset={data.offset}
|
||||
sum={data.collections.total} />
|
||||
</div>
|
||||
{#if $preferredView === 'list'}
|
||||
<TableView {data} />
|
||||
{:else}
|
||||
<GridView {data} bind:showCreate />
|
||||
{/if}
|
||||
{:else}
|
||||
<Empty
|
||||
single
|
||||
|
||||
+7
-3
@@ -1,18 +1,22 @@
|
||||
import { Query } from '@aw-labs/appwrite-console';
|
||||
import { sdkForProject } from '$lib/stores/sdk';
|
||||
import { pageToOffset } from '$lib/helpers/load';
|
||||
import { CARD_LIMIT } from '$lib/constants';
|
||||
import { CARD_LIMIT, PAGE_LIMIT } from '$lib/constants';
|
||||
import type { PageLoad } from './$types';
|
||||
import { preferredView } from '$lib/stores/layout';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
const limit = get(preferredView) === 'list' ? PAGE_LIMIT : CARD_LIMIT;
|
||||
|
||||
export const load: PageLoad = async ({ params, parent }) => {
|
||||
await parent();
|
||||
const page = Number(params.page);
|
||||
const offset = pageToOffset(page, CARD_LIMIT);
|
||||
const offset = pageToOffset(page, limit);
|
||||
|
||||
return {
|
||||
offset,
|
||||
collections: await sdkForProject.databases.listCollections(params.database, [
|
||||
Query.limit(CARD_LIMIT),
|
||||
Query.limit(limit),
|
||||
Query.offset(offset),
|
||||
Query.orderDesc('$createdAt')
|
||||
])
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { CardContainer, Copy, GridItem1, Pagination } from '$lib/components';
|
||||
import { CARD_LIMIT } from '$lib/constants';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { createPersistentPagination } from '$lib/stores/pagination';
|
||||
import type { PageData } from './$types';
|
||||
import { cardLimit } from '$lib/stores/layout';
|
||||
|
||||
export let data: PageData;
|
||||
export let showCreate = false;
|
||||
|
||||
const databaseId = $page.params.database;
|
||||
const project = $page.params.project;
|
||||
const offset = createPersistentPagination($cardLimit);
|
||||
</script>
|
||||
|
||||
<CardContainer
|
||||
event="collection"
|
||||
total={data.collections.total}
|
||||
offset={$offset}
|
||||
on:click={() => (showCreate = true)}>
|
||||
{#each data.collections.collections as collection}
|
||||
<GridItem1
|
||||
href={`${base}/console/project-${project}/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><span class="icon-duplicate" />Collection ID</Pill>
|
||||
</Copy>
|
||||
</GridItem1>
|
||||
{/each}
|
||||
<svelte:fragment slot="empty">
|
||||
<p>Create a new collection</p>
|
||||
</svelte:fragment>
|
||||
</CardContainer>
|
||||
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {data.collections.total}</p>
|
||||
<Pagination
|
||||
limit={CARD_LIMIT}
|
||||
path={`/console/project-${$page.params.project}/databases/database-${$page.params.database}`}
|
||||
offset={data.offset}
|
||||
sum={data.collections.total} />
|
||||
</div>
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { Copy, Pagination } from '$lib/components';
|
||||
import { PAGE_LIMIT } from '$lib/constants';
|
||||
import { Pill } from '$lib/elements';
|
||||
import {
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableCellHead,
|
||||
TableCellText,
|
||||
TableHeader,
|
||||
TableRowLink,
|
||||
TableScroll
|
||||
} from '$lib/elements/table';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
const project = $page.params.project;
|
||||
const databaseId = $page.params.database;
|
||||
</script>
|
||||
|
||||
<TableScroll>
|
||||
<TableHeader>
|
||||
<TableCellHead width={45}>Collection ID</TableCellHead>
|
||||
<TableCellHead width={100}>Name</TableCellHead>
|
||||
<TableCellHead width={100}>Updated At</TableCellHead>
|
||||
<TableCellHead width={100}>Created At</TableCellHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each data.collections.collections as collection}
|
||||
<TableRowLink
|
||||
href={`${base}/console/project-${project}/databases/database-${databaseId}/collection-${collection.$id}`}>
|
||||
<TableCell title="Deployment ID">
|
||||
<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>
|
||||
<TableCellText title="Name">
|
||||
{collection.name}
|
||||
</TableCellText>
|
||||
<TableCellText title="Updated">
|
||||
{toLocaleDateTime(collection.$updatedAt)}
|
||||
</TableCellText>
|
||||
<TableCellText title="Created">
|
||||
{toLocaleDateTime(collection.$createdAt)}
|
||||
</TableCellText>
|
||||
</TableRowLink>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</TableScroll>
|
||||
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {data.collections.total}</p>
|
||||
<Pagination
|
||||
offset={data.offset}
|
||||
limit={PAGE_LIMIT}
|
||||
sum={data.collections.total}
|
||||
path={`/console/project-${$page.params.project}/databases`} />
|
||||
</div>
|
||||
Reference in New Issue
Block a user