feat: add auto-name generation to all remaining creation modals
Some checks failed
Lint & Test / test (push) Failing after 27s

Audio sources: type + device/parent/channel/band detail
Weather sources: provider + coordinates (updates on geolocation)
Sync clocks: "Sync Clocks · Nx" (updates on speed slider)
Automations: scene name + condition count/logic
Scene presets: "Scenes · N targets" (updates on add/remove)
Pattern templates: "Pattern Templates · N rects" (updates on add/remove)

All follow the same pattern: name auto-generates on create, stops
when user manually edits the name field.
This commit is contained in:
2026-03-24 21:44:28 +03:00
parent d6f796a499
commit 347b252f06
7 changed files with 163 additions and 6 deletions

View File

@@ -70,6 +70,37 @@ function _buildBandItems() {
];
}
// ── Auto-name generation ──────────────────────────────────────
let _asNameManuallyEdited = false;
function _autoGenerateAudioSourceName() {
if (_asNameManuallyEdited) return;
if ((document.getElementById('audio-source-id') as HTMLInputElement).value) return;
const type = (document.getElementById('audio-source-type') as HTMLSelectElement).value;
let name = '';
if (type === 'multichannel') {
const devSel = document.getElementById('audio-source-device') as HTMLSelectElement | null;
const devName = devSel?.selectedOptions[0]?.textContent?.trim();
name = devName || t('audio_source.type.multichannel');
} else if (type === 'mono') {
const parentSel = document.getElementById('audio-source-parent') as HTMLSelectElement | null;
const parentName = parentSel?.selectedOptions[0]?.textContent?.trim() || '';
const ch = (document.getElementById('audio-source-channel') as HTMLSelectElement).value;
const chLabel = ch === 'left' ? 'L' : ch === 'right' ? 'R' : 'M';
name = parentName ? `${parentName} · ${chLabel}` : t('audio_source.type.mono');
} else if (type === 'band_extract') {
const parentSel = document.getElementById('audio-source-band-parent') as HTMLSelectElement | null;
const parentName = parentSel?.selectedOptions[0]?.textContent?.trim() || '';
const band = (document.getElementById('audio-source-band') as HTMLSelectElement).value;
const bandLabel = band === 'custom'
? `${(document.getElementById('audio-source-freq-low') as HTMLInputElement).value}${(document.getElementById('audio-source-freq-high') as HTMLInputElement).value} Hz`
: t(`audio_source.band.${band}`);
name = parentName ? `${parentName} · ${bandLabel}` : bandLabel;
}
(document.getElementById('audio-source-name') as HTMLInputElement).value = name;
}
// ── Modal ─────────────────────────────────────────────────────
const _titleKeys: Record<string, Record<string, string>> = {
@@ -99,12 +130,13 @@ export async function showAudioSourceModal(sourceType: any, editData?: any) {
if (editData.source_type === 'multichannel') {
_loadAudioTemplates(editData.audio_template_id);
(document.getElementById('audio-source-audio-template') as HTMLSelectElement).onchange = _filterDevicesBySelectedTemplate;
(document.getElementById('audio-source-audio-template') as HTMLSelectElement).onchange = () => { _filterDevicesBySelectedTemplate(); _autoGenerateAudioSourceName(); };
await _loadAudioDevices();
_selectAudioDevice(editData.device_index, editData.is_loopback);
} else if (editData.source_type === 'mono') {
_loadMultichannelSources(editData.audio_source_id);
(document.getElementById('audio-source-channel') as HTMLSelectElement).value = editData.channel || 'mono';
(document.getElementById('audio-source-channel') as HTMLSelectElement).onchange = () => _autoGenerateAudioSourceName();
} else if (editData.source_type === 'band_extract') {
_loadBandParentSources(editData.audio_source_id);
(document.getElementById('audio-source-band') as HTMLSelectElement).value = editData.band || 'bass';
@@ -119,10 +151,11 @@ export async function showAudioSourceModal(sourceType: any, editData?: any) {
if (sourceType === 'multichannel') {
_loadAudioTemplates();
(document.getElementById('audio-source-audio-template') as HTMLSelectElement).onchange = _filterDevicesBySelectedTemplate;
(document.getElementById('audio-source-audio-template') as HTMLSelectElement).onchange = () => { _filterDevicesBySelectedTemplate(); _autoGenerateAudioSourceName(); };
await _loadAudioDevices();
} else if (sourceType === 'mono') {
_loadMultichannelSources();
(document.getElementById('audio-source-channel') as HTMLSelectElement).onchange = () => _autoGenerateAudioSourceName();
} else if (sourceType === 'band_extract') {
_loadBandParentSources();
(document.getElementById('audio-source-band') as HTMLSelectElement).value = 'bass';
@@ -138,6 +171,11 @@ export async function showAudioSourceModal(sourceType: any, editData?: any) {
_audioSourceTagsInput = new TagInput(document.getElementById('audio-source-tags-container'), { placeholder: t('tags.placeholder') });
_audioSourceTagsInput.setValue(isEdit ? (editData.tags || []) : []);
// Auto-name wiring
_asNameManuallyEdited = isEdit;
(document.getElementById('audio-source-name') as HTMLElement).oninput = () => { _asNameManuallyEdited = true; };
if (!isEdit) _autoGenerateAudioSourceName();
audioSourceModal.open();
audioSourceModal.snapshot();
}
@@ -384,7 +422,7 @@ function _ensureBandIconSelect() {
target: sel,
items: _buildBandItems(),
columns: 2,
onChange: () => onBandPresetChange(),
onChange: () => { onBandPresetChange(); _autoGenerateAudioSourceName(); },
});
}