From 6f6b42c1d840815ac4e42732783ff9b3420f038d Mon Sep 17 00:00:00 2001 From: Chuck Date: Thu, 8 Jan 2026 14:47:00 -0500 Subject: [PATCH] fix: Set values from item data in fallback array-of-objects rendering Fix fallback code path for rendering array-of-objects items to properly set input values from existing item data, matching behavior of proper renderArrayObjectItem function. Problem: - Fallback code at lines 3078-3091 and 6471-6486 creates input elements without setting values from existing item data - Text inputs have no value attribute set - Checkboxes have no checked attribute computed from item properties - Users would see empty form fields instead of existing configuration data - Proper renderArrayObjectItem function correctly sets values (line 2556) Solution: - Extract propValue from item data: item[propKey] with schema default fallback - For text inputs: Set value attribute with HTML-escaped propValue - For checkboxes: Set checked attribute based on propValue truthiness - Add inline HTML escaping for XSS prevention (since fallback code may run outside IIFE scope where escapeHtml function may not be available) This ensures fallback rendering displays existing data correctly when window.renderArrayObjectItem is not available. --- web_interface/static/v3/plugins_manager.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/web_interface/static/v3/plugins_manager.js b/web_interface/static/v3/plugins_manager.js index f6a43057..b3fb8237 100644 --- a/web_interface/static/v3/plugins_manager.js +++ b/web_interface/static/v3/plugins_manager.js @@ -3079,12 +3079,16 @@ function generateFieldHtml(key, prop, value, prefix = '') { html += `
`; Object.keys(itemProperties || {}).forEach(propKey => { const propSchema = itemProperties[propKey]; + const propValue = item[propKey] !== undefined ? item[propKey] : propSchema.default; const propLabel = propSchema.title || propKey.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); html += `
`; if (propSchema.type === 'boolean') { - html += ``; + const checked = propValue ? 'checked' : ''; + html += ``; } else { - html += ``; + // Escape HTML to prevent XSS + const escapedValue = typeof propValue === 'string' ? propValue.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''') : (propValue || ''); + html += ``; } html += `
`; }); @@ -6471,15 +6475,21 @@ if (typeof window !== 'undefined') { itemHtml = window.renderArrayObjectItem(fieldId, fullKey, itemsSchema.properties, {}, newIndex, itemsSchema); } else { // Fallback: create basic HTML structure + // Note: newItem is {} for newly added items, so this will use schema defaults + const newItem = {}; itemHtml = `
`; Object.keys(itemsSchema.properties || {}).forEach(propKey => { const propSchema = itemsSchema.properties[propKey]; + const propValue = newItem[propKey] !== undefined ? newItem[propKey] : propSchema.default; const propLabel = propSchema.title || propKey.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); itemHtml += `
`; if (propSchema.type === 'boolean') { - itemHtml += ``; + const checked = propValue ? 'checked' : ''; + itemHtml += ``; } else { - itemHtml += ``; + // Escape HTML to prevent XSS + const escapedValue = typeof propValue === 'string' ? propValue.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''') : (propValue || ''); + itemHtml += ``; } itemHtml += `
`; });