Skip to content

Commit

Permalink
Add wizard for creating provider
Browse files Browse the repository at this point in the history
  • Loading branch information
stnguyen90 committed Oct 26, 2023
1 parent 8fa7408 commit 30f06ab
Show file tree
Hide file tree
Showing 13 changed files with 639 additions and 84 deletions.
5 changes: 4 additions & 1 deletion src/lib/actions/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,5 +282,8 @@ export enum Submit {
SmsResetTemplate = 'submit_sms_reset_template',
SmsUpdateInviteTemplate = 'submit_sms_update_invite_template',
SmsUpdateLoginTemplate = 'submit_sms_update_login_template',
SmsUpdateVerificationTemplate = 'submit_sms_update_verification_template'
SmsUpdateVerificationTemplate = 'submit_sms_update_verification_template',
MessagingProviderCreate = 'submit_messaging_provider_create',
MessagingProviderDelete = 'submit_messaging_provider_delete',
MessagingProviderUpdate = 'submit_messaging_provider_update'
}
11 changes: 11 additions & 0 deletions src/lib/components/labelCard.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<script lang="ts">
import { app } from '$lib/stores/app';
import { base } from '$app/paths';
export let name: string;
export let group: string;
export let value: string | number | boolean;
export let disabled = false;
export let padding = 1;
export let icon: string = null;
export let imageIcon: string = null;
export let fullHeight = true;
export let borderRadius: 'xsmall' | 'small' | 'medium' | 'large' = 'small';
export let backgroundColor: string = null;
Expand Down Expand Up @@ -47,5 +51,12 @@
{#if icon}
<span class={`icon-${icon} u-margin-inline-start-auto`} aria-hidden="true" />
{/if}
{#if imageIcon}
<img
class="u-margin-inline-start-auto"
style:--p-text-size="1.25rem"
src={`${base}/icons/${$app.themeInUse}/color/${imageIcon}.svg`}
alt={imageIcon} />
{/if}
</div>
</label>
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,30 @@
Id,
ViewSelector
} from '$lib/components';
import Create from './create.svelte';
import { goto } from '$app/navigation';
import { Container } from '$lib/layout';
import { base } from '$app/paths';
import type { Models } from '@appwrite.io/console';
import type { PageData } from './$types';
import { showCreate, columns } from './store';
import { columns } from './store';
import { Pill } from '$lib/elements';
import Filters from '../../databases/database-[database]/collection-[collection]/(filters)/filters.svelte';
import CreateProviderDropdown from './createProviderDropdown.svelte';
export let data: PageData;
let showCreateDropdownMobile = false;
let showCreateDropdownDesktop = false;
let showCreateDropdownEmpty = false;
let selected: string[] = [];
const project = $page.params.project;
const topicCreated = async (event: CustomEvent<Models.Team<Record<string, unknown>>>) => {
await goto(`${base}/console/project-${project}/messaging/topics/topic-${event.detail.$id}`);
};
</script>

<Container>
<div class="u-flex u-flex-vertical">
<div class="u-flex u-main-space-between">
<Heading tag="h2" size="5">Providers</Heading>
<div class="is-only-mobile">
<Button on:click={() => ($showCreate = true)} event="create_provider">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create provider</span>
</Button>
<CreateProviderDropdown bind:showCreateDropdown={showCreateDropdownMobile} />
</div>
</div>
<!-- TODO: fix width of search input in mobile -->
Expand All @@ -64,10 +60,7 @@
hideView
allowNoColumns
showColsTextMobile />
<Button on:click={() => ($showCreate = true)} event="create_provider">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create provider</span>
</Button>
<CreateProviderDropdown bind:showCreateDropdown={showCreateDropdownDesktop} />
</div>
</SearchQuery>
<div class="u-flex u-gap-16 is-only-mobile u-margin-block-start-16">
Expand Down Expand Up @@ -148,7 +141,7 @@
limit={data.limit}
offset={data.offset}
total={data.providers.total} />
{:else if data.search}
{:else if data.search && data.search != 'empty'}
<EmptySearch>
<div class="u-text-center">
<b>Sorry, we couldn't find '{data.search}'</b>
Expand All @@ -160,11 +153,33 @@
</EmptySearch>
{:else}
<!-- TODO: Update docs links -->
<Empty
single
href="https://appwrite.io/docs/references/cloud/client-web/providers"
target="provider" />
<Empty single target="provider">
<div class="u-text-center">
<Heading size="7" tag="h2" trimmed={false}>
Create your first provider to get started.
</Heading>
<p class="body-text-2 u-bold u-margin-block-start-4">
Need a hand? Learn more in our documentation.
</p>
</div>
<div class="u-flex u-flex-wrap u-gap-16 u-main-center">
<Button
external
href="https://appwrite.io/docs/references/cloud/client-web/providers"
text
event="empty_documentation"
ariaLabel={`create provider`}>
Documentation
</Button>
<CreateProviderDropdown bind:showCreateDropdown={showCreateDropdownEmpty}>
<Button
secondary
on:click={() => (showCreateDropdownEmpty = !showCreateDropdownEmpty)}
event="create_provider">
<span class="text">Create provider</span>
</Button>
</CreateProviderDropdown>
</div>
</Empty>
{/if}
</Container>

<Create bind:showCreate={$showCreate} on:created={topicCreated} />
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,34 @@ export const load = async ({ url, route }) => {
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);

// TODO: get rid of demo data
let providers: { providers: Provider[]; total: number } = { providers: [], total: 0 };
if (search == 'demo') {
providers = data;
} else {
const response = await sdk.forProject.client.call(
'GET',
new URL(sdk.forProject.client.config.endpoint + '/messaging/providers'),
{
'X-Appwrite-Project': sdk.forProject.client.config.project,
'content-type': 'application/json',
'X-Appwrite-Mode': 'admin'
},
{
queries: [Query.limit(limit), Query.offset(offset), Query.orderDesc('')],
search: search
}
);

providers = response;
}

return {
offset,
limit,
search,
page,
view,
providers: data
providers
};
};
175 changes: 120 additions & 55 deletions src/routes/console/project-[project]/messaging/providers/create.svelte
Original file line number Diff line number Diff line change
@@ -1,68 +1,133 @@
<script lang="ts">
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { Modal, CustomId } from '$lib/components';
import { Pill } from '$lib/elements';
import { InputText, Button, FormList } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { onDestroy } from 'svelte';
import { Wizard } from '$lib/layout';
import type { WizardStepsType } from '$lib/layout/wizard.svelte';
import Step1 from './wizard/step1.svelte';
import Step2 from './wizard/step2.svelte';
import Step3 from './wizard/step3.svelte';
import Step4 from './wizard/step4.svelte';
import { sdk } from '$lib/stores/sdk';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { addNotification } from '$lib/stores/notifications';
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { project } from '../../store';
import { wizard } from '$lib/stores/wizard';
import { provider, providerParams } from './wizard/store';
import { ID } from '@appwrite.io/console';
import { createEventDispatcher } from 'svelte';
export let showCreate = false;
const dispatch = createEventDispatcher();
let name: string, id: string, error: string;
let showCustomId = false;
const create = async () => {
async function create() {
try {
const team = await sdk.forProject.teams.create(id ?? ID.unique(), name);
name = '';
showCreate = false;
showCustomId = false;
let response = { $id: '', name: '' };
const providerId = $providerParams[$provider].providerId || ID.unique();
switch ($provider) {
case 'twilio':
response = await sdk.forProject.client.call(
'POST',
new URL(
sdk.forProject.client.config.endpoint + '/messaging/providers/twilio'
),
{
'X-Appwrite-Project': sdk.forProject.client.config.project,
'content-type': 'application/json',
'X-Appwrite-Mode': 'admin'
},
{
providerId: providerId,
name: $providerParams[$provider].name,
default: $providerParams[$provider].default,
enabled: $providerParams[$provider].enabled,
accountSid: '',
authToken: ''
}
);
break;
case 'mailgun':
response = await sdk.forProject.client.call(
'POST',
new URL(
sdk.forProject.client.config.endpoint + '/messaging/providers/mailgun'
),
{
'X-Appwrite-Project': sdk.forProject.client.config.project,
'content-type': 'application/json',
'X-Appwrite-Mode': 'admin'
},
{
providerId: providerId,
name: $providerParams[$provider].name,
default: $providerParams[$provider].default,
enabled: $providerParams[$provider].enabled,
isEuRegion: $providerParams[$provider].isEuRegion,
from: $providerParams[$provider].from,
apiKey: $providerParams[$provider].apiKey,
domain: $providerParams[$provider].domain
}
);
break;
case 'fcm':
response = await sdk.forProject.client.call(
'POST',
new URL(
sdk.forProject.client.config.endpoint + '/messaging/providers/mailgun'
),
{
'X-Appwrite-Project': sdk.forProject.client.config.project,
'content-type': 'application/json',
'X-Appwrite-Mode': 'admin'
},
{
providerId: providerId,
name: $providerParams[$provider].name,
default: $providerParams[$provider].default,
enabled: $providerParams[$provider].enabled,
serverKey: ''
}
);
break;
}
wizard.hide();
addNotification({
type: 'success',
message: `${team.name} has been created`
message: `${response.name} has been created`
});
trackEvent(Submit.TeamCreate, {
customId: !!id
trackEvent(Submit.MessagingProviderCreate);
await goto(
`${base}/console/project-${$project.$id}/messaging/providers/provider-${response.$id}`
);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
dispatch('created', team);
} catch (e) {
error = e.message;
trackError(e, Submit.TeamCreate);
trackError(error, Submit.MessagingProviderCreate);
}
};
$: if (!showCreate) {
showCustomId = false;
error = null;
}
onDestroy(() => {
console.log('destroy');
});
const stepsComponents: WizardStepsType = new Map();
stepsComponents.set(1, {
label: 'Proivder',
component: Step1
});
stepsComponents.set(2, {
label: 'Initialize',
component: Step2
// optional: true
});
stepsComponents.set(3, {
label: 'Configure',
component: Step3
// optional: true
});
stepsComponents.set(4, {
label: 'Finalize',
component: Step4
// optional: true
});
</script>

<Modal title="Create team" {error} size="big" bind:show={showCreate} onSubmit={create}>
<FormList>
<InputText
id="name"
label="Name"
placeholder="Enter name"
autofocus={true}
required
bind:value={name} />
{#if !showCustomId}
<div>
<Pill button on:click={() => (showCustomId = !showCustomId)}
><span class="icon-pencil" aria-hidden="true" />
<span class="text"> Team ID </span>
</Pill>
</div>
{:else}
<CustomId bind:show={showCustomId} name="Team" bind:id />
{/if}
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showCreate = false)}>Cancel</Button>
<Button submit>Create</Button>
</svelte:fragment>
</Modal>
<Wizard title="Create provider" steps={stepsComponents} on:finish={create} />
Loading

0 comments on commit 30f06ab

Please sign in to comment.