ui : follow the svelte runes guidance in chat message code

Two effects detected changes with manual previous-value refs and reset
flags. The permission request carries object identity, so its dismissal
is now a derived comparing the dismissed request; the continue request
is a bare boolean, so its dismissal only shrinks to a reset while no
request is pending. Also drop a dead if (browser) guard in the markdown
theme loader - effects never run on the server.

Assisted-by: pi:zai-org/GLM-5.3
This commit is contained in:
Aleksander Grygier
2026-09-06 01:57:00 +02:00
parent 3d1da290fe
commit e5f145bdef
2 changed files with 20 additions and 28 deletions
@@ -46,49 +46,44 @@
isLastAssistantMessage ? !!agenticStore.getLastError(message.convId) : false
);
let permissionDismissed = $state(false);
const pendingPermission = $derived(
isStreaming && isLastAssistantMessage
? agenticStore.getPendingPermissionRequest(message.convId)
: null
);
let prevPendingRef: typeof pendingPermission = null;
$effect(() => {
if (pendingPermission !== prevPendingRef) {
prevPendingRef = pendingPermission;
// dismissal applies to the request object, so the next request ( new
// identity ) shows the card again without any reset bookkeeping
let dismissedPermission: typeof pendingPermission = $state(null);
if (pendingPermission) {
permissionDismissed = false;
}
}
});
const visiblePermission = $derived(
pendingPermission && dismissedPermission !== pendingPermission ? pendingPermission : null
);
function handlePermission(decision: ToolPermissionDecision) {
permissionDismissed = true;
dismissedPermission = pendingPermission;
agenticStore.resolvePermission(message.convId, decision);
}
let continueDismissed = $state(false);
const pendingContinue = $derived(
isStreaming && isLastAssistantMessage
? agenticStore.getPendingContinueRequest(message.convId)
: false
);
let prevContinueRef = false;
$effect(() => {
if (pendingContinue !== prevContinueRef) {
prevContinueRef = pendingContinue;
let continueDismissed = $state(false);
if (pendingContinue) {
continueDismissed = false;
}
// the continue request is a plain boolean, so there is no identity to
// compare against; clear the dismissal whenever no request is pending so
// the next one starts from a clean state
$effect(() => {
if (!pendingContinue) {
continueDismissed = false;
}
});
const showContinue = $derived(Boolean(pendingContinue) && !continueDismissed);
function handleContinue(shouldContinue: boolean) {
continueDismissed = true;
agenticStore.resolveContinue(message.convId, shouldContinue);
@@ -238,15 +233,15 @@
{/each}
{/if}
{#if pendingPermission && !permissionDismissed}
{#if visiblePermission}
<ChatMessageActionCardPermissionRequest
onDecision={handlePermission}
serverLabel={pendingPermission.serverLabel}
toolName={pendingPermission.toolName}
serverLabel={visiblePermission.serverLabel}
toolName={visiblePermission.toolName}
/>
{/if}
{#if pendingContinue && !continueDismissed}
{#if showContinue}
<ChatMessageActionCardContinueRequest onDecision={handleContinue} />
{/if}
</div>
@@ -7,7 +7,6 @@
getMdastNodeHash,
isAppendMode
} from './markdown-utils';
import { browser } from '$app/environment';
import {
ActionIconCopyToClipboard,
CodeBlockActions,
@@ -153,8 +152,6 @@
* @param isDark - Whether to load the dark theme (true) or light theme (false)
*/
function loadHighlightTheme(isDark: boolean) {
if (!browser) return;
document
.querySelectorAll(`style[${UI_DATA_ATTRS.HIGHLIGHT_THEME_PREVIEW}]`)
.forEach((style) => style.remove());