@@ -368,30 +368,71 @@ export class IntegrationWebviewProvider {
368368
369369 function renderIntegrations() {
370370 const listEl = document.getElementById('integrationList');
371+
372+ // Clear existing content
373+ while (listEl.firstChild) {
374+ listEl.removeChild(listEl.firstChild);
375+ }
376+
371377 if (!integrations || integrations.length === 0) {
372- listEl.innerHTML = '<p>No integrations found in this project.</p>';
378+ const noIntegrationsMsg = document.createElement('p');
379+ noIntegrationsMsg.textContent = 'No integrations found in this project.';
380+ listEl.appendChild(noIntegrationsMsg);
373381 return;
374382 }
375383
376- listEl.innerHTML = integrations.map (integration => {
384+ integrations.forEach (integration => {
377385 const statusClass = integration.status === 'connected' ? 'status-connected' : 'status-disconnected';
378386 const statusText = integration.status === 'connected' ? 'Connected' : 'Not Configured';
379387 const configureText = integration.config ? 'Reconfigure' : 'Configure';
380388 const displayName = integration.config?.name || integration.id;
381389
382- return \`
383- <div class="integration-item">
384- <div class="integration-info">
385- <div class="integration-name">\${displayName}</div>
386- <div class="integration-status \${statusClass}">\${statusText}</div>
387- </div>
388- <div class="integration-actions">
389- <button data-action="configure" data-id="\${integration.id}">\${configureText}</button>
390- \${integration.config ? '<button class="secondary" data-action="delete" data-id="'+integration.id+'">Delete</button>' : ''}
391- </div>
392- </div>
393- \`;
394- }).join('');
390+ // Create item container
391+ const itemDiv = document.createElement('div');
392+ itemDiv.className = 'integration-item';
393+
394+ // Create info section
395+ const infoDiv = document.createElement('div');
396+ infoDiv.className = 'integration-info';
397+
398+ const nameDiv = document.createElement('div');
399+ nameDiv.className = 'integration-name';
400+ nameDiv.textContent = displayName;
401+
402+ const statusDiv = document.createElement('div');
403+ statusDiv.className = 'integration-status';
404+ statusDiv.classList.add(statusClass);
405+ statusDiv.textContent = statusText;
406+
407+ infoDiv.appendChild(nameDiv);
408+ infoDiv.appendChild(statusDiv);
409+
410+ // Create actions section
411+ const actionsDiv = document.createElement('div');
412+ actionsDiv.className = 'integration-actions';
413+
414+ const configureBtn = document.createElement('button');
415+ configureBtn.dataset.action = 'configure';
416+ configureBtn.dataset.id = integration.id;
417+ configureBtn.textContent = configureText;
418+
419+ actionsDiv.appendChild(configureBtn);
420+
421+ // Add delete button if configured
422+ if (integration.config) {
423+ const deleteBtn = document.createElement('button');
424+ deleteBtn.className = 'secondary';
425+ deleteBtn.dataset.action = 'delete';
426+ deleteBtn.dataset.id = integration.id;
427+ deleteBtn.textContent = 'Delete';
428+ actionsDiv.appendChild(deleteBtn);
429+ }
430+
431+ // Assemble the item
432+ itemDiv.appendChild(infoDiv);
433+ itemDiv.appendChild(actionsDiv);
434+ listEl.appendChild(itemDiv);
435+ });
395436 }
396437
397438 // Event delegation for button clicks
@@ -417,29 +458,59 @@ export class IntegrationWebviewProvider {
417458 }
418459 });
419460
461+ function createFormGroup(labelText, inputElement) {
462+ const formGroup = document.createElement('div');
463+ formGroup.className = 'form-group';
464+
465+ const label = document.createElement('label');
466+ label.textContent = labelText;
467+
468+ formGroup.appendChild(label);
469+ formGroup.appendChild(inputElement);
470+
471+ return formGroup;
472+ }
473+
420474 function showConfigurationForm(integrationId, existingConfig) {
421475 currentIntegrationId = integrationId;
422476 const formContainer = document.getElementById('formContainer');
423477
478+ // Clear existing content
479+ while (formContainer.firstChild) {
480+ formContainer.removeChild(formContainer.firstChild);
481+ }
482+
424483 // Determine integration type
425484 let integrationType = existingConfig?.type;
426485 if (!integrationType) {
427486 // Show type selection first
428- formContainer.innerHTML = \`
429- <h2>Configure \${integrationId}</h2>
430- <div class="form-group">
431- <label>Integration Type:</label>
432- <select id="integrationType">
433- <option value="">Select type...</option>
434- <option value="postgres">PostgreSQL</option>
435- <option value="bigquery">BigQuery</option>
436- </select>
437- </div>
438- \`;
487+ const heading = document.createElement('h2');
488+ heading.textContent = 'Configure ' + integrationId;
489+ formContainer.appendChild(heading);
490+
491+ const select = document.createElement('select');
492+ select.id = 'integrationType';
493+
494+ const defaultOption = document.createElement('option');
495+ defaultOption.value = '';
496+ defaultOption.textContent = 'Select type...';
497+ select.appendChild(defaultOption);
498+
499+ const postgresOption = document.createElement('option');
500+ postgresOption.value = 'postgres';
501+ postgresOption.textContent = 'PostgreSQL';
502+ select.appendChild(postgresOption);
503+
504+ const bigqueryOption = document.createElement('option');
505+ bigqueryOption.value = 'bigquery';
506+ bigqueryOption.textContent = 'BigQuery';
507+ select.appendChild(bigqueryOption);
508+
509+ formContainer.appendChild(createFormGroup('Integration Type:', select));
439510 formContainer.classList.add('visible');
440511
441512 // Add event listener for type selection
442- document.getElementById('integrationType') .addEventListener('change', (e) => {
513+ select .addEventListener('change', (e) => {
443514 showTypeSpecificForm(e.target.value);
444515 });
445516 return;
@@ -456,58 +527,135 @@ export class IntegrationWebviewProvider {
456527
457528 const formContainer = document.getElementById('formContainer');
458529
530+ // Clear existing content
531+ while (formContainer.firstChild) {
532+ formContainer.removeChild(formContainer.firstChild);
533+ }
534+
459535 if (type === 'postgres') {
460- formContainer.innerHTML = \`
461- <h2>Configure PostgreSQL: \${currentIntegrationId}</h2>
462- <div class="form-group">
463- <label>Display Name:</label>
464- <input type="text" id="name" value="\${config?.name || ''}" placeholder="My PostgreSQL Database" required>
465- </div>
466- <div class="form-group">
467- <label>Host:</label>
468- <input type="text" id="host" value="\${config?.host || ''}" placeholder="localhost" required>
469- </div>
470- <div class="form-group">
471- <label>Port:</label>
472- <input type="number" id="port" value="\${config?.port || 5432}" placeholder="5432" required>
473- </div>
474- <div class="form-group">
475- <label>Database:</label>
476- <input type="text" id="database" value="\${config?.database || ''}" placeholder="mydb" required>
477- </div>
478- <div class="form-group">
479- <label>Username:</label>
480- <input type="text" id="username" value="\${config?.username || ''}" placeholder="postgres" required>
481- </div>
482- <div class="form-group">
483- <label>Password:</label>
484- <input type="password" id="password" value="\${config?.password || ''}" placeholder="Enter password" required>
485- </div>
486- <div class="form-group">
487- <button data-action="save-postgres">Save</button>
488- <button class="secondary" data-action="cancel">Cancel</button>
489- </div>
490- \`;
536+ const heading = document.createElement('h2');
537+ heading.textContent = 'Configure PostgreSQL: ' + currentIntegrationId;
538+ formContainer.appendChild(heading);
539+
540+ // Display Name
541+ const nameInput = document.createElement('input');
542+ nameInput.type = 'text';
543+ nameInput.id = 'name';
544+ nameInput.value = config?.name || '';
545+ nameInput.placeholder = 'My PostgreSQL Database';
546+ nameInput.required = true;
547+ formContainer.appendChild(createFormGroup('Display Name:', nameInput));
548+
549+ // Host
550+ const hostInput = document.createElement('input');
551+ hostInput.type = 'text';
552+ hostInput.id = 'host';
553+ hostInput.value = config?.host || '';
554+ hostInput.placeholder = 'localhost';
555+ hostInput.required = true;
556+ formContainer.appendChild(createFormGroup('Host:', hostInput));
557+
558+ // Port
559+ const portInput = document.createElement('input');
560+ portInput.type = 'number';
561+ portInput.id = 'port';
562+ portInput.value = config?.port || 5432;
563+ portInput.placeholder = '5432';
564+ portInput.required = true;
565+ formContainer.appendChild(createFormGroup('Port:', portInput));
566+
567+ // Database
568+ const databaseInput = document.createElement('input');
569+ databaseInput.type = 'text';
570+ databaseInput.id = 'database';
571+ databaseInput.value = config?.database || '';
572+ databaseInput.placeholder = 'mydb';
573+ databaseInput.required = true;
574+ formContainer.appendChild(createFormGroup('Database:', databaseInput));
575+
576+ // Username
577+ const usernameInput = document.createElement('input');
578+ usernameInput.type = 'text';
579+ usernameInput.id = 'username';
580+ usernameInput.value = config?.username || '';
581+ usernameInput.placeholder = 'postgres';
582+ usernameInput.required = true;
583+ formContainer.appendChild(createFormGroup('Username:', usernameInput));
584+
585+ // Password
586+ const passwordInput = document.createElement('input');
587+ passwordInput.type = 'password';
588+ passwordInput.id = 'password';
589+ passwordInput.value = config?.password || '';
590+ passwordInput.placeholder = 'Enter password';
591+ passwordInput.required = true;
592+ formContainer.appendChild(createFormGroup('Password:', passwordInput));
593+
594+ // Buttons
595+ const buttonGroup = document.createElement('div');
596+ buttonGroup.className = 'form-group';
597+
598+ const saveBtn = document.createElement('button');
599+ saveBtn.dataset.action = 'save-postgres';
600+ saveBtn.textContent = 'Save';
601+
602+ const cancelBtn = document.createElement('button');
603+ cancelBtn.className = 'secondary';
604+ cancelBtn.dataset.action = 'cancel';
605+ cancelBtn.textContent = 'Cancel';
606+
607+ buttonGroup.appendChild(saveBtn);
608+ buttonGroup.appendChild(cancelBtn);
609+ formContainer.appendChild(buttonGroup);
610+
491611 } else if (type === 'bigquery') {
492- formContainer.innerHTML = \`
493- <h2>Configure BigQuery: \${currentIntegrationId}</h2>
494- <div class="form-group">
495- <label>Display Name:</label>
496- <input type="text" id="name" value="\${config?.name || ''}" placeholder="My BigQuery Project" required>
497- </div>
498- <div class="form-group">
499- <label>GCP Project ID:</label>
500- <input type="text" id="projectId" value="\${config?.projectId || ''}" placeholder="my-gcp-project" required>
501- </div>
502- <div class="form-group">
503- <label>Service Account Credentials (JSON):</label>
504- <textarea id="credentials" rows="10" placeholder="Paste service account JSON here" required>\${config?.credentials || ''}</textarea>
505- </div>
506- <div class="form-group">
507- <button data-action="save-bigquery">Save</button>
508- <button class="secondary" data-action="cancel">Cancel</button>
509- </div>
510- \`;
612+ const heading = document.createElement('h2');
613+ heading.textContent = 'Configure BigQuery: ' + currentIntegrationId;
614+ formContainer.appendChild(heading);
615+
616+ // Display Name
617+ const nameInput = document.createElement('input');
618+ nameInput.type = 'text';
619+ nameInput.id = 'name';
620+ nameInput.value = config?.name || '';
621+ nameInput.placeholder = 'My BigQuery Project';
622+ nameInput.required = true;
623+ formContainer.appendChild(createFormGroup('Display Name:', nameInput));
624+
625+ // GCP Project ID
626+ const projectIdInput = document.createElement('input');
627+ projectIdInput.type = 'text';
628+ projectIdInput.id = 'projectId';
629+ projectIdInput.value = config?.projectId || '';
630+ projectIdInput.placeholder = 'my-gcp-project';
631+ projectIdInput.required = true;
632+ formContainer.appendChild(createFormGroup('GCP Project ID:', projectIdInput));
633+
634+ // Service Account Credentials
635+ const credentialsTextarea = document.createElement('textarea');
636+ credentialsTextarea.id = 'credentials';
637+ credentialsTextarea.rows = 10;
638+ credentialsTextarea.placeholder = 'Paste service account JSON here';
639+ credentialsTextarea.required = true;
640+ credentialsTextarea.value = config?.credentials || '';
641+ formContainer.appendChild(createFormGroup('Service Account Credentials (JSON):', credentialsTextarea));
642+
643+ // Buttons
644+ const buttonGroup = document.createElement('div');
645+ buttonGroup.className = 'form-group';
646+
647+ const saveBtn = document.createElement('button');
648+ saveBtn.dataset.action = 'save-bigquery';
649+ saveBtn.textContent = 'Save';
650+
651+ const cancelBtn = document.createElement('button');
652+ cancelBtn.className = 'secondary';
653+ cancelBtn.dataset.action = 'cancel';
654+ cancelBtn.textContent = 'Cancel';
655+
656+ buttonGroup.appendChild(saveBtn);
657+ buttonGroup.appendChild(cancelBtn);
658+ formContainer.appendChild(buttonGroup);
511659 }
512660
513661 formContainer.classList.add('visible');
0 commit comments