Skip to content

Commit 1a78580

Browse files
authored
Merge pull request #574 from swingerman/copilot/fix-572
Add click-through functionality to access individual entity data
2 parents ada12d4 + 2752910 commit 1a78580

11 files changed

Lines changed: 230 additions & 63 deletions

File tree

config/ui-lovelace.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,55 @@ views:
1919
full_value: 1.8
2020
entity: input_number.energy_consumption
2121

22+
# Test case for issue #572 - click-through functionality
23+
- type: custom:fluid-level-background-card
24+
entity: input_number.battery_level
25+
card:
26+
type: glance
27+
title: Click-Through Test
28+
show_name: false
29+
show_icon: true
30+
show_state: true
31+
state_color: false
32+
columns: 3
33+
entities:
34+
- entity: input_number.battery_level
35+
name: Battery
36+
icon: mdi:battery
37+
- entity: input_boolean.battery_charging
38+
name: Charging
39+
icon: mdi:battery-charging
40+
- entity: input_number.energy_consumption
41+
name: Energy
42+
icon: mdi:lightning-bolt
43+
full_value: 100
44+
allow_click_through: true
45+
46+
# Test case without click-through (original behavior)
47+
- type: custom:fluid-level-background-card
48+
entity: input_number.battery_level
49+
card:
50+
type: glance
51+
title: Traditional Test
52+
show_name: false
53+
show_icon: true
54+
show_state: true
55+
state_color: false
56+
columns: 3
57+
entities:
58+
- entity: input_number.battery_level
59+
name: Battery
60+
icon: mdi:battery
61+
- entity: input_boolean.battery_charging
62+
name: Charging
63+
icon: mdi:battery-charging
64+
- entity: input_number.energy_consumption
65+
name: Energy
66+
icon: mdi:lightning-bolt
67+
full_value: 100
68+
tap_action:
69+
action: more-info
70+
2271
- type: entities
2372
entities:
2473
- input_number.battery_level

src/editor.ts

Lines changed: 138 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
122122

123123
public setConfig(config: FluidLevelBackgroundCardConfig): void {
124124
this._config = config;
125-
126125
this.loadCardHelpers();
127126
}
128127

@@ -178,6 +177,10 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
178177
return this._config?.random_start || false;
179178
}
180179

180+
get _allow_click_through(): boolean {
181+
return this._config?.allow_click_through || false;
182+
}
183+
181184
private _lastUsedBackgroundColor: number[] | undefined;
182185
private _lastUsedLevelColor: number[] | undefined;
183186

@@ -302,33 +305,76 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
302305
}
303306

304307
renderActionsTab(): TemplateResult {
305-
const actions = ['more-info', 'toggle', 'navigate', 'url', 'call-service', 'none'];
306308
return html`
307-
<hui-action-editor
308-
.label="${this.hass?.localize('ui.panel.lovelace.editor.card.generic.tap_action')} (${this.hass?.localize(
309-
'ui.panel.lovelace.editor.card.config.optional',
310-
)})"
311-
.hass=${this.hass}
312-
.config=${this._tap_action}
313-
.actions=${actions}
314-
.configValue=${'tap_action'}
315-
.tooltipText=${this.hass?.localize('ui.panel.lovelace.editor.card.button.default_action_help')}
316-
@value-changed=${this._actionChanged}
317-
></hui-action-editor>
318-
<hui-action-editor
319-
.label="${this.hass?.localize('ui.panel.lovelace.editor.card.generic.hold_action')} (${this.hass?.localize(
320-
'ui.panel.lovelace.editor.card.config.optional',
321-
)})"
309+
<div class="form-row-dual">
310+
<ha-formfield label=${localize('editor.tab.actions.labels.allow-click-through')}>
311+
<ha-switch .checked=${this._allow_click_through} @change=${this._toggleClickThrough}> </ha-switch>
312+
</ha-formfield>
313+
</div>
314+
<div class="help-text">${localize('editor.tab.actions.labels.allow-click-through-help')}</div>
315+
316+
${this._renderActionEditors()}
317+
`;
318+
}
319+
320+
private _renderActionEditors(): TemplateResult | string {
321+
if (this._allow_click_through) {
322+
return '';
323+
}
324+
325+
return html`
326+
<ha-form
322327
.hass=${this.hass}
323-
.config=${this._hold_action}
324-
.actions=${actions}
325-
.configValue=${'hold_action'}
326-
.tooltipText=${this.hass?.localize('ui.panel.lovelace.editor.card.button.default_action_help')}
328+
.data=${{
329+
tap_action: this._tap_action,
330+
hold_action: this._hold_action,
331+
double_tap_action: this._double_tap_action,
332+
}}
333+
.schema=${[
334+
{
335+
name: 'tap_action',
336+
selector: {
337+
ui_action: {
338+
default_action: 'more-info',
339+
},
340+
},
341+
},
342+
{
343+
name: 'hold_action',
344+
selector: {
345+
ui_action: {
346+
default_action: 'more-info',
347+
},
348+
},
349+
},
350+
{
351+
name: 'double_tap_action',
352+
selector: {
353+
ui_action: {
354+
default_action: 'none',
355+
},
356+
},
357+
},
358+
]}
359+
.computeLabel=${this._computeActionLabel}
327360
@value-changed=${this._actionChanged}
328-
></hui-action-editor>
361+
></ha-form>
329362
`;
330363
}
331364

365+
private readonly _computeActionLabel = (schema: { name: string }): string => {
366+
switch (schema.name) {
367+
case 'tap_action':
368+
return `${this.hass?.localize('ui.panel.lovelace.editor.card.generic.tap_action')} (${this.hass?.localize('ui.panel.lovelace.editor.card.config.optional')})`;
369+
case 'hold_action':
370+
return `${this.hass?.localize('ui.panel.lovelace.editor.card.generic.hold_action')} (${this.hass?.localize('ui.panel.lovelace.editor.card.config.optional')})`;
371+
case 'double_tap_action':
372+
return `${this.hass?.localize('ui.panel.lovelace.editor.card.generic.double_tap_action')} (${this.hass?.localize('ui.panel.lovelace.editor.card.config.optional')})`;
373+
default:
374+
return schema.name;
375+
}
376+
};
377+
332378
renderAppearanceTab(): TemplateResult {
333379
const themePrimaryColor = getThemeColor(THEME_PRIMARY_COLOR_VARIABLE, LEVEL_COLOR);
334380
const themeBackgroundColor = getThemeColor(THEME_BACKGROUND_COLOR_VARIABLE, BACKGROUND_COLOR);
@@ -469,6 +515,20 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
469515
fireEvent(this, 'config-changed', { config: this._config });
470516
}
471517

518+
protected _toggleClickThrough(): void {
519+
if (!this._config) {
520+
return;
521+
}
522+
523+
if (this._allow_click_through) {
524+
this._config = { ...this._config, allow_click_through: false };
525+
} else {
526+
this._config = { ...this._config, allow_click_through: true };
527+
}
528+
529+
fireEvent(this, 'config-changed', { config: this._config });
530+
}
531+
472532
protected _addSeverity(): void {
473533
if (!this._config) {
474534
return;
@@ -477,7 +537,7 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
477537
fireEvent(this, 'config-changed', { config: this._config });
478538
}
479539

480-
protected _removeSeverity(ev): void {
540+
protected _removeSeverity(ev: Event): void {
481541
if (!this._config) {
482542
return;
483543
}
@@ -487,27 +547,29 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
487547
fireEvent(this, 'config-changed', { config: this._config });
488548
}
489549

490-
protected _severityColorChanged(ev): void {
550+
protected _severityColorChanged(ev: CustomEvent): void {
491551
if (!this._config) {
492552
return;
493553
}
494-
let severityItem = this._severity[ev.target.index];
554+
const target = ev.target as any;
555+
let severityItem = this._severity[target.index];
495556
const color = ev.detail.value;
496557
const severity = [...this._severity];
497558

498559
severityItem = { ...severityItem, color };
499-
severity[ev.target.index] = severityItem;
560+
severity[target.index] = severityItem;
500561

501562
this._config = { ...this._config, severity };
502563
fireEvent(this, 'config-changed', { config: this._config });
503564
}
504565

505-
protected _severityValueChanged(ev): void {
566+
protected _severityValueChanged(ev: Event): void {
506567
if (!this._config) {
507568
return;
508569
}
509-
const index = ev.target.index;
510-
const value = ev.target.value;
570+
const target = ev.target as any;
571+
const index = target.index;
572+
const value = target.value;
511573
let severityItem = this._severity[index];
512574
const severity = [...this._severity];
513575

@@ -518,13 +580,14 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
518580
fireEvent(this, 'config-changed', { config: this._config });
519581
}
520582

521-
private _getSeverityItemFormEvent(ev): [number, any, Severity] {
522-
const index = ev.target.index;
523-
return [index, ev.target.value, this._severity[index]];
583+
private _getSeverityItemFormEvent(ev: Event): [number, any, Severity] {
584+
const target = ev.target as any;
585+
const index = target.index;
586+
return [index, target.value, this._severity[index]];
524587
}
525588

526589
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
527-
protected _handleCardPicked(ev): void {
590+
protected _handleCardPicked(ev: CustomEvent): void {
528591
ev.stopPropagation();
529592
if (!this._config) {
530593
return;
@@ -543,7 +606,7 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
543606
}
544607

545608
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
546-
protected _handleConfigChanged(ev): void {
609+
protected _handleConfigChanged(ev: CustomEvent): void {
547610
ev.stopPropagation();
548611
if (!this._config) {
549612
return;
@@ -564,20 +627,21 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
564627
this._helpers = await (window as any).loadCardHelpers();
565628
}
566629

567-
private _toggleAction(ev): void {
630+
private _toggleAction(ev: Event): void {
568631
this._toggleThing(ev, options.actions.options);
569632
}
570633

571-
private _toggleOption(ev): void {
634+
private _toggleOption(ev: Event): void {
572635
this._toggleThing(ev, options);
573636
}
574637

575-
private _toggleThing(ev, optionList): void {
576-
const show = !optionList[ev.target.option].show;
638+
private _toggleThing(ev: Event, optionList: any): void {
639+
const target = ev.target as any;
640+
const show = !optionList[target.option].show;
577641
for (const [key] of Object.entries(optionList)) {
578642
optionList[key].show = false;
579643
}
580-
optionList[ev.target.option].show = show;
644+
optionList[target.option].show = show;
581645
this._toggle = !this._toggle;
582646
}
583647

@@ -601,11 +665,11 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
601665
fireEvent(this, 'config-changed', { config: this._config });
602666
}
603667

604-
private _valueChanged(ev): void {
605-
if (!this._config || !this.hass || ev.target.value === '') {
668+
private _valueChanged(ev: Event): void {
669+
if (!this._config || !this.hass || (ev.target as any)?.value === '') {
606670
return;
607671
}
608-
const target = ev.target;
672+
const target = ev.target as any;
609673
if (this[`_${target.configValue}`] === target.value) {
610674
return;
611675
}
@@ -624,32 +688,50 @@ export class FluidLevelBackgroundCardEditor extends LitElement implements Lovela
624688
fireEvent(this, 'config-changed', { config: this._config });
625689
}
626690

627-
private _actionChanged(ev): void {
691+
private _actionChanged(ev: CustomEvent): void {
628692
if (!this._config || !this.hass) {
629693
return;
630694
}
631-
const target = ev.target!;
632-
const value = ev.detail.value;
633695

634-
if (this[`_${target.configValue}`] === value) {
696+
const formData = ev.detail.value;
697+
if (!formData || typeof formData !== 'object') {
635698
return;
636699
}
637-
let newConfig;
638-
if (target.configValue) {
639-
if (value !== false && !value) {
640-
newConfig = { ...this._config };
641-
delete newConfig[target.configValue!];
700+
701+
// Update config with the form data
702+
const newConfig = { ...this._config };
703+
704+
// Update tap_action if present
705+
if (formData.tap_action !== undefined) {
706+
if (!formData.tap_action || formData.tap_action.action === 'none') {
707+
delete newConfig.tap_action;
642708
} else {
643-
newConfig = {
644-
...this._config,
645-
[target.configValue!]: value,
646-
};
709+
newConfig.tap_action = formData.tap_action;
710+
}
711+
}
712+
713+
// Update hold_action if present
714+
if (formData.hold_action !== undefined) {
715+
if (!formData.hold_action || formData.hold_action.action === 'none') {
716+
delete newConfig.hold_action;
717+
} else {
718+
newConfig.hold_action = formData.hold_action;
647719
}
648720
}
721+
722+
// Update double_tap_action if present
723+
if (formData.double_tap_action !== undefined) {
724+
if (!formData.double_tap_action || formData.double_tap_action.action === 'none') {
725+
delete newConfig.double_tap_action;
726+
} else {
727+
newConfig.double_tap_action = formData.double_tap_action;
728+
}
729+
}
730+
649731
fireEvent(this, 'config-changed', { config: newConfig });
650732
}
651733

652-
private _handleSelectedCard(ev) {
734+
private _handleSelectedCard(ev: CustomEvent): void {
653735
this._selectedTab = parseInt(ev.detail.selected, 10);
654736
}
655737

src/fluid-level-background-card.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,13 @@ export class FluidLevelBackgroundCard extends LitElement {
451451
if (!this._card) {
452452
return html``;
453453
}
454+
455+
// If click-through is enabled, don't add action handlers to allow inner card interactions
456+
if (this.config.allow_click_through) {
457+
const cardLabel = `FluidProgressBar: ${this._level_entity || 'No Entity Defined'}`;
458+
return html` <ha-card tabindex="0" .label=${cardLabel}> ${this._card} </ha-card> `;
459+
}
460+
454461
return html` <ha-card
455462
@action=${this._handleAction}
456463
.actionHandler=${actionHandler({

0 commit comments

Comments
 (0)