diff --git a/src/lib/commandCenter/commands.ts b/src/lib/commandCenter/commands.ts index f12bbe2ed8..470a610129 100644 --- a/src/lib/commandCenter/commands.ts +++ b/src/lib/commandCenter/commands.ts @@ -17,6 +17,7 @@ const groups = [ 'platforms', 'databases', 'functions', + 'messaging', 'storage', 'domains', 'webhooks', diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts index 4b12577c84..01dc6ab25f 100644 --- a/src/lib/components/index.ts +++ b/src/lib/components/index.ts @@ -60,3 +60,5 @@ export { default as SvgIcon } from './svgIcon.svelte'; export { default as MigrationBox } from './migrationBox.svelte'; export { default as FloatingActionBar } from './floatingActionBar.svelte'; export { default as LoadingDots } from './loadingDots.svelte'; +export { default as Provider } from './provider.svelte'; +export { default as ProviderType } from './providerType.svelte'; diff --git a/src/lib/components/provider.svelte b/src/lib/components/provider.svelte new file mode 100644 index 0000000000..6e81c67a06 --- /dev/null +++ b/src/lib/components/provider.svelte @@ -0,0 +1,79 @@ + + + + +{#if icon === ''} + Invalid provider +{:else} +
+
+ {displayName} +
+ + {displayName} + +
+{/if} diff --git a/src/lib/components/providerType.svelte b/src/lib/components/providerType.svelte new file mode 100644 index 0000000000..f28f3485db --- /dev/null +++ b/src/lib/components/providerType.svelte @@ -0,0 +1,40 @@ + + + + +{#if text === ''} + Invalid provider type +{:else} +
+
+
+ {text} +
+{/if} diff --git a/src/routes/console/project-[project]/messaging/+layout.svelte b/src/routes/console/project-[project]/messaging/+layout.svelte new file mode 100644 index 0000000000..2b8b30178b --- /dev/null +++ b/src/routes/console/project-[project]/messaging/+layout.svelte @@ -0,0 +1,62 @@ + + + + Messaging - Appwrite + + + diff --git a/src/routes/console/project-[project]/messaging/+layout.ts b/src/routes/console/project-[project]/messaging/+layout.ts new file mode 100644 index 0000000000..7db345058e --- /dev/null +++ b/src/routes/console/project-[project]/messaging/+layout.ts @@ -0,0 +1,10 @@ +import Breadcrumbs from './breadcrumbs.svelte'; +import Header from './header.svelte'; +import type { LayoutLoad } from './$types'; + +export const load: LayoutLoad = async () => { + return { + header: Header, + breadcrumbs: Breadcrumbs + }; +}; diff --git a/src/routes/console/project-[project]/messaging/+page.svelte b/src/routes/console/project-[project]/messaging/+page.svelte new file mode 100644 index 0000000000..e4bc521af0 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/+page.svelte @@ -0,0 +1,247 @@ + + + +
+
+ Messages +
+ +
+
+ + +
+ + + + +
+
+
+
+ + +
+
+ + +
+
+
+ + {#if data.messages.total} + + + d.$id)} /> + {#each $columns as column} + {#if column.show} + {column.title} + {/if} + {/each} + + + {#each data.messages.messages as message} + {@const provider = data.providersById[message.providerId]} + + + + {#each $columns as column} + {#if column.show} + {#if column.id === '$id'} + {#key $columns} + + {message.$id} + + {/key} + {:else if column.id === 'message'} + + {#if provider?.type === ProviderTypes.Push} + {message.data.title} + {:else if provider?.type === ProviderTypes.Sms} + {message.data.content} + {:else if provider?.type === ProviderTypes.Email} + {message.data.subject} + {:else} + Invalid provider + {/if} + + {:else if column.id === 'channel'} + + {#if provider} + + {:else} + Invalid provider + {/if} + + {:else if column.id === 'providerId'} + + {#if provider} + + {:else} + Invalid provider + {/if} + + {:else if column.id === 'status'} + + + {#if message.status === 'sent'} + + {:else if message.status === 'scheduled'} + + {/if} + + {message[column.id]} + + + + {:else if column.id === 'deliveryTime'} + + {#if !message[column.id]} + - + {:else} + {toLocaleDateTime(message[column.id])} + {/if} + + {:else} + + {message[column.id]} + + {/if} + {/if} + {/each} + + {/each} + + + + 0}> +
+
+ {selected.length} +

+ + {selected.length > 1 ? 'messages' : 'message'} + + selected +

+
+ +
+ + + +
+
+
+ + + + {:else if data.search && data.search != 'empty'} + +
+ Sorry, we couldn't find '{data.search}' +

There are no messages that match your search.

+
+
+ + + +
+
+ {:else} + + ($showCreate = true)} /> + {/if} +
+ + + diff --git a/src/routes/console/project-[project]/messaging/+page.ts b/src/routes/console/project-[project]/messaging/+page.ts new file mode 100644 index 0000000000..7f4d14547d --- /dev/null +++ b/src/routes/console/project-[project]/messaging/+page.ts @@ -0,0 +1,40 @@ +import { View, getLimit, getPage, getSearch, getView, pageToOffset } from '$lib/helpers/load'; +import { CARD_LIMIT } from '$lib/constants'; +import type { PageLoad } from './$types'; +import { messages as data, providersById } from './store'; +import type { Message } from './store'; + +export const load: PageLoad = async ({ url, route }) => { + const page = getPage(url); + const search = getSearch(url); + const view = getView(url, route, View.Grid); + const limit = getLimit(url, route, CARD_LIMIT); + const offset = pageToOffset(page, limit); + + // TODO: uncomment when the API is ready with data + // const messages = await sdk.forProject.client.call( + // 'GET', + // new URL(sdk.forProject.client.config.endpoint + '/messaging/messages'), + // { + // 'X-Appwrite-Project': sdk.forProject.client.config.project, + // 'content-type': 'application/json' + // } + // ) as {total: number, messages: Message[]}; + + // TODO: remove when the API is ready with data + // This allows us to mock w/ data and when search returns 0 results + let messages: { messages: Message[]; total: number } = { messages: [], total: 0 }; + if (!search) { + messages = data; + } + + return { + offset, + limit, + search, + page, + view, + messages, + providersById + }; +}; diff --git a/src/routes/console/project-[project]/messaging/breadcrumbs.svelte b/src/routes/console/project-[project]/messaging/breadcrumbs.svelte new file mode 100644 index 0000000000..9e28bee679 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/breadcrumbs.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/routes/console/project-[project]/messaging/create.svelte b/src/routes/console/project-[project]/messaging/create.svelte new file mode 100644 index 0000000000..49a81af91f --- /dev/null +++ b/src/routes/console/project-[project]/messaging/create.svelte @@ -0,0 +1,73 @@ + + + + + + + {#if !showCustomId} +
+ (showCustomId = !showCustomId)}> + +
+ {:else} + + {/if} +
+ + + + +
diff --git a/src/routes/console/project-[project]/messaging/header.svelte b/src/routes/console/project-[project]/messaging/header.svelte new file mode 100644 index 0000000000..9534915abb --- /dev/null +++ b/src/routes/console/project-[project]/messaging/header.svelte @@ -0,0 +1,44 @@ + + + + + Messaging + + + {#each tabs as tab} + + {tab.title} + + {/each} + + diff --git a/src/routes/console/project-[project]/messaging/store.ts b/src/routes/console/project-[project]/messaging/store.ts new file mode 100644 index 0000000000..1371d303a0 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/store.ts @@ -0,0 +1,224 @@ +import { Providers } from '$lib/components/provider.svelte'; +import { ProviderTypes } from '$lib/components/providerType.svelte'; +import type { Column } from '$lib/components/viewSelector.svelte'; +import { writable } from 'svelte/store'; + +export const showCreate = writable(false); + +export const columns = writable([ + { id: '$id', title: 'Message ID', show: true, width: 140 }, + { id: 'message', title: 'Message', show: true, width: 140 }, + { id: 'channel', title: 'Channel', show: true, width: 100 }, + { id: 'to', title: 'Targets', show: true, width: 120 }, + { id: 'providerId', title: 'Provider', show: true, width: 120 }, + { id: 'status', title: 'Status', show: true, width: 120 }, + { id: 'deliveryTime', title: 'Delivery Time', show: true, width: 120 } +]); + +// TODO: remove this when the SDK and API are ready +export type Message = { + $id: string; + providerId: string; + to: string[]; + deliveryTime: string; + deliveredAt: string; + deliveryErrors: string; + deliveredTo: number; + status: string; + description: string; + data: { + content?: string; + body?: string; + subject?: string; + title?: string; + }; +}; + +// TODO: remove this when the SDK and API are ready +export const messages: { messages: Message[]; total: number } = { + messages: [ + { + $id: '637a40ba7a703e3936e1', + description: 'Welcome', + providerId: '637a40ba7a703e3936e1', // FCM + to: ['user-1', 'user-2'], + deliveryTime: '2021-03-01T00:00:00.000Z', + deliveredAt: '2021-03-01T00:00:00.000Z', + deliveryErrors: '', + deliveredTo: 2, + status: 'sent', + data: { + title: 'Welcome to the Cloud', + body: 'Detailed body' + } + }, + { + $id: '637a40ba7a703e3936e2', + description: 'Public beta announcement', + providerId: '637a40ba7a703e3936f0', // SMS + to: ['user-1', 'user-2'], + deliveryTime: '2021-03-01T00:00:00.000Z', + deliveredAt: '2021-03-01T00:00:00.000Z', + deliveryErrors: '', + deliveredTo: 2, + status: 'scheduled', + data: { + content: 'Cloud is live on public beta' + } + }, + { + $id: '637a40ba7a703e3936e3', + description: 'Welcome', + providerId: '637a40ba7a703e3936e4', // Email + to: ['user-1', 'user-2'], + deliveryTime: '', + deliveredAt: '', + deliveryErrors: '', + deliveredTo: 2, + status: 'draft', + data: { + subject: 'Welcome to the Cloud', + content: 'Detailed content' + } + } + ], + total: 3 +}; + +// TODO: remove this when the SDK and API are ready +export type Provider = { + $id: string; + $createdAt: string; + $updatedAt: string; + name: string; + provider: Providers; + default: boolean; + enabled: boolean; + type: ProviderTypes; + credentials: object; + options: object; +}; + +// TODO: remove this when the SDK and API are ready +export const providersById: { [providerId: string]: Provider } = { + '637a40ba7a703e3936e1': { + $id: '637a40ba7a703e3936e1', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Firebase', + provider: Providers.FCM, + type: ProviderTypes.Push, + default: false, + enabled: true, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e2': { + $id: '637a40ba7a703e3936e2', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My APNS', + provider: Providers.APNS, + type: ProviderTypes.Push, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e3': { + $id: '637a40ba7a703e3936e3', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My MQTT', + provider: Providers.MQTT, + type: ProviderTypes.Push, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e4': { + $id: '637a40ba7a703e3936e4', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Sendgrid', + provider: Providers.Sendgrid, + type: ProviderTypes.Email, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e5': { + $id: '637a40ba7a703e3936e5', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Mailgun', + provider: Providers.Mailgun, + type: ProviderTypes.Email, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e6': { + $id: '637a40ba7a703e3936e6', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Telesign', + provider: Providers.Telesign, + type: ProviderTypes.Sms, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e7': { + $id: '637a40ba7a703e3936e7', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Msg91', + provider: Providers.Msg91, + type: ProviderTypes.Sms, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e8': { + $id: '637a40ba7a703e3936e8', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Textmagic', + provider: Providers.Textmagic, + type: ProviderTypes.Sms, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936e9': { + $id: '637a40ba7a703e3936e9', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Vonage', + provider: Providers.Vonage, + type: ProviderTypes.Sms, + default: false, + enabled: false, + credentials: {}, + options: {} + }, + '637a40ba7a703e3936f0': { + $id: '637a40ba7a703e3936f0', + $createdAt: '2021-08-31T12:00:00.000Z', + $updatedAt: '2021-08-31T12:00:00.000Z', + name: 'My Twilio', + provider: Providers.Twilio, + type: ProviderTypes.Sms, + default: false, + enabled: false, + credentials: {}, + options: {} + } +};