30fa107ef7
- Add `tags: List[str]` field to all 13 entity types (devices, output targets, CSS sources, picture sources, audio sources, value sources, sync clocks, automations, scene presets, capture/audio/PP/pattern templates) - Update all stores, schemas, and route handlers for tag CRUD - Add GET /api/v1/tags endpoint aggregating unique tags across all stores - Create TagInput component with chip display, autocomplete dropdown, keyboard navigation, and API-backed suggestions - Display tag chips on all entity cards (searchable via existing text filter) - Add tag input to all 14 editor modals with dirty check support - Add CSS styles and i18n keys (en/ru/zh) for tag UI - Also includes code review fixes: thread safety, perf, store dedup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
106 lines
7.2 KiB
HTML
106 lines
7.2 KiB
HTML
<!-- Automation Editor Modal -->
|
|
<div id="automation-editor-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="automation-editor-title">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h2 id="automation-editor-title"><svg class="icon" viewBox="0 0 24 24"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M12 11h4"/><path d="M12 16h4"/><path d="M8 11h.01"/><path d="M8 16h.01"/></svg> <span data-i18n="automations.add">Add Automation</span></h2>
|
|
<button class="modal-close-btn" onclick="closeAutomationEditorModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="automation-editor-form">
|
|
<input type="hidden" id="automation-editor-id">
|
|
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label for="automation-editor-name" data-i18n="automations.name">Name:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="automations.name.hint">A descriptive name for this automation</small>
|
|
<input type="text" id="automation-editor-name" data-i18n-placeholder="automations.name.placeholder" placeholder="My Automation" required>
|
|
</div>
|
|
|
|
<div class="form-group settings-toggle-group">
|
|
<div class="label-row">
|
|
<label data-i18n="automations.enabled">Enabled:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="automations.enabled.hint">Disabled automations won't activate even when conditions are met</small>
|
|
<label class="settings-toggle">
|
|
<input type="checkbox" id="automation-editor-enabled" checked>
|
|
<span class="settings-toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label for="automation-editor-logic" data-i18n="automations.condition_logic">Condition Logic:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="automations.condition_logic.hint">How multiple conditions are combined: ANY (OR) or ALL (AND)</small>
|
|
<select id="automation-editor-logic">
|
|
<option value="or" data-i18n="automations.condition_logic.or">Any condition (OR)</option>
|
|
<option value="and" data-i18n="automations.condition_logic.and">All conditions (AND)</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label data-i18n="automations.conditions">Conditions:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="automations.conditions.hint">Rules that determine when this automation activates</small>
|
|
<div id="automation-conditions-list"></div>
|
|
<button type="button" class="btn btn-secondary btn-sm" onclick="addAutomationCondition()" style="margin-top: 6px;">
|
|
+ <span data-i18n="automations.conditions.add">Add Condition</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label for="automation-scene-id" data-i18n="automations.scene">Scene:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="automations.scene.hint">Scene preset to activate when conditions are met</small>
|
|
<select id="automation-scene-id"></select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label for="automation-deactivation-mode" data-i18n="automations.deactivation_mode">Deactivation:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="automations.deactivation_mode.hint">What happens when conditions stop matching</small>
|
|
<select id="automation-deactivation-mode">
|
|
<option value="none" data-i18n="automations.deactivation_mode.none">None — keep current state</option>
|
|
<option value="revert" data-i18n="automations.deactivation_mode.revert">Revert to previous state</option>
|
|
<option value="fallback_scene" data-i18n="automations.deactivation_mode.fallback_scene">Activate fallback scene</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group" id="automation-fallback-scene-group" style="display:none">
|
|
<div class="label-row">
|
|
<label for="automation-fallback-scene-id" data-i18n="automations.deactivation_scene">Fallback Scene:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="automations.deactivation_scene.hint">Scene to activate when this automation deactivates</small>
|
|
<select id="automation-fallback-scene-id"></select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label data-i18n="tags.label">Tags:</label>
|
|
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
|
</div>
|
|
<small class="input-hint" style="display:none" data-i18n="tags.hint">Assign tags for grouping and filtering cards</small>
|
|
<div id="automation-tags-container"></div>
|
|
</div>
|
|
|
|
<div id="automation-editor-error" class="error-message" style="display: none;"></div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn btn-icon btn-secondary" onclick="closeAutomationEditorModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
|
<button class="btn btn-icon btn-primary" onclick="saveAutomationEditor()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
|
</div>
|
|
</div>
|
|
</div>
|