Skip to content

Commit ae0961b

Browse files
committed
fix: provider-specific endpoints and save settings to .env
- Add separate OLLAMA_API_ENDPOINT and OPENAI_API_ENDPOINT env vars - Fix endpoint field not updating when switching providers - Add Save Settings button to persist config to .env file - Add OUTPUT_FILENAME_PATTERN to saved settings - Fix dropdown checkmark not showing correct selection - Add retry mechanism for empty dropdown options"
1 parent f99f696 commit ae0961b

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

src/web/static/js/ui/searchable-select.js

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ export class SearchableSelect {
5858
this._bindEvents();
5959
this._updateFromOriginalSelect();
6060

61+
// Debug: log if no options found
62+
if (this.allOptions.length === 0) {
63+
console.warn(`[SearchableSelect] No options found for #${this.originalSelect.id}, retrying...`);
64+
// Retry after a short delay (options might not be parsed yet)
65+
setTimeout(() => {
66+
this._updateFromOriginalSelect();
67+
if (this.allOptions.length > 0) {
68+
console.log(`[SearchableSelect] Options loaded for #${this.originalSelect.id}: ${this.allOptions.length} options`);
69+
} else {
70+
console.error(`[SearchableSelect] Still no options for #${this.originalSelect.id}`);
71+
}
72+
}, 100);
73+
}
74+
6175
// Hide original select
6276
this.originalSelect.style.display = 'none';
6377
}
@@ -327,6 +341,11 @@ export class SearchableSelect {
327341
this.displayText.textContent = option.label;
328342
this.displayText.classList.remove('placeholder');
329343

344+
// Update selected property for all options
345+
this.allOptions.forEach(opt => {
346+
opt.selected = (opt.value === option.value);
347+
});
348+
330349
// Update original select
331350
this.originalSelect.value = option.value;
332351
this.originalSelect.dispatchEvent(new Event('change', { bubbles: true }));
@@ -347,6 +366,11 @@ export class SearchableSelect {
347366
this.displayText.textContent = value;
348367
this.displayText.classList.remove('placeholder');
349368

369+
// Clear selected flag from all existing options
370+
this.allOptions.forEach(opt => {
371+
opt.selected = false;
372+
});
373+
350374
// Add option to original select if not exists
351375
let optionEl = this.originalSelect.querySelector(`option[value="${CSS.escape(value)}"]`);
352376
if (!optionEl) {
@@ -426,6 +450,12 @@ export class SearchableSelect {
426450
this.wrapper.classList.add('open');
427451
this.arrow.textContent = 'expand_less';
428452

453+
// Debug: log options state
454+
if (this.allOptions.length === 0) {
455+
console.warn(`[SearchableSelect] Opening dropdown for #${this.originalSelect.id} but allOptions is empty! Retrying...`);
456+
this._updateFromOriginalSelect();
457+
}
458+
429459
// Reset search and show all options
430460
this.searchInput.value = '';
431461
this.clearBtn.style.display = 'none';
@@ -490,20 +520,21 @@ export class SearchableSelect {
490520
let currentGroup = null;
491521

492522
options.forEach(opt => {
493-
if (opt.value === '' && (opt.textContent.includes('Loading') || opt.textContent.includes('Enter'))) {
523+
const text = opt.textContent.trim();
524+
if (opt.value === '' && (text.includes('Loading') || text.includes('Enter'))) {
494525
return; // Skip loading/placeholder
495526
}
496527

497528
// Check for optgroup
498-
if (opt.parentElement.tagName === 'OPTGROUP') {
529+
if (opt.parentElement && opt.parentElement.tagName === 'OPTGROUP') {
499530
currentGroup = opt.parentElement.label;
500531
} else {
501532
currentGroup = null;
502533
}
503534

504535
this.allOptions.push({
505536
value: opt.value,
506-
label: opt.textContent,
537+
label: text,
507538
description: opt.title || '',
508539
group: currentGroup,
509540
selected: opt.selected
@@ -529,6 +560,12 @@ export class SearchableSelect {
529560
this.displayText.classList.add('placeholder');
530561
}
531562

563+
// Sync 'selected' property with currentValue for all options
564+
// This ensures custom renderers show the correct checkmark
565+
this.allOptions.forEach(opt => {
566+
opt.selected = (opt.value === this.currentValue);
567+
});
568+
532569
this.filteredOptions = [...this.allOptions];
533570
this._updateBadge();
534571

src/web/templates/translation_interface.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ <h3>Drop files to translate</h3>
323323
<span class="material-symbols-outlined">save</span>
324324
Save Settings to .env
325325
</button>
326-
<p style="margin: 8px 0 0 0; font-size: 0.8125rem; color: var(--text-muted-light);">
326+
<p style="margin: 8px 0 15px 0; font-size: 0.8125rem; color: var(--text-muted-light);">
327327
Saves API keys, endpoints, naming convention, and current model as default values in the <code>.env</code> file.
328328
</p>
329329
</div>

0 commit comments

Comments
 (0)