From d57d68116ee8e5af583ef0bb1f87cf3f40d2b845 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Thu, 20 Feb 2025 17:21:18 -0500 Subject: Let Svelte's `$derived` handling figure out update ordering for the channels list. This fixes a bug. To reproduce: 1. Open the client and log in. 2. Create a new channel using the `create channel` UI. The expected result - and the behaviour after this commit - is that the newly-created channel will be shown in the sidebar immediately. The buggy behaviour is that it was not, but would appear in the sidebar once the client is reloaded. The channel would also not appear for other clients until they reloaded. I'm not actually completely sure of _why_ this fixes the bug, but it does. --- ui/routes/(app)/+layout.svelte | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'ui/routes/(app)/+layout.svelte') diff --git a/ui/routes/(app)/+layout.svelte b/ui/routes/(app)/+layout.svelte index cbfef54..3752bef 100644 --- a/ui/routes/(app)/+layout.svelte +++ b/ui/routes/(app)/+layout.svelte @@ -19,14 +19,8 @@ let loading = $state(true); let channel = $derived($page.params.channel); - let rawChannels; - channelsList.subscribe((val) => { - rawChannels = val.channels; - }); - let rawMessages; - messages.subscribe((val) => { - rawMessages = val; - }); + let rawChannels = $derived($channelsList.channels); + let rawMessages = $derived($messages); let enrichedChannels = $derived.by(() => { const channels = rawChannels; -- cgit v1.2.3 From 60f6b298329728fc8a91cd8c688c9b38fa302f0d Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Thu, 20 Feb 2025 18:41:18 -0500 Subject: Remove the last lingering Svelte4-style event bindings. --- ui/routes/(app)/+layout.svelte | 8 ++++---- ui/routes/(app)/ch/[channel]/+page.svelte | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'ui/routes/(app)/+layout.svelte') diff --git a/ui/routes/(app)/+layout.svelte b/ui/routes/(app)/+layout.svelte index 3752bef..5ec84d9 100644 --- a/ui/routes/(app)/+layout.svelte +++ b/ui/routes/(app)/+layout.svelte @@ -99,18 +99,18 @@ } }); - function beforeUnload(evt) { - evt.preventDefault(); + function onbeforeunload(event) { + event.preventDefault(); if (events !== null) { events.close(); } // For some compat reasons? - evt.returnValue = ''; + event.returnValue = ''; return ''; } - + diff --git a/ui/routes/(app)/ch/[channel]/+page.svelte b/ui/routes/(app)/ch/[channel]/+page.svelte index dbdb507..9335198 100644 --- a/ui/routes/(app)/ch/[channel]/+page.svelte +++ b/ui/routes/(app)/ch/[channel]/+page.svelte @@ -58,7 +58,7 @@ } let lastReadCallback = null; - function handleScroll() { + function onscroll() { clearTimeout(lastReadCallback); // Fine if lastReadCallback is null still. lastReadCallback = setTimeout(setLastRead, 2 * 1000); } @@ -66,7 +66,7 @@ -
+
-- 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/routes/(app)/+layout.svelte') 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 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/routes/(app)/+layout.svelte') 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 25daf36b18086096651b381223ad8f03fbca5045 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Fri, 21 Feb 2025 17:07:35 -0500 Subject: Retire use of $page store in favour of Sv5 page state --- ui/routes/(app)/+layout.svelte | 4 ++-- ui/routes/(app)/ch/[channel]/+page.svelte | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'ui/routes/(app)/+layout.svelte') diff --git a/ui/routes/(app)/+layout.svelte b/ui/routes/(app)/+layout.svelte index a81efce..6339abd 100644 --- a/ui/routes/(app)/+layout.svelte +++ b/ui/routes/(app)/+layout.svelte @@ -1,5 +1,5 @@