Merge branch 'main' of github.com:appwrite/appwrite-console-poc into functions

This commit is contained in:
Arman
2022-10-19 11:00:11 +02:00
60 changed files with 727 additions and 209 deletions
+1 -1
View File
@@ -14,7 +14,7 @@
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. .",
"test": "vitest run",
"test:ui": "vitest --ui",
"test:watch": "vitetest watch",
"test:watch": "vitest watch",
"e2e": "playwright test tests/e2e"
},
"dependencies": {
+2 -1
View File
@@ -1,4 +1,5 @@
<script>
import { Heading } from '$lib/components';
export let href;
</script>
@@ -6,7 +7,7 @@
<div class="grid-item-1">
<div class="grid-item-1-start-start">
<div class="eyebrow-heading-3"><slot name="eyebrow" /></div>
<h2 class="heading-level-6"><slot name="title" /></h2>
<Heading tag="h2" size="6"><slot name="title" /></Heading>
</div>
<div class="grid-item-1-start-end">
<slot name="status" />
+8
View File
@@ -0,0 +1,8 @@
<script lang="ts">
export let tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export let size: '1' | '2' | '3' | '4' | '5' | '6' | '7';
</script>
<svelte:element this={tag} class={`heading-level-${size}`}>
<slot />
</svelte:element>
+1
View File
@@ -39,3 +39,4 @@ export { default as Tab } from './tab.svelte';
export { default as EventModal } from './eventModal.svelte';
export { default as Status } from './status.svelte';
export { default as Logs } from './logs.svelte';
export { default as Heading } from './heading.svelte';
+3 -3
View File
@@ -2,7 +2,7 @@
import { browser } from '$app/environment';
import { createEventDispatcher } from 'svelte';
import { fade, fly, type FadeParams, type FlyParams } from 'svelte/transition';
import { Alert } from '$lib/components';
import { Alert, Heading } from '$lib/components';
import { clickOnEnter } from '$lib/helpers/a11y';
export let show = false;
@@ -76,9 +76,9 @@
<span class="icon-exclamation" aria-hidden="true" />
</div>
{/if}
<h4 class="heading-level-5">
<Heading tag="h4" size="5">
<slot name="header" />
</h4>
</Heading>
{#if closable}
<button
type="button"
+1
View File
@@ -2,6 +2,7 @@ export { default as Form } from './form.svelte';
export { default as FormItem } from './formItem.svelte';
export { default as FormList } from './formList.svelte';
export { default as Button } from './button.svelte';
export { default as InputDomain } from './inputDomain.svelte';
export { default as InputEmail } from './inputEmail.svelte';
export { default as InputPassword } from './inputPassword.svelte';
export { default as InputText } from './inputText.svelte';
+69
View File
@@ -0,0 +1,69 @@
<script lang="ts">
import { onMount } from 'svelte';
import { FormItem, Helper } from '.';
export let label: string;
export let showLabel = true;
export let id: string;
export let value = '';
export let placeholder = '';
export let required = false;
export let disabled = false;
export let readonly = false;
export let autofocus = false;
export let autocomplete = false;
export let maxlength: number = null;
// https://www.geeksforgeeks.org/how-to-validate-a-domain-name-using-regular-expression/
const pattern = String.raw`^(?!-)[A-Za-z0-9-]+([\-\.]{1}[a-z0-9]+)*\.[A-Za-z]{2,6}$`;
let element: HTMLInputElement;
let error: string;
onMount(() => {
if (element && autofocus) {
element.focus();
}
});
const handleInvalid = (event: Event) => {
event.preventDefault();
if (element.validity.patternMismatch) {
error = 'Must be a valid domain';
return;
}
if (element.validity.valueMissing) {
error = 'This field is required';
return;
}
error = element.validationMessage;
};
$: if (value) {
error = null;
}
</script>
<FormItem>
<label class:u-hide={!showLabel} class="label" for={id}>{label}</label>
<div class="input-text-wrapper">
<input
{id}
{placeholder}
{disabled}
{required}
{maxlength}
{pattern}
{readonly}
type="text"
autocomplete={autocomplete ? 'on' : 'off'}
bind:value
bind:this={element}
on:invalid={handleInvalid} />
</div>
{#if error}
<Helper type="warning">{error}</Helper>
{/if}
</FormItem>
+6 -5
View File
@@ -9,7 +9,8 @@
DropListLink,
AvatarGroup,
Tabs,
Tab
Tab,
Heading
} from '$lib/components';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
@@ -107,13 +108,13 @@
<button
class="button is-text u-padding-inline-0"
on:click={() => (showDropdown = !showDropdown)}>
<h1 class="heading-level-4">
<Heading tag="h1" size="4">
<span class="text"> {$organization.name}</span>
<span
class={`icon-cheveron-${showDropdown ? 'up' : 'down'}`}
aria-hidden="true" />
</h1>
</Heading>
</button>
<svelte:fragment slot="list">
{#each $titleDropdown as org}
@@ -148,9 +149,9 @@
</div>
</div>
{:else}
<h1 class="heading-level-4">
<Heading tag="h1" size="4">
<span class="text">{$title ? $title : '-'}</span>
</h1>
</Heading>
{/if}
{#if $page.url.pathname.includes('/console/account')}
<div class="u-margin-inline-start-auto">
+7 -7
View File
@@ -5,7 +5,7 @@
<script lang="ts">
import { Container } from '$lib/layout';
import { BarChart, LineChart } from '$lib/charts';
import { Card, DropTabs, DropTabsItem, Tiles } from '$lib/components';
import { Card, DropTabs, DropTabsItem, Heading, Tiles } from '$lib/components';
import { Colors } from '$lib/charts/config';
import type { Models } from '@aw-labs/appwrite-console';
@@ -39,7 +39,7 @@
<Container>
<div class="u-flex u-main-space-between common-section">
<h2 class="heading-level-5">{title}</h2>
<Heading tag="h2" size="5">{title}</Heading>
<DropTabs>
<DropTabsItem on:click={() => (range = '24h')} disabled={range === '24h'}>
24h
@@ -54,7 +54,7 @@
</div>
<Card>
{#if count}
<h6 class="heading-level-6">{last(count).value}</h6>
<Heading tag="h6" size="6">{last(count).value}</Heading>
<p>{countMetadata.title}</p>
<div class="u-margin-block-start-16" />
<BarChart
@@ -69,7 +69,7 @@
<Tiles>
<Card isTile>
{#if created}
<h6 class="heading-level-6">{total(created)}</h6>
<Heading tag="h6" size="6">{total(created)}</Heading>
<p>{createdMetadata.title}</p>
<div class="u-margin-block-start-16" />
<LineChart
@@ -84,7 +84,7 @@
</Card>
<Card isTile>
{#if read}
<h6 class="heading-level-6">{total(read)}</h6>
<Heading tag="h6" size="6">{total(read)}</Heading>
<p>{readMetadata.title}</p>
<div class="u-margin-block-start-16" />
<LineChart
@@ -99,7 +99,7 @@
</Card>
<Card isTile>
{#if updated}
<h6 class="heading-level-6">{total(updated)}</h6>
<Heading tag="h6" size="6">{total(updated)}</Heading>
<p>{updatedMetadata.title}</p>
<div class="u-margin-block-start-16" />
<LineChart
@@ -114,7 +114,7 @@
</Card>
<Card isTile>
{#if deleted}
<h6 class="heading-level-6">{total(deleted)}</h6>
<Heading tag="h6" size="6">{total(deleted)}</Heading>
<p>{deletedMetadata.title}</p>
<div class="u-margin-block-start-16" />
<LineChart
+3 -2
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import { Heading } from '$lib/components';
import { wizard } from '$lib/stores/wizard';
/**
@@ -12,9 +13,9 @@
</script>
<header class="form-header">
<h1 class="heading-level-6">
<Heading tag="h1" size="6">
<slot name="title" />
</h1>
</Heading>
{#if $$slots.subtitle}
<p>
<slot name="subtitle" />
+5 -5
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { Button, Form, FormList, InputText, InputPassword } from '$lib/elements/forms';
import { CardGrid, Box, Avatar } from '$lib/components';
import { CardGrid, Box, Avatar, Heading } from '$lib/components';
import { Container } from '$lib/layout';
import { onMount } from 'svelte';
import { user } from '$lib/stores/user';
@@ -78,7 +78,7 @@
<Container>
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -99,7 +99,7 @@
</Form>
<Form on:submit={updateEmail}>
<CardGrid>
<h6 class="heading-level-7">Update Email</h6>
<Heading tag="h6" size="7">Update Email</Heading>
<svelte:fragment slot="aside">
<FormList>
@@ -129,7 +129,7 @@
</Form>
<Form on:submit={updatePassword}>
<CardGrid>
<h6 class="heading-level-7">Update Password</h6>
<Heading tag="h6" size="7">Update Password</Heading>
<p class="text">
Forgot your password? <a class="link" href={`${base}/recover`}
>Recover your password</a>
@@ -161,7 +161,7 @@
</Form>
<CardGrid>
<div>
<h6 class="heading-level-7">Delete Account</h6>
<Heading tag="h6" size="7">Delete Account</Heading>
</div>
<p>
Your account will be permanently deleted and access will be lost to any of your teams
@@ -1,6 +1,13 @@
<script lang="ts">
import { base } from '$app/paths';
import { GridItem1, Empty, Pagination, AvatarGroup, CardContainer } from '$lib/components';
import {
GridItem1,
Empty,
Pagination,
AvatarGroup,
CardContainer,
Heading
} from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import CreateOrganization from '../../_createOrganization.svelte';
@@ -34,7 +41,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Organizations</h2>
<Heading tag="h2" size="5">Organizations</Heading>
<Button
on:click={() => {
@@ -1,5 +1,5 @@
<script lang="ts">
import { Empty, Pagination } from '$lib/components';
import { Empty, Heading, Pagination } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Pill } from '$lib/elements';
import {
@@ -41,7 +41,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Sessions</h2>
<Heading tag="h2" size="5">Sessions</Heading>
<Button secondary on:click={logoutAll}>
<span class="text">Logout all sessions</span>
@@ -2,7 +2,7 @@
import { afterNavigate, goto } from '$app/navigation';
import { base } from '$app/paths';
import { Pill } from '$lib/elements';
import { GridItem1, Empty, Pagination } from '$lib/components';
import { GridItem1, Heading, Empty, Pagination } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { Query, type Models } from '@aw-labs/appwrite-console';
@@ -68,8 +68,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Projects</h2>
<Heading tag="h2" size="5">Projects</Heading>
<Button
on:click={() => {
showCreate = true;
@@ -8,7 +8,7 @@
TableCellText,
TableRow
} from '$lib/elements/table';
import { Avatar, Pagination } from '$lib/components';
import { Avatar, Heading, Pagination } from '$lib/components';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
@@ -63,7 +63,7 @@
<Container>
{#if $memberList?.total}
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Members</h2>
<Heading tag="h2" size="5">Members</Heading>
<Button on:click={() => newMemberModal.set(true)}>
<span class="icon-plus" aria-hidden="true" />
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid, Box, AvatarGroup } from '$lib/components';
import { CardGrid, Box, AvatarGroup, Heading } from '$lib/components';
import { InputText, Form, Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { addNotification } from '$lib/stores/notifications';
@@ -55,7 +55,7 @@
{#if $organization}
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -76,7 +76,7 @@
<CardGrid>
<div>
<h6 class="heading-level-7">Delete Organization</h6>
<Heading tag="h6" size="7">Delete Organization</Heading>
</div>
<p>
The organization will be permanently deleted, including all projects and data
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Pill } from '$lib/elements/';
import { Button, InputNumber, InputSelect } from '$lib/elements/forms';
import { Container } from '$lib/layout';
@@ -71,7 +71,7 @@
<Container>
<CardGrid>
<h2 class="heading-level-6">Users Limit</h2>
<Heading tag="h2" size="6">Users Limit</Heading>
<p>
Limit new users from signing up for your project, regardless of authentication method.
You can still create users and team memberships from your Appwrite console. <b>
@@ -138,7 +138,7 @@
</CardGrid>
<CardGrid>
<h2 class="heading-level-6">Session Length (Coming Soon)</h2>
<Heading tag="h2" size="6">Session Length (Coming Soon)</Heading>
<p>
If you reduce the limit, users who are currently logged in will be logged out of the
application.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Pill } from '$lib/elements';
import { InputSwitch } from '$lib/elements/forms';
import { Container } from '$lib/layout';
@@ -47,7 +47,7 @@
{#if $authMethods && $OAuthProviders}
<Container>
<CardGrid>
<h2 class="heading-level-7">Authentication Methods</h2>
<Heading tag="h2" size="7">Authentication Methods</Heading>
<p>Enable the authentication methods you wish to use.</p>
<svelte:fragment slot="aside">
<form class="form">
@@ -1,6 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import { Avatar, CardGrid, Box } from '$lib/components';
import { Avatar, CardGrid, Box, Heading } from '$lib/components';
import { Container } from '$lib/layout';
import { Button, InputText, Form } from '$lib/elements/forms';
import { sdkForProject } from '$lib/stores/sdk';
@@ -46,7 +46,7 @@
<div class="grid-1-2-col-1 u-flex u-cross-center u-gap-16">
<Avatar size={48} name={$team.name} src={getAvatar($team.name)} />
<div>
<h6 class="heading-level-7">{$team.name}</h6>
<Heading tag="h6" size="7">{$team.name}</Heading>
</div>
</div>
<svelte:fragment slot="aside">
@@ -59,7 +59,7 @@
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -84,7 +84,7 @@
<CardGrid>
<div>
<h6 class="heading-level-7">Danger Zone</h6>
<Heading tag="h6" size="7">Danger Zone</Heading>
</div>
<p>
@@ -1,7 +1,7 @@
<script lang="ts">
import { page } from '$app/stores';
import { toLocaleDateTime } from '$lib/helpers/date';
import { Avatar, CardGrid, Box, DropList, DropListItem } from '$lib/components';
import { Avatar, CardGrid, Box, DropList, DropListItem, Heading } from '$lib/components';
import { Pill } from '$lib/elements';
import {
Button,
@@ -196,7 +196,7 @@
{#if $user.email || $user.phone}
{#if $user.name}
<Avatar size={48} src={getAvatar($user.name)} name={$user.name} />
<h6 class="heading-level-7">{$user.name}</h6>
<Heading tag="h6" size="7">{$user.name}</Heading>
{:else}
<div class="avatar">
<span class="icon-minus-sm" aria-hidden="true" />
@@ -283,7 +283,7 @@
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -304,7 +304,7 @@
<Form on:submit={updateEmail}>
<CardGrid>
<h6 class="heading-level-7">Update Email</h6>
<Heading tag="h6" size="7">Update Email</Heading>
<svelte:fragment slot="aside">
<ul>
<InputEmail
@@ -324,7 +324,7 @@
<Form on:submit={updatePhone}>
<CardGrid>
<h6 class="heading-level-7">Update Phone</h6>
<Heading tag="h6" size="7">Update Phone</Heading>
<svelte:fragment slot="aside">
<ul>
<InputPhone
@@ -345,7 +345,7 @@
<Form on:submit={updatePassword}>
<CardGrid>
<div>
<h6 class="heading-level-7">Update Password</h6>
<Heading tag="h6" size="7">Update Password</Heading>
</div>
<p>
@@ -372,7 +372,7 @@
<Form on:submit={updatePrefs}>
<CardGrid>
<h6 class="heading-level-7">User Preferences</h6>
<Heading tag="h6" size="7">User Preferences</Heading>
<p>
You can update your user preferences by storing information on the user's objects so
they can easily be shared across devices and sessions.
@@ -446,7 +446,7 @@
<CardGrid>
<div>
<h6 class="heading-level-7">Danger Zone</h6>
<Heading tag="h6" size="7">Danger Zone</Heading>
</div>
<p>
The user will be permanently deleted, including all data associated with this user. This
@@ -2,7 +2,7 @@
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { Button } from '$lib/elements/forms';
import { Empty, Pagination, Copy, GridItem1, CardContainer } from '$lib/components';
import { Empty, Pagination, Copy, GridItem1, CardContainer, Heading } from '$lib/components';
import { Pill } from '$lib/elements';
import { Query, type Models } from '@aw-labs/appwrite-console';
import Create from './_create.svelte';
@@ -31,7 +31,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Databases</h2>
<Heading tag="h2" size="5">Databases</Heading>
<Button on:click={() => (showCreate = true)}>
<span class="icon-plus" aria-hidden="true" /> <span class="text">Create database</span>
@@ -2,7 +2,7 @@
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { Button } from '$lib/elements/forms';
import { Empty, Pagination, Copy, GridItem1, CardContainer } from '$lib/components';
import { Empty, Pagination, Copy, GridItem1, CardContainer, Heading } from '$lib/components';
import { Pill } from '$lib/elements';
import { Query, type Models } from '@aw-labs/appwrite-console';
import Create from './_create.svelte';
@@ -34,7 +34,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Collections</h2>
<Heading tag="h2" size="5">Collections</Heading>
<Button on:click={() => (showCreate = true)}>
<span class="icon-plus" aria-hidden="true" />
@@ -8,7 +8,7 @@
TableCellHead,
TableCell
} from '$lib/elements/table';
import { Empty, Pagination, Copy } from '$lib/components';
import { Empty, Pagination, Copy, Heading } from '$lib/components';
import { Pill } from '$lib/elements';
import { collection, documentList } from './store';
import { Container } from '$lib/layout';
@@ -44,7 +44,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Documents</h2>
<Heading tag="h2" size="5">Documents</Heading>
<Button disabled={!$collection?.attributes?.length} on:click={openWizard}>
<span class="icon-plus" aria-hidden="true" />
@@ -9,7 +9,7 @@
TableCell
} from '$lib/elements/table';
import { Button } from '$lib/elements/forms';
import { DropList, DropListItem, Empty, Pagination } from '$lib/components';
import { DropList, DropListItem, Empty, Heading, Pagination } from '$lib/components';
import { collection } from '../store';
import type { Attributes } from '../store';
import { Container } from '$lib/layout';
@@ -33,7 +33,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Attributes</h2>
<Heading tag="h2" size="5">Attributes</Heading>
<Button on:click={() => (showCreate = true)}>
<span class="icon-plus" aria-hidden="true" />
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid, Box } from '$lib/components';
import { CardGrid, Box, Heading } from '$lib/components';
import { Container } from '$lib/layout';
import { Button } from '$lib/elements/forms';
import { sdkForProject } from '$lib/stores/sdk';
@@ -52,7 +52,7 @@
<Container>
{#if $doc}
<CardGrid>
<h2 class="heading-level-7">Document</h2>
<Heading tag="h2" size="7">Document</Heading>
<svelte:fragment slot="aside">
<div>
<p>Created: {toLocaleDateTime($doc.$createdAt)}</p>
@@ -63,7 +63,7 @@
<Document />
<CardGrid>
<h6 class="heading-level-7">Update Permissions</h6>
<Heading tag="h6" size="7">Update Permissions</Heading>
<p>
Assign read or write permissions at the <b> Collection Level</b> or
<b> Document Level</b>. If collection Level permissions are assigned, permissions
@@ -84,7 +84,7 @@
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">Delete document</h6>
<Heading tag="h6" size="7">Delete document</Heading>
<p>
The document will be permanently deleted, including all the data within it. This
action is irreversible.
@@ -1,6 +1,6 @@
<script lang="ts">
import { Button } from '$lib/elements/forms';
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { collection } from '../../store';
import { doc } from './store';
import { onMount } from 'svelte';
@@ -55,7 +55,7 @@
</script>
<CardGrid>
<h6 class="heading-level-7">Update Data</h6>
<Heading tag="h6" size="7">Update Data</Heading>
<p>Update document data based on the attributes created earlier.</p>
<svelte:fragment slot="aside">
<form class="form u-grid u-gap-16">
@@ -1,5 +1,5 @@
<script lang="ts">
import { Alert, CardGrid, Box } from '$lib/components';
import { Alert, CardGrid, Box, Heading } from '$lib/components';
import { Container } from '$lib/layout';
import { Button, InputText, InputSwitch, Helper } from '$lib/elements/forms';
import { Permissions } from '$lib/components/permissions';
@@ -117,7 +117,7 @@
<Container>
{#if $collection}
<CardGrid>
<h2 class="heading-level-7">{$collection.name}</h2>
<Heading tag="h2" size="7">{$collection.name}</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -140,7 +140,7 @@
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -163,7 +163,7 @@
</svelte:fragment>
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">Update Permissions</h6>
<Heading tag="h6" size="7">Update Permissions</Heading>
<p>
Assign read or write permissions at the <b>Collection Level</b> or
<b>Document Level</b>. If collection Level permissions are assigned, permissions
@@ -214,7 +214,7 @@
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">Delete collection</h6>
<Heading tag="h6" size="7">Delete collection</Heading>
<p>
The collection will be permanently deleted, including all the documents within it.
This action is irreversible.
@@ -1,6 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import { Card, Avatar, CardGrid, Box } from '$lib/components';
import { Card, Avatar, CardGrid, Box, Heading } from '$lib/components';
import { Container } from '$lib/layout';
import { Button, InputText, Helper } from '$lib/elements/forms';
import { sdkForProject } from '$lib/stores/sdk';
@@ -51,7 +51,7 @@
<div class="grid-1-2-col-1">
<div class="grid-1-2-col-1 u-flex u-cross-center u-gap-16">
<Avatar size={48} name={$database.name} src={getAvatar($database.name)} />
<h6 class="heading-level-7">{$database.name}</h6>
<Heading tag="h6" size="7">{$database.name}</Heading>
</div>
</div>
<div class="grid-1-2-col-2">
@@ -62,7 +62,7 @@
</Card>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -89,7 +89,7 @@
<CardGrid>
<div>
<h6 class="heading-level-7">Danger Zone</h6>
<Heading tag="h6" size="7">Danger Zone</Heading>
</div>
<p>
@@ -9,7 +9,7 @@
import { usage } from './store';
import { onMount } from 'svelte';
import { afterNavigate } from '$app/navigation';
import { DropList, DropListItem } from '$lib/components';
import { DropList, DropListItem, Heading } from '$lib/components';
import { BarChart, LineChart } from '$lib/charts';
import { humanFileSize } from '$lib/helpers/sizeConvertion';
@@ -284,7 +284,7 @@
{/if}
<section class="common-section u-margin-block-start-100">
<h2 class="heading-level-5">Integrations</h2>
<Heading tag="h2" size="5">Integrations</Heading>
<div class="tabs u-margin-block-start-24 u-sep-block-end">
<button
class="tabs-button-scroll is-start u-hide"
@@ -1,4 +1,5 @@
<script lang="ts">
import { Heading } from '$lib/components';
import { Button } from '$lib/elements/forms';
import {
Table,
@@ -16,7 +17,7 @@
</script>
<div class="common-section u-flex u-gap-12">
<h3 class="heading-level-7">API Keys</h3>
<Heading tag="h3" size="7">API Keys</Heading>
<span class="u-margin-inline-start-auto">
<Button on:click={() => (show = true)}>
<span class="icon-plus" aria-hidden="true" />
@@ -2,7 +2,7 @@
import { afterNavigate } from '$app/navigation';
import { base } from '$app/paths';
import { page } from '$app/stores';
import { CardGrid, Secret } from '$lib/components';
import { CardGrid, Heading, Secret } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import InputDateTime from '$lib/elements/forms/inputDateTime.svelte';
import { difference } from '$lib/helpers/array';
@@ -127,7 +127,7 @@
{@const accessedAt = $key.accessedAt ? toLocaleDateTime($key.accessedAt) : 'never'}
<CardGrid>
<div>
<h6 class="heading-level-7">{$key.name}</h6>
<Heading tag="h6" size="7">{$key.name}</Heading>
</div>
<svelte:fragment slot="aside">
<p>
@@ -138,7 +138,7 @@
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">API Key Secret</h6>
<Heading tag="h6" size="7">API Key Secret</Heading>
<svelte:fragment slot="aside">
<Secret bind:value={secret} />
</svelte:fragment>
@@ -146,7 +146,7 @@
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<p class="text">Choose any name that will help you distinguish between API keys.</p>
<svelte:fragment slot="aside">
<FormList>
@@ -166,7 +166,7 @@
</Form>
<Form on:submit={updateScopes}>
<CardGrid>
<h6 class="heading-level-7">Update Scopes</h6>
<Heading tag="h6" size="7">Update Scopes</Heading>
<p class="text">
You can choose which permission scope to grant your application. It is a best
practice to allow only the permissions you need to meet your project goals.
@@ -187,7 +187,7 @@
</Form>
<Form on:submit={updateExpire}>
<CardGrid>
<h6 class="heading-level-7">Update Expiration Date</h6>
<Heading tag="h6" size="7">Update Expiration Date</Heading>
<p class="text">Choose any name that will help you distinguish between API keys.</p>
<svelte:fragment slot="aside">
<FormList>
@@ -202,7 +202,7 @@
</Form>
<CardGrid>
<div>
<h6 class="heading-level-7">Delete API Key</h6>
<Heading tag="h6" size="7">Delete API Key</Heading>
</div>
<p>The API Key will be permanently deleted. This action is irreversible.</p>
<svelte:fragment slot="aside">
@@ -1,6 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import { DropList, DropListItem, GridItem1 } from '$lib/components';
import { DropList, DropListItem, GridItem1, Heading } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { toLocaleDateTime } from '$lib/helpers/date';
import { wizard } from '$lib/stores/wizard';
@@ -35,7 +35,7 @@
</script>
<div class="common-section u-flex u-gap-12">
<h3 class="heading-level-7">Platforms</h3>
<Heading tag="h3" size="7">Platforms</Heading>
<span class="u-margin-inline-start-auto">
<DropList
bind:show={showDropdown}
@@ -2,7 +2,7 @@
import { afterNavigate } from '$app/navigation';
import { base } from '$app/paths';
import { page } from '$app/stores';
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { updateLayout } from '$lib/stores/layout';
@@ -95,7 +95,7 @@
{#if loaded}
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<p class="text">
Choose any name that will help you distinguish between platforms.
</p>
@@ -120,7 +120,7 @@
<CardGrid>
<div>
<h6 class="heading-level-7">Delete Platform</h6>
<Heading tag="h6" size="7">Delete Platform</Heading>
</div>
<p>The Platform will be permanently deleted. This action is irreversible.</p>
<svelte:fragment slot="aside">
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Bundle ID</h6>
<Heading tag="h6" size="7">Update Bundle ID</Heading>
<p class="text">
You can find your Bundle Identifier in the General tab for your app's primary target in
Xcode.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Bundle ID</h6>
<Heading tag="h6" size="7">Update Bundle ID</Heading>
<p class="text">
You can find your Bundle Identifier in the General tab for your app's primary target in
Xcode.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Bundle ID</h6>
<Heading tag="h6" size="7">Update Bundle ID</Heading>
<p class="text">
You can find your Bundle Identifier in the General tab for your app's primary target in
Xcode.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Bundle ID</h6>
<Heading tag="h6" size="7">Update Bundle ID</Heading>
<p class="text">
You can find your Bundle Identifier in the General tab for your app's primary target in
Xcode.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Package Name</h6>
<Heading tag="h6" size="7">Update Package Name</Heading>
<p class="text">
Your package name is generally the applicationId in your app-level build.gradle file.
</p>
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Bundle ID</h6>
<Heading tag="h6" size="7">Update Bundle ID</Heading>
<p class="text">
You can find your Bundle Identifier in the General tab for your app's primary target in
Xcode.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Package Name</h6>
<Heading tag="h6" size="7">Update Package Name</Heading>
<p class="text">Your application name.</p>
<svelte:fragment slot="aside">
<FormList>
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Bundle ID</h6>
<Heading tag="h6" size="7">Update Bundle ID</Heading>
<p class="text">
You can find your Bundle Identifier in the General tab for your app's primary target in
Xcode.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -37,7 +37,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Package Name</h6>
<Heading tag="h6" size="7">Update Package Name</Heading>
<p class="text">Your application name.</p>
<svelte:fragment slot="aside">
<FormList>
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid } from '$lib/components';
import { CardGrid, Heading } from '$lib/components';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
@@ -39,7 +39,7 @@
<Form on:submit={updateHostname}>
<CardGrid>
<h6 class="heading-level-7">Update Hostname</h6>
<Heading tag="h6" size="7">Update Hostname</Heading>
<p class="text">You can use * to allow wildcard hostnames or subdomains.</p>
<svelte:fragment slot="aside">
<FormList>
@@ -6,7 +6,7 @@
import { addNotification } from '$lib/stores/notifications';
import { project } from '../store';
import { services, type Service } from '$lib/stores/project-services';
import { CardGrid, CopyInput, Box } from '$lib/components';
import { CardGrid, CopyInput, Box, Heading } from '$lib/components';
import { Button, Form, FormList, InputText, InputSwitch } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import Delete from './_deleteProject.svelte';
@@ -65,7 +65,7 @@
{#if $project}
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<FormList>
@@ -85,7 +85,7 @@
</Form>
<CardGrid>
<h6 class="heading-level-7">API Credentials</h6>
<Heading tag="h6" size="7">API Credentials</Heading>
<p class="text">
Access Appwrite services using your API Endpoint and Project ID. You can connect
Appwrite to your applications and server-side code by <a href="#/" class="link"
@@ -102,7 +102,7 @@
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">Services</h6>
<Heading tag="h6" size="7">Services</Heading>
<p class="text">Choose services you wish to enable or disable.</p>
<svelte:fragment slot="aside">
<FormList>
@@ -125,7 +125,7 @@
<CardGrid>
<div>
<h6 class="heading-level-7">Delete Project</h6>
<Heading tag="h6" size="7">Delete Project</Heading>
</div>
<p>
The project will be permanently deleted, including all the metadata, resources and
@@ -1,38 +0,0 @@
<script lang="ts">
import { Modal } from '$lib/components';
import { InputText, Button, Form } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { createEventDispatcher } from 'svelte';
import { project } from '../store';
export let show = false;
let domain: string;
const dispatch = createEventDispatcher();
const create = async () => {
try {
await sdkForConsole.projects.createDomain($project.$id, domain);
domain = null;
show = false;
dispatch('created');
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
};
</script>
<Form on:submit={create}>
<Modal bind:show>
<svelte:fragment slot="header">Add Domain</svelte:fragment>
<InputText id="domain" label="Domain" bind:value={domain} required />
<svelte:fragment slot="footer">
<Button submit>Create</Button>
<Button secondary on:click={() => (show = false)}>Cancel</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -1,64 +1,161 @@
<script lang="ts">
import { page } from '$app/stores';
import { tooltip } from '$lib/actions/tooltip';
import { Empty } from '$lib/components';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRow
} from '$lib/elements/table';
import { Container } from '$lib/layout';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import CreateDomain from '../_createDomain.svelte';
import { wizard } from '$lib/stores/wizard';
import Create from './_create.svelte';
import Delete from './_delete.svelte';
import { domainList } from './store';
import type { Models } from '@aw-labs/appwrite-console';
const projectId = $page.params.project;
const listDomains = () => sdkForConsole.projects.listDomains(projectId);
let showDelete = false;
let selectedDomain: Models.Domain;
let isVerifying = {};
let request = listDomains();
let addDomain = false;
const openWizard = () => {
wizard.start(Create);
};
const refreshDomain = async (domain: Models.Domain, i: number) => {
const domainId = domain.$id;
try {
isVerifying[domainId] = true;
if (domain.verification) {
await domainList.load(projectId);
return;
}
const result = await sdkForConsole.projects.updateDomainVerification(
projectId,
domainId
);
$domainList.domains[i] = result;
} catch (error) {
addNotification({
message: error.message,
type: 'error'
});
} finally {
isVerifying[domainId] = false;
}
};
</script>
<Container>
<h1>Custom Domains</h1>
{#await request}
<div aria-busy="true" />
{:then response}
<Table>
<TableHeader>
<TableCellHead width={96} />
<TableCellHead>Domain</TableCellHead>
<TableCellHead>TLS</TableCellHead>
</TableHeader>
<TableBody>
{#each response.domains as domain}
<TableRow>
<TableCellText title="Scopes">
<Pill danger={!domain.verification} success={domain.verification}>
{domain.verification ? 'verified' : 'unverified'}
</Pill>
</TableCellText>
<TableCellText title="Domain">
{domain.domain}
</TableCellText>
<TableCellText title="TLS">
{#if domain.certificateId}
Verified
{:else if domain.verification}
In Progress
{:else}
Pending Verification
{/if}
</TableCellText>
</TableRow>
{/each}
</TableBody>
</Table>
{/await}
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Custom Domains</h2>
<Button on:click={() => (addDomain = true)}>Add Domain</Button>
<Button on:click={openWizard}>
<span class="icon-plus" aria-hidden="true" /> <span class="text">Create domain</span>
</Button>
</div>
{#await domainList.load(projectId)}
<div aria-busy="true" />
{:then}
{#if $domainList.total}
<Table>
<TableHeader>
<TableCellHead />
<TableCellHead>Domain Name</TableCellHead>
<TableCellHead>TLS</TableCellHead>
<TableCellHead />
</TableHeader>
<TableBody>
{#each $domainList.domains as domain, i}
<TableRow>
<TableCellText title="Status">
<Pill warning={!domain.verification} success={domain.verification}>
{domain.verification ? 'verified' : 'unverified'}
</Pill>
</TableCellText>
<TableCellText title="Domain">
{domain.domain}
</TableCellText>
<TableCellText title="TLS">
{#if domain.certificateId}
<Pill success>enabled</Pill>
{:else}
<span
use:tooltip={{
content:
"The process might take a while, click the retry button to see if it's finished"
}}>
<Pill warning>
{!domain.verification
? 'pending verification'
: 'in progress'}
</Pill>
</span>
{/if}
</TableCellText>
<TableCell title="Actions">
<div class="u-flex u-gap-8 u-cross-center u-main-end">
{#if isVerifying[domain.$id]}
<!-- TODO: remove inline styles -->
<div
class="loader"
style="color: hsl(var(--color-neutral-50)); inline-size: 1.25rem; block-size: 1.25rem" />
{:else if !domain.certificateId}
<!-- TODO: remove inline styles -->
<button
class="button is-text is-only-icon u-padding-inline-0"
style="--p-button-size: var(--button-size, 2.0rem);"
aria-label="Verify item"
on:click={() => {
refreshDomain(domain, i);
}}>
<span class="icon-refresh" aria-hidden="true" />
</button>
{/if}
<!-- TODO: remove inline styles -->
<button
class="button tooltip is-text is-only-icon u-padding-inline-0"
style="--p-button-size: var(--button-size, 2.0rem);"
aria-label="Delete item"
on:click={async () => {
showDelete = true;
selectedDomain = domain;
}}>
<span class="icon-trash" aria-hidden="true" />
<span class="tooltip-popup is-bottom" role="tooltip">
Delete
</span>
</button>
</div>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
{:else}
<Empty isButton single on:click={openWizard}>
<div class="common-section">
<div class="u-text-center common-section">
<p>Create your first Domain to get started</p>
</div>
<div class="u-flex u-gap-16 common-section u-main-center">
<Button external href="#/" text>Documentation</Button>
<Button secondary>Create domain</Button>
</div>
</div>
</Empty>
{/if}
{/await}
</Container>
<CreateDomain bind:show={addDomain} on:created={() => (request = listDomains())} />
<Delete bind:showDelete bind:selectedDomain />
@@ -0,0 +1,44 @@
<script lang="ts">
import { Wizard } from '$lib/layout';
import { beforeNavigate } from '$app/navigation';
import { wizard } from '$lib/stores/wizard';
import type { WizardStepsType } from '$lib/layout/wizard.svelte';
import { domain } from './wizard/store';
import Step1 from './wizard/step1.svelte';
import Step2 from './wizard/step2.svelte';
import Step3 from './wizard/step3.svelte';
import Step4 from './wizard/step4.svelte';
import { onDestroy } from 'svelte';
onDestroy(() => {
domain.set({ id: '', name: '' });
});
beforeNavigate(() => {
wizard.hide();
});
const stepsComponents: WizardStepsType = new Map();
stepsComponents.set(1, {
label: 'Add your domain',
component: Step1
});
stepsComponents.set(2, {
label: 'Add a CNAME Record',
component: Step2
});
stepsComponents.set(3, {
label: 'Verify domain',
component: Step3
});
stepsComponents.set(4, {
label: 'SSL Certificate',
component: Step4
});
</script>
<Wizard
title="Create domain"
steps={stepsComponents}
finalAction="Go to console"
on:finish={wizard.hide} />
@@ -0,0 +1,42 @@
<script lang="ts">
import { Modal } from '$lib/components';
import { Button, Form } from '$lib/elements/forms';
import { project } from '../../store';
import type { Models } from '@aw-labs/appwrite-console';
import { sdkForConsole } from '$lib/stores/sdk';
import { addNotification } from '$lib/stores/notifications';
import { domainList } from './store';
export let showDelete = false;
export let selectedDomain: Models.Domain;
const deleteDomain = async () => {
try {
await sdkForConsole.projects.deleteDomain($project.$id, selectedDomain.$id);
domainList.load($project.$id);
showDelete = false;
addNotification({
type: 'success',
message: `${selectedDomain.domain} has been deleted`
});
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
};
</script>
<Form on:submit={deleteDomain}>
<Modal bind:show={showDelete} warning>
<svelte:fragment slot="header">Delete Domain</svelte:fragment>
<p>
Are you sure you want to delete <b>{selectedDomain.domain}</b> from '{$project.name}'?
</p>
<svelte:fragment slot="footer">
<Button text on:click={() => (showDelete = false)}>Cancel</Button>
<Button secondary submit>Delete</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -0,0 +1,17 @@
import { sdkForConsole } from '$lib/stores/sdk';
import type { Models } from '@aw-labs/appwrite-console';
import { cachedStore } from '$lib/helpers/cache';
export const domainList = cachedStore<
Models.DomainList,
{
load: (projectId: string) => Promise<void>;
}
>('domainList', function ({ set }) {
return {
load: async (projectId) => {
const response = await sdkForConsole.projects.listDomains(projectId);
set(response);
}
};
});
@@ -0,0 +1,39 @@
<script lang="ts">
import { Copy } from '$lib/components';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRow
} from '$lib/elements/table';
import { domain } from './store';
const parts = $domain.name.split('.');
const registerable = [parts[parts.length - 2], parts[parts.length - 1]].join('.');
const cnameValue = $domain.name.replace('.' + registerable, '');
</script>
<Table noStyles noMargin>
<TableHeader>
<TableCellHead>Type</TableCellHead>
<TableCellHead>Name</TableCellHead>
<TableCellHead>Value</TableCellHead>
</TableHeader>
<TableBody>
<TableRow>
<TableCellText title="Type">CNAME</TableCellText>
<TableCellText title="Name">{cnameValue}</TableCellText>
<TableCell title="Value">
<div class="u-flex u-main-space-between u-cross-center">
<span class="text">{$domain.name}</span>
<Copy value={$domain.name}>
<span class="icon-duplicate" aria-hidden="true" />
</Copy>
</div>
</TableCell>
</TableRow>
</TableBody>
</Table>
@@ -0,0 +1,51 @@
<script lang="ts">
import Button from '$lib/elements/forms/button.svelte';
import { sdkForConsole } from '$lib/stores/sdk';
import { domain } from './store';
import { project } from '../../../store';
import { addNotification } from '$lib/stores/notifications';
const projectId = $project.$id;
export let isVerifying = false;
export let isVerified = false;
const verifyDomain = async () => {
isVerifying = true;
try {
const result = await sdkForConsole.projects.updateDomainVerification(
projectId,
$domain.id
);
isVerified = result.verification;
} catch (error) {
addNotification({
message: error.message,
type: 'error'
});
} finally {
isVerifying = false;
}
};
</script>
<div class="box u-flex u-gap-16 u-cross-center">
{#if isVerifying}
<div
class="loader"
style="color: hsl(var(--color-neutral-50)); inline-size: 1.25rem; block-size: 1.25rem" />
{:else}
<span
class:u-hide={isVerifying}
class:icon-x={!isVerified}
class:icon-check={isVerified}
aria-hidden="true"
style="color: hsl(var(--color-neutral-50))" />
{/if}
<p class="u-stretch">
{!isVerified ? 'Domain is pending verification' : 'Verified domain'}
</p>
{#if !isVerifying && !isVerified}
<Button secondary on:click={verifyDomain}>Verify</Button>
{/if}
</div>
@@ -0,0 +1,64 @@
<script lang="ts">
import { FormList, InputDomain } from '$lib/elements/forms';
import { WizardStep } from '$lib/layout';
import { sdkForConsole } from '$lib/stores/sdk';
import { project } from '../../../store';
import { domain } from './store';
import { domainList } from '../store';
// Handle if user goes back to this step to update
// the domain name after creating the domain
const originalDomainName = $domain.name;
const originalDomainId = $domain.id;
const unsubscribe = domain.subscribe((newDomain) => {
if (
originalDomainName !== '' &&
newDomain.id !== '' &&
newDomain.name !== originalDomainName
) {
$domain.id = '';
}
});
const projectId = $project.$id;
const createDomain = async () => {
unsubscribe();
if ($domain.name !== originalDomainName && originalDomainId) {
await sdkForConsole.projects.deleteDomain(projectId, originalDomainId);
}
if ($domain.id == '') {
const newDomain = await sdkForConsole.projects.createDomain(projectId, $domain.name);
domainList.load(projectId);
$domain.id = newDomain.$id;
}
};
</script>
<WizardStep beforeSubmit={createDomain}>
<svelte:fragment slot="title">Add your domain</svelte:fragment>
<svelte:fragment slot="subtitle">
Use your self-owned domain as the endpoint of your Appwrite API.
</svelte:fragment>
<FormList>
<InputDomain
id="domain"
label="Custom Domain"
placeholder="appwrite.example.com"
autocomplete={false}
required
bind:value={$domain.name} />
</FormList>
<div class="common-section ">
<p>
You can find a list of domain providers and their DNS setting documentation <a
class="link"
href="https://appwrite.io/docs/custom-domains#addCNAME"
target="_blank"
rel="noreferrer">here</a
>. If your domain provider isn't listed, please contact us, and we'll include their
settings as well.
</p>
</div>
</WizardStep>
@@ -0,0 +1,13 @@
<script lang="ts">
import { WizardStep } from '$lib/layout';
import CnameTable from './_cnameTable.svelte';
</script>
<WizardStep>
<svelte:fragment slot="title">Add a CNAME record</svelte:fragment>
<svelte:fragment slot="subtitle">
In order to continue, set the following record on your DNS provider
</svelte:fragment>
<CnameTable />
</WizardStep>
@@ -0,0 +1,25 @@
<script lang="ts">
import { WizardStep } from '$lib/layout';
import CnameTable from './_cnameTable.svelte';
import VerificationBox from './_verificationBox.svelte';
let isVerifying = false;
let isVerified = false;
</script>
<WizardStep>
<svelte:fragment slot="title">Add a CNAME record</svelte:fragment>
<svelte:fragment slot="subtitle">
In order to continue, set the following record on your DNS provider
</svelte:fragment>
<input class="u-hide" type="checkbox" name="isVerified" required bind:checked={isVerified} />
<CnameTable />
<div class="container u-padding-inline-0">
<p>Changes may take some time to take effect depending on your provider.</p>
<div class="container u-padding-inline-0">
<VerificationBox {isVerifying} bind:isVerified />
</div>
</div>
</WizardStep>
@@ -0,0 +1,58 @@
<script lang="ts">
import { WizardStep } from '$lib/layout';
import { sdkForConsole } from '$lib/stores/sdk';
import { domain } from './store';
import { project } from '../../../store';
import { domainList } from '../store';
import CnameTable from './_cnameTable.svelte';
import VerificationBox from './_verificationBox.svelte';
const projectId = $project.$id;
let certificate = false;
const checkCertificate = () => {
setTimeout(async () => {
const result = await sdkForConsole.projects.getDomain(projectId, $domain.id);
if (!result.certificateId) {
checkCertificate();
return;
}
const i = $domainList.domains.findIndex((d) => d.$id === $domain.id);
if (i >= 0) {
$domainList.domains[i] = result;
}
certificate = true;
}, 2000);
};
checkCertificate();
</script>
<WizardStep>
<svelte:fragment slot="title">Add a CNAME record</svelte:fragment>
<svelte:fragment slot="subtitle">
In order to continue, set the following record on your DNS provider
</svelte:fragment>
<CnameTable />
<div class="boxes-wrapper u-margin-block-start-24">
<VerificationBox isVerifying={false} isVerified={true} />
<div class="box">
<div class="u-flex u-gap-16 u-cross-center">
{#if !certificate}
<div
class="loader"
style="color: hsl(var(--color-neutral-50)); inline-size: 1.25rem; block-size: 1.25rem" />
{:else}
<span
class="icon-check"
aria-hidden="true"
style="color: hsl(var(--color-neutral-50))" />
{/if}
<p class="u-stretch">
{!certificate ? 'Generating SSL certificate' : 'Generated SSL certificate'}
</p>
</div>
</div>
</div>
</WizardStep>
@@ -0,0 +1,3 @@
import { writable } from 'svelte/store';
export const domain = writable<{ id: string; name: string }>({ id: '', name: '' });
@@ -2,7 +2,7 @@
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { Button } from '$lib/elements/forms';
import { Empty, Pagination, Copy, GridItem1, CardContainer } from '$lib/components';
import { Empty, Pagination, Copy, GridItem1, CardContainer, Heading } from '$lib/components';
import { Pill } from '$lib/elements';
import { Query, type Models } from '@aw-labs/appwrite-console';
import Create from './_create.svelte';
@@ -32,7 +32,7 @@
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Buckets</h2>
<Heading tag="h2" size="5">Buckets</Heading>
<Button on:click={() => (showCreate = true)}>
<span class="icon-plus" aria-hidden="true" /> <span class="text">Create bucket</span>
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid, Box, Copy } from '$lib/components';
import { CardGrid, Box, Copy, Heading } from '$lib/components';
import { Container } from '$lib/layout';
import { Button } from '$lib/elements/forms';
import { Pill } from '$lib/elements';
@@ -86,7 +86,7 @@
</div>
</a>
<div>
<h2 class="heading-level-7">{$file.name}</h2>
<Heading tag="h2" size="7">{$file.name}</Heading>
<Copy value={getView($file.$id)}>
<Pill button><i class="icon-duplicate" />File URL</Pill>
</Copy>
@@ -109,7 +109,7 @@
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">Update Permissions</h6>
<Heading tag="h6" size="7">Update Permissions</Heading>
<p>
Assign read or write permissions at the Bucket Level or File Level. If Bucket Level
permissions are enabled, file permissions will be ignored.
@@ -128,7 +128,7 @@
</CardGrid>
<CardGrid>
<h6 class="heading-level-7">Delete file</h6>
<Heading tag="h6" size="7">Delete file</Heading>
<p>
The file will be permanently deleted, including all the files within it. This action
is irreversible.
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid, Box } from '$lib/components';
import { CardGrid, Box, Heading } from '$lib/components';
import { Container } from '$lib/layout';
import {
Form,
@@ -208,7 +208,7 @@
{#if $bucket}
<Form on:submit={toggleBucket}>
<CardGrid>
<h2 class="heading-level-7">{$bucket.name}</h2>
<Heading tag="h2" size="7">{$bucket.name}</Heading>
<svelte:fragment slot="aside">
<ul>
@@ -229,7 +229,7 @@
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<Heading tag="h6" size="7">Update Name</Heading>
<svelte:fragment slot="aside">
<ul>
<InputText
@@ -250,7 +250,7 @@
<Form on:submit={updatePermissions}>
<CardGrid>
<h6 class="heading-level-7">Update Permissions</h6>
<Heading tag="h6" size="7">Update Permissions</Heading>
<p>
Assign read or write permissions at the <b>Bucket Level</b> or
<b>File Level</b>. If Bucket Level permissions are assigned, file permissions
@@ -293,7 +293,7 @@
<Form on:submit={updateSecurity}>
<CardGrid>
<h2 class="heading-level-7">Update Security Settings</h2>
<Heading tag="h2" size="7">Update Security Settings</Heading>
<p>
Enable or disable security services for the bucket including <b>Ecryption</b>
and <b>Antivirus scanning.</b>
@@ -362,7 +362,7 @@
<Form on:submit={updateMaxSize}>
<CardGrid>
<h2 class="heading-level-6">Update Maximum File Size</h2>
<Heading tag="h2" size="6">Update Maximum File Size</Heading>
<p>Set the maximum file size allowed in the bucket.</p>
<svelte:fragment slot="aside">
<ul class="u-flex u-gap-12">
@@ -383,7 +383,7 @@
<Form on:submit={updateAllowedExtensions}>
<CardGrid>
<h6 class="heading-level-7">Update Allowed File Extensions</h6>
<Heading tag="h6" size="7">Update Allowed File Extensions</Heading>
<p>
A maxiumum of 100 file extensions can be added. Leave blank to allow all file
types.
@@ -419,7 +419,7 @@
</Form>
<CardGrid>
<h6 class="heading-level-7">Delete Bucket</h6>
<Heading tag="h6" size="7">Delete Bucket</Heading>
<p>
The bucket will be permanently deleted, including all the files within it. This
action is irreversible.
+14
View File
@@ -0,0 +1,14 @@
import '@testing-library/jest-dom';
import { render } from '@testing-library/svelte';
import { Heading } from '../../../src/lib/components';
test('shows heading', () => {
const tag = 'h1';
const size = '7';
const { container } = render(Heading, { tag, size });
const headings = container.querySelectorAll(tag);
expect(headings.length).toEqual(1);
expect(headings[0].className).toEqual(`heading-level-${size}`);
});