mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'main' of https://github.com/appwrite/appwrite-console-poc into feat-platforms
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
+7
-7
@@ -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>
|
||||
|
||||
+24
-21
@@ -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>
|
||||
|
||||
+5
-6
@@ -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>
|
||||
|
||||
+13
-11
@@ -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>
|
||||
|
||||
+6
-5
@@ -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>
|
||||
|
||||
+9
-8
@@ -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}>
|
||||
|
||||
+7
-2
@@ -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)}>
|
||||
|
||||
+4
@@ -49,6 +49,10 @@
|
||||
xdefault = selectedAttribute.default;
|
||||
}
|
||||
|
||||
$: if (required) {
|
||||
xdefault = null;
|
||||
}
|
||||
|
||||
//TODO: refactor to use context module instead of submitted
|
||||
</script>
|
||||
|
||||
|
||||
+6
@@ -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)}>
|
||||
|
||||
+4
@@ -51,6 +51,10 @@
|
||||
({ required, array } = selectedAttribute);
|
||||
xdefault = selectedAttribute.default;
|
||||
}
|
||||
|
||||
$: if (required) {
|
||||
xdefault = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputText
|
||||
|
||||
+3
@@ -58,6 +58,9 @@
|
||||
({ required, array, elements } = selectedAttribute);
|
||||
xdefault = selectedAttribute.default;
|
||||
}
|
||||
$: if (required) {
|
||||
xdefault = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputTags
|
||||
|
||||
+4
@@ -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} />
|
||||
|
||||
+3
@@ -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} />
|
||||
|
||||
+3
@@ -51,6 +51,9 @@
|
||||
({ required, array } = selectedAttribute);
|
||||
xdefault = selectedAttribute.default;
|
||||
}
|
||||
$: if (required) {
|
||||
xdefault = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputText
|
||||
|
||||
+3
@@ -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} />
|
||||
|
||||
+3
@@ -51,6 +51,9 @@
|
||||
({ required, array } = selectedAttribute);
|
||||
xdefault = selectedAttribute.default;
|
||||
}
|
||||
$: if (required) {
|
||||
xdefault = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputText
|
||||
|
||||
+3
-2
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user