From 5ae54019ba01d12cd570755dfd63bfc7c81b4b05 Mon Sep 17 00:00:00 2001 From: Pulse Monitor Date: Thu, 4 Sep 2025 20:09:38 +0000 Subject: [PATCH] fix: use Index instead of For loop for webhook header inputs (addresses #412) Switched from For to Index loop which provides better stability for input elements in SolidJS. Also removed circular dependency between headerInputs and formData that was causing re-renders. --- .../src/components/Alerts/WebhookConfig.tsx | 81 ++++++++----------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/frontend-modern/src/components/Alerts/WebhookConfig.tsx b/frontend-modern/src/components/Alerts/WebhookConfig.tsx index 39246248a..2f49ae347 100644 --- a/frontend-modern/src/components/Alerts/WebhookConfig.tsx +++ b/frontend-modern/src/components/Alerts/WebhookConfig.tsx @@ -1,4 +1,4 @@ -import { createSignal, createEffect, Show, For } from 'solid-js'; +import { createSignal, createEffect, Show, For, Index } from 'solid-js'; import { NotificationsAPI, Webhook } from '@/api/notifications'; interface WebhookTemplate { @@ -38,34 +38,6 @@ export function WebhookConfig(props: WebhookConfigProps) { // Track header inputs separately to avoid focus loss const [headerInputs, setHeaderInputs] = createSignal>([]); - // Sync headerInputs with formData.headers - createEffect(() => { - const headers = formData().headers || {}; - const currentInputs = headerInputs(); - - // Only update if we're starting fresh (not already editing headers) - if (currentInputs.length === 0 && Object.keys(headers).length > 0) { - setHeaderInputs( - Object.entries(headers).map(([key, value], index) => ({ - id: `header-${Date.now()}-${index}`, - key, - value - })) - ); - } - }); - - // Update formData.headers when headerInputs change - const updateHeadersInFormData = () => { - const headers: Record = {}; - headerInputs().forEach(input => { - if (input.key) { - headers[input.key] = input.value; - } - }); - setFormData({ ...formData(), headers }); - }; - // Load webhook templates createEffect(async () => { try { @@ -77,16 +49,22 @@ export function WebhookConfig(props: WebhookConfigProps) { }); const saveWebhook = () => { - // First sync headers from inputs to formData - updateHeadersInFormData(); - const data = formData(); if (!data.name || !data.url) return; + // Build headers from headerInputs + const headers: Record = {}; + headerInputs().forEach(input => { + if (input.key) { + headers[input.key] = input.value; + } + }); + if (editingId()) { props.onUpdate({ ...data, id: editingId()!, + headers, service: data.service, template: data.payloadTemplate }); @@ -99,7 +77,7 @@ export function WebhookConfig(props: WebhookConfigProps) { name: data.name, url: data.url, method: data.method, - headers: data.headers, + headers, enabled: data.enabled, service: data.service, template: data.payloadTemplate @@ -431,29 +409,33 @@ export function WebhookConfig(props: WebhookConfigProps) {
- - {(header) => ( + + {(header, index) => (
{ const newKey = e.currentTarget.value; - setHeaderInputs(inputs => - inputs.map(h => h.id === header.id ? { ...h, key: newKey } : h) - ); + setHeaderInputs(inputs => { + const newInputs = [...inputs]; + newInputs[index] = { ...newInputs[index], key: newKey }; + return newInputs; + }); }} placeholder="Header Name" class="flex-1 px-3 py-2 text-sm border rounded-lg dark:bg-gray-700 dark:border-gray-600" /> { const newValue = e.currentTarget.value; - setHeaderInputs(inputs => - inputs.map(h => h.id === header.id ? { ...h, value: newValue } : h) - ); + setHeaderInputs(inputs => { + const newInputs = [...inputs]; + newInputs[index] = { ...newInputs[index], value: newValue }; + return newInputs; + }); }} placeholder="Header Value" class="flex-1 px-3 py-2 text-sm border rounded-lg dark:bg-gray-700 dark:border-gray-600" @@ -461,7 +443,7 @@ export function WebhookConfig(props: WebhookConfigProps) {
)} -
+