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

This commit is contained in:
Torsten Dittmann
2022-10-13 13:04:47 +02:00
38 changed files with 469 additions and 213 deletions
+1 -1
View File
@@ -69,7 +69,7 @@
<button
type="button"
class="button"
on:click={() => handleOptionClick(page)}
on:click={() => handleOptionClick(+page)}
class:is-disabled={currentPage === page}
class:is-text={currentPage !== page}
aria-label="page">
+67
View File
@@ -0,0 +1,67 @@
import { afterNavigate, goto } from '$app/navigation';
import { page } from '$app/stores';
import { get, writable } from 'svelte/store';
export function createPersistentPagination(limit: number) {
const url = get(page).url;
const current = +(url.searchParams.get('page') ?? 1);
const offset = current * limit - limit;
const { subscribe, set } = writable<number>(offset < 0 ? 0 : offset);
let keepHistory = false;
const apply = (n: number) => {
const { pathname, searchParams, href } = get(page).url;
const newPage = n / limit + 1;
if (newPage > 1) {
searchParams.set('page', newPage.toString());
} else {
searchParams.delete('page');
}
let target = pathname;
const hasParams = searchParams.toString() !== '';
if (hasParams) {
target += `?${searchParams.toString()}`;
}
if (keepHistory) {
keepHistory = false;
return;
}
if (href.endsWith(target)) {
return;
}
goto(target, {
noscroll: true
});
};
afterNavigate(({ type, to }) => {
const target = +(to.url.searchParams.get('page') ?? 1);
/**
* Listens to back/forward of the browser.
*/
if (type === 'popstate') {
/**
* Keep the history state of the browser.
*/
keepHistory = true;
set(target * limit - limit);
} else if (type === 'link') {
set(target * limit - limit);
}
});
subscribe(apply);
return {
subscribe,
set
};
}
@@ -17,14 +17,15 @@
import { onMount } from 'svelte';
import { accountActivity } from '../store';
import { Query } from '@aw-labs/appwrite-console';
import { createPersistentPagination } from '$lib/stores/pagination';
let offset = 0;
const offset = createPersistentPagination($pageLimit);
onMount(async () => {
await accountActivity.load([Query.offset(offset), Query.limit($pageLimit)]);
await accountActivity.load([Query.offset($offset), Query.limit($pageLimit)]);
});
$: accountActivity.load([Query.offset(offset), Query.limit($pageLimit)]);
$: accountActivity.load([Query.offset($offset), Query.limit($pageLimit)]);
const getBrowser = (clientCode: string) => {
return sdkForConsole.avatars.getBrowser(clientCode, 40, 40);
@@ -104,6 +105,6 @@
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$accountActivity?.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$accountActivity?.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$accountActivity?.total} />
</div>
</Container>
@@ -8,6 +8,7 @@
import { onMount } from 'svelte';
import { sdkForConsole } from '$lib/stores/sdk';
import { cardLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
onMount(async () => {
await organizationList.load();
@@ -28,7 +29,7 @@
};
let addOrganization = false;
let offset = 0;
const offset = createPersistentPagination($cardLimit);
</script>
<Container>
@@ -47,11 +48,11 @@
{#if $organizationList?.teams?.length}
<CardContainer
total={$organizationList.total}
{offset}
offset={$offset}
on:click={() => (addOrganization = true)}>
{#each $organizationList.teams as organization, index}
{@const avatarList = getMemberships(organization.$id)}
{#if index >= offset && index < $cardLimit + offset}
{#if index >= $offset && index < $cardLimit + $offset}
<GridItem1 href={`${base}/console/organization-${organization.$id}`}>
<svelte:fragment slot="eyebrow"
>{organization?.total ? organization?.total : 'No'} projects</svelte:fragment>
@@ -70,20 +71,15 @@
<p>Create a new organization</p>
</svelte:fragment>
</CardContainer>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$organizationList?.total}</p>
<Pagination limit={$cardLimit} bind:offset sum={$organizationList?.total} />
</div>
{:else}
<Empty isButton single on:click={() => (addOrganization = true)}>
<p>Create a new organization</p>
</Empty>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$organizationList?.total}</p>
<Pagination limit={$cardLimit} bind:offset sum={$organizationList?.total} />
</div>
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$organizationList?.total}</p>
<Pagination limit={$cardLimit} bind:offset={$offset} sum={$organizationList?.total} />
</div>
</Container>
<CreateOrganization bind:show={addOrganization} />
@@ -17,8 +17,9 @@
import type { Models } from '@aw-labs/appwrite-console';
import { accountSession } from '../store';
import { onMount } from 'svelte';
import { createPersistentPagination } from '$lib/stores/pagination';
let offset = 0;
const offset = createPersistentPagination($pageLimit);
onMount(async () => {
await accountSession.load();
@@ -112,14 +113,15 @@
<Button
external
secondary
href="https://appwrite.io/docs/server/authentication?sdk=nodejs-default#usersGetsessions"
>Documentation</Button>
href="https://appwrite.io/docs/server/authentication?sdk=nodejs-default#usersGetsessions">
Documentation
</Button>
</div>
</div>
</Empty>
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$accountSession?.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$accountSession?.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$accountSession?.total} />
</div>
</Container>
@@ -14,8 +14,8 @@
import CreateProject from './_createProject.svelte';
import { cardLimit } from '$lib/stores/layout';
import CardContainer from '$lib/components/cardContainer.svelte';
import { createPersistentPagination } from '$lib/stores/pagination';
let projects: Models.Project[] = [];
$: organizationId = $page.params.organization;
onMount(handle);
@@ -23,7 +23,7 @@
async function handle() {
await projectList.load([
Query.offset(offset),
Query.offset($offset),
Query.limit($cardLimit),
Query.equal('teamId', organizationId)
]);
@@ -31,7 +31,7 @@
let showCreate = false;
let addOrganization = false;
let offset = 0;
const offset = createPersistentPagination($cardLimit);
const projectCreated = async (event: CustomEvent<Models.Project>) => {
await project.load(event.detail.$id);
@@ -79,9 +79,12 @@
</div>
{#if $projectList?.total}
<CardContainer total={$projectList.total} {offset} on:click={() => (showCreate = true)}>
<CardContainer
total={$projectList.total}
offset={$offset}
on:click={() => (showCreate = true)}>
{#each $projectList.projects as project, index}
{#if index >= offset && index < $cardLimit + offset}
{#if index >= $offset && index < $cardLimit + $offset}
<GridItem1 href={`${base}/console/project-${project.$id}`}>
<svelte:fragment slot="eyebrow">
{project?.platforms?.length ? project?.platforms?.length : 'No'} apps
@@ -113,20 +116,15 @@
<p>Create a new project</p>
</svelte:fragment>
</CardContainer>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$projectList.total}</p>
<Pagination limit={$cardLimit} bind:offset sum={$projectList.total} />
</div>
{:else}
<Empty isButton single on:click={() => (showCreate = true)}>
<p>Create a new project</p>
</Empty>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {projects?.length}</p>
<Pagination limit={$cardLimit} bind:offset sum={projects?.length} />
</div>
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$projectList?.total}</p>
<Pagination limit={$cardLimit} bind:offset={$offset} sum={$projectList?.total} />
</div>
</Container>
<CreateOrganization bind:show={addOrganization} />
@@ -19,18 +19,22 @@
import { pageLimit } from '$lib/stores/layout';
import { page } from '$app/stores';
import { addNotification } from '$lib/stores/notifications';
import { createPersistentPagination } from '$lib/stores/pagination';
let search = '';
let offset = 0;
let selectedMember: Models.Membership;
let showDelete = false;
const url = `${$page.url.origin}/console/`;
const offset = createPersistentPagination($pageLimit);
const getAvatar = (name: string) =>
sdkForConsole.avatars.getInitials(name, 120, 120).toString();
const deleted = () =>
memberList.load($organization.$id, [Query.limit($pageLimit), Query.offset(offset)], search);
memberList.load(
$organization.$id,
[Query.limit($pageLimit), Query.offset($offset)],
search
);
const resend = async (member: Models.Membership) => {
try {
await sdkForConsole.teams.createMembership(
@@ -52,8 +56,8 @@
}
};
$: if (search) offset = 0;
$: memberList.load($organization.$id, [Query.limit($pageLimit), Query.offset(offset)], search);
$: if (search) $offset = 0;
$: memberList.load($organization.$id, [Query.limit($pageLimit), Query.offset($offset)], search);
</script>
<Container>
@@ -61,10 +65,7 @@
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Members</h2>
<Button
on:click={() => {
newMemberModal.set(true);
}}>
<Button on:click={() => newMemberModal.set(true)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Invite</span>
</Button>
@@ -86,8 +87,9 @@
size={40}
src={getAvatar(member.userName)}
name={member.userName} />
<span class="text u-trim"
>{member.userName ? member.userName : 'n/a'}</span>
<span class="text u-trim">
{member.userName ? member.userName : 'n/a'}
</span>
{#if member.invited && !member.joined}
<Pill warning>Pending</Pill>
{/if}
@@ -120,7 +122,7 @@
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$memberList.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$memberList.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$memberList.total} />
</div>
{/if}
</Container>
@@ -22,10 +22,11 @@
import { usersList } from './store';
import { Query, type Models } from '@aw-labs/appwrite-console';
import { pageLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
let showCreate = false;
let search = '';
let offset = 0;
const offset = createPersistentPagination($pageLimit);
const project = $page.params.project;
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
@@ -33,9 +34,9 @@
await goto(`${base}/console/project-${project}/authentication/user/${event.detail.$id}`);
};
$: if (search) offset = 0;
$: if (search) $offset = 0;
$: usersList.load(
[Query.limit($pageLimit), Query.offset(offset), Query.orderDesc('$createdAt')],
[Query.limit($pageLimit), Query.offset($offset), Query.orderDesc('$createdAt')],
search
);
</script>
@@ -126,7 +127,7 @@
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$usersList.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$usersList.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$usersList.total} />
</div>
{:else if search}
<EmptySearch>
@@ -12,23 +12,37 @@
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import type { Provider } from '$lib/stores/oauth-providers';
import { onMount } from 'svelte';
export let showModal = false;
export let provider: Provider;
let { keyID, teamID, p8 } = JSON.parse(provider.secret);
let id: string = null;
let active = false;
let keyID: string = null;
let teamID: string = null;
let p8: string = null;
onMount(() => {
id ??= provider.id;
active ??= provider.active;
if (provider.secret) ({ keyID, teamID, p8 } = JSON.parse(provider.secret));
});
let error: string;
const projectId = $page.params.project;
const update = async () => {
try {
const secret = JSON.stringify({ keyID, teamID, p8 });
await sdkForConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
provider.id,
id,
secret
);
provider.active = active;
provider.id = id;
provider.secret = secret;
showModal = false;
addNotification({
type: 'success',
@@ -40,9 +54,11 @@
error = message;
}
};
$: secret = keyID && teamID && p8 ? JSON.stringify({ keyID, teamID, p8 }) : provider.secret;
</script>
<Form on:submit={update}>
<Form noMargin on:submit={update}>
<Modal {error} size="big" bind:show={showModal}>
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
<FormList>
@@ -53,16 +69,13 @@
visit the docs.
</a>
</p>
<InputSwitch
id="state"
bind:value={provider.active}
label={provider.active ? 'Enabled' : 'Disabled'} />
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
<InputText
id="bundleID"
label="Bundle ID"
autofocus={true}
placeholder="com.company.appname"
bind:value={provider.id} />
bind:value={id} />
<InputText id="keyID" label="Key ID" placeholder="SHAB13ROFN" bind:value={keyID} />
<InputText id="teamID" label="Team ID" placeholder="ELA2CD3AED" bind:value={teamID} />
<InputTextarea id="p8" label="P8 File" placeholder="" bind:value={p8} />
@@ -79,7 +92,12 @@
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
<Button submit>Update</Button>
<Button
disabled={(secret === provider.secret &&
active === provider.active &&
id === provider.id) ||
!(id && keyID && teamID && p8)}
submit>Update</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -12,23 +12,35 @@
import { sdkForConsole } from '$lib/stores/sdk';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { onMount } from 'svelte';
export let showModal = false;
export let provider: Provider;
let { clientSecret, auth0Domain } = JSON.parse(provider.secret);
let id: string = null;
let active = false;
let clientSecret: string = null;
let auth0Domain: string = null;
let error: string;
onMount(() => {
id ??= provider.id;
active ??= provider.active;
if (provider.secret) ({ clientSecret, auth0Domain } = JSON.parse(provider.secret));
});
const projectId = $page.params.project;
const update = async () => {
try {
const secret = JSON.stringify({ clientSecret, auth0Domain });
await sdkForConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
provider.id,
id,
secret
);
provider.active = active;
provider.id = id;
provider.secret = secret;
showModal = false;
addNotification({
type: 'success',
@@ -40,9 +52,14 @@
error = message;
}
};
$: secret =
clientSecret && auth0Domain
? JSON.stringify({ clientSecret, auth0Domain })
: provider.secret;
</script>
<Form on:submit={update}>
<Form noMargin on:submit={update}>
<Modal {error} size="big" bind:show={showModal}>
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
<FormList>
@@ -52,20 +69,18 @@
<a class="link" href={provider.docs} target="_blank" rel="noopener noreferrer"
>visit the docs.</a>
</p>
<InputSwitch
id="state"
bind:value={provider.active}
label={provider.active ? 'Enabled' : 'Disabled'} />
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
<InputText
id="clientID"
label="Client ID"
autofocus={true}
placeholder="Enter ID"
bind:value={provider.id} />
bind:value={id} />
<InputPassword
id="secret"
label="Client Secret"
placeholder="Enter Client Secret"
minlength={0}
showPasswordButton
bind:value={clientSecret} />
<InputText
@@ -86,7 +101,12 @@
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
<Button submit>Update</Button>
<Button
disabled={(secret === provider.secret &&
active === provider.active &&
id === provider.id) ||
!(id && clientSecret && auth0Domain)}
submit>Update</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -12,12 +12,22 @@
import { sdkForConsole } from '$lib/stores/sdk';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { onMount } from 'svelte';
export let showModal = false;
export let provider: Provider;
const projectId = $page.params.project;
let active = false;
let id: string = null;
let secret: string = null;
onMount(() => {
active ??= provider.active;
id ??= provider.id;
secret ??= provider.secret;
});
let error: string;
const update = async () => {
@@ -25,9 +35,12 @@
await sdkForConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
provider.id,
provider.secret
id,
secret
);
provider.active = active;
provider.id = id;
provider.secret = secret;
showModal = false;
addNotification({
type: 'success',
@@ -41,7 +54,7 @@
};
</script>
<Form on:submit={update}>
<Form noMargin on:submit={update}>
<Modal {error} size="big" bind:show={showModal}>
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
<FormList>
@@ -51,22 +64,20 @@
<a class="link" href={provider.docs} target="_blank" rel="noopener noreferrer"
>visit the docs.</a>
</p>
<InputSwitch
id="state"
bind:value={provider.active}
label={provider.active ? 'Enabled' : 'Disabled'} />
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
<InputText
id="appID"
label="App ID"
autofocus={true}
placeholder="Enter ID"
bind:value={provider.id} />
bind:value={id} />
<InputPassword
id="secret"
label="App Secret"
placeholder="Enter App Secret"
minlength={0}
showPasswordButton
bind:value={provider.secret} />
bind:value={secret} />
<Alert type="info">
To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration.
</Alert>
@@ -80,7 +91,13 @@
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
<Button submit>Update</Button>
<Button
disabled={!id ||
!secret ||
(id === provider.id &&
secret === provider.secret &&
active === provider.active)}
submit>Update</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -12,24 +12,36 @@
import { sdkForConsole } from '$lib/stores/sdk';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { onMount } from 'svelte';
export let showModal = false;
export let provider: Provider;
let { clientSecret, tenantID } = JSON.parse(provider.secret);
let id: string = null;
let active = false;
let clientSecret: string = null;
let tenantID: string = null;
let error: string;
onMount(() => {
id ??= provider.id;
active ??= provider.active;
if (provider.secret) ({ clientSecret, tenantID } = JSON.parse(provider.secret));
});
const projectId = $page.params.project;
const update = async () => {
try {
const secret = JSON.stringify({ clientSecret, tenantID });
await sdkForConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
provider.id,
id,
secret
);
provider.active = active;
provider.id = id;
provider.secret = secret;
showModal = false;
addNotification({
@@ -42,9 +54,12 @@
error = message;
}
};
$: secret =
clientSecret && tenantID ? JSON.stringify({ clientSecret, tenantID }) : provider.secret;
</script>
<Form on:submit={update}>
<Form noMargin on:submit={update}>
<Modal {error} size="big" bind:show={showModal}>
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
<FormList>
@@ -55,21 +70,19 @@
visit the docs.
</a>
</p>
<InputSwitch
id="state"
bind:value={provider.active}
label={provider.active ? 'Enabled' : 'Disabled'} />
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
<InputText
id="appID"
label="Application (client) ID"
autofocus={true}
placeholder="Enter ID"
bind:value={provider.id} />
bind:value={id} />
<InputPassword
id="secret"
label="Client Secret"
placeholder="Enter Client Secret"
showPasswordButton
minlength={0}
bind:value={clientSecret} />
<InputText
id="tenant"
@@ -89,7 +102,12 @@
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
<Button submit>Update</Button>
<Button
disabled={(secret === provider.secret &&
active === provider.active &&
id === provider.id) ||
!(id && clientSecret && tenantID)}
submit>Update</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -12,24 +12,39 @@
import { sdkForConsole } from '$lib/stores/sdk';
import type { Provider } from '$lib/stores/oauth-providers';
import { addNotification } from '$lib/stores/notifications';
import { onMount } from 'svelte';
export let showModal = false;
export let provider: Provider;
let { clientSecret, oktaDomain, authorizationServerId } = JSON.parse(provider.secret);
let id: string = null;
let active = false;
let clientSecret: string = null;
let oktaDomain: string = null;
let authorizationServerId: string = null;
onMount(() => {
id ??= provider.id;
active ??= provider.active;
if (provider.secret)
({ clientSecret, oktaDomain, authorizationServerId } = JSON.parse(provider.secret));
});
let error: string;
const projectId = $page.params.project;
const update = async () => {
try {
const secret = JSON.stringify({ clientSecret, oktaDomain, authorizationServerId });
await sdkForConsole.projects.updateOAuth2(
projectId,
provider.name.toLowerCase(),
provider.id,
id,
secret
);
provider.active = active;
provider.id = id;
provider.secret = secret;
showModal = false;
addNotification({
type: 'success',
@@ -41,9 +56,14 @@
error = message;
}
};
$: secret =
clientSecret && oktaDomain && authorizationServerId
? JSON.stringify({ clientSecret, oktaDomain, authorizationServerId })
: provider.secret;
</script>
<Form on:submit={update}>
<Form noMargin on:submit={update}>
<Modal {error} size="big" bind:show={showModal}>
<svelte:fragment slot="header">{provider.name} OAuth2 Settings</svelte:fragment>
<FormList>
@@ -53,20 +73,18 @@
<a class="link" href={provider.docs} target="_blank" rel="noopener noreferrer"
>visit the docs.</a>
</p>
<InputSwitch
id="state"
bind:value={provider.active}
label={provider.active ? 'Enabled' : 'Disabled'} />
<InputSwitch id="state" bind:value={active} label={active ? 'Enabled' : 'Disabled'} />
<InputText
id="appID"
label="Client ID"
autofocus={true}
placeholder="Enter ID"
bind:value={provider.id} />
bind:value={id} />
<InputPassword
id="secret"
label="Client Secret"
placeholder="Enter Client Secret"
minlength={0}
showPasswordButton
bind:value={clientSecret} />
<InputText
@@ -93,7 +111,12 @@
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showModal = false)}>Cancel</Button>
<Button submit>Update</Button>
<Button
disabled={(secret === provider.secret &&
active === provider.active &&
id === provider.id) ||
!(id && clientSecret && oktaDomain && authorizationServerId)}
submit>Update</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -70,6 +70,7 @@
<ul class="grid-box common-section">
{#each $OAuthProviders.providers as provider}
<button
class="card u-flex u-flex-vertical u-cross-center"
on:click={() => {
selectedProvider = provider;
showModal = true;
@@ -81,8 +82,7 @@
parameters: {
provider: provider.name
}
}}
class="card u-flex u-flex-vertical u-cross-center">
}}>
<div class="image-item">
<img
height="20"
@@ -21,10 +21,11 @@
import { teamsList } from '../store';
import { Query, type Models } from '@aw-labs/appwrite-console';
import { pageLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
let search = '';
let showCreate = false;
let offset = 0;
const offset = createPersistentPagination($pageLimit);
const project = $page.params.project;
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
@@ -32,9 +33,9 @@
await goto(`${base}/console/project-${project}/authentication/teams/${event.detail.$id}`);
};
$: if (search) offset = 0;
$: if (search) $offset = 0;
$: teamsList.load(
[Query.limit($pageLimit), Query.offset(offset), Query.orderDesc('$createdAt')],
[Query.limit($pageLimit), Query.offset($offset), Query.orderDesc('$createdAt')],
search
);
</script>
@@ -81,7 +82,7 @@
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$teamsList.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$teamsList.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$teamsList.total} />
</div>
{:else if search}
<EmptySearch>
@@ -16,12 +16,13 @@
import { sdkForProject } from '$lib/stores/sdk';
import { pageLimit } from '$lib/stores/layout';
import { Query } from '@aw-labs/appwrite-console';
import { createPersistentPagination } from '$lib/stores/pagination';
let offset = 0;
const offset = createPersistentPagination($pageLimit);
$: request = sdkForProject.teams.listLogs($page.params.team, [
Query.limit($pageLimit),
Query.offset(offset)
Query.offset($offset)
]);
const getBrowser = (clientCode: string) => {
@@ -66,14 +67,12 @@
<div class="u-flex u-cross-center u-gap-12">
<p class="text u-trim">
<span class="avatar is-color-empty" />
Unknown
</p>
</div>
{/if}
</TableCell>
<TableCellText title="Event">{log.event}</TableCellText>
<TableCellText title="Location">
{#if log.countryCode !== '--'}
{log.countryName}
@@ -94,15 +93,16 @@
<p>No logs available</p>
</div>
<div class="common-section">
<Button external secondary href="https://appwrite.io/docs/server/teams"
>Documentation</Button>
<Button external secondary href="https://appwrite.io/docs/server/teams">
Documentation
</Button>
</div>
</div>
</Empty>
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {response.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={response.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={response.total} />
</div>
{/await}
</Container>
@@ -20,36 +20,42 @@
import CreateMember from '../_createMembership.svelte';
import DeleteMembership from '../_deleteMembership.svelte';
import { pageLimit } from '$lib/stores/layout';
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
const deleted = () =>
memberships.load(
$page.params.team,
[Query.limit($pageLimit), Query.offset(offset)],
search
);
const project = $page.params.project;
import { createPersistentPagination } from '$lib/stores/pagination';
let showCreate = false;
let showDelete = false;
let search = '';
let offset = 0;
let selectedMembership: Models.Membership;
$: if (search) offset = 0;
$: memberships.load($page.params.team, [Query.limit($pageLimit), Query.offset(offset)], search);
const project = $page.params.project;
const offset = createPersistentPagination($pageLimit);
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
const memberCreated = async (event: CustomEvent<Models.Membership>) => {
$: if (search) $offset = 0;
$: memberships.load(
$page.params.team,
[Query.limit($pageLimit), Query.offset($offset)],
search
);
async function memberCreated(event: CustomEvent<Models.Membership>) {
memberships.load(
$page.params.team,
[Query.limit($pageLimit), Query.offset(offset)],
[Query.limit($pageLimit), Query.offset($offset)],
search
);
await goto(
`${base}/console/project-${project}/authentication/teams/${event.detail.teamId}/members`
);
};
}
function deleted() {
memberships.load(
$page.params.team,
[Query.limit($pageLimit), Query.offset($offset)],
search
);
}
</script>
<Container>
@@ -77,7 +83,6 @@
size={32}
src={getAvatar(membership.userName)}
name={membership.userName} />
<span>{membership.userName ? membership.userName : 'n/a'}</span>
</div>
</TableCellText>
@@ -99,11 +104,9 @@
{/each}
</TableBody>
</Table>
<div
class="u-flex u-margin-block-start-32
u-main-space-between">
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$memberships.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$memberships.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$memberships.total} />
</div>
{:else if search}
<EmptySearch>
@@ -16,17 +16,16 @@
import { sdkForProject } from '$lib/stores/sdk';
import { pageLimit } from '$lib/stores/layout';
import { Query } from '@aw-labs/appwrite-console';
import { createPersistentPagination } from '$lib/stores/pagination';
let offset = 0;
const offset = createPersistentPagination($pageLimit);
$: request = sdkForProject.users.listLogs($page.params.user, [
Query.limit($pageLimit),
Query.offset(offset)
Query.offset($offset)
]);
const getBrowser = (clientCode: string) => {
return sdkForProject.avatars.getBrowser(clientCode, 80, 80);
};
const getBrowser = (clientCode: string) => sdkForProject.avatars.getBrowser(clientCode, 80, 80);
</script>
<Container>
@@ -99,7 +98,7 @@
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {response.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={response.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={response.total} />
</div>
{/await}
</Container>
@@ -1,5 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import { base } from '$app/paths';
import { Pagination, Empty, Avatar } from '$lib/components';
import {
Table,
@@ -12,23 +13,26 @@
} from '$lib/elements/table';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import { sdkForProject } from '$lib/stores/sdk';
import { pageLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
import DeleteMembership from '../_deleteMembership.svelte';
import DeleteAllMemberships from '../_deleteAllMemberships.svelte';
import type { Models } from '@aw-labs/appwrite-console';
import { pageLimit } from '$lib/stores/layout';
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
const deleted = () => (request = sdkForProject.users.listMemberships($page.params.user));
const project = $page.params.project;
let offset = 0;
let selectedMembership: Models.Membership;
let showDelete = false;
let showDeleteAll = false;
const project = $page.params.project;
const offset = createPersistentPagination($pageLimit);
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
$: request = sdkForProject.users.listMemberships($page.params.user);
function deleted() {
request = sdkForProject.users.listMemberships($page.params.user);
}
</script>
<Container>
@@ -86,11 +90,9 @@
>Documentation</Button>
</Empty>
{/if}
<div
class="u-flex u-margin-block-start-32
u-main-space-between">
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {response.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={response.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={response.total} />
</div>
{/await}
</Container>
@@ -19,19 +19,20 @@
import { pageLimit } from '$lib/stores/layout';
import { onMount } from 'svelte';
import type { Models } from '@aw-labs/appwrite-console';
import { createPersistentPagination } from '$lib/stores/pagination';
let offset = 0;
let showDelete = false;
let showDeleteAll = false;
let selectedSessionId: string = null;
let sessionList: Models.SessionList = null;
const offset = createPersistentPagination($pageLimit);
onMount(async () => {
sessionList = await sdkForProject.users.listSessions($page.params.user);
});
const getBrowser = (clientCode: string) => {
return sdkForProject.avatars.getBrowser(clientCode, 40, 40);
};
const getBrowser = (clientCode: string) => sdkForProject.avatars.getBrowser(clientCode, 40, 40);
</script>
<Container>
@@ -102,7 +103,7 @@
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {sessionList?.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={sessionList?.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={sessionList?.total} />
</div>
</Container>
@@ -10,19 +10,21 @@
import { base } from '$app/paths';
import { databaseList } from './store';
import { cardLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
let showCreate = false;
let search = '';
let offset = 0;
const project = $page.params.project;
const handleCreate = async (event: CustomEvent<Models.Database>) => {
const offset = createPersistentPagination($cardLimit);
async function handleCreate(event: CustomEvent<Models.Database>) {
showCreate = false;
await goto(`${base}/console/project-${project}/databases/database/${event.detail.$id}`);
};
}
$: databaseList.load(
[Query.limit($cardLimit), Query.offset(offset), Query.orderDesc('$createdAt')],
[Query.limit($cardLimit), Query.offset($offset), Query.orderDesc('$createdAt')],
search
);
</script>
@@ -37,7 +39,10 @@
</div>
{#if $databaseList?.total}
<CardContainer total={$databaseList.total} {offset} on:click={() => (showCreate = true)}>
<CardContainer
total={$databaseList.total}
offset={$offset}
on:click={() => (showCreate = true)}>
{#each $databaseList.databases as database}
<GridItem1
href={`${base}/console/project-${project}/databases/database/${database.$id}`}>
@@ -56,11 +61,18 @@
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$databaseList.total}</p>
<Pagination limit={$cardLimit} bind:offset sum={$databaseList.total} />
<Pagination limit={$cardLimit} bind:offset={$offset} sum={$databaseList.total} />
</div>
{:else}
<Empty isButton single on:click={() => (showCreate = true)}>
<p>Create your first Database to get started</p>
<div class="u-text-center">
<p class="text u-line-height-1-5">Create your first Database to get started</p>
<p class="text u-line-height-1-5">Need a hand? Check out our documentation.</p>
</div>
<div class="u-flex u-gap-12">
<Button external href="#/" text>Documentation</Button>
<Button secondary>Create Database</Button>
</div>
</Empty>
{/if}
</Container>
@@ -10,22 +10,24 @@
import { base } from '$app/paths';
import { collections } from './store';
import { cardLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
let showCreate = false;
let offset = 0;
const project = $page.params.project;
const databaseId = $page.params.database;
const handleCreate = async (event: CustomEvent<Models.Collection>) => {
const offset = createPersistentPagination($cardLimit);
async function handleCreate(event: CustomEvent<Models.Collection>) {
showCreate = false;
await goto(
`${base}/console/project-${project}/databases/database/${databaseId}/collection/${event.detail.$id}`
);
};
}
$: collections.load(databaseId, [
Query.limit($cardLimit),
Query.offset(offset),
Query.offset($offset),
Query.orderDesc('$createdAt')
]);
</script>
@@ -41,7 +43,10 @@
</div>
{#if $collections?.total}
<CardContainer total={$collections.total} {offset} on:click={() => (showCreate = true)}>
<CardContainer
total={$collections.total}
offset={$offset}
on:click={() => (showCreate = true)}>
{#each $collections.collections as collection}
<GridItem1
href={`${base}/console/project-${project}/databases/database/${databaseId}/collection/${collection.$id}`}>
@@ -69,11 +74,18 @@
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$collections.total}</p>
<Pagination limit={$cardLimit} bind:offset sum={$collections.total} />
<Pagination limit={$cardLimit} bind:offset={$offset} sum={$collections.total} />
</div>
{:else}
<Empty isButton single on:click={() => (showCreate = true)}>
<p>Create your first collection to get started</p>
<div class="u-text-center">
<p class="text u-line-height-1-5">Create your first collection to get started</p>
<p class="text u-line-height-1-5">Need a hand? Check out our documentation.</p>
</div>
<div class="u-flex u-gap-12 ">
<Button external href="#/" text>Documentation</Button>
<Button secondary>Create Collection</Button>
</div>
</Empty>
{/if}
</Container>
@@ -18,27 +18,28 @@
import Create from './createDocument.svelte';
import { Query } from '@aw-labs/appwrite-console';
import { pageLimit } from '$lib/stores/layout';
let offset = 0;
import { createPersistentPagination } from '$lib/stores/pagination';
const projectId = $page.params.project;
const databaseId = $page.params.database;
const offset = createPersistentPagination($pageLimit);
function openWizard() {
wizard.start(Create);
}
$: documentList.load(databaseId, $collection.$id, [
Query.limit($pageLimit),
Query.offset(offset),
Query.offset($offset),
Query.orderDesc('$createdAt')
]);
$: columns = [
...$collection.attributes.map((attribute) => ({
key: attribute.key,
title: attribute.key
}))
];
function openWizard() {
wizard.start(Create);
}
</script>
<Container>
@@ -84,7 +85,7 @@
<div class="u-flex common-section u-main-space-between">
<p class="text">Total results: {$documentList.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$documentList.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$documentList.total} />
</div>
{:else}
<Empty isButton single on:click={openWizard}>
@@ -19,14 +19,16 @@
import Delete from './deleteAttribute.svelte';
import Overview from './overview.svelte';
import { pageLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
let offset = 0;
let showDropdown = [];
let selectedAttribute: Attributes = null;
let showCreate = false;
let showDelete = false;
let showOverview = false;
let showCreateIndex = false;
const offset = createPersistentPagination($pageLimit);
</script>
<Container>
@@ -112,7 +114,10 @@
</Table>
<div class="u-flex common-section u-main-space-between">
<p class="text">Total results: {$collection?.attributes?.length}</p>
<Pagination limit={$pageLimit} bind:offset sum={$collection?.attributes?.length} />
<Pagination
limit={$pageLimit}
bind:offset={$offset}
sum={$collection?.attributes?.length} />
</div>
{:else}
<Empty isButton single on:click={() => (showCreate = true)}>
@@ -49,6 +49,10 @@
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
//TODO: refactor to use context module instead of submitted
</script>
@@ -19,6 +19,12 @@
$: if (selectedOption) {
$option = options.find((option) => option.name === selectedOption);
}
$: if (!showCreate) {
key = null;
selectedOption = null;
submitted = false;
}
</script>
<Form on:submit={() => (submitted = true)}>
@@ -51,6 +51,10 @@
({ required, array } = selectedAttribute);
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
</script>
<InputText
@@ -58,6 +58,9 @@
({ required, array, elements } = selectedAttribute);
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
</script>
<InputTags
@@ -55,6 +55,10 @@
({ required, array, min, max } = selectedAttribute);
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
</script>
<InputNumber id="min" label="Min" bind:value={min} readonly={overview} />
@@ -55,6 +55,9 @@
({ required, array, min, max } = selectedAttribute);
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
</script>
<InputNumber id="min" label="Min" bind:value={min} readonly={overview} />
@@ -51,6 +51,9 @@
({ required, array } = selectedAttribute);
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
</script>
<InputText
@@ -53,6 +53,9 @@
({ required, array, size } = selectedAttribute);
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
</script>
<InputNumber id="size" label="Size" bind:value={size} required readonly={overview} />
@@ -51,6 +51,9 @@
({ required, array } = selectedAttribute);
xdefault = selectedAttribute.default;
}
$: if (required) {
xdefault = null;
}
</script>
<InputText
@@ -8,6 +8,7 @@
import { database } from '../store';
import Delete from '../_delete.svelte';
import { onMount } from 'svelte';
import { toLocaleDateTime } from '$lib/helpers/date';
const databaseId = $page.params.database;
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 48, 48).toString();
@@ -54,8 +55,8 @@
</div>
</div>
<div class="grid-1-2-col-2">
<p>Created: TO IMPLEMENT</p>
<p>Last Updated: TO IMPLEMENT</p>
<p>Created: {toLocaleDateTime($database.$createdAt)}</p>
<p>Last Updated: {toLocaleDateTime($database.$updatedAt)}</p>
</div>
</div>
</Card>
@@ -11,19 +11,21 @@
import { bucketList } from './store';
import { tooltip } from '$lib/actions/tooltip';
import { cardLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
let showCreate = false;
let offset = 0;
const project = $page.params.project;
const bucketCreated = async (event: CustomEvent<Models.Bucket>) => {
const offset = createPersistentPagination($cardLimit);
async function bucketCreated(event: CustomEvent<Models.Bucket>) {
showCreate = false;
await goto(`${base}/console/project-${project}/storage/bucket/${event.detail.$id}`);
};
}
$: bucketList.load([
Query.limit($cardLimit),
Query.offset(offset),
Query.offset($offset),
Query.orderDesc('$createdAt')
]);
</script>
@@ -38,7 +40,10 @@
</div>
{#if $bucketList?.total}
<CardContainer total={$bucketList.total} {offset} on:click={() => (showCreate = true)}>
<CardContainer
total={$bucketList.total}
offset={$offset}
on:click={() => (showCreate = true)}>
{#each $bucketList.buckets as bucket}
<GridItem1 href={`${base}/console/project-${project}/storage/bucket/${bucket.$id}`}>
<svelte:fragment slot="eyebrow">XX Files</svelte:fragment>
@@ -86,11 +91,18 @@
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$bucketList.total}</p>
<Pagination limit={$cardLimit} bind:offset sum={$bucketList.total} />
<Pagination limit={$cardLimit} bind:offset={$offset} sum={$bucketList.total} />
</div>
{:else}
<Empty isButton single on:click={() => (showCreate = true)}>
<p>Add your first bucket to get started</p>
<div class="u-text-center">
<p class="text u-line-height-1-5">Create your first bucket to get started</p>
<p class="text u-line-height-1-5">Need a hand? Check out our documentation.</p>
</div>
<div class="u-flex u-gap-12">
<Button external href="#/" text>Documentation</Button>
<Button secondary>Create bucket</Button>
</div>
</Empty>
{/if}
</Container>
@@ -34,50 +34,54 @@
import { uploader } from '$lib/stores/uploader';
import { addNotification } from '$lib/stores/notifications';
import { pageLimit } from '$lib/stores/layout';
import { createPersistentPagination } from '$lib/stores/pagination';
let search = '';
let showCreate = false;
let showDropdown = [];
let showDelete = false;
let showDropdown = [];
let selectedFile: Models.File = null;
let offset = 0;
const project = $page.params.project;
const bucket = $page.params.bucket;
const offset = createPersistentPagination($pageLimit);
const getPreview = (fileId: string) =>
sdkForProject.storage.getFilePreview(bucket, fileId, 32, 32).toString() + '&mode=admin';
const fileCreated = () => {
showCreate = false;
files.load(bucket, [Query.limit($pageLimit), Query.offset(offset)], search);
};
async function loadFiles() {
files.load(bucket, [Query.limit($pageLimit), Query.offset($offset)], search);
}
const fileDeleted = (event: CustomEvent<Models.File>) => {
function fileCreated() {
showCreate = false;
loadFiles();
}
function fileDeleted(event: CustomEvent<Models.File>) {
showDelete = false;
uploader.removeFile(event.detail);
files.load(bucket, [Query.limit($pageLimit), Query.offset(offset)], search);
};
loadFiles();
}
const deleteFile = async (file: Models.File) => {
async function deleteFile(file: Models.File) {
try {
await sdkForProject.storage.deleteFile(file.bucketId, file.$id);
uploader.removeFile(file);
files.load(bucket, [Query.limit($pageLimit), Query.offset(offset)], search);
loadFiles();
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
};
}
$: files.load(
bucket,
[Query.limit($pageLimit), Query.offset(offset), Query.orderDesc('$createdAt')],
[Query.limit($pageLimit), Query.offset($offset), Query.orderDesc('$createdAt')],
search
);
$: if (search) offset = 0;
$: if (search) $offset = 0;
</script>
<Container>
@@ -181,7 +185,7 @@
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$files.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$files.total} />
<Pagination limit={$pageLimit} bind:offset={$offset} sum={$files.total} />
</div>
{:else if search}
<EmptySearch>
@@ -193,7 +197,14 @@
</EmptySearch>
{:else}
<Empty isButton single on:click={() => (showCreate = true)}>
<p>Upload some files to get started</p>
<div class="u-text-center">
<p class="text u-line-height-1-5">Upload some files to get started</p>
<p class="text u-line-height-1-5">Need a hand? Check out our documentation.</p>
</div>
<div class="u-flex u-gap-12 ">
<Button external href="#/" text>Documentation</Button>
<Button secondary>Add file</Button>
</div>
</Empty>
{/if}
</Container>
@@ -85,7 +85,7 @@
<div class="u-grid u-gap-16">
<p>Drag and drop files here to upload</p>
<div>
<Button secondary on:click={input.click}>
<Button secondary on:click={() => input.click()}>
<span class="icon-upload" aria-hidden="true" />
<span class="text">Choose File</span>
</Button>
@@ -257,8 +257,8 @@
will be ignored.
</p>
<svelte:fragment slot="aside">
<ul class="u-flex u-gap-12 common-section">
<li>
<ul class="checkboxes-list">
<li class="checkboxes-item">
<label class="label">
<input
type="radio"
@@ -269,7 +269,7 @@
<span>Bucket Level</span>
</label>
</li>
<li>
<li class="checkboxes-item">
<label class="label">
<input
type="radio"
@@ -295,8 +295,8 @@
<CardGrid>
<h2 class="heading-level-7">Update Security Settings</h2>
<p>
Enable or disable security services for the bucket including <b> Ecryption</b>
and <b> Antivirus scanning.</b>
Enable or disable security services for the bucket including <b>Ecryption</b>
and <b>Antivirus scanning.</b>
</p>
<svelte:fragment slot="aside">
<ul class="form-list">