@@ -1620,6 +1620,216 @@ const SettingsForms = {
16201620 } ) ;
16211621 } ) ;
16221622 } ) ;
1623+
1624+ // Set up remove buttons for existing instances
1625+ const removeButtons = container . querySelectorAll ( '.remove-instance-btn' ) ;
1626+ removeButtons . forEach ( btn => {
1627+ btn . addEventListener ( 'click' , function ( ) {
1628+ const instancePanel = btn . closest ( '.instance-item' ) || btn . closest ( '.instance-panel' ) ;
1629+ if ( instancePanel && instancePanel . parentNode ) {
1630+ instancePanel . parentNode . removeChild ( instancePanel ) ;
1631+
1632+ // Update the button text with new count if updateAddButtonText exists
1633+ const addBtn = container . querySelector ( `.add-${ appType } -instance-btn` ) ;
1634+ if ( addBtn ) {
1635+ const instancesContainer = container . querySelector ( '.instances-container' ) ;
1636+ if ( instancesContainer ) {
1637+ const currentCount = instancesContainer . querySelectorAll ( '.instance-item' ) . length ;
1638+ addBtn . innerHTML = `<i class="fas fa-plus"></i> Add ${ appType . charAt ( 0 ) . toUpperCase ( ) + appType . slice ( 1 ) } Instance (${ currentCount } /9)` ;
1639+
1640+ // Re-enable button if we're under the limit
1641+ if ( currentCount < 9 ) {
1642+ addBtn . disabled = false ;
1643+ addBtn . title = "" ;
1644+ }
1645+ }
1646+ }
1647+
1648+ // Trigger change event to update save button state
1649+ const changeEvent = new Event ( 'change' ) ;
1650+ container . dispatchEvent ( changeEvent ) ;
1651+ }
1652+ } ) ;
1653+ } ) ;
1654+
1655+ // Add instance button functionality
1656+ const addBtn = container . querySelector ( `.add-${ appType } -instance-btn` ) ;
1657+ if ( addBtn ) {
1658+ // Function to update the button text with current instance count
1659+ const updateAddButtonText = ( ) => {
1660+ const instancesContainer = container . querySelector ( '.instances-container' ) ;
1661+ if ( ! instancesContainer ) return ;
1662+ const currentCount = instancesContainer . querySelectorAll ( '.instance-item' ) . length ;
1663+ addBtn . innerHTML = `<i class="fas fa-plus"></i> Add ${ appType . charAt ( 0 ) . toUpperCase ( ) + appType . slice ( 1 ) } Instance (${ currentCount } /9)` ;
1664+
1665+ // Disable button if we've reached the limit
1666+ if ( currentCount >= 9 ) {
1667+ addBtn . disabled = true ;
1668+ addBtn . title = "Maximum of 9 instances allowed" ;
1669+ } else {
1670+ addBtn . disabled = false ;
1671+ addBtn . title = "" ;
1672+ }
1673+ } ;
1674+
1675+ // Initial button text update
1676+ updateAddButtonText ( ) ;
1677+
1678+ // Add event listener for the add button
1679+ addBtn . addEventListener ( 'click' , function ( ) {
1680+ const instancesContainer = container . querySelector ( '.instances-container' ) ;
1681+ if ( ! instancesContainer ) return ;
1682+
1683+ const existingInstances = instancesContainer . querySelectorAll ( '.instance-item' ) ;
1684+ const currentCount = existingInstances . length ;
1685+
1686+ // Don't allow more than 9 instances
1687+ if ( currentCount >= 9 ) {
1688+ alert ( 'Maximum of 9 instances allowed' ) ;
1689+ return ;
1690+ }
1691+
1692+ const newIndex = currentCount ; // Use current count as new index
1693+
1694+ // Create new instance HTML
1695+ const newInstanceHtml = `
1696+ <div class="instance-item" data-instance-id="${ newIndex } ">
1697+ <div class="instance-header">
1698+ <h4>Instance ${ newIndex + 1 } : New Instance</h4>
1699+ <div class="instance-actions">
1700+ <button type="button" class="remove-instance-btn">Remove</button>
1701+ <button type="button" class="test-connection-btn" data-instance="${ newIndex } " style="margin-left: 10px;">
1702+ <i class="fas fa-plug"></i> Test Connection
1703+ </button>
1704+ </div>
1705+ </div>
1706+ <div class="instance-content">
1707+ <div class="setting-item">
1708+ <label for="${ appType } -name-${ newIndex } ">Name:</label>
1709+ <input type="text" id="${ appType } -name-${ newIndex } " name="name" value="" placeholder="Friendly name for this ${ appType } instance">
1710+ <p class="setting-help">Friendly name for this ${ appType } instance</p>
1711+ </div>
1712+ <div class="setting-item">
1713+ <label for="${ appType } -url-${ newIndex } ">URL:</label>
1714+ <input type="text" id="${ appType } -url-${ newIndex } " name="api_url" value="" placeholder="Base URL for ${ appType } (e.g., http://localhost:8989)">
1715+ <p class="setting-help">Base URL for ${ appType } </p>
1716+ </div>
1717+ <div class="setting-item">
1718+ <label for="${ appType } -key-${ newIndex } ">API Key:</label>
1719+ <input type="text" id="${ appType } -key-${ newIndex } " name="api_key" value="" placeholder="API key for ${ appType } ">
1720+ <p class="setting-help">API key for ${ appType } </p>
1721+ </div>
1722+ <div class="setting-item">
1723+ <label for="${ appType } -enabled-${ newIndex } ">Enabled:</label>
1724+ <label class="toggle-switch" style="width:40px; height:20px; display:inline-block; position:relative;">
1725+ <input type="checkbox" id="${ appType } -enabled-${ newIndex } " name="enabled" checked>
1726+ <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>
1727+ </label>
1728+ </div>
1729+ </div>
1730+ </div>
1731+ ` ;
1732+
1733+ // Add the new instance to the container
1734+ instancesContainer . insertAdjacentHTML ( 'beforeend' , newInstanceHtml ) ;
1735+
1736+ // Get the newly added instance element
1737+ const newInstance = instancesContainer . querySelector ( `[data-instance-id="${ newIndex } "]` ) ;
1738+
1739+ // Set up event listeners for the new instance's buttons
1740+ const newTestBtn = newInstance . querySelector ( '.test-connection-btn' ) ;
1741+ const newRemoveBtn = newInstance . querySelector ( '.remove-instance-btn' ) ;
1742+
1743+ // Test connection button
1744+ if ( newTestBtn ) {
1745+ newTestBtn . addEventListener ( 'click' , ( e ) => {
1746+ e . preventDefault ( ) ;
1747+ const instancePanel = newTestBtn . closest ( '.instance-item' ) ;
1748+ const urlInput = instancePanel . querySelector ( 'input[name="api_url"]' ) ;
1749+ const keyInput = instancePanel . querySelector ( 'input[name="api_key"]' ) ;
1750+
1751+ if ( ! urlInput || ! keyInput ) {
1752+ alert ( 'Error: Could not find URL or API key inputs' ) ;
1753+ return ;
1754+ }
1755+
1756+ const url = urlInput . value . trim ( ) ;
1757+ const apiKey = keyInput . value . trim ( ) ;
1758+
1759+ if ( ! url ) {
1760+ alert ( 'Please enter a valid URL' ) ;
1761+ urlInput . focus ( ) ;
1762+ return ;
1763+ }
1764+
1765+ if ( ! apiKey ) {
1766+ alert ( 'Please enter a valid API key' ) ;
1767+ keyInput . focus ( ) ;
1768+ return ;
1769+ }
1770+
1771+ // Use the same test connection logic as existing buttons
1772+ const originalButtonHTML = newTestBtn . innerHTML ;
1773+ newTestBtn . innerHTML = '<i class="fas fa-spinner fa-spin"></i> Testing...' ;
1774+ newTestBtn . disabled = true ;
1775+
1776+ HuntarrUtils . fetchWithTimeout ( `/api/${ appType } /test-connection` , {
1777+ method : 'POST' ,
1778+ headers : { 'Content-Type' : 'application/json' } ,
1779+ body : JSON . stringify ( { api_url : url , api_key : apiKey } )
1780+ } )
1781+ . then ( response => response . json ( ) )
1782+ . then ( data => {
1783+ newTestBtn . disabled = false ;
1784+ if ( data . success ) {
1785+ newTestBtn . innerHTML = '<i class="fas fa-check"></i> Connected!' ;
1786+ alert ( `Successfully connected to ${ appType } ` ) ;
1787+ setTimeout ( ( ) => {
1788+ newTestBtn . innerHTML = originalButtonHTML ;
1789+ } , 3000 ) ;
1790+ } else {
1791+ newTestBtn . innerHTML = '<i class="fas fa-times"></i> Failed' ;
1792+ alert ( `Connection failed: ${ data . message || 'Unknown error' } ` ) ;
1793+ setTimeout ( ( ) => {
1794+ newTestBtn . innerHTML = originalButtonHTML ;
1795+ } , 3000 ) ;
1796+ }
1797+ } )
1798+ . catch ( error => {
1799+ newTestBtn . disabled = false ;
1800+ newTestBtn . innerHTML = '<i class="fas fa-times"></i> Error' ;
1801+ alert ( `Connection test failed: ${ error . message } ` ) ;
1802+ setTimeout ( ( ) => {
1803+ newTestBtn . innerHTML = originalButtonHTML ;
1804+ } , 3000 ) ;
1805+ } ) ;
1806+ } ) ;
1807+ }
1808+
1809+ // Remove button
1810+ if ( newRemoveBtn ) {
1811+ newRemoveBtn . addEventListener ( 'click' , function ( ) {
1812+ newInstance . remove ( ) ;
1813+ updateAddButtonText ( ) ;
1814+
1815+ // Trigger change event
1816+ const changeEvent = new Event ( 'change' ) ;
1817+ container . dispatchEvent ( changeEvent ) ;
1818+ } ) ;
1819+ }
1820+
1821+ // Update button text and trigger change event
1822+ updateAddButtonText ( ) ;
1823+ const changeEvent = new Event ( 'change' ) ;
1824+ container . dispatchEvent ( changeEvent ) ;
1825+
1826+ // Focus on the name input of the new instance
1827+ const nameInput = newInstance . querySelector ( 'input[name="name"]' ) ;
1828+ if ( nameInput ) {
1829+ nameInput . focus ( ) ;
1830+ }
1831+ } ) ;
1832+ }
16231833 } ,
16241834
16251835 // Test connection to an *arr API
0 commit comments