mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
fix: create webhook wizard
This commit is contained in:
@@ -13,6 +13,7 @@ Sentry.init({
|
||||
|
||||
export const handleError: HandleClientError = Sentry.handleErrorWithSentry(
|
||||
async ({ error, message, status }) => {
|
||||
console.error(error);
|
||||
if (error instanceof AppwriteException) {
|
||||
status = error.code === 0 ? undefined : error.code;
|
||||
message = error.message;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
export let single = false;
|
||||
export let target: string = null;
|
||||
export let href: string = null;
|
||||
export let marginTop = false;
|
||||
export let allowCreate = true;
|
||||
export let description = 'Need a hand? Learn more in our documentation.';
|
||||
export let src: string = null;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
export let noStyle = false;
|
||||
export let isModal = false;
|
||||
export let onSubmit: (e: SubmitEvent) => Promise<void> | void;
|
||||
export let onSubmit: (e: SubmitEvent) => Promise<unknown> | unknown;
|
||||
let classes = '';
|
||||
export { classes as class };
|
||||
|
||||
|
||||
@@ -59,11 +59,11 @@
|
||||
EmailTemplateType,
|
||||
EmailTemplateLocale
|
||||
} from '@appwrite.io/console';
|
||||
import { Accordion, Layout, Alert, Tag, Badge, Link } from '@appwrite.io/pink-svelte';
|
||||
import { Accordion, Layout, Alert, Badge, Link, Typography } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
let emailOpen = 'verification';
|
||||
let emailOpen = null;
|
||||
$: emailVerificationOpen = emailOpen === 'verification';
|
||||
$: emailMagicSessionOpen = emailOpen === 'magicSession';
|
||||
$: emailOtpSessionOpen = emailOpen === 'otpSession';
|
||||
@@ -72,27 +72,13 @@
|
||||
$: email2FAVerificationOpen = emailOpen === 'mfaChallenge';
|
||||
$: emailSessionAlertOpen = emailOpen === 'sessionAlert';
|
||||
|
||||
// let smsOpen = 'verification';
|
||||
// $: smsVerificationOpen = smsOpen === 'verification';
|
||||
// $: smsLoginOpen = smsOpen === 'login';
|
||||
// $: smsInvitationOpen = smsOpen === 'invitation';
|
||||
|
||||
onMount(async () => {
|
||||
openEmail('verification');
|
||||
// openSms('verification');
|
||||
});
|
||||
openEmail('verification');
|
||||
|
||||
async function openEmail(type: string) {
|
||||
type === emailOpen ? (emailOpen = null) : (emailOpen = type);
|
||||
$emailTemplate = await loadEmailTemplate(data.project.$id, type, 'en');
|
||||
$baseEmailTemplate = { ...$emailTemplate };
|
||||
}
|
||||
|
||||
// async function openSms(type: string) {
|
||||
// type === smsOpen ? (smsOpen = null) : (smsOpen = type);
|
||||
// $smsTemplate = await loadSmsTemplate(projectId, type, 'en');
|
||||
// $baseSmsTemplate = { ...$smsTemplate };
|
||||
// }
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
@@ -113,8 +99,9 @@
|
||||
{/if}
|
||||
|
||||
<CardGrid>
|
||||
<svelte:fragment slot="title"
|
||||
>Email templates <Badge variant="secondary" content="Experimental" /></svelte:fragment>
|
||||
<svelte:fragment slot="title">
|
||||
Email templates <Badge variant="secondary" content="Experimental" />
|
||||
</svelte:fragment>
|
||||
Use templates to send and process account management emails.
|
||||
<Link.Anchor href="https://appwrite.io/docs/advanced/platform/message-templates">
|
||||
Learn more
|
||||
@@ -124,16 +111,16 @@
|
||||
<Accordion
|
||||
title="Verification"
|
||||
bind:open={emailVerificationOpen}
|
||||
on:click={(e) => {
|
||||
// preventing default and propagation to open the collapsible correctly
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
openEmail('verification');
|
||||
}}>
|
||||
Send a verification email to users that sign in with their email and password.
|
||||
<EmailVerificationTemplate />
|
||||
on:click={() => openEmail('verification')}>
|
||||
<Layout.Stack>
|
||||
<Typography.Text>
|
||||
Send a verification email to users that sign in with their email and
|
||||
password.
|
||||
</Typography.Text>
|
||||
<EmailVerificationTemplate />
|
||||
</Layout.Stack>
|
||||
</Accordion>
|
||||
<Accordion
|
||||
<!-- <Accordion
|
||||
title="Magic URL"
|
||||
bind:open={emailMagicSessionOpen}
|
||||
on:click={(e) => {
|
||||
@@ -192,7 +179,7 @@
|
||||
}}>
|
||||
Send an email to users when a new session is created.
|
||||
<EmailSessionAlertTemplate />
|
||||
</Accordion>
|
||||
</Accordion> -->
|
||||
</Layout.Stack>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
@@ -201,55 +188,6 @@
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<!-- <CardGrid>
|
||||
<Heading size="7" tag="h3">SMS templates</Heading>
|
||||
<p class="text">
|
||||
Use templates to send and process account management mobile messages. <a
|
||||
href="https://appwrite.io/docs/advanced/platform/message-templates"
|
||||
class="link">
|
||||
Learn more about SMS templates</a
|
||||
</p>
|
||||
|
||||
<svelte:fragment slot="aside">
|
||||
<Collapsible>
|
||||
<CollapsibleItem
|
||||
bind:open={smsVerificationOpen}
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
openSms('verification');
|
||||
}}>
|
||||
<svelte:fragment slot="title">Verification</svelte:fragment>
|
||||
<p class="text">
|
||||
Send a verification SMS to users that sign in with their phone
|
||||
</p>
|
||||
<SmsVerificationTemplate />
|
||||
</CollapsibleItem>
|
||||
<CollapsibleItem
|
||||
bind:open={smsLoginOpen}
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
openSms('login');
|
||||
}}>
|
||||
<svelte:fragment slot="title">Login</svelte:fragment>
|
||||
<p class="text">
|
||||
Send a one-time passcode to users' mobile phones to allow them to sign in.
|
||||
</p>
|
||||
<SmsLoginTemplate />
|
||||
</CollapsibleItem>
|
||||
<CollapsibleItem
|
||||
bind:open={smsInvitationOpen}
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
openSms('invitation');
|
||||
}}>
|
||||
<svelte:fragment slot="title">Invitation</svelte:fragment>
|
||||
<p class="text">Send an invitation SMS to become a member of your project.</p>
|
||||
<SmsLoginTemplate />
|
||||
</CollapsibleItem>
|
||||
</Collapsible>
|
||||
</svelte:fragment>
|
||||
</CardGrid>-->
|
||||
{#if isCloud && $currentPlan.emailBranding}
|
||||
<EmailSignature />
|
||||
{/if}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<EmailTemplate bind:loading>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
<Id value={'{{project}}'}>{'{{project}}'}</Id>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<EmailTemplate bind:loading>
|
||||
<Id value={'{{team}}'}>{'{{team}}'}</Id>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<EmailTemplate bind:loading>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
<Id value={'{{project}}'}>{'{{project}}'}</Id>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<EmailTemplate bind:loading>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
<Id value={'{{project}}'}>{'{{project}}'}</Id>
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<EmailTemplate bind:loading>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
<Id value={'{{project}}'}>{'{{project}}'}</Id>
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
FormList,
|
||||
InputEmail,
|
||||
InputText,
|
||||
InputTextarea
|
||||
} from '$lib/elements/forms';
|
||||
import { Button, Form, InputEmail, InputText, InputTextarea } from '$lib/elements/forms';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { project } from '../../store';
|
||||
@@ -14,9 +7,8 @@
|
||||
import { baseEmailTemplate, emailTemplate } from './store';
|
||||
import deepEqual from 'deep-equal';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { Box } from '$lib/components';
|
||||
import type { EmailTemplateLocale, EmailTemplateType } from '@appwrite.io/console';
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
import { Card, Layout } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let loading = false;
|
||||
let openResetModal = false;
|
||||
@@ -87,11 +79,10 @@
|
||||
}
|
||||
|
||||
$: isButtonDisabled = deepEqual($emailTemplate, $baseEmailTemplate);
|
||||
|
||||
$: isSmtpEnabled = $project?.smtpEnabled;
|
||||
</script>
|
||||
|
||||
<Box class="u-position-relative">
|
||||
<Card.Base variant="secondary" padding="s">
|
||||
{#if loading}
|
||||
<div
|
||||
class="u-position-absolute u-width-full-line u-flex u-flex-vertical u-main-center u-cross-center u-gap-16 u-margin-block-start-32"
|
||||
@@ -107,16 +98,14 @@
|
||||
id="senderName"
|
||||
label="Sender name"
|
||||
bind:value={$emailTemplate.senderName}
|
||||
tooltip="Set up an SMTP server to edit the sender name"
|
||||
placeholder="Enter sender name"
|
||||
readonly={!isSmtpEnabled} />
|
||||
disabled={!isSmtpEnabled} />
|
||||
<InputEmail
|
||||
bind:value={$emailTemplate.senderEmail}
|
||||
id="senderEmail"
|
||||
label="Sender email"
|
||||
tooltip="Set up an SMTP server to edit the sender email"
|
||||
placeholder="Enter sender email"
|
||||
readonly={!isSmtpEnabled} />
|
||||
disabled={!isSmtpEnabled} />
|
||||
<InputEmail
|
||||
bind:value={$emailTemplate.replyTo}
|
||||
id="replyTo"
|
||||
@@ -154,6 +143,6 @@
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</Box>
|
||||
</Card.Base>
|
||||
|
||||
<ResetEmail bind:show={openResetModal} />
|
||||
|
||||
+4
-3
@@ -7,6 +7,7 @@
|
||||
import { Id } from '$lib/components';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
|
||||
const projectId = $page.params.project;
|
||||
|
||||
@@ -35,12 +36,12 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<Layout.Stack>
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
|
||||
<EmailTemplate bind:loading>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
<Id value={'{{project}}'}>{'{{project}}'}</Id>
|
||||
<Id value={'{{redirect}}'}>{'{{redirect}}'}</Id>
|
||||
</EmailTemplate>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { Box } from '$lib/components';
|
||||
import { Input } from '@appwrite.io/pink-svelte';
|
||||
import { Card, Input } from '@appwrite.io/pink-svelte';
|
||||
import { localeCodes } from './store';
|
||||
|
||||
export let value = 'en';
|
||||
@@ -11,21 +10,14 @@
|
||||
}));
|
||||
</script>
|
||||
|
||||
<Box radius="small" class="u-flex u-gap-16 u-cross-center">
|
||||
<div class="u-un-break-text is-not-mobile">
|
||||
<span class="icon-translate" />
|
||||
<span class="text">Template language</span>
|
||||
</div>
|
||||
<Input.Combobox
|
||||
on:select
|
||||
<Card.Base variant="secondary" padding="s">
|
||||
<Input.ComboBox
|
||||
label="Template language"
|
||||
on:change
|
||||
id="language"
|
||||
placeholder="Select a language"
|
||||
name="locale"
|
||||
bind:value
|
||||
required
|
||||
fullWidth
|
||||
stretch={false}
|
||||
showLabel={false}
|
||||
interactiveOutput
|
||||
{options} />
|
||||
</Box>
|
||||
</Card.Base>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<SmsTemplate bind:loading>
|
||||
<Id value={'{{team}}'}>{'{{team}}'}</Id>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<SmsTemplate bind:loading>
|
||||
<Id value={'{{team}}'}>{'{{team}}'}</Id>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
</script>
|
||||
|
||||
<div class="boxes-wrapper u-margin-block-start-16">
|
||||
<LocaleOptions on:select={onLocaleChange} bind:value={locale} />
|
||||
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
|
||||
<SmsTemplate bind:loading>
|
||||
<Id value={'{{team}}'}>{'{{team}}'}</Id>
|
||||
<Id value={'{{user}}'}>{'{{user}}'}</Id>
|
||||
|
||||
+39
-81
@@ -9,7 +9,7 @@
|
||||
import { preferences } from '$lib/stores/preferences';
|
||||
import { canWriteCollections, canWriteDocuments } from '$lib/stores/roles';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import { Icon } from '@appwrite.io/pink-svelte';
|
||||
import { Card, Icon, Layout, Empty as PinkEmpty } from '@appwrite.io/pink-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import CreateAttributeDropdown from './attributes/createAttributeDropdown.svelte';
|
||||
import type { Option } from './attributes/store';
|
||||
@@ -22,7 +22,6 @@
|
||||
export let data: PageData;
|
||||
|
||||
let showCreateAttribute = false;
|
||||
let showCreateDropdown = false;
|
||||
let selectedAttribute: Option['name'] = null;
|
||||
|
||||
$: selected = preferences.getCustomCollectionColumns($page.params.collection);
|
||||
@@ -50,9 +49,13 @@
|
||||
|
||||
{#key $page.params.collection}
|
||||
<Container>
|
||||
<div class="heading-grid u-main-justify-between u-cross-center">
|
||||
<Heading tag="h2" size="5">Documents</Heading>
|
||||
<div class="u-flex u-main-end is-only-mobile">
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Filters
|
||||
query={data.query}
|
||||
{columns}
|
||||
disabled={!(hasAttributes && hasValidAttributes)} />
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<ViewSelector view={data.view} {columns} hideView allowNoColumns />
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
@@ -60,32 +63,8 @@
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create document
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Filters
|
||||
query={data.query}
|
||||
{columns}
|
||||
disabled={!(hasAttributes && hasValidAttributes)} />
|
||||
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<ViewSelector
|
||||
view={data.view}
|
||||
{columns}
|
||||
isCustomCollection
|
||||
hideView
|
||||
allowNoColumns
|
||||
showColsTextMobile />
|
||||
<div class="is-not-mobile">
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
event="create_document">
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create document
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
|
||||
{#if hasAttributes && hasValidAttributes}
|
||||
{#if data.documents.total}
|
||||
@@ -124,57 +103,36 @@
|
||||
on:click={openWizard} />
|
||||
{/if}
|
||||
{:else}
|
||||
<Empty
|
||||
allowCreate={$canWriteCollections}
|
||||
single
|
||||
target="attribute"
|
||||
on:click={() => (showCreateDropdown = true)}>
|
||||
<div class="u-text-center">
|
||||
<Heading size="7" tag="h2">Create an attribute 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-gap-16 u-main-center">
|
||||
<Button
|
||||
external
|
||||
href="https://appwrite.io/docs/products/databases/collections#attributes"
|
||||
text
|
||||
event="empty_documentation"
|
||||
ariaLabel={`create {target}`}>Documentation</Button>
|
||||
{#if $canWriteCollections}
|
||||
<CreateAttributeDropdown
|
||||
bind:showCreateDropdown
|
||||
bind:showCreate={showCreateAttribute}
|
||||
bind:selectedOption={selectedAttribute}>
|
||||
<Button
|
||||
secondary
|
||||
event="create_attribute"
|
||||
on:click={() => {
|
||||
showCreateDropdown = !showCreateDropdown;
|
||||
}}>
|
||||
Create attribute
|
||||
</Button>
|
||||
</CreateAttributeDropdown>
|
||||
{/if}
|
||||
</div>
|
||||
</Empty>
|
||||
<Card.Base padding="none">
|
||||
<PinkEmpty
|
||||
title="Create an attribute to get started."
|
||||
description="Need a hand? Learn more in our documentation.">
|
||||
<slot name="actions" slot="actions">
|
||||
<Button
|
||||
external
|
||||
href="https://appwrite.io/docs/products/databases/collections#attributes"
|
||||
text
|
||||
event="empty_documentation"
|
||||
size="s">Documentation</Button>
|
||||
{#if $canWriteCollections}
|
||||
<CreateAttributeDropdown
|
||||
bind:selectedOption={selectedAttribute}
|
||||
bind:showCreate={showCreateAttribute}
|
||||
let:toggle>
|
||||
<Button secondary event="create_attribute" on:click={toggle}>
|
||||
Create attribute
|
||||
</Button>
|
||||
</CreateAttributeDropdown>
|
||||
{/if}
|
||||
</slot>
|
||||
</PinkEmpty>
|
||||
</Card.Base>
|
||||
{/if}
|
||||
</Container>
|
||||
{/key}
|
||||
|
||||
<CreateAttribute bind:showCreate={showCreateAttribute} bind:selectedOption={selectedAttribute} />
|
||||
|
||||
<style lang="scss">
|
||||
.heading-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:global(h2) {
|
||||
grid-column: span 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{#if showCreateAttribute}
|
||||
<CreateAttribute
|
||||
bind:showCreate={showCreateAttribute}
|
||||
bind:selectedOption={selectedAttribute} />
|
||||
{/if}
|
||||
|
||||
+17
-7
@@ -36,6 +36,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { InputChoice, InputSelect } from '$lib/elements/forms';
|
||||
import InputCheckbox from '$lib/elements/forms/inputCheckbox.svelte';
|
||||
|
||||
export let editing = false;
|
||||
export let data: Partial<Models.AttributeBoolean> = {
|
||||
@@ -45,6 +46,7 @@
|
||||
};
|
||||
|
||||
import { createConservative } from '$lib/helpers/stores';
|
||||
import { Selector } from '@appwrite.io/pink-svelte';
|
||||
|
||||
let savedDefault = data.default;
|
||||
|
||||
@@ -81,10 +83,18 @@
|
||||
{ label: 'False', value: false }
|
||||
]}
|
||||
bind:value={data.default} />
|
||||
<InputChoice id="required" label="Required" bind:value={data.required} disabled={data.array}>
|
||||
Indicate whether this is a required attribute
|
||||
</InputChoice>
|
||||
<InputChoice id="array" label="Array" bind:value={data.array} disabled={data.required || editing}>
|
||||
Indicate whether this attribute should act as an array, with the default value set as an empty
|
||||
array.
|
||||
</InputChoice>
|
||||
<Selector.Checkbox
|
||||
size="s"
|
||||
id="required"
|
||||
label="Required"
|
||||
bind:checked={data.required}
|
||||
disabled={data.array}
|
||||
description="Indicate whether this attribute is required" />
|
||||
<Selector.Checkbox
|
||||
size="s"
|
||||
id="array"
|
||||
label="Array"
|
||||
bind:checked={data.array}
|
||||
disabled={data.required || editing}
|
||||
description="Indicate whether this attribute should act as an array, with the default value set as an empty
|
||||
array." />
|
||||
|
||||
+22
-46
@@ -66,53 +66,29 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
{error}
|
||||
size="big"
|
||||
bind:show={showCreate}
|
||||
onSubmit={submit}
|
||||
icon={$option?.icon}
|
||||
iconNotMobile={selectedOption === 'Relationship'}>
|
||||
<svelte:fragment slot="title">
|
||||
{#if selectedOption === 'Relationship'}
|
||||
<span class="u-flex u-gap-16 u-cross-center">
|
||||
{selectedOption}
|
||||
<div class="tag eyebrow-heading-3">
|
||||
<span class="text u-x-small">Experimental</span>
|
||||
</div>
|
||||
</span>
|
||||
{:else}
|
||||
{selectedOption}
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<FormList>
|
||||
{#if selectedOption !== 'Relationship'}
|
||||
<div>
|
||||
<InputText
|
||||
id="key"
|
||||
label="Attribute Key"
|
||||
placeholder="Enter Key"
|
||||
bind:value={key}
|
||||
autofocus
|
||||
required />
|
||||
|
||||
<div class="u-flex u-gap-4 u-margin-block-start-8 u-small">
|
||||
<span
|
||||
class="icon-info u-cross-center u-margin-block-start-2 u-line-height-1 u-icon-small"
|
||||
aria-hidden="true" />
|
||||
<span class="text u-line-height-1-5">
|
||||
Allowed characters: alphanumeric, hyphen, non-leading underscore, period.
|
||||
</span>
|
||||
</div>
|
||||
<Modal {error} bind:show={showCreate} onSubmit={submit} title={selectedOption}>
|
||||
{#if selectedOption !== 'Relationship'}
|
||||
<div>
|
||||
<InputText
|
||||
id="key"
|
||||
label="Attribute Key"
|
||||
placeholder="Enter Key"
|
||||
bind:value={key}
|
||||
autofocus
|
||||
required />
|
||||
<div class="u-flex u-gap-4 u-margin-block-start-8 u-small">
|
||||
<span
|
||||
class="icon-info u-cross-center u-margin-block-start-2 u-line-height-1 u-icon-small"
|
||||
aria-hidden="true" />
|
||||
<span class="text u-line-height-1-5">
|
||||
Allowed characters: alphanumeric, hyphen, non-leading underscore, period.
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
{#if selectedOption}
|
||||
<svelte:component
|
||||
this={$option.component}
|
||||
bind:data
|
||||
on:close={() => ($option = null)} />
|
||||
{/if}
|
||||
</FormList>
|
||||
</div>
|
||||
{/if}
|
||||
{#if selectedOption}
|
||||
<svelte:component this={$option.component} bind:data on:close={() => ($option = null)} />
|
||||
{/if}
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (showCreate = false)}>Cancel</Button>
|
||||
<Button submit disabled={!selectedOption}>Create</Button>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { registerCommands, updateCommandGroupRanks } from '$lib/commandCenter';
|
||||
import { canWriteProjects } from '$lib/stores/roles';
|
||||
import { openWebhooksWizard } from './webhooks/+page.svelte';
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
|
||||
$: $registerCommands([
|
||||
@@ -11,7 +12,7 @@
|
||||
icon: IconPlus,
|
||||
keys: $page.url.pathname.includes('webhooks') ? ['c'] : ['c', 'w'],
|
||||
callback: () => {
|
||||
openWebhooksWizard();
|
||||
goto(`${base}/project-${$page.params.project}/settings/webhooks/create`);
|
||||
},
|
||||
group: 'webhooks',
|
||||
disabled: !$canWriteProjects
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
import UpdateInstallations from './updateInstallations.svelte';
|
||||
import UpdateVariables from '../updateVariables.svelte';
|
||||
import DeleteProject from './deleteProject.svelte';
|
||||
import { CardGrid, Heading } from '$lib/components';
|
||||
import { Button, FormList, InputSelect } from '$lib/elements/forms';
|
||||
import { CardGrid } from '$lib/components';
|
||||
import { Button, InputSelect } from '$lib/elements/forms';
|
||||
import { Submit, trackEvent } from '$lib/actions/analytics';
|
||||
import Transfer from './transferProject.svelte';
|
||||
import { canWriteProjects } from '$lib/stores/roles';
|
||||
|
||||
+6
-10
@@ -3,7 +3,6 @@
|
||||
import { page } from '$app/stores';
|
||||
import { Wizard } from '$lib/layout';
|
||||
import {
|
||||
Alert,
|
||||
Card,
|
||||
Fieldset,
|
||||
Icon,
|
||||
@@ -15,14 +14,12 @@
|
||||
import Button from '$lib/elements/forms/button.svelte';
|
||||
import Form from '$lib/elements/forms/form.svelte';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { onboarding } from '$routes/(console)/project-[project]/store';
|
||||
import { goto, invalidate } from '$app/navigation';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { writable } from 'svelte/store';
|
||||
import Retry from '$lib/pages/domains/wizard/retry.svelte';
|
||||
import Box from '$lib/components/box.svelte';
|
||||
import { IconClock } from '@appwrite.io/pink-icons-svelte';
|
||||
|
||||
let retrying = false;
|
||||
@@ -67,17 +64,16 @@
|
||||
column>
|
||||
<Form {onSubmit} bind:isSubmitting>
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card.Base padding="s"
|
||||
><Layout.Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Layout.Stack gap="xxs" direction="row">
|
||||
<Typography.Text variant="m-500">{data.domain.domain}</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<Card.Base padding="s">
|
||||
<Layout.Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Typography.Text variant="m-500">{data.domain.domain}</Typography.Text>
|
||||
<Button
|
||||
secondary
|
||||
size="s"
|
||||
href={`${base}/project-${$page.params.project}/settings/domains/create?domain=${data.domain.domain}&$id=${data.domain.$id}`}
|
||||
>Change</Button>
|
||||
</Layout.Stack></Card.Base>
|
||||
</Layout.Stack>
|
||||
</Card.Base>
|
||||
<Fieldset legend="DNS">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack>
|
||||
|
||||
@@ -1,55 +1,27 @@
|
||||
<script lang="ts" context="module">
|
||||
export function openWebhooksWizard() {
|
||||
if (!get(canWriteWebhooks)) {
|
||||
return;
|
||||
}
|
||||
wizard.start(Create);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { Empty, Id } from '$lib/components';
|
||||
import {
|
||||
TableBody,
|
||||
TableRowLink,
|
||||
TableCellHead,
|
||||
TableCell,
|
||||
TableCellText,
|
||||
TableHeader,
|
||||
TableScroll
|
||||
} from '$lib/elements/table';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import { Container } from '$lib/layout';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import type { PageData } from './$types';
|
||||
import { columns } from './store';
|
||||
import { updateCommandGroupRanks } from '$lib/commandCenter';
|
||||
import { type Models } from '@appwrite.io/console';
|
||||
import Create from './createWebhook.svelte';
|
||||
import FailedModal from './failedModal.svelte';
|
||||
import MessageStatusPill from './messageStatusPill.svelte';
|
||||
import { canWriteWebhooks } from '$lib/stores/roles';
|
||||
import { get } from 'svelte/store';
|
||||
import { Badge, Icon, Layout, Link, Status, Table } from '@appwrite.io/pink-svelte';
|
||||
import { Icon, Layout, Link, Status, Table } from '@appwrite.io/pink-svelte';
|
||||
import ViewSelector from '$lib/components/viewSelector.svelte';
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
import { View } from '$lib/helpers/load';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
let showFailed = false;
|
||||
let selectedWebhook: Models.Webhook;
|
||||
|
||||
function openWizard() {
|
||||
if (!$canWriteWebhooks) {
|
||||
return;
|
||||
}
|
||||
wizard.start(Create);
|
||||
}
|
||||
|
||||
const projectId = $page.params.project;
|
||||
|
||||
$: $updateCommandGroupRanks({ webhooks: 20, domains: 10 });
|
||||
@@ -63,7 +35,9 @@
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<ViewSelector {columns} view={View.Table} hideView />
|
||||
{#if $canWriteWebhooks}
|
||||
<Button on:click={openWizard} event="create_webhook">
|
||||
<Button
|
||||
href={`${base}/project-${projectId}/settings/webhooks/create`}
|
||||
event="create_webhook">
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create webhook
|
||||
</Button>
|
||||
@@ -135,7 +109,7 @@
|
||||
single
|
||||
href="https://appwrite.io/docs/advanced/platform/webhooks"
|
||||
target="webhook"
|
||||
on:click={openWizard} />
|
||||
on:click={() => goto(`${base}/projects-${projectId}/settings/webhooks/create`)} />
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { Wizard } from '$lib/layout';
|
||||
import { Card, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
import Form from '$lib/elements/forms/form.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import Step1 from './step1.svelte';
|
||||
import Step2 from './step2.svelte';
|
||||
import Step3 from './step3.svelte';
|
||||
import Button from '$lib/elements/forms/button.svelte';
|
||||
|
||||
let showExitModal = false;
|
||||
|
||||
let name = '',
|
||||
events = [],
|
||||
url = '',
|
||||
security = true,
|
||||
httpUser = '',
|
||||
httpPass = '';
|
||||
|
||||
export let data;
|
||||
async function create() {
|
||||
try {
|
||||
const webhook = await sdk.forConsole.projects.createWebhook(
|
||||
data.project.$id,
|
||||
name,
|
||||
events,
|
||||
url,
|
||||
security,
|
||||
true,
|
||||
httpUser || undefined,
|
||||
httpPass || undefined
|
||||
);
|
||||
addNotification({
|
||||
message: 'Webhook has been created',
|
||||
type: 'success'
|
||||
});
|
||||
trackEvent(Submit.WebhookCreate, {
|
||||
events: events
|
||||
});
|
||||
goto(`${base}/project-${$page.params.project}/settings/webhooks/${webhook.$id}`);
|
||||
} catch (error) {
|
||||
trackError(error.message, Submit.DomainCreate);
|
||||
throw new Error(error.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Form onSubmit={create}>
|
||||
<Wizard
|
||||
title="Create webhook"
|
||||
href={`${base}/project-${$page.params.project}/settings/webhooks`}
|
||||
bind:showExitModal
|
||||
column
|
||||
confirmExit>
|
||||
<Layout.Stack gap="xxl">
|
||||
<Step1 bind:name bind:url />
|
||||
<Step2 bind:events />
|
||||
<Step3 bind:httpUser bind:httpPass bind:security />
|
||||
</Layout.Stack>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<Button submit>Create webhook</Button>
|
||||
</svelte:fragment>
|
||||
</Wizard>
|
||||
</Form>
|
||||
|
||||
@@ -1,27 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { InputText, InputURL, FormList } from '$lib/elements/forms';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { InputText, InputURL } from '$lib/elements/forms';
|
||||
import { Fieldset, Layout } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let name: string;
|
||||
export let url: string;
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Configuration</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">
|
||||
Use webhooks to build integrations that subscribe to specific events on Appwrite. Appwrite
|
||||
will send an HTTP POST payload to the webhook's configured URL when one of the specified
|
||||
events is triggered.
|
||||
</svelte:fragment>
|
||||
<FormList>
|
||||
<InputText
|
||||
label="Name"
|
||||
id="name"
|
||||
placeholder="Enter name"
|
||||
bind:value={$createWebhook.name}
|
||||
required />
|
||||
<Fieldset legend="Configuration">
|
||||
<Layout.Stack gap="s">
|
||||
<InputText label="Name" id="name" placeholder="Enter name" bind:value={name} required />
|
||||
<InputURL
|
||||
label="POST URL"
|
||||
id="url"
|
||||
placeholder="https://example.com/callback"
|
||||
bind:value={$createWebhook.url}
|
||||
bind:value={url}
|
||||
required />
|
||||
</FormList>
|
||||
</WizardStep>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
|
||||
@@ -1,63 +1,59 @@
|
||||
<script lang="ts">
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Empty } from '$lib/components';
|
||||
import { EventModal } from '$lib/components';
|
||||
import { Icon, Typography, Link, Table, Layout } from '@appwrite.io/pink-svelte';
|
||||
import { Icon, Typography, Link, Table, Layout, Fieldset } from '@appwrite.io/pink-svelte';
|
||||
import { IconPlus, IconX } from '@appwrite.io/pink-icons-svelte';
|
||||
|
||||
let showCreate = false;
|
||||
|
||||
export let events: string[];
|
||||
|
||||
let eventSet = new Set<string>();
|
||||
const eventSet = new Set<string>();
|
||||
|
||||
function handleCreated(event: CustomEvent) {
|
||||
eventSet.add(event.detail);
|
||||
$createWebhook.events = Array.from(eventSet);
|
||||
events = Array.from(eventSet);
|
||||
}
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Webhook events</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">
|
||||
Set the events that will trigger your function. Maximum 100 events allowed.
|
||||
</svelte:fragment>
|
||||
|
||||
{#if $createWebhook?.events?.length}
|
||||
{#each $createWebhook.events as event}
|
||||
<Fieldset legend="Events">
|
||||
<Layout.Stack gap="s">
|
||||
{#if events.length}
|
||||
<Table.Root>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center">
|
||||
{event}
|
||||
<Button
|
||||
extraCompact
|
||||
ariaLabel="delete event"
|
||||
on:click={() => {
|
||||
eventSet.delete(event);
|
||||
$createWebhook.events = Array.from(eventSet);
|
||||
}}>
|
||||
<Icon icon={IconX} size="s" />
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{#each events as event}
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center">
|
||||
{event}
|
||||
<Button
|
||||
extraCompact
|
||||
ariaLabel="delete event"
|
||||
on:click={() => {
|
||||
eventSet.delete(event);
|
||||
events = Array.from(eventSet);
|
||||
}}>
|
||||
<Icon icon={IconX} size="s" />
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
{/each}
|
||||
<div>
|
||||
<Button secondary on:click={() => (showCreate = !showCreate)}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add event
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Empty on:click={() => (showCreate = !showCreate)}>Add an event</Empty>
|
||||
{/if}
|
||||
</WizardStep>
|
||||
<div>
|
||||
<Button secondary on:click={() => (showCreate = !showCreate)}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add event
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Empty on:click={() => (showCreate = !showCreate)}>Add an event</Empty>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
|
||||
{#if showCreate}
|
||||
<EventModal bind:show={showCreate} on:created={handleCreated}>
|
||||
|
||||
@@ -1,36 +1,46 @@
|
||||
<script lang="ts">
|
||||
import { InputText, InputPassword, InputChoice } from '$lib/elements/forms';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import Button from '$lib/elements/forms/button.svelte';
|
||||
import { Alert, Fieldset, Layout, Link, Typography } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let httpUser: string;
|
||||
export let httpPass: string;
|
||||
export let security: boolean;
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Security</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">
|
||||
Set an optional basic HTTP authentication username and password to protect your endpoint
|
||||
from unauthorized access.
|
||||
</svelte:fragment>
|
||||
<div>
|
||||
<h2 class="heading-level-7">HTTP Authentication</h2>
|
||||
<p class="text">Use to secure your endpoint from untrusted sources.</p>
|
||||
</div>
|
||||
<InputText label="User" id="user" placeholder="Enter username" bind:value={httpUser} />
|
||||
<InputPassword
|
||||
label="Password"
|
||||
id="password"
|
||||
placeholder="Enter password"
|
||||
minlength={0}
|
||||
bind:value={httpPass} />
|
||||
<InputChoice id="Security" label="Certificate verification (SSL/TLS)" bind:value={security}>
|
||||
<span class="u-color-text-danger">Warning:</span> Untrusted or self-signed certificates may
|
||||
not be secure.
|
||||
<a
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/tls-certificates"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link">
|
||||
Learn more</a
|
||||
></InputChoice>
|
||||
</WizardStep>
|
||||
<Fieldset legend="Security">
|
||||
<Layout.Stack gap="xl">
|
||||
<Layout.Stack gap="s">
|
||||
<InputChoice
|
||||
type="switchbox"
|
||||
id="Security"
|
||||
label="Certificate verification (SSL/TLS)"
|
||||
bind:value={security} />
|
||||
{#if !security}
|
||||
<Alert.Inline
|
||||
status="warning"
|
||||
title="Untrusted or self-signed certificates may not be secure.">
|
||||
<Button
|
||||
compact
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/tls-certificates"
|
||||
external>
|
||||
Learn more</Button>
|
||||
</Alert.Inline>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<Layout.Stack gap="m">
|
||||
<div>
|
||||
<Typography.Text variant="m-600">HTTP authentication</Typography.Text>
|
||||
<Typography.Text
|
||||
>Use to secure your endpoint from untrusted sources.</Typography.Text>
|
||||
</div>
|
||||
<InputText label="User" id="user" placeholder="Enter username" bind:value={httpUser} />
|
||||
<InputPassword
|
||||
label="Password"
|
||||
id="password"
|
||||
placeholder="Enter password"
|
||||
minlength={0}
|
||||
bind:value={httpPass} />
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { WizardWithSteps } from '$lib/layout';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import { createWebhook } from './wizard/store';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { page } from '$app/stores';
|
||||
import Step1 from './wizard/step1.svelte';
|
||||
import Step2 from './wizard/step2.svelte';
|
||||
import Step3 from './wizard/step3.svelte';
|
||||
import type { WizardStepsType } from '$lib/layout/wizardWithSteps.svelte';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
|
||||
|
||||
const projectId = $page.params.project;
|
||||
async function create() {
|
||||
try {
|
||||
await sdk.forConsole.projects.createWebhook(
|
||||
projectId,
|
||||
$createWebhook.name,
|
||||
$createWebhook.events,
|
||||
$createWebhook.url,
|
||||
$createWebhook.security,
|
||||
true,
|
||||
$createWebhook.httpUser || undefined,
|
||||
$createWebhook.httpPass || undefined
|
||||
);
|
||||
await invalidate(Dependencies.WEBHOOKS);
|
||||
addNotification({
|
||||
message: 'Webhook has been created',
|
||||
type: 'success'
|
||||
});
|
||||
wizard.hide();
|
||||
trackEvent(Submit.WebhookCreate, {
|
||||
events: $createWebhook.events
|
||||
});
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
message: error.message,
|
||||
type: 'error'
|
||||
});
|
||||
trackError(error, Submit.WebhookCreate);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
$createWebhook = {
|
||||
name: null,
|
||||
url: null,
|
||||
events: [],
|
||||
security: false,
|
||||
httpUser: null,
|
||||
httpPass: null
|
||||
};
|
||||
});
|
||||
|
||||
const stepsComponents: WizardStepsType = new Map();
|
||||
stepsComponents.set(1, {
|
||||
label: 'Configure',
|
||||
component: Step1
|
||||
});
|
||||
stepsComponents.set(2, {
|
||||
label: 'Events',
|
||||
component: Step2
|
||||
});
|
||||
stepsComponents.set(3, {
|
||||
label: 'Security',
|
||||
component: Step3,
|
||||
optional: true
|
||||
});
|
||||
</script>
|
||||
|
||||
<WizardWithSteps confirmExit title="Create Webhook" steps={stepsComponents} on:finish={create}>
|
||||
<svelte:fragment slot="exit">Are you sure you want to exit from this process?</svelte:fragment>
|
||||
</WizardWithSteps>
|
||||
@@ -1,28 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { InputText, InputURL, FormList } from '$lib/elements/forms';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { createWebhook } from './store';
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Configuration</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">
|
||||
Use webhooks to build integrations that subscribe to specific events on Appwrite. Appwrite
|
||||
will send an HTTP POST payload to the webhook's configured URL when one of the specified
|
||||
events is triggered.
|
||||
</svelte:fragment>
|
||||
<FormList>
|
||||
<InputText
|
||||
label="Name"
|
||||
id="name"
|
||||
placeholder="Enter name"
|
||||
bind:value={$createWebhook.name}
|
||||
required />
|
||||
<InputURL
|
||||
label="POST URL"
|
||||
id="url"
|
||||
placeholder="https://example.com/callback"
|
||||
bind:value={$createWebhook.url}
|
||||
required />
|
||||
</FormList>
|
||||
</WizardStep>
|
||||
@@ -1,71 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Empty } from '$lib/components';
|
||||
import { createWebhook } from './store';
|
||||
import { EventModal } from '$lib/components';
|
||||
import { Icon, Typography, Link, Table, Layout } from '@appwrite.io/pink-svelte';
|
||||
import { IconPlus, IconX } from '@appwrite.io/pink-icons-svelte';
|
||||
|
||||
let showCreate = false;
|
||||
|
||||
let eventSet = new Set<string>();
|
||||
|
||||
function handleCreated(event: CustomEvent) {
|
||||
eventSet.add(event.detail);
|
||||
$createWebhook.events = Array.from(eventSet);
|
||||
}
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Webhook events</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">
|
||||
Set the events that will trigger your function. Maximum 100 events allowed.
|
||||
</svelte:fragment>
|
||||
|
||||
{#if $createWebhook?.events?.length}
|
||||
{#each $createWebhook.events as event}
|
||||
<Table.Root>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center">
|
||||
{event}
|
||||
<Button
|
||||
extraCompact
|
||||
ariaLabel="delete event"
|
||||
on:click={() => {
|
||||
eventSet.delete(event);
|
||||
$createWebhook.events = Array.from(eventSet);
|
||||
}}>
|
||||
<Icon icon={IconX} size="s" />
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Root>
|
||||
{/each}
|
||||
<div>
|
||||
<Button secondary on:click={() => (showCreate = !showCreate)}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add event
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Empty on:click={() => (showCreate = !showCreate)}>Add an event</Empty>
|
||||
{/if}
|
||||
</WizardStep>
|
||||
|
||||
{#if showCreate}
|
||||
<EventModal bind:show={showCreate} on:created={handleCreated}>
|
||||
<Typography.Text>
|
||||
Select events in your Appwrite project that will trigger your webhook. <Link.Anchor
|
||||
href="https://appwrite.io/docs/advanced/platform/events"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link">Learn more</Link.Anchor>
|
||||
</Typography.Text>
|
||||
</EventModal>
|
||||
{/if}
|
||||
@@ -1,45 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { FormList, InputText, InputPassword, InputChoice } from '$lib/elements/forms';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { createWebhook } from './store';
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Security</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">
|
||||
Set an optional basic HTTP authentication username and password to protect your endpoint
|
||||
from unauthorized access.
|
||||
</svelte:fragment>
|
||||
<FormList>
|
||||
<div>
|
||||
<h2 class="heading-level-7">HTTP Authentication</h2>
|
||||
<p class="text">Use to secure your endpoint from untrusted sources.</p>
|
||||
</div>
|
||||
<InputText
|
||||
label="User"
|
||||
id="user"
|
||||
placeholder="Enter username"
|
||||
bind:value={$createWebhook.httpUser} />
|
||||
<InputPassword
|
||||
label="Password"
|
||||
id="password"
|
||||
showPasswordButton
|
||||
placeholder="Enter password"
|
||||
minlength={0}
|
||||
bind:value={$createWebhook.httpPass} />
|
||||
|
||||
<InputChoice
|
||||
id="Security"
|
||||
label="Certificate verification (SSL/TLS)"
|
||||
bind:value={$createWebhook.security}>
|
||||
<span class="u-color-text-danger">Warning:</span> Untrusted or self-signed certificates
|
||||
may not be secure.
|
||||
<a
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/tls-certificates"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link">
|
||||
Learn more</a
|
||||
></InputChoice>
|
||||
</FormList>
|
||||
</WizardStep>
|
||||
@@ -1,11 +0,0 @@
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const createWebhook = writable<Partial<Models.Webhook>>({
|
||||
name: null,
|
||||
url: null,
|
||||
events: [],
|
||||
security: false,
|
||||
httpUser: null,
|
||||
httpPass: null
|
||||
});
|
||||
Reference in New Issue
Block a user