Skip to content

Commit

Permalink
Merge pull request #597 from appwrite/feat-messaging-topics
Browse files Browse the repository at this point in the history
Add messaging topics route
  • Loading branch information
TorstenDittmann authored Jan 2, 2024
2 parents 7669ad7 + fee8e9c commit 6b371da
Show file tree
Hide file tree
Showing 32 changed files with 1,589 additions and 38 deletions.
8 changes: 7 additions & 1 deletion src/lib/actions/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,5 +292,11 @@ export enum Submit {
MessagingProviderDelete = 'submit_messaging_provider_delete',
MessagingProviderUpdate = 'submit_messaging_provider_update',
MessagingMessageCreate = 'submit_messaging_message_create',
MessagingMessageDelete = 'submit_messaging_message_delete'
MessagingMessageDelete = 'submit_messaging_message_delete',
MessagingTopicCreate = 'submit_messaging_topic_create',
MessagingTopicDelete = 'submit_messaging_topic_delete',
MessagingTopicUpdateName = 'submit_messaging_topic_update_name',
MessagingTopicUpdateDescription = 'submit_messaging_topic_update_description',
MessagingTopicSubscriberAdd = 'submit_messaging_topic_subscriber_add',
MessagingTopicSubscriberDelete = 'submit_messaging_topic_subscriber_delete'
}
5 changes: 4 additions & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ export enum Dependencies {
CONSOLE_VARIABLES = 'dependency:console_variables',
MESSAGING_PROVIDERS = 'dependency:messaging_providers',
MESSAGING_PROVIDER = 'dependency:messaging_provider',
MESSAGING_MESSAGE = 'dependency:messaging_message'
MESSAGING_MESSAGE = 'dependency:messaging_message',
MESSAGING_TOPICS = 'dependency:messaging_topics',
MESSAGING_TOPIC = 'dependency:messaging_topic',
MESSAGING_TOPIC_SUBSCRIBERS = 'dependency:messaging_topic_subscribers'
}

export const scopes: {
Expand Down
44 changes: 44 additions & 0 deletions src/routes/console/project-[project]/messaging/actions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script lang="ts">
import { DropList, DropListItem } from '$lib/components';
import { createEventDispatcher } from 'svelte';
import { targetsById } from './wizard/store';
import UserTargetsModal from './userTargetsModal.svelte';
import type { ProviderTypes } from './providerType.svelte';
import TopicsModal from './topicsModal.svelte';
import { topicsById } from './store';
export let showDropdown: boolean;
export let showUserTargets: boolean;
export let showTopics: boolean;
export let providerType: ProviderTypes = null;
const dispatch = createEventDispatcher();
$: if (showUserTargets || showTopics) {
showDropdown = false;
}
</script>

<DropList bind:show={showDropdown} placement="bottom-end" fixed>
<slot />
<svelte:fragment slot="list">
<DropListItem on:click={() => (showTopics = true)}>Select topics</DropListItem>
<DropListItem on:click={() => (showUserTargets = true)}>Select targets</DropListItem>
</svelte:fragment>
</DropList>

<TopicsModal
bind:show={showTopics}
bind:topicsById={$topicsById}
on:update={(e) => {
showTopics = false;
dispatch('addTopics', e.detail);
}} />
<UserTargetsModal
{providerType}
bind:show={showUserTargets}
bind:targetsById={$targetsById}
on:update={(e) => {
showUserTargets = false;
dispatch('addTargets', e.detail);
}} />
5 changes: 0 additions & 5 deletions src/routes/console/project-[project]/messaging/create.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import { Wizard } from '$lib/layout';
import type { WizardStepsType } from '$lib/layout/wizard.svelte';
import Step1 from './wizard/step1.svelte';
Expand Down Expand Up @@ -97,10 +96,6 @@
}
}
onDestroy(() => {
console.log('destroy');
});
const stepsComponents: WizardStepsType = new Map();
stepsComponents.set(1, {
label: 'Message',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import Create from './create.svelte';
import { messageParams, providerType, targetsById } from './wizard/store';
import { ProviderTypes } from './providerType.svelte';
import { topicsById } from './store';
export let showCreateDropdown = false;
</script>
Expand All @@ -29,6 +30,7 @@
)
return;
$providerType = type;
$topicsById = {};
$targetsById = {};
const common = {
topics: [],
Expand Down
25 changes: 25 additions & 0 deletions src/routes/console/project-[project]/messaging/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export const columns = writable<Column[]>([
{ id: 'deliveredAt', title: 'Delivered at', type: 'datetime', show: false, width: 120 }
]);

export const targetsById = writable<Record<string, Target>>({});
export const topicsById = writable<Record<string, Topic>>({});

// TODO: remove this when the SDK and API are ready
export type Message = {
$id: string;
Expand Down Expand Up @@ -238,3 +241,25 @@ export const providersById: { [providerId: string]: Provider } = {
options: {}
}
};

// TODO: remove when sdk has the model
export type Topic = {
$id: string;
$createdAt: string;
$updatedAt: string;
providerId: string;
name: string;
total: number;
description: string;
};

export type Target = {
$id: string;
$createdAt: string;
$updatedAt: string;
name: string;
userId: string;
providerId: string;
providerType: ProviderTypes;
identifier: string;
};
103 changes: 103 additions & 0 deletions src/routes/console/project-[project]/messaging/topics/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<script lang="ts">
import { page } from '$app/stores';
import { Button } from '$lib/elements/forms';
import {
Empty,
EmptySearch,
SearchQuery,
PaginationWithLimit,
Heading,
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 { columns, showCreate } from './store';
import { View } from '$lib/helpers/load';
import Filters from '$lib/components/filters/filters.svelte';
import Table from './table.svelte';
export let data: PageData;
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">Topics</Heading>
<div class="is-only-mobile">
<Button on:click={() => ($showCreate = true)} event="create_topic">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create topic</span>
</Button>
</div>
</div>
<!-- TODO: fix width of search input in mobile -->
<SearchQuery search={data.search} placeholder="Search by name or ID">
<div class="u-flex u-gap-16 is-not-mobile">
<Filters query={data.query} {columns} />
<ViewSelector
view={View.Table}
{columns}
hideView
allowNoColumns
showColsTextMobile />
<Button on:click={() => ($showCreate = true)} event="create_topic">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create topic</span>
</Button>
</div>
</SearchQuery>
<div class="u-flex u-gap-16 is-only-mobile u-margin-block-start-16">
<div class="u-flex-basis-50-percent">
<!-- TODO: fix width -->
<ViewSelector
view={View.Table}
{columns}
hideView
allowNoColumns
showColsTextMobile />
</div>
<div class="u-flex-basis-50-percent">
<!-- TODO: fix width -->
<Filters query={data.query} {columns} />
</div>
</div>
</div>
{#if data.topics.total}
<Table {data} />

<PaginationWithLimit
name="Topics"
limit={data.limit}
offset={data.offset}
total={data.topics.total} />
<!-- TODO: remove data.search != 'empty' when the API is ready with data -->
{:else if data.search && data.search != 'empty'}
<EmptySearch>
<div class="u-text-center">
<b>Sorry, we couldn't find '{data.search}'</b>
<p>There are no topics that match your search.</p>
</div>
<Button secondary href={`/console/project-${$page.params.project}/messaging/topics`}>
Clear Search
</Button>
</EmptySearch>
{:else}
<!-- TODO: update docs link -->
<Empty
single
on:click={() => ($showCreate = true)}
href="https://appwrite.io/docs/references/cloud/client-web/teams"
target="topic" />
{/if}
</Container>

<Create bind:showCreate={$showCreate} on:created={topicCreated} />
53 changes: 53 additions & 0 deletions src/routes/console/project-[project]/messaging/topics/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Query } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getQuery, getSearch, pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { queryParamToMap, queries } from '$lib/components/filters/store';
import type { Topic } from '../store';

export const load = async ({ depends, url, route }) => {
depends(Dependencies.MESSAGING_TOPICS);
const page = getPage(url);
const search = getSearch(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const query = getQuery(url);

const parsedQueries = queryParamToMap(query || '[]');
queries.set(parsedQueries);

const payload = {
queries: [
Query.limit(limit),
Query.offset(offset),
Query.orderDesc(''),
...parsedQueries.values()
]
};

if (search) {
payload['search'] = search;
}

// TODO: remove when the API is ready with data
// This allows us to mock w/ data and when search returns 0 results
const topics: { topics: Topic[]; total: number } = await sdk.forProject.client.call(
'GET',
new URL(sdk.forProject.client.config.endpoint + '/messaging/topics'),
{
'X-Appwrite-Project': sdk.forProject.client.config.project,
'content-type': 'application/json',
'X-Appwrite-Mode': 'admin'
},
payload
);

return {
offset,
limit,
search,
query,
page,
topics
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<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 { sdk } from '$lib/stores/sdk';
import { ID } from '@appwrite.io/console';
import { createEventDispatcher } from 'svelte';
export let showCreate = false;
const dispatch = createEventDispatcher();
let name: string, description: string, id: string, error: string;
let showCustomId = false;
const create = async () => {
try {
const topic = await sdk.forProject.client.call(
'POST',
new URL(sdk.forProject.client.config.endpoint + '/messaging/topics'),
{
'X-Appwrite-Project': sdk.forProject.client.config.project,
'content-type': 'application/json',
'X-Appwrite-Mode': 'admin'
},
{
name,
description,
topicId: id ?? ID.unique()
}
);
name = '';
description = '';
showCreate = false;
showCustomId = false;
addNotification({
type: 'success',
message: `${topic.name} has been created`
});
trackEvent(Submit.MessagingTopicCreate, {
customId: !!id
});
dispatch('created', topic);
} catch (e) {
error = e.message;
trackError(e, Submit.MessagingTopicCreate);
}
};
$: if (!showCreate) {
showCustomId = false;
error = null;
}
</script>

<Modal title="Create topic" {error} size="big" bind:show={showCreate} onSubmit={create}>
<FormList>
<InputText
id="name"
label="Name"
placeholder="Enter name"
autofocus={true}
required
bind:value={name} />
<InputText
id="description"
label="Description"
placeholder="Enter description"
bind:value={description}>
</InputText>
{#if !showCustomId}
<div>
<Pill button on:click={() => (showCustomId = !showCustomId)}
><span class="icon-pencil" aria-hidden="true" />
<span class="text"> Topic ID </span>
</Pill>
</div>
{:else}
<CustomId bind:show={showCustomId} name="Topic" bind:id />
{/if}
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showCreate = false)}>Cancel</Button>
<Button submit>Create</Button>
</svelte:fragment>
</Modal>
12 changes: 12 additions & 0 deletions src/routes/console/project-[project]/messaging/topics/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Column } from '$lib/helpers/types';
import { writable } from 'svelte/store';

export let showCreate = writable(false);

export const columns = writable<Column[]>([
{ id: '$id', title: 'Topic ID', type: 'string', show: true, width: 140 },
{ id: 'name', title: 'Name', type: 'string', show: true, width: 140 },
{ id: 'description', title: 'Description', type: 'string', show: true, width: 140 },
{ id: 'total', title: 'Subscribers', type: 'integer', show: true, width: 140 },
{ id: '$createdAt', title: 'Created', type: 'datetime', show: true, width: 140 }
]);
Loading

0 comments on commit 6b371da

Please sign in to comment.