Add native select entity support.
This commit is contained in:
+108
-6
@@ -1,17 +1,27 @@
|
||||
import type { Corner } from '@material/mwc-menu';
|
||||
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
|
||||
import {
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
unsafeCSS,
|
||||
} from 'lit';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import {
|
||||
frigateCardHasAction,
|
||||
refreshDynamicStateParameters,
|
||||
shouldUpdateBasedOnHass,
|
||||
stopEventFromActivatingCardWideActions,
|
||||
} from '../common.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import { MenuSubmenu, MenuSubmenuItem } from '../types.js';
|
||||
import { MenuSubmenu, MenuSubmenuItem, MenuSubmenuSelect } from '../types.js';
|
||||
import { actionHandler } from '../action-handler-directive.js';
|
||||
import { domainIcon } from '../icons/domain-icon.js';
|
||||
|
||||
import submenuStyle from '../scss/submenu.scss';
|
||||
|
||||
@@ -35,7 +45,7 @@ export class FrigateCardSubmenu extends LitElement {
|
||||
return html`
|
||||
<mwc-list-item
|
||||
style="${styleMap(stateParameters.style || {})}"
|
||||
graphic="icon"
|
||||
graphic=${ifDefined(stateParameters.icon ? 'icon' : undefined)}
|
||||
?twoline=${!!item.subtitle}
|
||||
?selected=${item.selected}
|
||||
?activated=${item.selected}
|
||||
@@ -51,9 +61,7 @@ export class FrigateCardSubmenu extends LitElement {
|
||||
})}
|
||||
>
|
||||
<span>${stateParameters.title || ''}</span>
|
||||
${item.subtitle
|
||||
? html`<span slot="secondary">${item.subtitle}</span>`
|
||||
: ''}
|
||||
${item.subtitle ? html`<span slot="secondary">${item.subtitle}</span>` : ''}
|
||||
${stateParameters.icon
|
||||
? html` <ha-icon
|
||||
data-domain=${ifDefined(stateParameters.data_domain)}
|
||||
@@ -109,3 +117,97 @@ export class FrigateCardSubmenu extends LitElement {
|
||||
return unsafeCSS(submenuStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('frigate-card-submenu-select')
|
||||
export class FrigateCardSubmenuSelect extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false })
|
||||
public submenuSelect?: MenuSubmenuSelect;
|
||||
|
||||
@property({ attribute: false })
|
||||
public corner?: Corner;
|
||||
|
||||
protected _generatedSubmenu?: MenuSubmenu;
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
// No need to update the submenu unless the select entity has changed.
|
||||
const oldHass = changedProps.get('hass') as HomeAssistant | undefined;
|
||||
return (
|
||||
changedProps.size != 1 ||
|
||||
!this.submenuSelect ||
|
||||
(!!oldHass &&
|
||||
shouldUpdateBasedOnHass(this.hass, oldHass, [this.submenuSelect.entity]))
|
||||
);
|
||||
}
|
||||
|
||||
protected willUpdate(): void {
|
||||
if (!this.submenuSelect || !this.hass) {
|
||||
return;
|
||||
}
|
||||
const entity = this.submenuSelect.entity;
|
||||
const stateObj = this.hass.states[entity];
|
||||
const options = stateObj?.attributes?.options;
|
||||
if (!stateObj || !options) {
|
||||
return;
|
||||
}
|
||||
|
||||
const submenu: MenuSubmenu = {
|
||||
// Default icon. It should be impossible for this to be used, since
|
||||
// this.submenuSelect will always have an entity, which means
|
||||
// refreshDynamicStateParameters will always return an icon.
|
||||
icon: domainIcon('select'),
|
||||
|
||||
// Pull out the dynamic properties (like icon, and title) from the state.
|
||||
...refreshDynamicStateParameters(this.hass, this.submenuSelect),
|
||||
|
||||
// Override it with anything explicitly set in the submenuSelect.
|
||||
...this.submenuSelect,
|
||||
|
||||
type: 'custom:frigate-card-menu-submenu',
|
||||
items: [],
|
||||
}
|
||||
|
||||
// Remove the options parameter which is unused/unsupported in submenu.
|
||||
delete submenu['options'];
|
||||
|
||||
for (const option of options) {
|
||||
// If there's a device_class there may be a localized translation of the
|
||||
// select title available via HASS.
|
||||
const title = stateObj.attributes.device_class
|
||||
? this.hass.localize(
|
||||
`component.select.state.${stateObj.attributes.device_class}.${option}`,
|
||||
)
|
||||
: option;
|
||||
submenu.items.push({
|
||||
selected: stateObj.state === option,
|
||||
title: title || option,
|
||||
...((entity.startsWith('select.') || entity.startsWith('input_select.')) && {
|
||||
tap_action: {
|
||||
action: 'call-service',
|
||||
service: entity.startsWith('select.')
|
||||
? 'select.select_option'
|
||||
: 'input_select.select_option',
|
||||
service_data: {
|
||||
entity_id: entity,
|
||||
option: option,
|
||||
},
|
||||
},
|
||||
}),
|
||||
// Apply overrides the user may have specified for a given option.
|
||||
...(this.submenuSelect.options && this.submenuSelect.options[option]),
|
||||
});
|
||||
}
|
||||
|
||||
this._generatedSubmenu = submenu;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html` <frigate-card-submenu
|
||||
.hass=${this.hass}
|
||||
.corner=${this.corner}
|
||||
.submenu=${this._generatedSubmenu}
|
||||
></frigate-card-submenu>`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user