From d0cc34800243807dc1e4d352375566fde3b0f950 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Thu, 20 Feb 2025 21:15:44 -0500 Subject: Use axios to compute event stream URL, why not. It's amazing what you can learn by skimming the docs. --- ui/lib/apiServer.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'ui/lib') diff --git a/ui/lib/apiServer.js b/ui/lib/apiServer.js index e52daff..e541d43 100644 --- a/ui/lib/apiServer.js +++ b/ui/lib/apiServer.js @@ -55,9 +55,13 @@ export async function acceptInvite(inviteId, username, password) { } export function subscribeToEvents(resumePoint) { - const eventsUrl = new URL('/api/events', window.location); - eventsUrl.searchParams.append('resume_point', resumePoint); - const evtSource = new EventSource(eventsUrl.toString()); + const eventsUrl = apiServer.getUri({ + url: '/events', + params: { + resume_point: resumePoint + } + }); + const evtSource = new EventSource(eventsUrl); // TODO: this should process all incoming events and store them. // TODO: eventually we'll need to handle expiring old info, so as not to use // infinite browser memory. -- cgit v1.2.3 From 5cff84a375f64537c44f6418496f1dc1b24a1de8 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Fri, 21 Feb 2025 13:08:14 -0500 Subject: Split "set up the event source" and "apply events to state" from one another. --- ui/lib/apiServer.js | 70 +----------------------------------------- ui/lib/store.js | 61 ++++++++++++++++++++++++++++++++++++ ui/routes/(app)/+layout.svelte | 3 +- 3 files changed, 64 insertions(+), 70 deletions(-) (limited to 'ui/lib') diff --git a/ui/lib/apiServer.js b/ui/lib/apiServer.js index e541d43..bb0a587 100644 --- a/ui/lib/apiServer.js +++ b/ui/lib/apiServer.js @@ -61,73 +61,5 @@ export function subscribeToEvents(resumePoint) { resume_point: resumePoint } }); - const evtSource = new EventSource(eventsUrl); - // TODO: this should process all incoming events and store them. - // TODO: eventually we'll need to handle expiring old info, so as not to use - // infinite browser memory. - /* - * Known message types as of now: - * - created: a channel is created. - * - action: ignore. - * - message: a message is created. - * - action: display message in channel. - * - message_deleted: a message is deleted. - * - action: replace message with <...>. - * - deleted: a channel is deleted. - * - action: remove channel from sidebar. - */ - evtSource.onmessage = (evt) => { - const data = JSON.parse(evt.data); - - switch (data.type) { - case 'login': - onLoginEvent(data); - break; - case 'channel': - onChannelEvent(data); - break; - case 'message': - onMessageEvent(data); - break; - } - }; - - return evtSource; -} - -function onLoginEvent(data) { - switch (data.event) { - case 'created': - logins.update((value) => value.addLogin(data.id, data.name)); - break; - } -} - -function onChannelEvent(data) { - switch (data.event) { - case 'created': - channelsList.update((value) => value.addChannel(data.id, data.name)); - break; - case 'deleted': - channelsList.update((value) => value.deleteChannel(data.id)); - messages.update((value) => value.deleteChannel(data.id)); - break; - } -} - -function onMessageEvent(data) { - switch (data.event) { - case 'sent': - messages.update((value) => - value.addMessage(data.channel, data.id, { - at: data.at, - sender: data.sender, - body: data.body - }) - ); - break; - case 'deleted': - messages.update((value) => value.deleteMessage(data.id)); - break; - } + return new EventSource(eventsUrl); } diff --git a/ui/lib/store.js b/ui/lib/store.js index 47ebbc2..c179dac 100644 --- a/ui/lib/store.js +++ b/ui/lib/store.js @@ -7,3 +7,64 @@ export const currentUser = writable(null); export const logins = writable(new Logins()); export const channelsList = writable(new Channels()); export const messages = writable(new Messages()); + +export function onEvent(event) { + switch (event.type) { + case 'login': + onLoginEvent(event); + break; + case 'channel': + onChannelEvent(event); + break; + case 'message': + onMessageEvent(event); + break; + } +} + +onEvent.fromJson = (event) => { + const parsed = JSON.parse(event); + return onEvent(parsed); +}; + +onEvent.fromMessage = (message) => { + const data = message.data; + return onEvent.fromJson(data); +}; + +function onLoginEvent(event) { + switch (event.event) { + case 'created': + logins.update((value) => value.addLogin(event.id, event.name)); + break; + } +} + +function onChannelEvent(event) { + switch (event.event) { + case 'created': + channelsList.update((value) => value.addChannel(event.id, event.name)); + break; + case 'deleted': + channelsList.update((value) => value.deleteChannel(event.id)); + messages.update((value) => value.deleteChannel(event.id)); + break; + } +} + +function onMessageEvent(event) { + switch (event.event) { + case 'sent': + messages.update((value) => + value.addMessage(event.channel, event.id, { + at: event.at, + sender: event.sender, + body: event.body + }) + ); + break; + case 'deleted': + messages.update((value) => value.deleteMessage(event.id)); + break; + } +} diff --git a/ui/routes/(app)/+layout.svelte b/ui/routes/(app)/+layout.svelte index 5ec84d9..dff9245 100644 --- a/ui/routes/(app)/+layout.svelte +++ b/ui/routes/(app)/+layout.svelte @@ -6,7 +6,7 @@ import TinyGesture from 'tinygesture'; import { boot, subscribeToEvents } from '$lib/apiServer'; - import { currentUser, logins, channelsList, messages } from '$lib/store'; + import { currentUser, logins, channelsList, messages, onEvent } from '$lib/store'; import ChannelList from '$lib/components/ChannelList.svelte'; import CreateChannelForm from '$lib/components/CreateChannelForm.svelte'; @@ -72,6 +72,7 @@ case 200: onBooted(response.data); events = subscribeToEvents(response.data.resume_point); + events.onmessage = onEvent.fromMessage; break; case 401: currentUser.set(null); -- cgit v1.2.3 From 01368abc9893caa7acd3d632fd7a2d4284e64167 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Fri, 21 Feb 2025 16:21:43 -0500 Subject: Remove unused type attribute on textarea --- ui/lib/components/MessageInput.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ui/lib') diff --git a/ui/lib/components/MessageInput.svelte b/ui/lib/components/MessageInput.svelte index 5869654..1eb1d7b 100644 --- a/ui/lib/components/MessageInput.svelte +++ b/ui/lib/components/MessageInput.svelte @@ -24,7 +24,6 @@
- +
-- cgit v1.2.3 From 5245aba8b80f458d25eb3249c0b8cc3fe744311d Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Fri, 21 Feb 2025 16:27:00 -0500 Subject: Be a bit more careful with the nesting of anchors and list items. Browsers cope with weird nestings mostly fine, but there's no upside for us in testing that. --- ui/lib/components/Channel.svelte | 8 ++++---- ui/styles/sidebar.css | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'ui/lib') diff --git a/ui/lib/components/Channel.svelte b/ui/lib/components/Channel.svelte index c73340f..4f908d2 100644 --- a/ui/lib/components/Channel.svelte +++ b/ui/lib/components/Channel.svelte @@ -2,13 +2,13 @@ let { id, name, active, hasUnreads } = $props(); - -
  • +
  • + {#if hasUnreads} {:else} {/if} {name} -
  • - + + diff --git a/ui/styles/sidebar.css b/ui/styles/sidebar.css index 5e5e16a..c6aab6a 100644 --- a/ui/styles/sidebar.css +++ b/ui/styles/sidebar.css @@ -4,6 +4,8 @@ } .list-nav a { + display: block; + padding: 0.5rem; text-decoration: none; } @@ -12,7 +14,6 @@ } .list-nav li { - padding: 0.5rem; border-radius: 0.5rem; border: 1px solid var(--colour-navbar-border); margin: 0.25rem; -- cgit v1.2.3 From b9bc643af0d0523a70d76236d9277539da083b36 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Fri, 21 Feb 2025 16:35:56 -0500 Subject: Add missing awaits on goto() calls --- ui/lib/components/LogOut.svelte | 2 +- ui/routes/(app)/+layout.svelte | 8 ++++---- ui/routes/(login)/invite/[invite]/+page.svelte | 2 +- ui/routes/(login)/login/+page.svelte | 2 +- ui/routes/(login)/setup/+page.svelte | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'ui/lib') diff --git a/ui/lib/components/LogOut.svelte b/ui/lib/components/LogOut.svelte index b699cfd..1cb8fb5 100644 --- a/ui/lib/components/LogOut.svelte +++ b/ui/lib/components/LogOut.svelte @@ -8,7 +8,7 @@ const response = await logOut(); if (200 <= response.status && response.status < 300) { currentUser.set(null); - goto('/login'); + await goto('/login'); } } diff --git a/ui/routes/(app)/+layout.svelte b/ui/routes/(app)/+layout.svelte index dff9245..a81efce 100644 --- a/ui/routes/(app)/+layout.svelte +++ b/ui/routes/(app)/+layout.svelte @@ -2,11 +2,11 @@ import { page } from '$app/stores'; import { goto } from '$app/navigation'; import { browser } from '$app/environment'; - import { onMount, onDestroy, getContext } from 'svelte'; + import { getContext, onDestroy, onMount } from 'svelte'; import TinyGesture from 'tinygesture'; import { boot, subscribeToEvents } from '$lib/apiServer'; - import { currentUser, logins, channelsList, messages, onEvent } from '$lib/store'; + import { channelsList, currentUser, logins, messages, onEvent } from '$lib/store'; import ChannelList from '$lib/components/ChannelList.svelte'; import CreateChannelForm from '$lib/components/CreateChannelForm.svelte'; @@ -76,11 +76,11 @@ break; case 401: currentUser.set(null); - goto('/login'); + await goto('/login'); break; case 503: currentUser.set(null); - goto('/setup'); + await goto('/setup'); break; default: // TODO: display error. diff --git a/ui/routes/(login)/invite/[invite]/+page.svelte b/ui/routes/(login)/invite/[invite]/+page.svelte index 132cbc1..0c01286 100644 --- a/ui/routes/(login)/invite/[invite]/+page.svelte +++ b/ui/routes/(login)/invite/[invite]/+page.svelte @@ -18,7 +18,7 @@ if (200 <= response.status && response.status < 300) { username = ''; password = ''; - goto('/'); + await goto('/'); } pending = false; } diff --git a/ui/routes/(login)/login/+page.svelte b/ui/routes/(login)/login/+page.svelte index a1291ea..9157cef 100644 --- a/ui/routes/(login)/login/+page.svelte +++ b/ui/routes/(login)/login/+page.svelte @@ -16,7 +16,7 @@ if (200 <= response.status && response.status < 300) { username = ''; password = ''; - goto('/'); + await goto('/'); } pending = false; } diff --git a/ui/routes/(login)/setup/+page.svelte b/ui/routes/(login)/setup/+page.svelte index f162ded..c63f198 100644 --- a/ui/routes/(login)/setup/+page.svelte +++ b/ui/routes/(login)/setup/+page.svelte @@ -16,7 +16,7 @@ if (200 <= response.status && response.status < 300) { username = ''; password = ''; - goto('/'); + await goto('/'); } pending = false; } -- cgit v1.2.3 From c49c7184f69c6ec7a050679116f0d55623d80af1 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Fri, 21 Feb 2025 17:10:35 -0500 Subject: Remove stray imports --- ui/lib/apiServer.js | 1 - 1 file changed, 1 deletion(-) (limited to 'ui/lib') diff --git a/ui/lib/apiServer.js b/ui/lib/apiServer.js index bb0a587..c65b743 100644 --- a/ui/lib/apiServer.js +++ b/ui/lib/apiServer.js @@ -1,5 +1,4 @@ import axios from 'axios'; -import { channelsList, logins, messages } from '$lib/store'; export const apiServer = axios.create({ baseURL: '/api/', -- cgit v1.2.3