fix: replace HA test icon with refresh, make automation rules collapsible
Lint & Test / test (push) Has been cancelled

Use refresh icon instead of flask for HA test connection buttons.
Add collapse/expand chevron to automation rule rows (collapsed by default).
This commit is contained in:
2026-04-04 21:28:51 +03:00
parent b7da4ab6b5
commit edc6d27e2e
4 changed files with 37 additions and 6 deletions
@@ -52,9 +52,26 @@
.rule-header { .rule-header {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 8px; gap: 6px;
}
.rule-collapse-chevron {
cursor: pointer;
font-size: 0.7rem;
color: var(--text-muted);
transition: transform 0.15s ease;
user-select: none;
flex-shrink: 0;
padding: 2px;
}
.rule-collapse-chevron:hover {
color: var(--text-color);
}
.rule-header .btn-remove-rule {
margin-left: auto;
} }
.rule-type-label { .rule-type-label {
@@ -97,6 +114,10 @@
height: 16px; height: 16px;
} }
.rule-fields-container {
margin-top: 8px;
}
.rule-fields { .rule-fields {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -637,14 +637,24 @@ function addAutomationRuleRow(rule: any) {
row.innerHTML = ` row.innerHTML = `
<div class="rule-header"> <div class="rule-header">
<span class="rule-collapse-chevron">&#9654;</span>
<select class="rule-type-select"> <select class="rule-type-select">
${RULE_TYPE_KEYS.map(k => `<option value="${k}" ${ruleType === k ? 'selected' : ''}>${t('automations.rule.' + k)}</option>`).join('')} ${RULE_TYPE_KEYS.map(k => `<option value="${k}" ${ruleType === k ? 'selected' : ''}>${t('automations.rule.' + k)}</option>`).join('')}
</select> </select>
<button type="button" class="btn-remove-rule" onclick="this.closest('.automation-rule-row').remove(); if(window._autoGenerateAutomationName) window._autoGenerateAutomationName();" title="Remove">${ICON_TRASH}</button> <button type="button" class="btn-remove-rule" onclick="this.closest('.automation-rule-row').remove(); if(window._autoGenerateAutomationName) window._autoGenerateAutomationName();" title="Remove">${ICON_TRASH}</button>
</div> </div>
<div class="rule-fields-container"></div> <div class="rule-fields-container" style="display:none"></div>
`; `;
// Wire collapse/expand toggle
const chevron = row.querySelector('.rule-collapse-chevron') as HTMLElement;
chevron.addEventListener('click', () => {
const fields = row.querySelector('.rule-fields-container') as HTMLElement;
const collapsed = fields.style.display === 'none';
fields.style.display = collapsed ? '' : 'none';
chevron.style.transform = collapsed ? 'rotate(90deg)' : '';
});
const typeSelect = row.querySelector('.rule-type-select') as HTMLSelectElement; const typeSelect = row.querySelector('.rule-type-select') as HTMLSelectElement;
const container = row.querySelector('.rule-fields-container') as HTMLElement; const container = row.querySelector('.rule-fields-container') as HTMLElement;
@@ -7,7 +7,7 @@ import { fetchWithAuth, escapeHtml } from '../core/api.ts';
import { t } from '../core/i18n.ts'; import { t } from '../core/i18n.ts';
import { Modal } from '../core/modal.ts'; import { Modal } from '../core/modal.ts';
import { showToast, showConfirm } from '../core/ui.ts'; import { showToast, showConfirm } from '../core/ui.ts';
import { ICON_CLONE, ICON_EDIT, ICON_TEST } from '../core/icons.ts'; import { ICON_CLONE, ICON_EDIT, ICON_REFRESH } from '../core/icons.ts';
import * as P from '../core/icon-paths.ts'; import * as P from '../core/icon-paths.ts';
import { wrapCard } from '../core/card-colors.ts'; import { wrapCard } from '../core/card-colors.ts';
import { TagInput, renderTagChips } from '../core/tag-input.ts'; import { TagInput, renderTagChips } from '../core/tag-input.ts';
@@ -251,7 +251,7 @@ export function createHASourceCard(source: HomeAssistantSource) {
${renderTagChips(source.tags)} ${renderTagChips(source.tags)}
${source.description ? `<div class="template-config" style="opacity:0.7;">${escapeHtml(source.description)}</div>` : ''}`, ${source.description ? `<div class="template-config" style="opacity:0.7;">${escapeHtml(source.description)}</div>` : ''}`,
actions: ` actions: `
<button class="btn btn-icon btn-secondary" data-action="test" title="${t('ha_source.test')}">${ICON_TEST}</button> <button class="btn btn-icon btn-secondary" data-action="test" title="${t('ha_source.test')}">${ICON_REFRESH}</button>
<button class="btn btn-icon btn-secondary" data-action="clone" title="${t('common.clone')}">${ICON_CLONE}</button> <button class="btn btn-icon btn-secondary" data-action="clone" title="${t('common.clone')}">${ICON_CLONE}</button>
<button class="btn btn-icon btn-secondary" data-action="edit" title="${t('common.edit')}">${ICON_EDIT}</button>`, <button class="btn btn-icon btn-secondary" data-action="edit" title="${t('common.edit')}">${ICON_EDIT}</button>`,
}); });
@@ -74,7 +74,7 @@
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-icon btn-secondary" onclick="closeHASourceModal()" title="Cancel" data-i18n-title="settings.button.cancel" data-i18n-aria-label="aria.cancel">&#x2715;</button> <button class="btn btn-icon btn-secondary" onclick="closeHASourceModal()" title="Cancel" data-i18n-title="settings.button.cancel" data-i18n-aria-label="aria.cancel">&#x2715;</button>
<button class="btn btn-icon btn-secondary" id="ha-source-test-btn" onclick="testHASource()" title="Test" data-i18n-title="ha_source.test" style="display:none"> <button class="btn btn-icon btn-secondary" id="ha-source-test-btn" onclick="testHASource()" title="Test" data-i18n-title="ha_source.test" style="display:none">
<svg class="icon" viewBox="0 0 24 24"><path d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"/><path d="M6.453 15h11.094"/><path d="M8.5 2h7"/></svg> <svg class="icon" viewBox="0 0 24 24"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg>
</button> </button>
<button class="btn btn-icon btn-primary" onclick="saveHASource()" title="Save" data-i18n-title="settings.button.save" data-i18n-aria-label="aria.save">&#x2713;</button> <button class="btn btn-icon btn-primary" onclick="saveHASource()" title="Save" data-i18n-title="settings.button.save" data-i18n-aria-label="aria.save">&#x2713;</button>
</div> </div>