@@ -11178,10 +11178,279 @@ class FastSearchCard extends HTMLElement {
1117811178 </div>
1117911179 `;
1118011180
11181- // TODO: Filter Event Listeners und Action Loading
11181+ // Setup Filter Event Listeners
11182+ this.setupActionsFilterListeners(item, container);
11183+
11184+ // Load Actions
11185+ this.loadRelatedActions(item, container);
11186+
1118211187 console.log('Actions Tab HTML erstellt');
1118311188 }
1118411189
11190+ // 🎯 ACTIONS FILTER LISTENERS
11191+ setupActionsFilterListeners(item, container) {
11192+ const filterChips = container.querySelectorAll('.action-filter-chip');
11193+
11194+ filterChips.forEach(chip => {
11195+ chip.addEventListener('click', () => {
11196+ // Update active state
11197+ filterChips.forEach(c => c.classList.remove('active'));
11198+ chip.classList.add('active');
11199+
11200+ // Filter results
11201+ const filter = chip.dataset.actionFilter;
11202+ console.log(`🔽 Filtering actions: ${filter}`);
11203+ });
11204+ });
11205+ }
11206+
11207+ // 🎯 LOAD RELATED ACTIONS - Echte Discovery
11208+ loadRelatedActions(item, container) {
11209+ console.log(`🔍 Loading actions for device: ${item.name} in area: ${item.area}`);
11210+
11211+ const deviceArea = item.area;
11212+ const deviceId = item.id;
11213+ const loadingDiv = container.querySelector('.actions-loading');
11214+ const resultsDiv = container.querySelector('.actions-results');
11215+
11216+ // Show loading
11217+ loadingDiv.style.display = 'block';
11218+ resultsDiv.style.display = 'none';
11219+
11220+ // ✅ SAMMLE ALLE RELEVANTEN ACTIONS
11221+ const relatedActions = {
11222+ scenes: this.findRelatedScenes(deviceId, deviceArea),
11223+ scripts: this.findRelatedScripts(deviceId, deviceArea),
11224+ automations: this.findRelatedAutomations(deviceId, deviceArea)
11225+ };
11226+
11227+ console.log('🎯 Found actions:', relatedActions);
11228+
11229+ // Update counts
11230+ this.updateActionCounts(relatedActions, container);
11231+
11232+ // Render results
11233+ const totalActions = Object.values(relatedActions).flat().length;
11234+
11235+ if (totalActions === 0) {
11236+ loadingDiv.style.display = 'none';
11237+ resultsDiv.innerHTML = '<p>Keine Aktionen gefunden für dieses Gerät.</p>';
11238+ resultsDiv.style.display = 'block';
11239+ } else {
11240+ this.renderActionResults(relatedActions, resultsDiv, 'all');
11241+ loadingDiv.style.display = 'none';
11242+ resultsDiv.style.display = 'block';
11243+ }
11244+ }
11245+
11246+ // 🎯 UPDATE ACTION COUNTS
11247+ updateActionCounts(relatedActions, container) {
11248+ const totalCount = Object.values(relatedActions).flat().length;
11249+
11250+ // Update chip counts
11251+ const allChip = container.querySelector('#actions-all-count');
11252+ const scenesChip = container.querySelector('#actions-scenes-count');
11253+ const scriptsChip = container.querySelector('#actions-scripts-count');
11254+ const automationsChip = container.querySelector('#actions-automations-count');
11255+
11256+ if (allChip) allChip.textContent = totalCount;
11257+ if (scenesChip) scenesChip.textContent = relatedActions.scenes.length;
11258+ if (scriptsChip) scriptsChip.textContent = relatedActions.scripts.length;
11259+ if (automationsChip) automationsChip.textContent = relatedActions.automations.length;
11260+ }
11261+
11262+ // 🎯 FIND RELATED SCENES
11263+ findRelatedScenes(deviceId, deviceArea) {
11264+ if (!this._hass || !this.allItems) return [];
11265+
11266+ return this.allItems.filter(item => {
11267+ if (item.domain !== 'scene') return false;
11268+
11269+ // METHODE 1: Direkte Entity-Analyse
11270+ const state = this._hass.states[item.id];
11271+ if (state && state.attributes.entity_id) {
11272+ const targetEntities = state.attributes.entity_id;
11273+ if (targetEntities.includes(deviceId)) {
11274+ console.log(`✅ Scene ${item.name} targets device directly`);
11275+ return true; // Szene betrifft dieses Gerät direkt
11276+ }
11277+ }
11278+
11279+ // METHODE 2: Gleiche Area
11280+ if (item.area === deviceArea && deviceArea !== 'Ohne Raum') {
11281+ console.log(`✅ Scene ${item.name} in same area: ${deviceArea}`);
11282+ return true;
11283+ }
11284+
11285+ return false;
11286+ });
11287+ }
11288+
11289+ // 🎯 FIND RELATED SCRIPTS
11290+ findRelatedScripts(deviceId, deviceArea) {
11291+ if (!this._hass || !this.allItems) return [];
11292+
11293+ return this.allItems.filter(item => {
11294+ if (item.domain !== 'script') return false;
11295+
11296+ // METHODE 1: Gleiche Area
11297+ if (item.area === deviceArea && deviceArea !== 'Ohne Raum') {
11298+ console.log(`✅ Script ${item.name} in same area: ${deviceArea}`);
11299+ return true;
11300+ }
11301+
11302+ // METHODE 2: Name-Matching
11303+ const scriptName = item.name.toLowerCase();
11304+ const deviceName = deviceId.split('.')[1].toLowerCase();
11305+ const areaName = deviceArea.toLowerCase();
11306+
11307+ if (scriptName.includes(deviceName) || scriptName.includes(areaName)) {
11308+ console.log(`✅ Script ${item.name} matches by name`);
11309+ return true;
11310+ }
11311+
11312+ return false;
11313+ });
11314+ }
11315+
11316+ // 🎯 FIND RELATED AUTOMATIONS
11317+ findRelatedAutomations(deviceId, deviceArea) {
11318+ if (!this._hass || !this.allItems) return [];
11319+
11320+ return this.allItems.filter(item => {
11321+ if (item.domain !== 'automation') return false;
11322+
11323+ // Gleiche Logik wie Scripts
11324+ if (item.area === deviceArea && deviceArea !== 'Ohne Raum') {
11325+ console.log(`✅ Automation ${item.name} in same area: ${deviceArea}`);
11326+ return true;
11327+ }
11328+
11329+ const autoName = item.name.toLowerCase();
11330+ const deviceName = deviceId.split('.')[1].toLowerCase();
11331+ const areaName = deviceArea.toLowerCase();
11332+
11333+ if (autoName.includes(deviceName) || autoName.includes(areaName)) {
11334+ console.log(`✅ Automation ${item.name} matches by name`);
11335+ return true;
11336+ }
11337+
11338+ return false;
11339+ });
11340+ }
11341+
11342+ // 🎯 RENDER ACTION RESULTS
11343+ renderActionResults(relatedActions, container, filter = 'all') {
11344+ let actionsToShow = [];
11345+
11346+ if (filter === 'all') {
11347+ actionsToShow = [
11348+ ...relatedActions.scenes,
11349+ ...relatedActions.scripts,
11350+ ...relatedActions.automations
11351+ ];
11352+ } else {
11353+ actionsToShow = relatedActions[filter] || [];
11354+ }
11355+
11356+ // Sort by area, then by name
11357+ actionsToShow.sort((a, b) => {
11358+ const areaCompare = (a.area || 'Ohne Raum').localeCompare(b.area || 'Ohne Raum');
11359+ if (areaCompare !== 0) return areaCompare;
11360+ return a.name.localeCompare(b.name);
11361+ });
11362+
11363+ const resultsHTML = actionsToShow.map(action => this.renderActionItem(action)).join('');
11364+
11365+ container.innerHTML = `
11366+ <div class="actions-grid">
11367+ ${resultsHTML}
11368+ </div>
11369+ `;
11370+
11371+ // Setup click handlers
11372+ this.setupActionClickHandlers(container);
11373+ }
11374+
11375+ // 🎯 RENDER ACTION ITEM
11376+ renderActionItem(action) {
11377+ const state = this._hass.states[action.id];
11378+ const isActive = this.isEntityActive(state);
11379+ const icon = this.getEntityIcon(action.domain);
11380+
11381+ return `
11382+ <div class="action-item ${isActive ? 'active' : ''}" data-action-id="${action.id}">
11383+ <div class="action-icon">${icon}</div>
11384+ <div class="action-info">
11385+ <div class="action-name">${action.name}</div>
11386+ <div class="action-meta">
11387+ <span class="action-type">${this.getActionTypeLabel(action.domain)}</span>
11388+ ${action.area !== 'Ohne Raum' ? `<span class="action-area">${action.area}</span>` : ''}
11389+ </div>
11390+ </div>
11391+ <div class="action-trigger">
11392+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
11393+ <path d="M8 5l8 7-8 7"/>
11394+ </svg>
11395+ </div>
11396+ </div>
11397+ `;
11398+ }
11399+
11400+ // 🎯 HELPER METHODS
11401+ getActionTypeLabel(domain) {
11402+ const labels = {
11403+ scene: 'Szene',
11404+ script: 'Skript',
11405+ automation: 'Automation'
11406+ };
11407+ return labels[domain] || domain;
11408+ }
11409+
11410+ // 🎯 SETUP ACTION CLICK HANDLERS
11411+ setupActionClickHandlers(container) {
11412+ const actionItems = container.querySelectorAll('.action-item');
11413+
11414+ actionItems.forEach(item => {
11415+ item.addEventListener('click', () => {
11416+ const actionId = item.dataset.actionId;
11417+ console.log(`🎯 Action clicked: ${actionId}`);
11418+
11419+ // Visual feedback
11420+ item.classList.add('clicked');
11421+ setTimeout(() => item.classList.remove('clicked'), 200);
11422+
11423+ // Execute action
11424+ this.triggerAction(actionId);
11425+ });
11426+ });
11427+ }
11428+
11429+ // 🎯 TRIGGER ACTION
11430+ triggerAction(actionId) {
11431+ const domain = actionId.split('.')[0];
11432+
11433+ console.log(`🚀 Triggering ${domain}: ${actionId}`);
11434+
11435+ switch(domain) {
11436+ case 'scene':
11437+ this._hass.callService('scene', 'turn_on', { entity_id: actionId });
11438+ console.log(`✅ Scene activated: ${actionId}`);
11439+ break;
11440+ case 'script':
11441+ this._hass.callService('script', 'turn_on', { entity_id: actionId });
11442+ console.log(`✅ Script executed: ${actionId}`);
11443+ break;
11444+ case 'automation':
11445+ this._hass.callService('automation', 'trigger', { entity_id: actionId });
11446+ console.log(`✅ Automation triggered: ${actionId}`);
11447+ break;
11448+ default:
11449+ console.warn(`❌ Unknown action domain: ${domain}`);
11450+ }
11451+ }
11452+
11453+
1118511454 initializeTimerTab(item, container) {
1118611455 console.log('🔥 NEUE VERSION 2024 - Initializing Timer Tab for', item.name);
1118711456
0 commit comments