@@ -126,13 +126,15 @@ const SettingsForms = {
126126 ` ;
127127
128128 // Generate cards for each instance
129- settings . instances . forEach ( ( instance , index ) => {
130- instancesHtml += SettingsForms . renderInstanceCard ( 'sonarr' , instance , index ) ;
131- } ) ;
129+ if ( settings . instances && settings . instances . length > 0 ) {
130+ settings . instances . forEach ( ( instance , index ) => {
131+ instancesHtml += SettingsForms . renderInstanceCard ( 'sonarr' , instance , index ) ;
132+ } ) ;
133+ }
132134
133- // Add "Add Instance" card
135+ // Add "Add Instance" card (always present)
134136 instancesHtml += `
135- <div class="add-instance-card" onclick="SettingsForms.openInstanceModal(' sonarr') ">
137+ <div class="add-instance-card" data-app-type=" sonarr">
136138 <div class="add-icon"><i class="fas fa-plus-circle"></i></div>
137139 <div class="add-text">Add Sonarr Instance</div>
138140 </div>
@@ -244,6 +246,29 @@ const SettingsForms = {
244246 container . innerHTML =
245247 sonarrSaveButtonHtml + instancesHtml + searchSettingsHtml ;
246248
249+ // Attach event listeners dynamically
250+ const grid = container . querySelector ( '#sonarr-instances-grid' ) ;
251+ if ( grid ) {
252+ grid . addEventListener ( 'click' , ( e ) => {
253+ const editBtn = e . target . closest ( '.btn-card.edit' ) ;
254+ const deleteBtn = e . target . closest ( '.btn-card.delete' ) ;
255+ const addCard = e . target . closest ( '.add-instance-card' ) ;
256+
257+ if ( editBtn ) {
258+ const appType = editBtn . dataset . appType ;
259+ const index = parseInt ( editBtn . dataset . instanceIndex ) ;
260+ SettingsForms . openInstanceModal ( appType , index ) ;
261+ } else if ( deleteBtn ) {
262+ const appType = deleteBtn . dataset . appType ;
263+ const index = parseInt ( deleteBtn . dataset . instanceIndex ) ;
264+ SettingsForms . deleteInstance ( appType , index ) ;
265+ } else if ( addCard ) {
266+ const appType = addCard . dataset . appType ;
267+ SettingsForms . openInstanceModal ( appType ) ;
268+ }
269+ } ) ;
270+ }
271+
247272
248273 // Add event listeners for custom tags visibility
249274 const tagProcessedItemsToggle = container . querySelector (
@@ -2131,13 +2156,15 @@ const SettingsForms = {
21312156 ` ;
21322157
21332158 // Generate cards for each instance
2134- settings . instances . forEach ( ( instance , index ) => {
2135- instancesHtml += SettingsForms . renderInstanceCard ( 'eros' , instance , index ) ;
2136- } ) ;
2159+ if ( settings . instances && settings . instances . length > 0 ) {
2160+ settings . instances . forEach ( ( instance , index ) => {
2161+ instancesHtml += SettingsForms . renderInstanceCard ( 'eros' , instance , index ) ;
2162+ } ) ;
2163+ }
21372164
2138- // Add "Add Instance" card
2165+ // Add "Add Instance" card (always present)
21392166 instancesHtml += `
2140- <div class="add-instance-card" onclick="SettingsForms.openInstanceModal(' eros') ">
2167+ <div class="add-instance-card" data-app-type=" eros">
21412168 <div class="add-icon"><i class="fas fa-plus-circle"></i></div>
21422169 <div class="add-text">Add Whisparr V3 Instance</div>
21432170 </div>
@@ -2148,10 +2175,37 @@ const SettingsForms = {
21482175 </div> <!-- settings-group -->
21492176 ` ;
21502177
2151- // Search Mode dropdown
2152- let searchSettingsHtml = `
2178+ // Continue with the rest of the settings form
2179+ container . innerHTML = `
2180+ ${ erosSaveButtonHtml }
2181+ ${ instancesHtml }
2182+
21532183 <div class="settings-group">
21542184 <h3>Search Settings</h3>
2185+ ` ;
2186+
2187+ // Attach event listeners dynamically
2188+ const grid = container . querySelector ( '#eros-instances-grid' ) ;
2189+ if ( grid ) {
2190+ grid . addEventListener ( 'click' , ( e ) => {
2191+ const editBtn = e . target . closest ( '.btn-card.edit' ) ;
2192+ const deleteBtn = e . target . closest ( '.btn-card.delete' ) ;
2193+ const addCard = e . target . closest ( '.add-instance-card' ) ;
2194+
2195+ if ( editBtn ) {
2196+ const appType = editBtn . dataset . appType ;
2197+ const index = parseInt ( editBtn . dataset . instanceIndex ) ;
2198+ SettingsForms . openInstanceModal ( appType , index ) ;
2199+ } else if ( deleteBtn ) {
2200+ const appType = deleteBtn . dataset . appType ;
2201+ const index = parseInt ( deleteBtn . dataset . instanceIndex ) ;
2202+ SettingsForms . deleteInstance ( appType , index ) ;
2203+ } else if ( addCard ) {
2204+ const appType = addCard . dataset . appType ;
2205+ SettingsForms . openInstanceModal ( appType ) ;
2206+ }
2207+ } ) ;
2208+ }
21552209 < div class = "setting-item" >
21562210 < label for = "eros_search_mode" > < a href = "https://plexguide.github.io/Huntarr.io/apps/eros.html#search-mode" class = "info-icon" title = "Learn more about search modes" target = "_blank" rel = "noopener" > < i class = "fas fa-info-circle" > </ i > </ a > Search Mode:</ label >
21572211 < select id = "eros_search_mode" name = "search_mode" >
@@ -7517,6 +7571,7 @@ const SettingsForms = {
75177571 ` ;
75187572
75197573 // Create the Prowlarr configuration container
7574+ // Prowlarr is a single instance, but we reuse the card design
75207575 let prowlarrHtml = `
75217576 <div class="settings-group" style="
75227577 background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #334155 100%);
@@ -7527,57 +7582,119 @@ const SettingsForms = {
75277582 box-shadow: 0 4px 12px rgba(90, 109, 137, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.1);
75287583 ">
75297584 <h3>Prowlarr Configuration</h3>
7530- <div class="prowlarr-container">
7531- <div class="instance-item" data-instance-id="0">
7532- <div class="instance-header">
7533- <h4>Prowlarr</h4>
7534- <div class="instance-actions">
7535- <span class="connection-status" id="prowlarr-status-0"></span>
7536- </div>
7537- </div>
7538- <div class="instance-content">
7539- <div class="setting-item">
7540- <label for="prowlarr-enabled-0">Enabled:</label>
7541- <label class="toggle-switch" style="width:40px; height:20px; display:inline-block; position:relative;">
7542- <input type="checkbox" id="prowlarr-enabled-0" name="enabled" ${
7543- settings . enabled !== false
7544- ? "checked"
7545- : ""
7546- } >
7547- <span class="toggle-slider" style="position:absolute; cursor:pointer; top:0; left:0; right:0; bottom:0; background-color:#3d4353; border-radius:20px; transition:0.4s;"></span>
7548- </label>
7549- <p class="setting-help">Enable or disable Prowlarr integration</p>
7550- </div>
7551- <div class="setting-item">
7552- <label for="prowlarr-url-0">URL:</label>
7553- <input type="text" id="prowlarr-url-0" name="api_url" value="${
7554- settings . api_url || ""
7555- } " placeholder="Base URL for Prowlarr (e.g., http://localhost:9696)" data-instance-index="0">
7556- <p class="setting-help">Base URL for Prowlarr (e.g., http://localhost:9696)</p>
7557- </div>
7558- <div class="setting-item">
7559- <label for="prowlarr-key-0">API Key:</label>
7560- <input type="text" id="prowlarr-key-0" name="api_key" value="${
7561- settings . api_key || ""
7562- } " placeholder="API key for Prowlarr" data-instance-index="0">
7563- <p class="setting-help">API key for Prowlarr</p>
7564- </div>
7565- </div>
7566- </div>
7585+ <div class="instance-card-grid" id="prowlarr-instances-grid">
7586+ ` ;
7587+
7588+ // Normalize Prowlarr settings to look like an instance object for the card renderer
7589+ // Prowlarr settings are flat, not in an 'instances' array
7590+ const prowlarrInstance = {
7591+ name : 'Prowlarr' ,
7592+ api_url : settings . api_url || '' ,
7593+ api_key : settings . api_key || '' ,
7594+ enabled : settings . enabled !== false
7595+ } ;
7596+
7597+ // Render single card
7598+ prowlarrHtml += SettingsForms . renderInstanceCard ( 'prowlarr' , prowlarrInstance , 0 ) ;
7599+
7600+ prowlarrHtml += `
75677601 </div>
75687602 </div>
75697603 ` ;
75707604
75717605 // Set the content with save button at the top
75727606 container . innerHTML = prowlarrSaveButtonHtml + prowlarrHtml ;
75737607
7574- // Setup auto-detection (like Sonarr)
7575- this . setupProwlarrAutoDetection ( container ) ;
7608+ // Attach event listeners dynamically
7609+ const grid = container . querySelector ( '#prowlarr-instances-grid' ) ;
7610+ if ( grid ) {
7611+ grid . addEventListener ( 'click' , ( e ) => {
7612+ const editBtn = e . target . closest ( '.btn-card.edit' ) ;
7613+ if ( editBtn ) {
7614+ // Open modal for single instance Prowlarr
7615+ SettingsForms . openProwlarrModal ( ) ;
7616+ }
7617+ } ) ;
7618+ }
75767619
75777620 // Set up manual save functionality for Prowlarr
75787621 this . setupAppManualSave ( container , "prowlarr" , settings ) ;
75797622 } ,
75807623
7624+ // Open modal specifically for Prowlarr (since it has a different data structure)
7625+ openProwlarrModal : function ( ) {
7626+ const settings = window . huntarrUI . originalSettings . prowlarr ;
7627+ if ( ! settings ) return ;
7628+
7629+ // Create modal container if it doesn't exist
7630+ let modalOverlay = document . getElementById ( 'huntarr-instance-modal' ) ;
7631+ if ( ! modalOverlay ) {
7632+ modalOverlay = document . createElement ( 'div' ) ;
7633+ modalOverlay . id = 'huntarr-instance-modal' ;
7634+ modalOverlay . className = 'huntarr-modal-overlay' ;
7635+ document . body . appendChild ( modalOverlay ) ;
7636+ }
7637+
7638+ const formFields = `
7639+ <div class="modal-form-section">
7640+ <div class="modal-section-title">Connection Details</div>
7641+ <div class="setting-item">
7642+ <label>Enabled</label>
7643+ <label class="toggle-switch">
7644+ <input type="checkbox" id="modal-enabled" ${ settings . enabled !== false ? 'checked' : '' } >
7645+ <span class="toggle-slider"></span>
7646+ </label>
7647+ </div>
7648+ <div class="setting-item">
7649+ <label>URL</label>
7650+ <input type="text" id="modal-url" value="${ settings . api_url || '' } " placeholder="http://localhost:9696">
7651+ </div>
7652+ <div class="setting-item">
7653+ <label>API Key</label>
7654+ <input type="text" id="modal-key" value="${ settings . api_key || '' } " placeholder="API Key">
7655+ </div>
7656+ </div>
7657+ ` ;
7658+
7659+ modalOverlay . innerHTML = `
7660+ <div class="huntarr-modal">
7661+ <div class="huntarr-modal-header">
7662+ <h3 class="huntarr-modal-title">Edit Prowlarr Configuration</h3>
7663+ <button class="huntarr-modal-close" onclick="document.getElementById('huntarr-instance-modal').classList.remove('active')">
7664+ <i class="fas fa-times"></i>
7665+ </button>
7666+ </div>
7667+ <div class="huntarr-modal-body">
7668+ <div class="modal-form-grid">
7669+ ${ formFields }
7670+ </div>
7671+ </div>
7672+ <div class="huntarr-modal-footer">
7673+ <button class="btn-modal btn-modal-secondary" onclick="document.getElementById('huntarr-instance-modal').classList.remove('active')">Cancel</button>
7674+ <button class="btn-modal btn-modal-primary" onclick="SettingsForms.saveProwlarrFromModal()">Save Changes</button>
7675+ </div>
7676+ </div>
7677+ ` ;
7678+
7679+ setTimeout ( ( ) => modalOverlay . classList . add ( 'active' ) , 10 ) ;
7680+ } ,
7681+
7682+ // Save Prowlarr settings from modal
7683+ saveProwlarrFromModal : function ( ) {
7684+ const settings = window . huntarrUI . originalSettings . prowlarr ;
7685+
7686+ // Update settings object
7687+ settings . enabled = document . getElementById ( 'modal-enabled' ) . checked ;
7688+ settings . api_url = document . getElementById ( 'modal-url' ) . value ;
7689+ settings . api_key = document . getElementById ( 'modal-key' ) . value ;
7690+
7691+ // Save to server
7692+ this . saveAppSettings ( 'prowlarr' , settings ) ;
7693+
7694+ // Close modal
7695+ document . getElementById ( 'huntarr-instance-modal' ) . classList . remove ( 'active' ) ;
7696+ } ,
7697+
75817698 // Setup auto-detection for Prowlarr (similar to Sonarr)
75827699 setupProwlarrAutoDetection : function ( container ) {
75837700 console . log ( "[SettingsForms] Setting up Prowlarr auto-detection" ) ;
@@ -7639,10 +7756,12 @@ const SettingsForms = {
76397756
76407757 // Render a single instance card
76417758 renderInstanceCard : function ( appType , instance , index ) {
7642- const statusClass = instance . enabled ? 'status-connected' : 'status-unknown' ; // We can improve this with real status later
7759+ const statusClass = instance . enabled ? 'status-connected' : 'status-unknown' ;
76437760 const statusIcon = instance . enabled ? 'fa-check-circle' : 'fa-pause-circle' ;
76447761 const isDefault = index === 0 ;
7762+ const indexAttr = index !== null ? index : '' ;
76457763
7764+ // Use window.SettingsForms explicitly in onclick to ensure scope resolution
76467765 return `
76477766 <div class="instance-card ${ isDefault ? 'default-instance' : '' } " data-instance-index="${ index } ">
76487767 <div class="instance-card-header">
@@ -7666,11 +7785,11 @@ const SettingsForms = {
76667785 </div>
76677786 </div>
76687787 <div class="instance-card-footer">
7669- <button type="button" class="btn-card edit" onclick="SettingsForms.openInstanceModal(' ${ appType } ', ${ index } ) ">
7788+ <button type="button" class="btn-card edit" data-app-type=" ${ appType } " data-instance-index=" ${ index } ">
76707789 <i class="fas fa-edit"></i> Edit
76717790 </button>
76727791 ${ ! isDefault ? `
7673- <button type="button" class="btn-card delete" onclick="SettingsForms.deleteInstance(' ${ appType } ', ${ index } ) ">
7792+ <button type="button" class="btn-card delete" data-app-type=" ${ appType } " data-instance-index=" ${ index } ">
76747793 <i class="fas fa-trash"></i> Delete
76757794 </button>
76767795 ` : '' }
0 commit comments