Add visual selectors to automation and KC target editors

Automation editor:
- IconSelect grid for condition logic (OR/AND) with descriptions

KC target editor:
- IconSelect for color mode (average/median/dominant) with SVG previews
- EntitySelect palette for picture source, pattern template, brightness source

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 10:12:57 +03:00
parent 8061c26bef
commit 5b4813368b
6 changed files with 140 additions and 2 deletions

View File

@@ -10,7 +10,9 @@ import { Modal } from '../core/modal.js';
import { CardSection } from '../core/card-sections.js';
import { updateTabBadge } from './tabs.js';
import { ICON_SETTINGS, ICON_START, ICON_PAUSE, ICON_CLOCK, ICON_AUTOMATION, ICON_HELP, ICON_OK, ICON_TIMER, ICON_MONITOR, ICON_RADIO, ICON_SCENE, ICON_CLONE } from '../core/icons.js';
import * as P from '../core/icon-paths.js';
import { wrapCard } from '../core/card-colors.js';
import { IconSelect } from '../core/icon-select.js';
import { attachProcessPicker } from '../core/process-picker.js';
import { csScenes, createSceneCard } from './scene-presets.js';
@@ -33,6 +35,23 @@ class AutomationEditorModal extends Modal {
const automationModal = new AutomationEditorModal();
const csAutomations = new CardSection('automations', { titleKey: 'automations.title', gridClass: 'devices-grid', addCardOnclick: "openAutomationEditor()", keyAttr: 'data-automation-id' });
/* ── Condition logic IconSelect ───────────────────────────────── */
const _icon = (d) => `<svg class="icon" viewBox="0 0 24 24">${d}</svg>`;
let _conditionLogicIconSelect = null;
function _ensureConditionLogicIconSelect() {
const sel = document.getElementById('automation-editor-logic');
if (!sel) return;
const items = [
{ value: 'or', icon: _icon(P.zap), label: t('automations.condition_logic.or'), desc: t('automations.condition_logic.or.desc') },
{ value: 'and', icon: _icon(P.link), label: t('automations.condition_logic.and'), desc: t('automations.condition_logic.and.desc') },
];
if (_conditionLogicIconSelect) { _conditionLogicIconSelect.updateItems(items); return; }
_conditionLogicIconSelect = new IconSelect({ target: sel, items, columns: 2 });
}
// Re-render automations when language changes (only if tab is active)
document.addEventListener('languageChanged', () => {
if (apiKey && (localStorage.getItem('activeTab') || 'dashboard') === 'automations') loadAutomations();
@@ -207,6 +226,8 @@ export async function openAutomationEditor(automationId, cloneData) {
errorEl.style.display = 'none';
condList.innerHTML = '';
_ensureConditionLogicIconSelect();
// Fetch scenes for selector
try {
await scenePresetsCache.fetch();
@@ -227,6 +248,7 @@ export async function openAutomationEditor(automationId, cloneData) {
nameInput.value = automation.name;
enabledInput.checked = automation.enabled;
logicSelect.value = automation.condition_logic;
if (_conditionLogicIconSelect) _conditionLogicIconSelect.setValue(automation.condition_logic);
for (const c of automation.conditions) {
addAutomationConditionRow(c);
@@ -250,6 +272,7 @@ export async function openAutomationEditor(automationId, cloneData) {
nameInput.value = (cloneData.name || '') + ' (Copy)';
enabledInput.checked = cloneData.enabled !== false;
logicSelect.value = cloneData.condition_logic || 'or';
if (_conditionLogicIconSelect) _conditionLogicIconSelect.setValue(cloneData.condition_logic || 'or');
// Clone conditions (strip webhook tokens — they must be unique)
for (const c of (cloneData.conditions || [])) {
@@ -269,6 +292,7 @@ export async function openAutomationEditor(automationId, cloneData) {
nameInput.value = '';
enabledInput.checked = true;
logicSelect.value = 'or';
if (_conditionLogicIconSelect) _conditionLogicIconSelect.setValue('or');
_initSceneSelector('automation-scene', null);
_initSceneSelector('automation-fallback-scene', null);
}