insteon-frontend-home-assistant 0.3.2__py3-none-any.whl → 0.3.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of insteon-frontend-home-assistant might be problematic. Click here for more details.
- insteon_frontend/constants.py +1 -1
- insteon_frontend/{entrypoint-34178dea.js → entrypoint-805dad43.js} +2 -2
- insteon_frontend/entrypoint-805dad43.js.gz +0 -0
- insteon_frontend/entrypoint-fbe0ce27.js +16 -0
- insteon_frontend/entrypoint-fbe0ce27.js.gz +0 -0
- insteon_frontend/frontend_es5/2ef4f4ba.js +2 -0
- insteon_frontend/frontend_es5/2ef4f4ba.js.gz +0 -0
- insteon_frontend/frontend_es5/6419e8c2.js +2 -0
- insteon_frontend/frontend_es5/6419e8c2.js.gz +0 -0
- insteon_frontend/frontend_es5/a02336a2.js +2 -0
- insteon_frontend/frontend_es5/a02336a2.js.gz +0 -0
- insteon_frontend/frontend_es5/{2ce83def.js → c4d6bf84.js} +1 -1
- insteon_frontend/frontend_es5/c4d6bf84.js.gz +0 -0
- insteon_frontend/frontend_es5/c52f8a9d.js +2 -0
- insteon_frontend/frontend_es5/c52f8a9d.js.gz +0 -0
- insteon_frontend/frontend_es5/d20f3e47.js +2 -0
- insteon_frontend/frontend_es5/d20f3e47.js.gz +0 -0
- insteon_frontend/frontend_es5/{entrypoint-ca6ab8c2.js → entrypoint-877f2520.js} +2 -2
- insteon_frontend/frontend_es5/entrypoint-877f2520.js.gz +0 -0
- insteon_frontend/frontend_es5/entrypoint-acae4cac.js +2 -0
- insteon_frontend/frontend_es5/entrypoint-acae4cac.js.LICENSE.txt +134 -0
- insteon_frontend/frontend_es5/entrypoint-acae4cac.js.gz +0 -0
- insteon_frontend/frontend_es5/manifest.json +1 -1
- insteon_frontend/frontend_latest/{c825c48d.js → 122cc134.js} +2 -2
- insteon_frontend/frontend_latest/122cc134.js.gz +0 -0
- insteon_frontend/frontend_latest/{c825c48d.js.map → 122cc134.js.map} +1 -1
- insteon_frontend/frontend_latest/{f42f213e.js → 152db136.js} +3 -3
- insteon_frontend/frontend_latest/152db136.js.gz +0 -0
- insteon_frontend/frontend_latest/152db136.js.map +1 -0
- insteon_frontend/frontend_latest/1972789a.js +106 -0
- insteon_frontend/frontend_latest/1972789a.js.gz +0 -0
- insteon_frontend/frontend_latest/{055f55c1.js.map → 1972789a.js.map} +1 -1
- insteon_frontend/frontend_latest/{eb18a35e.js → 24065ffe.js} +2 -2
- insteon_frontend/frontend_latest/24065ffe.js.gz +0 -0
- insteon_frontend/frontend_latest/{eb18a35e.js.map → 24065ffe.js.map} +1 -1
- insteon_frontend/frontend_latest/{3720fc56.js → 36f999eb.js} +3 -3
- insteon_frontend/frontend_latest/36f999eb.js.gz +0 -0
- insteon_frontend/frontend_latest/{3720fc56.js.map → 36f999eb.js.map} +1 -1
- insteon_frontend/frontend_latest/{451cad84.js → 6bdb6d31.js} +2 -2
- insteon_frontend/frontend_latest/6bdb6d31.js.gz +0 -0
- insteon_frontend/frontend_latest/{451cad84.js.map → 6bdb6d31.js.map} +1 -1
- insteon_frontend/frontend_latest/{entrypoint-34178dea.js → entrypoint-805dad43.js} +4 -4
- insteon_frontend/frontend_latest/entrypoint-805dad43.js.gz +0 -0
- insteon_frontend/frontend_latest/{entrypoint-34178dea.js.map → entrypoint-805dad43.js.map} +1 -1
- insteon_frontend/frontend_latest/entrypoint-fbe0ce27.js +1260 -0
- insteon_frontend/frontend_latest/entrypoint-fbe0ce27.js.LICENSE.txt +152 -0
- insteon_frontend/frontend_latest/entrypoint-fbe0ce27.js.gz +0 -0
- insteon_frontend/frontend_latest/entrypoint-fbe0ce27.js.map +1 -0
- insteon_frontend/frontend_latest/manifest.json +1 -1
- insteon_frontend_git/constants.py +2 -0
- {insteon_frontend_home_assistant-0.3.2.dist-info → insteon_frontend_home_assistant-0.3.4.dist-info}/METADATA +1 -1
- {insteon_frontend_home_assistant-0.3.2.dist-info → insteon_frontend_home_assistant-0.3.4.dist-info}/RECORD +64 -54
- insteon_frontend_home_assistant-0.3.4.dist-info/top_level.txt +2 -0
- insteon_frontend/entrypoint-34178dea.js.gz +0 -0
- insteon_frontend/frontend_es5/08a50ea3.js +0 -2
- insteon_frontend/frontend_es5/08a50ea3.js.gz +0 -0
- insteon_frontend/frontend_es5/2ce83def.js.gz +0 -0
- insteon_frontend/frontend_es5/5684895d.js +0 -2
- insteon_frontend/frontend_es5/5684895d.js.gz +0 -0
- insteon_frontend/frontend_es5/6bdcda43.js +0 -2
- insteon_frontend/frontend_es5/6bdcda43.js.gz +0 -0
- insteon_frontend/frontend_es5/a724d8fb.js +0 -2
- insteon_frontend/frontend_es5/a724d8fb.js.gz +0 -0
- insteon_frontend/frontend_es5/d40d49d3.js +0 -2
- insteon_frontend/frontend_es5/d40d49d3.js.gz +0 -0
- insteon_frontend/frontend_es5/entrypoint-ca6ab8c2.js.gz +0 -0
- insteon_frontend/frontend_latest/055f55c1.js +0 -106
- insteon_frontend/frontend_latest/055f55c1.js.gz +0 -0
- insteon_frontend/frontend_latest/3720fc56.js.gz +0 -0
- insteon_frontend/frontend_latest/451cad84.js.gz +0 -0
- insteon_frontend/frontend_latest/c825c48d.js.gz +0 -0
- insteon_frontend/frontend_latest/eb18a35e.js.gz +0 -0
- insteon_frontend/frontend_latest/entrypoint-34178dea.js.gz +0 -0
- insteon_frontend/frontend_latest/f42f213e.js.gz +0 -0
- insteon_frontend/frontend_latest/f42f213e.js.map +0 -1
- insteon_frontend_home_assistant-0.3.2.dist-info/top_level.txt +0 -1
- /insteon_frontend/frontend_es5/{08a50ea3.js.LICENSE.txt → 2ef4f4ba.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_es5/{5684895d.js.LICENSE.txt → 6419e8c2.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_es5/{6bdcda43.js.LICENSE.txt → a02336a2.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_es5/{2ce83def.js.LICENSE.txt → c4d6bf84.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_es5/{a724d8fb.js.LICENSE.txt → c52f8a9d.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_es5/{d40d49d3.js.LICENSE.txt → d20f3e47.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_es5/{entrypoint-ca6ab8c2.js.LICENSE.txt → entrypoint-877f2520.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_latest/{451cad84.js.LICENSE.txt → 6bdb6d31.js.LICENSE.txt} +0 -0
- /insteon_frontend/frontend_latest/{entrypoint-34178dea.js.LICENSE.txt → entrypoint-805dad43.js.LICENSE.txt} +0 -0
- {insteon_frontend_home_assistant-0.3.2.dist-info → insteon_frontend_home_assistant-0.3.4.dist-info}/LICENSE +0 -0
- {insteon_frontend_home_assistant-0.3.2.dist-info → insteon_frontend_home_assistant-0.3.4.dist-info}/WHEEL +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eb18a35e.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsEA;AAIA;;AAKA;;;;;;ACzDA;;;;AAKA;;;;;;;;;;;;;;;;;;;;ACkBA;ACJA;;AAEA;AACA;;;AA8KA;AACA;AAGA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAhBA;;ACrKA;;AAGA;AACA;AACA;;AAEA;AAGA;;AAEA;;;AAGA;;AAGA;AACA;;;;AAIA;;;AAGA;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FA;;AC3JA;;;;AAOA;;;;;;AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4FA;;AC2CA;AACA;AACA;AACA;AACA;;;;;AAKA;;;;;AAKA;AAtLA;;;;AA2LA;AACA;AACA;;;AAGA;;AAEA;;AAEA;;;;;AAKA;AACA;;;AAGA;;AAIA;AACA;;;;;AAMA;;;;;AAMA;;AAEA;AACA;AACA;;AAlOA;;;AAwOA;AAIA;;;;;AAKA;AACA;AACA;AACA;;;;;AAKA;;AAEA;;;AAGA;;;AAGA;;;AAKA;;AAEA;AACA;AAGA;AACA;;;AAGA;;;AAOA;AACA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;;;AAvBA;;;;;;AAkCA;;;;AAIA;AACA;AACA;AACA;AACA;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2iBA","sources":["webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-card.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-fab.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-switch.ts","webpack://insteon-panel-frontend/./src/device/insteon-device-picker.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/layouts/hass-subpage.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/panels/config/ha-config-section.ts","webpack://insteon-panel-frontend/./src/scene/insteon-scene-editor.ts"],"sourcesContent":["import { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\n\n@customElement(\"ha-card\")\nexport class HaCard extends LitElement {\n @property() public header?: string;\n\n @property({ type: Boolean, reflect: true }) public raised = false;\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n background: var(\n --ha-card-background,\n var(--card-background-color, white)\n );\n box-shadow: var(--ha-card-box-shadow, none);\n box-sizing: border-box;\n border-radius: var(--ha-card-border-radius, 12px);\n border-width: var(--ha-card-border-width, 1px);\n border-style: solid;\n border-color: var(\n --ha-card-border-color,\n var(--divider-color, #e0e0e0)\n );\n color: var(--primary-text-color);\n display: block;\n transition: all 0.3s ease-out;\n position: relative;\n }\n\n :host([raised]) {\n border: none;\n box-shadow: var(\n --ha-card-box-shadow,\n 0px 2px 1px -1px rgba(0, 0, 0, 0.2),\n 0px 1px 1px 0px rgba(0, 0, 0, 0.14),\n 0px 1px 3px 0px rgba(0, 0, 0, 0.12)\n );\n }\n\n .card-header,\n :host ::slotted(.card-header) {\n color: var(--ha-card-header-color, --primary-text-color);\n font-family: var(--ha-card-header-font-family, inherit);\n font-size: var(--ha-card-header-font-size, 24px);\n letter-spacing: -0.012em;\n line-height: 48px;\n padding: 12px 16px 16px;\n display: block;\n margin-block-start: 0px;\n margin-block-end: 0px;\n font-weight: normal;\n }\n\n :host ::slotted(.card-content:not(:first-child)),\n slot:not(:first-child)::slotted(.card-content) {\n padding-top: 0px;\n margin-top: -8px;\n }\n\n :host ::slotted(.card-content) {\n padding: 16px;\n }\n\n :host ::slotted(.card-actions) {\n border-top: 1px solid var(--divider-color, #e8e8e8);\n padding: 5px 16px;\n }\n `;\n }\n\n protected render(): TemplateResult {\n return html`\n ${this.header\n ? html`<h1 class=\"card-header\">${this.header}</h1>`\n : html``}\n <slot></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-card\": HaCard;\n }\n}\n","import { FabBase } from \"@material/mwc-fab/mwc-fab-base\";\nimport { styles } from \"@material/mwc-fab/mwc-fab.css\";\nimport { customElement } from \"lit/decorators\";\nimport { css } from \"lit\";\n\n@customElement(\"ha-fab\")\nexport class HaFab extends FabBase {\n protected firstUpdated(changedProperties) {\n super.firstUpdated(changedProperties);\n this.style.setProperty(\"--mdc-theme-secondary\", \"var(--primary-color)\");\n }\n\n static override styles = [\n styles,\n css`\n :host .mdc-fab--extended .mdc-fab__icon {\n margin-inline-start: -8px;\n margin-inline-end: 12px;\n direction: var(--direction);\n }\n `,\n // safari workaround - must be explicit\n document.dir === \"rtl\"\n ? css`\n :host .mdc-fab--extended .mdc-fab__icon {\n direction: rtl;\n }\n `\n : css``,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-fab\": HaFab;\n }\n}\n","import { SwitchBase } from \"@material/mwc-switch/deprecated/mwc-switch-base\";\nimport { styles } from \"@material/mwc-switch/deprecated/mwc-switch.css\";\nimport { css } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\nimport { forwardHaptic } from \"../data/haptics\";\n\n@customElement(\"ha-switch\")\nexport class HaSwitch extends SwitchBase {\n // Generate a haptic vibration.\n // Only set to true if the new value of the switch is applied right away when toggling.\n // Do not add haptic when a user is required to press save.\n @property({ type: Boolean }) public haptic = false;\n\n protected firstUpdated() {\n super.firstUpdated();\n this.addEventListener(\"change\", () => {\n if (this.haptic) {\n forwardHaptic(\"light\");\n }\n });\n }\n\n static override styles = [\n styles,\n css`\n :host {\n --mdc-theme-secondary: var(--switch-checked-color);\n }\n .mdc-switch.mdc-switch--checked .mdc-switch__thumb {\n background-color: var(--switch-checked-button-color);\n border-color: var(--switch-checked-button-color);\n }\n .mdc-switch.mdc-switch--checked .mdc-switch__track {\n background-color: var(--switch-checked-track-color);\n border-color: var(--switch-checked-track-color);\n }\n .mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb {\n background-color: var(--switch-unchecked-button-color);\n border-color: var(--switch-unchecked-button-color);\n }\n .mdc-switch:not(.mdc-switch--checked) .mdc-switch__track {\n background-color: var(--switch-unchecked-track-color);\n border-color: var(--switch-unchecked-track-color);\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-switch\": HaSwitch;\n }\n}\n","import \"@material/mwc-list/mwc-list-item\";\nimport { UnsubscribeFunc } from \"home-assistant-js-websocket\";\nimport { html, LitElement, PropertyValues, TemplateResult } from \"lit\";\nimport { ComboBoxLitRenderer } from \"@vaadin/combo-box/lit\";\nimport { customElement, property, query, state } from \"lit/decorators\";\nimport memoizeOne from \"memoize-one\";\nimport { fireEvent } from \"../../homeassistant-frontend/src/common/dom/fire_event\";\nimport { stringCompare } from \"../../homeassistant-frontend/src/common/string/compare\";\nimport {\n AreaRegistryEntry,\n subscribeAreaRegistry,\n} from \"../../homeassistant-frontend/src/data/area_registry\";\nimport {\n computeDeviceName,\n DeviceEntityLookup,\n DeviceRegistryEntry,\n subscribeDeviceRegistry,\n} from \"../../homeassistant-frontend/src/data/device_registry\";\nimport {\n EntityRegistryEntry,\n subscribeEntityRegistry,\n} from \"../../homeassistant-frontend/src/data/entity_registry\";\nimport { SubscribeMixin } from \"../../homeassistant-frontend/src/mixins/subscribe-mixin\";\nimport { PolymerChangedEvent } from \"../../homeassistant-frontend/src/polymer-types\";\nimport { HomeAssistant } from \"../../homeassistant-frontend/src/types\";\nimport \"../../homeassistant-frontend/src/components/ha-combo-box\";\nimport type { HaComboBox } from \"../../homeassistant-frontend/src/components/ha-combo-box\";\nimport { Insteon } from \"../data/insteon\";\nimport { computeDomain } from \"../../homeassistant-frontend/src/common/entity/compute_domain\";\n\ninterface Device {\n name: string;\n area: string;\n id: string;\n}\n\nexport type HaDevicePickerDeviceFilterFunc = (\n device: DeviceRegistryEntry\n) => boolean;\n\nconst rowRenderer: ComboBoxLitRenderer<Device> = (item) => html`<mwc-list-item\n .twoline=${!!item.area}\n>\n <span>${item.name}</span>\n <span slot=\"secondary\">${item.area}</span>\n</mwc-list-item>`;\n\n@customElement(\"insteon-device-picker\")\nexport class InsteonDevicePicker extends SubscribeMixin(LitElement) {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property({ attribute: false }) public insteon!: Insteon;\n\n @property() public label?: string;\n\n @property() public value?: string;\n\n @property() public helper?: string;\n\n @property() public devices?: DeviceRegistryEntry[];\n\n @property() public areas?: AreaRegistryEntry[];\n\n @property() public entities?: EntityRegistryEntry[];\n\n @property({ type: Array, attribute: \"includedDomains\" })\n public includedDomains?: string[];\n\n @property({ type: Array, attribute: \"excludedDomains\" })\n public excludedDomains?: string[];\n\n /**\n * Show the modem in the list of devices.\n * @type {Array}\n * @attr include-modem\n */\n @property({\n type: Boolean,\n attribute: \"exclude-modem\",\n })\n public excludeModem?: boolean = false;\n\n @property({ type: Boolean }) public disabled?: boolean;\n\n @property({ type: Boolean }) public required?: boolean;\n\n @state() private _opened?: boolean;\n\n @query(\"ha-combo-box\", true) public comboBox!: HaComboBox;\n\n private _init = false;\n\n private _getDevices = memoizeOne(\n (\n devices: DeviceRegistryEntry[],\n areas: AreaRegistryEntry[],\n entities: EntityRegistryEntry[]\n ): Device[] => {\n if (!devices.length) {\n return [\n {\n id: \"no_devices\",\n area: \"\",\n name: this.hass.localize(\"ui.components.device-picker.no_devices\"),\n },\n ];\n }\n\n const deviceEntityLookup: DeviceEntityLookup = {};\n\n const filtered_included_entities = entities.filter(\n (entity) =>\n !this.includedDomains ||\n this.includedDomains.includes(computeDomain(entity.entity_id))\n );\n\n const filtered_entities = filtered_included_entities.filter(\n (entity) =>\n !this.excludedDomains ||\n !this.excludedDomains.includes(computeDomain(entity.entity_id))\n );\n\n for (const entity of filtered_entities) {\n if (!entity.device_id) {\n continue;\n }\n if (!(entity.device_id in deviceEntityLookup)) {\n deviceEntityLookup[entity.device_id] = [];\n }\n deviceEntityLookup[entity.device_id].push(entity);\n }\n\n const areaLookup: { [areaId: string]: AreaRegistryEntry } = {};\n for (const area of areas) {\n areaLookup[area.area_id] = area;\n }\n\n const outputDevices = devices\n .filter((device) => deviceEntityLookup.hasOwnProperty(device.id))\n .map((device) => ({\n id: device.id,\n name: computeDeviceName(\n device,\n this.hass,\n deviceEntityLookup[device.id]\n ),\n area:\n device.area_id && areaLookup[device.area_id]\n ? areaLookup[device.area_id].name\n : this.hass.localize(\"ui.components.device-picker.no_area\"),\n }));\n if (!outputDevices.length) {\n return [\n {\n id: \"no_devices\",\n area: \"\",\n name: this.hass.localize(\"ui.components.device-picker.no_match\"),\n },\n ];\n }\n if (outputDevices.length === 1) {\n return outputDevices;\n }\n return outputDevices.sort((a, b) =>\n stringCompare(a.name || \"\", b.name || \"\")\n );\n }\n );\n\n public open() {\n this.comboBox?.open();\n }\n\n public focus() {\n this.comboBox?.focus();\n }\n\n public hassSubscribe(): UnsubscribeFunc[] {\n return [\n subscribeDeviceRegistry(this.hass.connection!, (devices) => {\n this.devices = devices.filter(\n (device) =>\n device.config_entries &&\n device.config_entries.includes(\n this.insteon.config_entry.entry_id\n ) &&\n (!this.excludeModem || !device.model?.includes(\"(0x03\"))\n );\n }),\n subscribeAreaRegistry(this.hass.connection!, (areas) => {\n this.areas = areas;\n }),\n subscribeEntityRegistry(this.hass.connection!, (entities) => {\n this.entities = entities;\n }),\n ];\n }\n\n protected updated(changedProps: PropertyValues) {\n if (\n (!this._init && this.devices && this.areas && this.entities) ||\n (changedProps.has(\"_opened\") && this._opened)\n ) {\n this._init = true;\n (this.comboBox as any).items = this._getDevices(\n this.devices!,\n this.areas!,\n this.entities!\n );\n }\n }\n\n protected render(): TemplateResult {\n if (!this.devices || !this.areas || !this.entities) {\n return html``;\n }\n return html`\n <ha-combo-box\n .hass=${this.hass}\n .label=${this.label === undefined && this.hass\n ? this.hass.localize(\"ui.components.device-picker.device\")\n : this.label}\n .value=${this._value}\n .helper=${this.helper}\n .renderer=${rowRenderer}\n .disabled=${this.disabled}\n .required=${this.required}\n item-value-path=\"id\"\n item-label-path=\"name\"\n @opened-changed=${this._openedChanged}\n @value-changed=${this._deviceChanged}\n ></ha-combo-box>\n `;\n }\n\n private get _value() {\n return this.value || \"\";\n }\n\n private _deviceChanged(ev: PolymerChangedEvent<string>) {\n ev.stopPropagation();\n let newValue = ev.detail.value;\n\n if (newValue === \"no_devices\") {\n newValue = \"\";\n }\n\n if (newValue !== this._value) {\n this._setValue(newValue);\n }\n }\n\n private _openedChanged(ev: PolymerChangedEvent<boolean>) {\n this._opened = ev.detail.value;\n }\n\n private _setValue(value: string) {\n this.value = value;\n setTimeout(() => {\n fireEvent(this, \"value-changed\", { value });\n fireEvent(this, \"change\");\n }, 0);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"insteon-device-picker\": InsteonDevicePicker;\n }\n}\n","import {\n css,\n CSSResultGroup,\n html,\n LitElement,\n PropertyValues,\n TemplateResult,\n} from \"lit\";\nimport { customElement, eventOptions, property } from \"lit/decorators\";\nimport { restoreScroll } from \"../common/decorators/restore-scroll\";\nimport { toggleAttribute } from \"../common/dom/toggle_attribute\";\nimport { computeRTL } from \"../common/util/compute_rtl\";\nimport \"../components/ha-icon-button-arrow-prev\";\nimport \"../components/ha-menu-button\";\nimport { HomeAssistant } from \"../types\";\n\n@customElement(\"hass-subpage\")\nclass HassSubpage extends LitElement {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property() public header?: string;\n\n @property({ type: Boolean, attribute: \"main-page\" }) public mainPage = false;\n\n @property({ type: String, attribute: \"back-path\" }) public backPath?: string;\n\n @property() public backCallback?: () => void;\n\n @property({ type: Boolean, reflect: true }) public narrow = false;\n\n @property({ type: Boolean }) public supervisor = false;\n\n // @ts-ignore\n @restoreScroll(\".content\") private _savedScrollPos?: number;\n\n protected willUpdate(changedProps: PropertyValues): void {\n super.willUpdate(changedProps);\n if (!changedProps.has(\"hass\")) {\n return;\n }\n const oldHass = changedProps.get(\"hass\") as HomeAssistant | undefined;\n if (!oldHass || oldHass.locale !== this.hass.locale) {\n toggleAttribute(this, \"rtl\", computeRTL(this.hass));\n }\n }\n\n protected render(): TemplateResult {\n return html`\n <div class=\"toolbar\">\n ${this.mainPage || history.state?.root\n ? html`\n <ha-menu-button\n .hassio=${this.supervisor}\n .hass=${this.hass}\n .narrow=${this.narrow}\n ></ha-menu-button>\n `\n : this.backPath\n ? html`\n <a href=${this.backPath}>\n <ha-icon-button-arrow-prev\n .hass=${this.hass}\n ></ha-icon-button-arrow-prev>\n </a>\n `\n : html`\n <ha-icon-button-arrow-prev\n .hass=${this.hass}\n @click=${this._backTapped}\n ></ha-icon-button-arrow-prev>\n `}\n\n <div class=\"main-title\">${this.header}</div>\n <slot name=\"toolbar-icon\"></slot>\n </div>\n <div class=\"content\" @scroll=${this._saveScrollPos}><slot></slot></div>\n <div id=\"fab\">\n <slot name=\"fab\"></slot>\n </div>\n `;\n }\n\n @eventOptions({ passive: true })\n private _saveScrollPos(e: Event) {\n this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;\n }\n\n private _backTapped(): void {\n if (this.backCallback) {\n this.backCallback();\n return;\n }\n history.back();\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n display: block;\n height: 100%;\n background-color: var(--primary-background-color);\n }\n\n :host([narrow]) {\n width: 100%;\n position: fixed;\n }\n\n .toolbar {\n display: flex;\n align-items: center;\n font-size: 20px;\n height: var(--header-height);\n padding: 0 16px;\n pointer-events: none;\n background-color: var(--app-header-background-color);\n font-weight: 400;\n color: var(--app-header-text-color, white);\n border-bottom: var(--app-header-border-bottom, none);\n box-sizing: border-box;\n }\n .toolbar a {\n color: var(--sidebar-text-color);\n text-decoration: none;\n }\n\n ha-menu-button,\n ha-icon-button-arrow-prev,\n ::slotted([slot=\"toolbar-icon\"]) {\n pointer-events: auto;\n color: var(--sidebar-icon-color);\n }\n\n .main-title {\n margin: 0 0 0 24px;\n line-height: 20px;\n flex-grow: 1;\n }\n\n .content {\n position: relative;\n width: 100%;\n height: calc(100% - 1px - var(--header-height));\n overflow-y: auto;\n overflow: auto;\n -webkit-overflow-scrolling: touch;\n }\n\n #fab {\n position: fixed;\n right: calc(16px + env(safe-area-inset-right));\n bottom: calc(16px + env(safe-area-inset-bottom));\n z-index: 1;\n }\n :host([narrow]) #fab.tabs {\n bottom: calc(84px + env(safe-area-inset-bottom));\n }\n #fab[is-wide] {\n bottom: 24px;\n right: 24px;\n }\n :host([rtl]) #fab {\n right: auto;\n left: calc(16px + env(safe-area-inset-left));\n }\n :host([rtl][is-wide]) #fab {\n bottom: 24px;\n left: 24px;\n right: auto;\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"hass-subpage\": HassSubpage;\n }\n}\n","import { css, html, LitElement } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\nimport { classMap } from \"lit/directives/class-map\";\n\n@customElement(\"ha-config-section\")\nexport class HaConfigSection extends LitElement {\n @property() public isWide = false;\n\n @property({ type: Boolean }) public vertical = false;\n\n @property({ type: Boolean, attribute: \"full-width\" })\n public fullWidth = false;\n\n protected render() {\n return html`\n <div\n class=\"content ${classMap({\n narrow: !this.isWide,\n \"full-width\": this.fullWidth,\n })}\"\n >\n <div class=\"header\"><slot name=\"header\"></slot></div>\n <div\n class=\"together layout ${classMap({\n narrow: !this.isWide,\n vertical: this.vertical || !this.isWide,\n horizontal: !this.vertical && this.isWide,\n })}\"\n >\n <div class=\"intro\"><slot name=\"introduction\"></slot></div>\n <div class=\"panel flex-auto\"><slot></slot></div>\n </div>\n </div>\n `;\n }\n\n static get styles() {\n return css`\n :host {\n display: block;\n }\n .content {\n padding: 28px 20px 0;\n max-width: 1040px;\n margin: 0 auto;\n }\n\n .layout {\n display: flex;\n }\n\n .horizontal {\n flex-direction: row;\n }\n\n .vertical {\n flex-direction: column;\n }\n\n .flex-auto {\n flex: 1 1 auto;\n }\n\n .header {\n font-family: var(--paper-font-headline_-_font-family);\n -webkit-font-smoothing: var(\n --paper-font-headline_-_-webkit-font-smoothing\n );\n font-size: var(--paper-font-headline_-_font-size);\n font-weight: var(--paper-font-headline_-_font-weight);\n letter-spacing: var(--paper-font-headline_-_letter-spacing);\n line-height: var(--paper-font-headline_-_line-height);\n opacity: var(--dark-primary-opacity);\n }\n\n .together {\n margin-top: 32px;\n }\n\n .intro {\n font-family: var(--paper-font-subhead_-_font-family);\n -webkit-font-smoothing: var(\n --paper-font-subhead_-_-webkit-font-smoothing\n );\n font-weight: var(--paper-font-subhead_-_font-weight);\n line-height: var(--paper-font-subhead_-_line-height);\n width: 100%;\n opacity: var(--dark-primary-opacity);\n font-size: 14px;\n padding-bottom: 20px;\n }\n\n .horizontal .intro {\n max-width: 400px;\n margin-right: 40px;\n }\n\n .panel {\n margin-top: -24px;\n }\n\n .panel ::slotted(*) {\n margin-top: 24px;\n display: block;\n }\n\n .narrow.content {\n max-width: 640px;\n }\n .narrow .together {\n margin-top: 20px;\n }\n .narrow .intro {\n padding-bottom: 20px;\n margin-right: 0;\n max-width: 500px;\n }\n\n .full-width {\n padding: 0;\n }\n\n .full-width .layout {\n flex-direction: column;\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-config-section\": HaConfigSection;\n }\n}\n","import { ActionDetail } from \"@material/mwc-list/mwc-list-foundation\";\nimport \"@material/mwc-list/mwc-list-item\";\nimport { mdiContentSave, mdiDelete, mdiDotsVertical } from \"@mdi/js\";\nimport \"@polymer/paper-item/paper-icon-item\";\nimport \"@polymer/paper-item/paper-item\";\nimport \"@polymer/paper-item/paper-item-body\";\nimport {\n css,\n CSSResultGroup,\n html,\n LitElement,\n PropertyValues,\n TemplateResult,\n} from \"lit\";\nimport { customElement, property, state } from \"lit/decorators\";\nimport { classMap } from \"lit/directives/class-map\";\nimport { afterNextRender } from \"../../homeassistant-frontend/src/common/util/render-status\";\nimport { computeDomain } from \"../../homeassistant-frontend/src/common/entity/compute_domain\";\nimport { computeStateName } from \"../../homeassistant-frontend/src/common/entity/compute_state_name\";\nimport { computeRTL } from \"../../homeassistant-frontend/src/common/util/compute_rtl\";\nimport \"../device/insteon-device-picker\";\nimport \"../../homeassistant-frontend/src/layouts/hass-subpage\";\nimport \"../../homeassistant-frontend/src/components/ha-area-picker\";\nimport \"../../homeassistant-frontend/src/components/ha-card\";\nimport \"../../homeassistant-frontend/src/components/ha-fab\";\nimport \"../../homeassistant-frontend/src/components/ha-icon-button\";\nimport \"../../homeassistant-frontend/src/components/ha-icon-picker\";\nimport \"../../homeassistant-frontend/src/components/ha-svg-icon\";\nimport \"../../homeassistant-frontend/src/components/ha-textfield\";\nimport \"../../homeassistant-frontend/src/components/ha-checkbox\";\nimport \"../../homeassistant-frontend/src/components/ha-switch\";\nimport {\n computeDeviceName,\n DeviceRegistryEntry,\n subscribeDeviceRegistry,\n} from \"../../homeassistant-frontend/src/data/device_registry\";\nimport {\n EntityRegistryEntry,\n subscribeEntityRegistry,\n} from \"../../homeassistant-frontend/src/data/entity_registry\";\nimport {\n getSceneEditorInitData,\n SCENE_IGNORED_DOMAINS,\n} from \"../../homeassistant-frontend/src/data/scene\";\nimport {\n showConfirmationDialog,\n showAlertDialog,\n} from \"../../homeassistant-frontend/src/dialogs/generic/show-dialog-box\";\nimport { KeyboardShortcutMixin } from \"../../homeassistant-frontend/src/mixins/keyboard-shortcut-mixin\";\nimport { SubscribeMixin } from \"../../homeassistant-frontend/src/mixins/subscribe-mixin\";\nimport { haStyle } from \"../../homeassistant-frontend/src/resources/styles\";\nimport { HomeAssistant, Route } from \"../../homeassistant-frontend/src/types\";\nimport \"../../homeassistant-frontend/src/panels/config/ha-config-section\";\nimport {\n Insteon,\n InsteonScene,\n InsteonSceneDeviceData,\n fetchInsteonScene,\n sceneDataSchema,\n saveInsteonScene,\n deleteInsteonScene,\n InsteonSceneLinkData,\n} from \"../data/insteon\";\nimport \"../../homeassistant-frontend/src/components/ha-form/ha-form\";\nimport { showInsteonSetOnLevelDialog } from \"./show-dialog-insteon-scene-set-on-level\";\nimport { navigate } from \"../../homeassistant-frontend/src/common/navigate\";\n\ninterface DeviceEntitiesLookup {\n [deviceId: string]: string[];\n}\n\ninterface InsteonSceneEntity {\n entity_id: string;\n name: string;\n is_in_scene: boolean;\n data1: number;\n data2: number;\n data3: number;\n}\n\ninterface InsteonSceneDevice {\n address: string;\n device_id: string;\n name: string | null | undefined;\n entities: InsteonSceneEntity[];\n}\n\ninterface InsteonToHaDeviceMap {\n device: DeviceRegistryEntry;\n entities: { [group: number]: EntityRegistryEntry };\n}\n\nconst DIMMABLE_DOMAINS = [\"light\", \"fan\"];\n\n@customElement(\"insteon-scene-editor\")\nexport class InsteonSceneEditor extends SubscribeMixin(\n KeyboardShortcutMixin(LitElement)\n) {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property({ attribute: false }) public insteon!: Insteon;\n\n @property() public narrow!: boolean;\n\n @property() public isWide!: boolean;\n\n @property() public route!: Route;\n\n @property() public sceneId: string | null = null;\n\n @state() public _scene?: InsteonScene;\n\n @state() private _dirty = false;\n\n @state() private _errors?: string;\n\n @state() private _deviceRegistryEntries: DeviceRegistryEntry[] = [];\n\n @state() private _entityRegistryEntries: EntityRegistryEntry[] = [];\n\n private _insteonToHaDeviceMap: { [address: string]: InsteonToHaDeviceMap } =\n {};\n\n private _haToinsteonDeviceMap: { [deviceId: string]: string } = {};\n\n private _unsubscribeEvents?: () => void;\n\n private _deviceEntityLookup: DeviceEntitiesLookup = {};\n\n @state() private _saving = false;\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n if (this._unsubscribeEvents) {\n this._unsubscribeEvents();\n this._unsubscribeEvents = undefined;\n }\n }\n\n public hassSubscribe() {\n return [\n subscribeEntityRegistry(this.hass.connection, (entries) => {\n this._entityRegistryEntries = entries.filter(\n (entity) =>\n entity.config_entry_id == this.insteon.config_entry.entry_id &&\n !SCENE_IGNORED_DOMAINS.includes(computeDomain(entity.entity_id))\n );\n }),\n subscribeDeviceRegistry(this.hass.connection, (entries) => {\n this._deviceRegistryEntries = entries.filter(\n (device) =>\n device.config_entries &&\n device.config_entries.includes(this.insteon.config_entry.entry_id)\n );\n }),\n ];\n }\n\n protected render(): TemplateResult {\n if (!this.hass || !this._scene) {\n return html``;\n }\n const name = this._scene\n ? this._scene.name\n : this.insteon.localize(\"scenes.scene.default_name\");\n\n const devices = this._setSceneDevices();\n return html`\n <hass-subpage\n .hass=${this.hass}\n .narrow=${this.narrow}\n .route=${this.route}\n .backCallback=${this._backTapped}\n .header=${name}\n >\n <ha-button-menu\n corner=\"BOTTOM_START\"\n slot=\"toolbar-icon\"\n @action=${this._handleMenuAction}\n activatable\n >\n <ha-icon-button\n slot=\"trigger\"\n .label=${this.hass.localize(\"ui.common.menu\")}\n .path=${mdiDotsVertical}\n ></ha-icon-button>\n\n <mwc-list-item\n .disabled=${!this.sceneId}\n aria-label=${this.insteon.localize(\"scenes.scene.delete\")}\n class=${classMap({ warning: Boolean(this.sceneId) })}\n graphic=\"icon\"\n >\n ${this.insteon.localize(\"scenes.scene.delete\")}\n <ha-svg-icon\n class=${classMap({ warning: Boolean(this.sceneId) })}\n slot=\"graphic\"\n .path=${mdiDelete}\n >\n </ha-svg-icon>\n </mwc-list-item>\n </ha-button-menu>\n ${this._errors ? html` <div class=\"errors\">${this._errors}</div> ` : \"\"}\n ${!this.narrow ? html` <span slot=\"header\">${name}</span> ` : \"\"}\n <div\n id=\"root\"\n class=${classMap({\n rtl: computeRTL(this.hass),\n })}\n >\n <ha-config-section vertical .isWide=${this.isWide}>\n ${this._saving\n ? html`<div>\n <ha-circular-progress\n active\n alt=\"Loading\"\n ></ha-circular-progress>\n </div>`\n : this._showEditorArea(name, devices)}\n </ha-config-section>\n </div>\n <ha-fab\n slot=\"fab\"\n .label=${this.insteon.localize(\"scenes.scene.save\")}\n extended\n .disabled=${this._saving}\n @click=${this._saveScene}\n class=${classMap({ dirty: this._dirty, saving: this._saving })}\n >\n <ha-svg-icon slot=\"icon\" .path=${mdiContentSave}></ha-svg-icon>\n </ha-fab>\n </hass-subpage>\n `;\n }\n\n private _showEditorArea(name, devices) {\n return html`<div slot=\"introduction\">\n ${this.insteon.localize(\"scenes.scene.introduction\")}\n </div>\n <ha-card outlined>\n <div class=\"card-content\">\n <ha-textfield\n .value=${name}\n .name=${\"name\"}\n @change=${this._nameChanged}\n .label=${this.insteon.localize(\"scenes.scene.name\")}\n ></ha-textfield>\n </div>\n </ha-card>\n\n <ha-config-section vertical .isWide=${this.isWide}>\n <div slot=\"header\">\n ${this.insteon.localize(\"scenes.scene.devices.header\")}\n </div>\n <div slot=\"introduction\">\n ${this.insteon.localize(\"scenes.scene.devices.introduction\")}\n </div>\n\n ${devices.map(\n (device) =>\n html`\n <ha-card outlined>\n <h1 class=\"card-header\">\n ${device.name}\n <ha-icon-button\n .path=${mdiDelete}\n .label=${this.hass.localize(\n \"ui.panel.config.scene.editor.devices.delete\"\n )}\n .device_address=${device.address}\n @click=${this._deleteDevice}\n ></ha-icon-button>\n </h1>\n ${!device.entities\n ? html` <ha-form .schema=${sceneDataSchema}></ha-form> `\n : device.entities.map(\n (entity) =>\n html`\n <paper-icon-item class=\"device-entity\">\n <ha-checkbox\n .checked=${entity.is_in_scene}\n @change=${this._toggleSelection}\n .device_address=${device.address}\n .group=${entity.data3}\n ></ha-checkbox>\n <paper-item-body\n @click=${this._showSetOnLevel}\n .device_address=${device.address}\n .group=${entity.data3}\n >\n ${entity.name}\n </paper-item-body>\n <ha-switch\n .checked=${entity.data1 > 0}\n @change=${this._toggleOnLevel}\n .device_address=${device.address}\n .group=${entity.data3}\n ></ha-switch>\n </paper-icon-item>\n `\n )};\n </ha-card>\n `\n )}\n\n <ha-card\n outlined\n .header=${this.insteon.localize(\"scenes.scene.devices.add\")}\n >\n <div class=\"card-content\">\n <insteon-device-picker\n @value-changed=${this._devicePicked}\n .hass=${this.hass}\n .insteon=${this.insteon}\n .label=${this.insteon.localize(\"scenes.scene.devices.add\")}\n .excludedDomains=${SCENE_IGNORED_DOMAINS}\n ></insteon-device-picker>\n </div>\n </ha-card>\n </ha-config-section>`;\n }\n\n private _setSceneDevices(): InsteonSceneDevice[] {\n const outputDevices: InsteonSceneDevice[] = [];\n if (!this._scene) {\n return [];\n }\n for (const [address, links] of Object.entries(this._scene.devices)) {\n const haDevice = this._insteonToHaDeviceMap[address] || undefined;\n const deviceEntities = haDevice.entities || {};\n const theseEntities: InsteonSceneEntity[] = [];\n let thisDevice: InsteonSceneDevice | undefined = undefined;\n\n for (const [group, entity] of Object.entries(deviceEntities)) {\n const insteonEntityData: InsteonSceneDeviceData | undefined =\n links.find((link) => link.data3 == +group);\n const data1 = insteonEntityData?.data1 || 0;\n const data2 = insteonEntityData?.data2 || 28;\n const data3 = insteonEntityData?.data3 || group;\n const is_in_scene = insteonEntityData ? true : false;\n theseEntities.push({\n entity_id: entity.entity_id,\n name:\n computeStateName(this.hass.states[entity.entity_id]) ||\n \"Device button \" + group,\n is_in_scene: is_in_scene,\n data1: data1,\n data2: data2,\n data3: +data3,\n });\n thisDevice = {\n address: address,\n device_id: haDevice.device.id,\n name: computeDeviceName(\n haDevice.device,\n this.hass,\n this._deviceEntityLookup[haDevice.device.id]\n ),\n entities: theseEntities,\n };\n }\n if (thisDevice) {\n outputDevices.push(thisDevice);\n }\n }\n return outputDevices;\n }\n\n protected firstUpdated(\n _changedProperties: Map<string | number | symbol, unknown>\n ): void {\n super.firstUpdated(_changedProperties);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n this.hassSubscribe();\n\n if (!this._scene && this.sceneId) {\n this._loadScene();\n } else {\n this._initNewScene();\n }\n\n //Copied from ha-panel-config to retain consistancy\n this.style.setProperty(\n \"--app-header-background-color\",\n \"var(--sidebar-background-color)\"\n );\n this.style.setProperty(\n \"--app-header-text-color\",\n \"var(--sidebar-text-color)\"\n );\n this.style.setProperty(\n \"--app-header-border-bottom\",\n \"1px solid var(--divider-color)\"\n );\n this.style.setProperty(\n \"--ha-card-border-radius\",\n \"var(--ha-config-card-border-radius, 8px)\"\n );\n }\n\n protected updated(changedProps: PropertyValues): void {\n super.updated(changedProps);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n\n if (\n changedProps.has(\"_deviceRegistryEntries\") ||\n changedProps.has(\"_entityRegistryEntries\")\n ) {\n this._mapDeviceEntities();\n }\n }\n\n private _initNewScene() {\n this._dirty = false;\n const initData = getSceneEditorInitData();\n this._scene = {\n name: this.insteon.localize(\"scenes.scene.default_name\"),\n devices: {},\n group: -1,\n };\n // if (initData?.areaId) {\n // this._updatedAreaId = initData.areaId;\n // }\n this._dirty =\n initData !== undefined &&\n (initData.areaId !== undefined || initData.config !== undefined);\n }\n\n private _mapDeviceEntities() {\n this._insteonToHaDeviceMap = {};\n this._haToinsteonDeviceMap = {};\n this._deviceRegistryEntries.map((haDevice) => {\n const address: string = haDevice.identifiers[0][1];\n const entities: { [group: number]: EntityRegistryEntry } = {};\n this._entityRegistryEntries\n .filter((entity) => entity.device_id == haDevice.id)\n .map((entity) => {\n const stateobj = this.hass.states[entity.entity_id];\n const group = stateobj.attributes.insteon_group;\n entities[group] = entity;\n });\n this._insteonToHaDeviceMap[address] = {\n device: haDevice,\n entities: entities,\n };\n this._haToinsteonDeviceMap[haDevice.id] = address;\n });\n for (const entity of this._entityRegistryEntries) {\n if (\n !entity.device_id ||\n SCENE_IGNORED_DOMAINS.includes(computeDomain(entity.entity_id))\n ) {\n continue;\n }\n if (!(entity.device_id in this._deviceEntityLookup)) {\n this._deviceEntityLookup[entity.device_id] = [];\n }\n if (\n !this._deviceEntityLookup[entity.device_id].includes(entity.entity_id)\n ) {\n this._deviceEntityLookup[entity.device_id].push(entity.entity_id);\n }\n }\n }\n\n private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {\n switch (ev.detail.index) {\n case 0:\n this._deleteTapped();\n break;\n }\n }\n\n private _showSetOnLevel(ev: Event) {\n ev.stopPropagation();\n const address = (ev.currentTarget as any).device_address;\n const group = (ev.currentTarget as any).group;\n const device = this._scene!.devices[address];\n let link = device.find((curr_link) => curr_link.data3 == +group);\n if (!link) {\n this._selectEntity(true, device, group);\n link = device.find((curr_link) => curr_link.data3 == +group);\n }\n const haDevice = this._insteonToHaDeviceMap[address];\n const deviceEntities = haDevice.entities || {};\n const entity = deviceEntities[+group];\n if (DIMMABLE_DOMAINS.includes(computeDomain(entity.entity_id))) {\n this._setOnLevel(\n address,\n group,\n link!.data1,\n link!.data2 == 0 ? 28 : link!.data2\n );\n }\n }\n\n private async _setOnLevel(\n address: string,\n group: number,\n on_level: number,\n ramp_rate: number\n ): Promise<void> {\n showInsteonSetOnLevelDialog(this, {\n hass: this.hass,\n insteon: this.insteon,\n title: this.insteon.localize(\"device.actions.add\"),\n address: address,\n group: group,\n value: on_level,\n ramp_rate: ramp_rate,\n callback: async (address_out, group_out, on_level_out, ramp_rate_out) =>\n this._handleSetOnLevel(\n address_out,\n group_out,\n on_level_out,\n ramp_rate_out\n ),\n });\n history.back();\n }\n\n private _handleSetOnLevel(\n address: string,\n group: number,\n on_level: number,\n ramp_rate: number\n ) {\n const device = this._scene!.devices[address];\n const existing_link = device.find((link) => link.data3 == +group);\n if (existing_link!.data1 != on_level) {\n existing_link!.data1 = on_level;\n this._dirty = true;\n }\n if (existing_link!.data2 != ramp_rate) {\n existing_link!.data2 = ramp_rate;\n this._dirty = true;\n }\n if (this._dirty) {\n this._scene = { ...this._scene! };\n }\n }\n\n private async _loadScene() {\n // let config: SceneConfig;\n this._scene = await fetchInsteonScene(this.hass, +this.sceneId!);\n for (const address in Object.keys(this._scene.devices)) {\n const ha_device = this._deviceRegistryEntries.find(\n (haDevice) => haDevice.identifiers[0][1] === address\n );\n const device_id = ha_device?.id || undefined;\n if (device_id) {\n this._pickDevice(device_id);\n }\n }\n this._dirty = false;\n }\n\n private _pickDevice(deviceId: string) {\n const haDevice = this._deviceRegistryEntries.find((haCurrDevice) => {\n return haCurrDevice.id == deviceId;\n });\n const address = haDevice?.identifiers[0][1];\n if (!address) {\n return;\n }\n if (this._scene!.devices.hasOwnProperty(address)) {\n return;\n }\n const updated_scene: InsteonScene = { ...this._scene! };\n updated_scene.devices[address] = [];\n this._scene = { ...updated_scene };\n this._dirty = true;\n }\n\n private _devicePicked(ev: CustomEvent) {\n const deviceId = ev.detail.value;\n (ev.target as any).value = \"\";\n this._pickDevice(deviceId);\n }\n\n private _deleteDevice(ev: Event) {\n const address = (ev.target as any).device_address;\n const updated_scene: InsteonScene = { ...this._scene! };\n if (updated_scene.devices.hasOwnProperty(address)) {\n delete updated_scene.devices[address];\n }\n this._scene = { ...updated_scene };\n this._dirty = true;\n }\n\n private _toggleSelection(ev: Event) {\n const address = (ev.target as any).device_address;\n const checked = (ev.target as any).checked;\n const group = (ev.target as any).group;\n const device = this._scene!.devices[address];\n this._selectEntity(checked, device, group);\n this._scene = { ...this._scene! };\n this._dirty = true;\n }\n\n private _selectEntity(\n checked: boolean,\n device: InsteonSceneDeviceData[],\n group: number\n ) {\n if (checked) {\n const existing_link = device.find((link) => link.data3 == +group);\n if (existing_link) {\n return;\n }\n const link: InsteonSceneDeviceData = {\n data1: 0,\n data2: 0,\n data3: group,\n has_controller: false,\n has_responder: false,\n };\n device.push(link);\n } else {\n const existing_link = device.findIndex((link) => link.data3 == +group);\n if (existing_link !== -1) {\n device.splice(existing_link, 1);\n }\n }\n this._dirty = true;\n }\n\n private _toggleOnLevel(ev: Event) {\n const address = (ev.target as any).device_address;\n const checked = (ev.target as any).checked;\n const group = (ev.target as any).group;\n const device = this._scene!.devices[address];\n let existing_link = device.find((link) => link.data3 == +group);\n if (!existing_link) {\n this._selectEntity(true, device, +group);\n existing_link = device.find((link) => link.data3 == +group);\n }\n if (checked) {\n existing_link!.data1 = 255;\n const haDevice = this._insteonToHaDeviceMap[address] || undefined;\n const deviceEntities = haDevice.entities || {};\n const entity = deviceEntities[+group];\n if (DIMMABLE_DOMAINS.includes(computeDomain(entity.entity_id))) {\n existing_link!.data2 = 28;\n }\n } else {\n existing_link!.data1 = 0;\n existing_link!.data2 = 0;\n }\n this._scene = { ...this._scene! };\n this._dirty = true;\n }\n\n private _nameChanged(ev: Event) {\n ev.stopPropagation();\n const target = ev.target as any;\n const name = target.name;\n if (!name) {\n return;\n }\n let newVal = (ev as CustomEvent).detail?.value ?? target.value;\n if (target.type === \"number\") {\n newVal = Number(newVal);\n }\n if ((this._scene![name] || \"\") === newVal) {\n return;\n }\n if (!newVal) {\n delete this._scene![name];\n this._scene = { ...this._scene! };\n } else {\n this._scene = { ...this._scene!, [name]: newVal };\n }\n this._scene = { ...this._scene! };\n this._dirty = true;\n }\n\n private _backTapped = async (): Promise<void> => {\n const result = await this.confirmUnsavedChanged();\n if (result) {\n this._goBack();\n }\n };\n\n private _goBack(): void {\n afterNextRender(() => history.back());\n }\n\n private async confirmUnsavedChanged(): Promise<boolean> {\n if (this._dirty) {\n const action = showConfirmationDialog(this, {\n title: this.hass!.localize(\n \"ui.panel.config.scene.editor.unsaved_confirm_title\"\n ),\n text: this.hass!.localize(\n \"ui.panel.config.scene.editor.unsaved_confirm_text\"\n ),\n confirmText: this.hass!.localize(\"ui.common.leave\"),\n dismissText: this.hass!.localize(\"ui.common.stay\"),\n destructive: true,\n });\n history.back();\n return action;\n }\n return true;\n }\n\n private _deleteTapped(): void {\n showConfirmationDialog(this, {\n text: this.hass!.localize(\"ui.panel.config.scene.picker.delete_confirm\"),\n confirmText: this.hass!.localize(\"ui.common.delete\"),\n dismissText: this.hass!.localize(\"ui.common.cancel\"),\n confirm: () => this._delete(),\n });\n history.back();\n }\n\n private async _delete(): Promise<void> {\n this._saving = true;\n const sceneId: number = +this.sceneId!;\n const result = await deleteInsteonScene(this.hass, sceneId!);\n this._saving = false;\n if (!result.result) {\n showAlertDialog(this, {\n text: this.insteon!.localize(\"common.error.scene_write\"),\n confirmText: this.hass!.localize(\"ui.common.close\"),\n });\n history.back();\n }\n history.back();\n }\n\n private async _saveScene(): Promise<void> {\n if (!this._checkDeviceEntitySelections()) {\n showAlertDialog(this, {\n text: this.insteon!.localize(\"common.error.scene_device_no_entities\"),\n confirmText: this.hass!.localize(\"ui.common.close\"),\n });\n history.back();\n return;\n }\n this._saving = true;\n const links: InsteonSceneLinkData[] = [];\n Object.keys(this._scene!.devices).forEach((address) => {\n const link_data = this._scene!.devices[address];\n link_data.forEach((link_info) => {\n const link = {\n address: address,\n data1: link_info.data1,\n data2: link_info.data2,\n data3: link_info.data3,\n };\n links.push(link);\n });\n });\n const result = await saveInsteonScene(\n this.hass,\n this._scene!.group,\n links,\n this._scene!.name\n );\n this._saving = false;\n this._dirty = false;\n if (!result.result) {\n showAlertDialog(this, {\n text: this.insteon!.localize(\"common.error.scene_write\"),\n confirmText: this.hass!.localize(\"ui.common.close\"),\n });\n history.back();\n } else {\n if (!this.sceneId) {\n navigate(`/insteon/scene/${result.scene_id}`, { replace: true });\n }\n }\n }\n\n private _checkDeviceEntitySelections(): boolean {\n for (const [_, links] of Object.entries(this._scene!.devices)) {\n if (links.length == 0) {\n return false;\n }\n }\n return true;\n }\n\n protected handleKeyboardSave() {\n this._saveScene();\n }\n\n static get styles(): CSSResultGroup {\n return [\n haStyle,\n css`\n ha-card {\n overflow: hidden;\n }\n .errors {\n padding: 20px;\n font-weight: bold;\n color: var(--error-color);\n }\n ha-config-section:last-child {\n padding-bottom: 20px;\n }\n .triggers,\n .script {\n margin-top: -16px;\n }\n .triggers ha-card,\n .script ha-card {\n margin-top: 16px;\n }\n .add-card mwc-button {\n display: block;\n text-align: center;\n }\n .card-menu {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 1;\n color: var(--primary-text-color);\n }\n .rtl .card-menu {\n right: auto;\n left: 0;\n }\n .card-menu paper-item {\n cursor: pointer;\n }\n paper-icon-item {\n padding: 8px 16px;\n }\n ha-card ha-icon-button {\n color: var(--secondary-text-color);\n }\n .card-header > ha-icon-button {\n float: right;\n position: relative;\n top: -8px;\n }\n .device-entity {\n cursor: pointer;\n }\n span[slot=\"introduction\"] a {\n color: var(--primary-color);\n }\n ha-fab {\n position: relative;\n bottom: calc(-80px - env(safe-area-inset-bottom));\n transition: bottom 0.3s;\n }\n ha-fab.dirty {\n bottom: 0;\n }\n ha-fab.saving {\n opacity: var(--light-disabled-opacity);\n }\n ha-icon-picker,\n ha-area-picker,\n ha-entity-picker {\n display: block;\n margin-top: 8px;\n }\n ha-textfield {\n display: block;\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"insteon-scene-editor\": InsteonSceneEditor;\n }\n}\n"],"names":[],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"24065ffe.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsEA;AAIA;;AAKA;;;;;;ACzDA;;;;AAKA;;;;;;;;;;;;;;;;;;;;ACkBA;ACJA;;AAEA;AACA;;;AA8KA;AACA;AAGA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAhBA;;ACrKA;;AAGA;AACA;AACA;;AAEA;AAGA;;AAEA;;;AAGA;;AAGA;AACA;;;;AAIA;;;AAGA;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FA;;AC3JA;;;;AAOA;;;;;;AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4FA;;AC2CA;AACA;AACA;AACA;AACA;;;;;AAKA;;;;;AAKA;AAtLA;;;;AA2LA;AACA;AACA;;;AAGA;;AAEA;;AAEA;;;;;AAKA;AACA;;;AAGA;;AAIA;AACA;;;;;AAMA;;;;;AAMA;;AAEA;AACA;AACA;;AAlOA;;;AAwOA;AAIA;;;;;AAKA;AACA;AACA;AACA;;;;;AAKA;;AAEA;;;AAGA;;;AAGA;;;AAKA;;AAEA;AACA;AAGA;AACA;;;AAGA;;;AAOA;AACA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;;;AAvBA;;;;;;AAkCA;;;;AAIA;AACA;AACA;AACA;AACA;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2iBA","sources":["webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-card.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-fab.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-switch.ts","webpack://insteon-panel-frontend/./src/device/insteon-device-picker.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/layouts/hass-subpage.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/panels/config/ha-config-section.ts","webpack://insteon-panel-frontend/./src/scene/insteon-scene-editor.ts"],"sourcesContent":["import { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\n\n@customElement(\"ha-card\")\nexport class HaCard extends LitElement {\n @property() public header?: string;\n\n @property({ type: Boolean, reflect: true }) public raised = false;\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n background: var(\n --ha-card-background,\n var(--card-background-color, white)\n );\n box-shadow: var(--ha-card-box-shadow, none);\n box-sizing: border-box;\n border-radius: var(--ha-card-border-radius, 12px);\n border-width: var(--ha-card-border-width, 1px);\n border-style: solid;\n border-color: var(\n --ha-card-border-color,\n var(--divider-color, #e0e0e0)\n );\n color: var(--primary-text-color);\n display: block;\n transition: all 0.3s ease-out;\n position: relative;\n }\n\n :host([raised]) {\n border: none;\n box-shadow: var(\n --ha-card-box-shadow,\n 0px 2px 1px -1px rgba(0, 0, 0, 0.2),\n 0px 1px 1px 0px rgba(0, 0, 0, 0.14),\n 0px 1px 3px 0px rgba(0, 0, 0, 0.12)\n );\n }\n\n .card-header,\n :host ::slotted(.card-header) {\n color: var(--ha-card-header-color, --primary-text-color);\n font-family: var(--ha-card-header-font-family, inherit);\n font-size: var(--ha-card-header-font-size, 24px);\n letter-spacing: -0.012em;\n line-height: 48px;\n padding: 12px 16px 16px;\n display: block;\n margin-block-start: 0px;\n margin-block-end: 0px;\n font-weight: normal;\n }\n\n :host ::slotted(.card-content:not(:first-child)),\n slot:not(:first-child)::slotted(.card-content) {\n padding-top: 0px;\n margin-top: -8px;\n }\n\n :host ::slotted(.card-content) {\n padding: 16px;\n }\n\n :host ::slotted(.card-actions) {\n border-top: 1px solid var(--divider-color, #e8e8e8);\n padding: 5px 16px;\n }\n `;\n }\n\n protected render(): TemplateResult {\n return html`\n ${this.header\n ? html`<h1 class=\"card-header\">${this.header}</h1>`\n : html``}\n <slot></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-card\": HaCard;\n }\n}\n","import { FabBase } from \"@material/mwc-fab/mwc-fab-base\";\nimport { styles } from \"@material/mwc-fab/mwc-fab.css\";\nimport { customElement } from \"lit/decorators\";\nimport { css } from \"lit\";\n\n@customElement(\"ha-fab\")\nexport class HaFab extends FabBase {\n protected firstUpdated(changedProperties) {\n super.firstUpdated(changedProperties);\n this.style.setProperty(\"--mdc-theme-secondary\", \"var(--primary-color)\");\n }\n\n static override styles = [\n styles,\n css`\n :host .mdc-fab--extended .mdc-fab__icon {\n margin-inline-start: -8px;\n margin-inline-end: 12px;\n direction: var(--direction);\n }\n `,\n // safari workaround - must be explicit\n document.dir === \"rtl\"\n ? css`\n :host .mdc-fab--extended .mdc-fab__icon {\n direction: rtl;\n }\n `\n : css``,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-fab\": HaFab;\n }\n}\n","import { SwitchBase } from \"@material/mwc-switch/deprecated/mwc-switch-base\";\nimport { styles } from \"@material/mwc-switch/deprecated/mwc-switch.css\";\nimport { css } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\nimport { forwardHaptic } from \"../data/haptics\";\n\n@customElement(\"ha-switch\")\nexport class HaSwitch extends SwitchBase {\n // Generate a haptic vibration.\n // Only set to true if the new value of the switch is applied right away when toggling.\n // Do not add haptic when a user is required to press save.\n @property({ type: Boolean }) public haptic = false;\n\n protected firstUpdated() {\n super.firstUpdated();\n this.addEventListener(\"change\", () => {\n if (this.haptic) {\n forwardHaptic(\"light\");\n }\n });\n }\n\n static override styles = [\n styles,\n css`\n :host {\n --mdc-theme-secondary: var(--switch-checked-color);\n }\n .mdc-switch.mdc-switch--checked .mdc-switch__thumb {\n background-color: var(--switch-checked-button-color);\n border-color: var(--switch-checked-button-color);\n }\n .mdc-switch.mdc-switch--checked .mdc-switch__track {\n background-color: var(--switch-checked-track-color);\n border-color: var(--switch-checked-track-color);\n }\n .mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb {\n background-color: var(--switch-unchecked-button-color);\n border-color: var(--switch-unchecked-button-color);\n }\n .mdc-switch:not(.mdc-switch--checked) .mdc-switch__track {\n background-color: var(--switch-unchecked-track-color);\n border-color: var(--switch-unchecked-track-color);\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-switch\": HaSwitch;\n }\n}\n","import \"@material/mwc-list/mwc-list-item\";\nimport { UnsubscribeFunc } from \"home-assistant-js-websocket\";\nimport { html, LitElement, PropertyValues, TemplateResult } from \"lit\";\nimport { ComboBoxLitRenderer } from \"@vaadin/combo-box/lit\";\nimport { customElement, property, query, state } from \"lit/decorators\";\nimport memoizeOne from \"memoize-one\";\nimport { fireEvent } from \"../../homeassistant-frontend/src/common/dom/fire_event\";\nimport { stringCompare } from \"../../homeassistant-frontend/src/common/string/compare\";\nimport {\n AreaRegistryEntry,\n subscribeAreaRegistry,\n} from \"../../homeassistant-frontend/src/data/area_registry\";\nimport {\n computeDeviceName,\n DeviceEntityLookup,\n DeviceRegistryEntry,\n subscribeDeviceRegistry,\n} from \"../../homeassistant-frontend/src/data/device_registry\";\nimport {\n EntityRegistryEntry,\n subscribeEntityRegistry,\n} from \"../../homeassistant-frontend/src/data/entity_registry\";\nimport { SubscribeMixin } from \"../../homeassistant-frontend/src/mixins/subscribe-mixin\";\nimport { PolymerChangedEvent } from \"../../homeassistant-frontend/src/polymer-types\";\nimport { HomeAssistant } from \"../../homeassistant-frontend/src/types\";\nimport \"../../homeassistant-frontend/src/components/ha-combo-box\";\nimport type { HaComboBox } from \"../../homeassistant-frontend/src/components/ha-combo-box\";\nimport { Insteon } from \"../data/insteon\";\nimport { computeDomain } from \"../../homeassistant-frontend/src/common/entity/compute_domain\";\n\ninterface Device {\n name: string;\n area: string;\n id: string;\n}\n\nexport type HaDevicePickerDeviceFilterFunc = (\n device: DeviceRegistryEntry\n) => boolean;\n\nconst rowRenderer: ComboBoxLitRenderer<Device> = (item) => html`<mwc-list-item\n .twoline=${!!item.area}\n>\n <span>${item.name}</span>\n <span slot=\"secondary\">${item.area}</span>\n</mwc-list-item>`;\n\n@customElement(\"insteon-device-picker\")\nexport class InsteonDevicePicker extends SubscribeMixin(LitElement) {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property({ attribute: false }) public insteon!: Insteon;\n\n @property() public label?: string;\n\n @property() public value?: string;\n\n @property() public helper?: string;\n\n @property() public devices?: DeviceRegistryEntry[];\n\n @property() public areas?: AreaRegistryEntry[];\n\n @property() public entities?: EntityRegistryEntry[];\n\n @property({ type: Array, attribute: \"includedDomains\" })\n public includedDomains?: string[];\n\n @property({ type: Array, attribute: \"excludedDomains\" })\n public excludedDomains?: string[];\n\n /**\n * Show the modem in the list of devices.\n * @type {Array}\n * @attr include-modem\n */\n @property({\n type: Boolean,\n attribute: \"exclude-modem\",\n })\n public excludeModem?: boolean = false;\n\n @property({ type: Boolean }) public disabled?: boolean;\n\n @property({ type: Boolean }) public required?: boolean;\n\n @state() private _opened?: boolean;\n\n @query(\"ha-combo-box\", true) public comboBox!: HaComboBox;\n\n private _init = false;\n\n private _getDevices = memoizeOne(\n (\n devices: DeviceRegistryEntry[],\n areas: AreaRegistryEntry[],\n entities: EntityRegistryEntry[]\n ): Device[] => {\n if (!devices.length) {\n return [\n {\n id: \"no_devices\",\n area: \"\",\n name: this.hass.localize(\"ui.components.device-picker.no_devices\"),\n },\n ];\n }\n\n const deviceEntityLookup: DeviceEntityLookup = {};\n\n const filtered_included_entities = entities.filter(\n (entity) =>\n !this.includedDomains ||\n this.includedDomains.includes(computeDomain(entity.entity_id))\n );\n\n const filtered_entities = filtered_included_entities.filter(\n (entity) =>\n !this.excludedDomains ||\n !this.excludedDomains.includes(computeDomain(entity.entity_id))\n );\n\n for (const entity of filtered_entities) {\n if (!entity.device_id) {\n continue;\n }\n if (!(entity.device_id in deviceEntityLookup)) {\n deviceEntityLookup[entity.device_id] = [];\n }\n deviceEntityLookup[entity.device_id].push(entity);\n }\n\n const areaLookup: { [areaId: string]: AreaRegistryEntry } = {};\n for (const area of areas) {\n areaLookup[area.area_id] = area;\n }\n\n const outputDevices = devices\n .filter((device) => deviceEntityLookup.hasOwnProperty(device.id))\n .map((device) => ({\n id: device.id,\n name: computeDeviceName(\n device,\n this.hass,\n deviceEntityLookup[device.id]\n ),\n area:\n device.area_id && areaLookup[device.area_id]\n ? areaLookup[device.area_id].name\n : this.hass.localize(\"ui.components.device-picker.no_area\"),\n }));\n if (!outputDevices.length) {\n return [\n {\n id: \"no_devices\",\n area: \"\",\n name: this.hass.localize(\"ui.components.device-picker.no_match\"),\n },\n ];\n }\n if (outputDevices.length === 1) {\n return outputDevices;\n }\n return outputDevices.sort((a, b) =>\n stringCompare(a.name || \"\", b.name || \"\")\n );\n }\n );\n\n public open() {\n this.comboBox?.open();\n }\n\n public focus() {\n this.comboBox?.focus();\n }\n\n public hassSubscribe(): UnsubscribeFunc[] {\n return [\n subscribeDeviceRegistry(this.hass.connection!, (devices) => {\n this.devices = devices.filter(\n (device) =>\n device.config_entries &&\n device.config_entries.includes(\n this.insteon.config_entry.entry_id\n ) &&\n (!this.excludeModem || !device.model?.includes(\"(0x03\"))\n );\n }),\n subscribeAreaRegistry(this.hass.connection!, (areas) => {\n this.areas = areas;\n }),\n subscribeEntityRegistry(this.hass.connection!, (entities) => {\n this.entities = entities;\n }),\n ];\n }\n\n protected updated(changedProps: PropertyValues) {\n if (\n (!this._init && this.devices && this.areas && this.entities) ||\n (changedProps.has(\"_opened\") && this._opened)\n ) {\n this._init = true;\n (this.comboBox as any).items = this._getDevices(\n this.devices!,\n this.areas!,\n this.entities!\n );\n }\n }\n\n protected render(): TemplateResult {\n if (!this.devices || !this.areas || !this.entities) {\n return html``;\n }\n return html`\n <ha-combo-box\n .hass=${this.hass}\n .label=${this.label === undefined && this.hass\n ? this.hass.localize(\"ui.components.device-picker.device\")\n : this.label}\n .value=${this._value}\n .helper=${this.helper}\n .renderer=${rowRenderer}\n .disabled=${this.disabled}\n .required=${this.required}\n item-value-path=\"id\"\n item-label-path=\"name\"\n @opened-changed=${this._openedChanged}\n @value-changed=${this._deviceChanged}\n ></ha-combo-box>\n `;\n }\n\n private get _value() {\n return this.value || \"\";\n }\n\n private _deviceChanged(ev: PolymerChangedEvent<string>) {\n ev.stopPropagation();\n let newValue = ev.detail.value;\n\n if (newValue === \"no_devices\") {\n newValue = \"\";\n }\n\n if (newValue !== this._value) {\n this._setValue(newValue);\n }\n }\n\n private _openedChanged(ev: PolymerChangedEvent<boolean>) {\n this._opened = ev.detail.value;\n }\n\n private _setValue(value: string) {\n this.value = value;\n setTimeout(() => {\n fireEvent(this, \"value-changed\", { value });\n fireEvent(this, \"change\");\n }, 0);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"insteon-device-picker\": InsteonDevicePicker;\n }\n}\n","import {\n css,\n CSSResultGroup,\n html,\n LitElement,\n PropertyValues,\n TemplateResult,\n} from \"lit\";\nimport { customElement, eventOptions, property } from \"lit/decorators\";\nimport { restoreScroll } from \"../common/decorators/restore-scroll\";\nimport { toggleAttribute } from \"../common/dom/toggle_attribute\";\nimport { computeRTL } from \"../common/util/compute_rtl\";\nimport \"../components/ha-icon-button-arrow-prev\";\nimport \"../components/ha-menu-button\";\nimport { HomeAssistant } from \"../types\";\n\n@customElement(\"hass-subpage\")\nclass HassSubpage extends LitElement {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property() public header?: string;\n\n @property({ type: Boolean, attribute: \"main-page\" }) public mainPage = false;\n\n @property({ type: String, attribute: \"back-path\" }) public backPath?: string;\n\n @property() public backCallback?: () => void;\n\n @property({ type: Boolean, reflect: true }) public narrow = false;\n\n @property({ type: Boolean }) public supervisor = false;\n\n // @ts-ignore\n @restoreScroll(\".content\") private _savedScrollPos?: number;\n\n protected willUpdate(changedProps: PropertyValues): void {\n super.willUpdate(changedProps);\n if (!changedProps.has(\"hass\")) {\n return;\n }\n const oldHass = changedProps.get(\"hass\") as HomeAssistant | undefined;\n if (!oldHass || oldHass.locale !== this.hass.locale) {\n toggleAttribute(this, \"rtl\", computeRTL(this.hass));\n }\n }\n\n protected render(): TemplateResult {\n return html`\n <div class=\"toolbar\">\n ${this.mainPage || history.state?.root\n ? html`\n <ha-menu-button\n .hassio=${this.supervisor}\n .hass=${this.hass}\n .narrow=${this.narrow}\n ></ha-menu-button>\n `\n : this.backPath\n ? html`\n <a href=${this.backPath}>\n <ha-icon-button-arrow-prev\n .hass=${this.hass}\n ></ha-icon-button-arrow-prev>\n </a>\n `\n : html`\n <ha-icon-button-arrow-prev\n .hass=${this.hass}\n @click=${this._backTapped}\n ></ha-icon-button-arrow-prev>\n `}\n\n <div class=\"main-title\">${this.header}</div>\n <slot name=\"toolbar-icon\"></slot>\n </div>\n <div class=\"content\" @scroll=${this._saveScrollPos}><slot></slot></div>\n <div id=\"fab\">\n <slot name=\"fab\"></slot>\n </div>\n `;\n }\n\n @eventOptions({ passive: true })\n private _saveScrollPos(e: Event) {\n this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;\n }\n\n private _backTapped(): void {\n if (this.backCallback) {\n this.backCallback();\n return;\n }\n history.back();\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n display: block;\n height: 100%;\n background-color: var(--primary-background-color);\n }\n\n :host([narrow]) {\n width: 100%;\n position: fixed;\n }\n\n .toolbar {\n display: flex;\n align-items: center;\n font-size: 20px;\n height: var(--header-height);\n padding: 0 16px;\n pointer-events: none;\n background-color: var(--app-header-background-color);\n font-weight: 400;\n color: var(--app-header-text-color, white);\n border-bottom: var(--app-header-border-bottom, none);\n box-sizing: border-box;\n }\n .toolbar a {\n color: var(--sidebar-text-color);\n text-decoration: none;\n }\n\n ha-menu-button,\n ha-icon-button-arrow-prev,\n ::slotted([slot=\"toolbar-icon\"]) {\n pointer-events: auto;\n color: var(--sidebar-icon-color);\n }\n\n .main-title {\n margin: 0 0 0 24px;\n line-height: 20px;\n flex-grow: 1;\n }\n\n .content {\n position: relative;\n width: 100%;\n height: calc(100% - 1px - var(--header-height));\n overflow-y: auto;\n overflow: auto;\n -webkit-overflow-scrolling: touch;\n }\n\n #fab {\n position: fixed;\n right: calc(16px + env(safe-area-inset-right));\n bottom: calc(16px + env(safe-area-inset-bottom));\n z-index: 1;\n }\n :host([narrow]) #fab.tabs {\n bottom: calc(84px + env(safe-area-inset-bottom));\n }\n #fab[is-wide] {\n bottom: 24px;\n right: 24px;\n }\n :host([rtl]) #fab {\n right: auto;\n left: calc(16px + env(safe-area-inset-left));\n }\n :host([rtl][is-wide]) #fab {\n bottom: 24px;\n left: 24px;\n right: auto;\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"hass-subpage\": HassSubpage;\n }\n}\n","import { css, html, LitElement } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\nimport { classMap } from \"lit/directives/class-map\";\n\n@customElement(\"ha-config-section\")\nexport class HaConfigSection extends LitElement {\n @property() public isWide = false;\n\n @property({ type: Boolean }) public vertical = false;\n\n @property({ type: Boolean, attribute: \"full-width\" })\n public fullWidth = false;\n\n protected render() {\n return html`\n <div\n class=\"content ${classMap({\n narrow: !this.isWide,\n \"full-width\": this.fullWidth,\n })}\"\n >\n <div class=\"header\"><slot name=\"header\"></slot></div>\n <div\n class=\"together layout ${classMap({\n narrow: !this.isWide,\n vertical: this.vertical || !this.isWide,\n horizontal: !this.vertical && this.isWide,\n })}\"\n >\n <div class=\"intro\"><slot name=\"introduction\"></slot></div>\n <div class=\"panel flex-auto\"><slot></slot></div>\n </div>\n </div>\n `;\n }\n\n static get styles() {\n return css`\n :host {\n display: block;\n }\n .content {\n padding: 28px 20px 0;\n max-width: 1040px;\n margin: 0 auto;\n }\n\n .layout {\n display: flex;\n }\n\n .horizontal {\n flex-direction: row;\n }\n\n .vertical {\n flex-direction: column;\n }\n\n .flex-auto {\n flex: 1 1 auto;\n }\n\n .header {\n font-family: var(--paper-font-headline_-_font-family);\n -webkit-font-smoothing: var(\n --paper-font-headline_-_-webkit-font-smoothing\n );\n font-size: var(--paper-font-headline_-_font-size);\n font-weight: var(--paper-font-headline_-_font-weight);\n letter-spacing: var(--paper-font-headline_-_letter-spacing);\n line-height: var(--paper-font-headline_-_line-height);\n opacity: var(--dark-primary-opacity);\n }\n\n .together {\n margin-top: 32px;\n }\n\n .intro {\n font-family: var(--paper-font-subhead_-_font-family);\n -webkit-font-smoothing: var(\n --paper-font-subhead_-_-webkit-font-smoothing\n );\n font-weight: var(--paper-font-subhead_-_font-weight);\n line-height: var(--paper-font-subhead_-_line-height);\n width: 100%;\n opacity: var(--dark-primary-opacity);\n font-size: 14px;\n padding-bottom: 20px;\n }\n\n .horizontal .intro {\n max-width: 400px;\n margin-right: 40px;\n }\n\n .panel {\n margin-top: -24px;\n }\n\n .panel ::slotted(*) {\n margin-top: 24px;\n display: block;\n }\n\n .narrow.content {\n max-width: 640px;\n }\n .narrow .together {\n margin-top: 20px;\n }\n .narrow .intro {\n padding-bottom: 20px;\n margin-right: 0;\n max-width: 500px;\n }\n\n .full-width {\n padding: 0;\n }\n\n .full-width .layout {\n flex-direction: column;\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-config-section\": HaConfigSection;\n }\n}\n","import { ActionDetail } from \"@material/mwc-list/mwc-list-foundation\";\nimport \"@material/mwc-list/mwc-list-item\";\nimport { mdiContentSave, mdiDelete, mdiDotsVertical } from \"@mdi/js\";\nimport \"@polymer/paper-item/paper-icon-item\";\nimport \"@polymer/paper-item/paper-item\";\nimport \"@polymer/paper-item/paper-item-body\";\nimport {\n css,\n CSSResultGroup,\n html,\n LitElement,\n PropertyValues,\n TemplateResult,\n} from \"lit\";\nimport { customElement, property, state } from \"lit/decorators\";\nimport { classMap } from \"lit/directives/class-map\";\nimport { afterNextRender } from \"../../homeassistant-frontend/src/common/util/render-status\";\nimport { computeDomain } from \"../../homeassistant-frontend/src/common/entity/compute_domain\";\nimport { computeStateName } from \"../../homeassistant-frontend/src/common/entity/compute_state_name\";\nimport { computeRTL } from \"../../homeassistant-frontend/src/common/util/compute_rtl\";\nimport \"../device/insteon-device-picker\";\nimport \"../../homeassistant-frontend/src/layouts/hass-subpage\";\nimport \"../../homeassistant-frontend/src/components/ha-area-picker\";\nimport \"../../homeassistant-frontend/src/components/ha-card\";\nimport \"../../homeassistant-frontend/src/components/ha-fab\";\nimport \"../../homeassistant-frontend/src/components/ha-icon-button\";\nimport \"../../homeassistant-frontend/src/components/ha-icon-picker\";\nimport \"../../homeassistant-frontend/src/components/ha-svg-icon\";\nimport \"../../homeassistant-frontend/src/components/ha-textfield\";\nimport \"../../homeassistant-frontend/src/components/ha-checkbox\";\nimport \"../../homeassistant-frontend/src/components/ha-switch\";\nimport {\n computeDeviceName,\n DeviceRegistryEntry,\n subscribeDeviceRegistry,\n} from \"../../homeassistant-frontend/src/data/device_registry\";\nimport {\n EntityRegistryEntry,\n subscribeEntityRegistry,\n} from \"../../homeassistant-frontend/src/data/entity_registry\";\nimport {\n getSceneEditorInitData,\n SCENE_IGNORED_DOMAINS,\n} from \"../../homeassistant-frontend/src/data/scene\";\nimport {\n showConfirmationDialog,\n showAlertDialog,\n} from \"../../homeassistant-frontend/src/dialogs/generic/show-dialog-box\";\nimport { KeyboardShortcutMixin } from \"../../homeassistant-frontend/src/mixins/keyboard-shortcut-mixin\";\nimport { SubscribeMixin } from \"../../homeassistant-frontend/src/mixins/subscribe-mixin\";\nimport { haStyle } from \"../../homeassistant-frontend/src/resources/styles\";\nimport { HomeAssistant, Route } from \"../../homeassistant-frontend/src/types\";\nimport \"../../homeassistant-frontend/src/panels/config/ha-config-section\";\nimport {\n Insteon,\n InsteonScene,\n InsteonSceneDeviceData,\n fetchInsteonScene,\n sceneDataSchema,\n saveInsteonScene,\n deleteInsteonScene,\n InsteonSceneLinkData,\n} from \"../data/insteon\";\nimport \"../../homeassistant-frontend/src/components/ha-form/ha-form\";\nimport { showInsteonSetOnLevelDialog } from \"./show-dialog-insteon-scene-set-on-level\";\nimport { navigate } from \"../../homeassistant-frontend/src/common/navigate\";\n\ninterface DeviceEntitiesLookup {\n [deviceId: string]: string[];\n}\n\ninterface InsteonSceneEntity {\n entity_id: string;\n name: string;\n is_in_scene: boolean;\n data1: number;\n data2: number;\n data3: number;\n}\n\ninterface InsteonSceneDevice {\n address: string;\n device_id: string;\n name: string | null | undefined;\n entities: InsteonSceneEntity[];\n}\n\ninterface InsteonToHaDeviceMap {\n device: DeviceRegistryEntry;\n entities: { [group: number]: EntityRegistryEntry };\n}\n\nconst DIMMABLE_DOMAINS = [\"light\", \"fan\"];\n\n@customElement(\"insteon-scene-editor\")\nexport class InsteonSceneEditor extends SubscribeMixin(\n KeyboardShortcutMixin(LitElement)\n) {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property({ attribute: false }) public insteon!: Insteon;\n\n @property() public narrow!: boolean;\n\n @property() public isWide!: boolean;\n\n @property() public route!: Route;\n\n @property() public sceneId: string | null = null;\n\n @state() public _scene?: InsteonScene;\n\n @state() private _dirty = false;\n\n @state() private _errors?: string;\n\n @state() private _deviceRegistryEntries: DeviceRegistryEntry[] = [];\n\n @state() private _entityRegistryEntries: EntityRegistryEntry[] = [];\n\n private _insteonToHaDeviceMap: { [address: string]: InsteonToHaDeviceMap } =\n {};\n\n private _haToinsteonDeviceMap: { [deviceId: string]: string } = {};\n\n private _unsubscribeEvents?: () => void;\n\n private _deviceEntityLookup: DeviceEntitiesLookup = {};\n\n @state() private _saving = false;\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n if (this._unsubscribeEvents) {\n this._unsubscribeEvents();\n this._unsubscribeEvents = undefined;\n }\n }\n\n public hassSubscribe() {\n return [\n subscribeEntityRegistry(this.hass.connection, (entries) => {\n this._entityRegistryEntries = entries.filter(\n (entity) =>\n entity.config_entry_id == this.insteon.config_entry.entry_id &&\n !SCENE_IGNORED_DOMAINS.includes(computeDomain(entity.entity_id))\n );\n }),\n subscribeDeviceRegistry(this.hass.connection, (entries) => {\n this._deviceRegistryEntries = entries.filter(\n (device) =>\n device.config_entries &&\n device.config_entries.includes(this.insteon.config_entry.entry_id)\n );\n }),\n ];\n }\n\n protected render(): TemplateResult {\n if (!this.hass || !this._scene) {\n return html``;\n }\n const name = this._scene\n ? this._scene.name\n : this.insteon.localize(\"scenes.scene.default_name\");\n\n const devices = this._setSceneDevices();\n return html`\n <hass-subpage\n .hass=${this.hass}\n .narrow=${this.narrow}\n .route=${this.route}\n .backCallback=${this._backTapped}\n .header=${name}\n >\n <ha-button-menu\n corner=\"BOTTOM_START\"\n slot=\"toolbar-icon\"\n @action=${this._handleMenuAction}\n activatable\n >\n <ha-icon-button\n slot=\"trigger\"\n .label=${this.hass.localize(\"ui.common.menu\")}\n .path=${mdiDotsVertical}\n ></ha-icon-button>\n\n <mwc-list-item\n .disabled=${!this.sceneId}\n aria-label=${this.insteon.localize(\"scenes.scene.delete\")}\n class=${classMap({ warning: Boolean(this.sceneId) })}\n graphic=\"icon\"\n >\n ${this.insteon.localize(\"scenes.scene.delete\")}\n <ha-svg-icon\n class=${classMap({ warning: Boolean(this.sceneId) })}\n slot=\"graphic\"\n .path=${mdiDelete}\n >\n </ha-svg-icon>\n </mwc-list-item>\n </ha-button-menu>\n ${this._errors ? html` <div class=\"errors\">${this._errors}</div> ` : \"\"}\n ${!this.narrow ? html` <span slot=\"header\">${name}</span> ` : \"\"}\n <div\n id=\"root\"\n class=${classMap({\n rtl: computeRTL(this.hass),\n })}\n >\n <ha-config-section vertical .isWide=${this.isWide}>\n ${this._saving\n ? html`<div>\n <ha-circular-progress\n active\n alt=\"Loading\"\n ></ha-circular-progress>\n </div>`\n : this._showEditorArea(name, devices)}\n </ha-config-section>\n </div>\n <ha-fab\n slot=\"fab\"\n .label=${this.insteon.localize(\"scenes.scene.save\")}\n extended\n .disabled=${this._saving}\n @click=${this._saveScene}\n class=${classMap({ dirty: this._dirty, saving: this._saving })}\n >\n <ha-svg-icon slot=\"icon\" .path=${mdiContentSave}></ha-svg-icon>\n </ha-fab>\n </hass-subpage>\n `;\n }\n\n private _showEditorArea(name, devices) {\n return html`<div slot=\"introduction\">\n ${this.insteon.localize(\"scenes.scene.introduction\")}\n </div>\n <ha-card outlined>\n <div class=\"card-content\">\n <ha-textfield\n .value=${name}\n .name=${\"name\"}\n @change=${this._nameChanged}\n .label=${this.insteon.localize(\"scenes.scene.name\")}\n ></ha-textfield>\n </div>\n </ha-card>\n\n <ha-config-section vertical .isWide=${this.isWide}>\n <div slot=\"header\">\n ${this.insteon.localize(\"scenes.scene.devices.header\")}\n </div>\n <div slot=\"introduction\">\n ${this.insteon.localize(\"scenes.scene.devices.introduction\")}\n </div>\n\n ${devices.map(\n (device) =>\n html`\n <ha-card outlined>\n <h1 class=\"card-header\">\n ${device.name}\n <ha-icon-button\n .path=${mdiDelete}\n .label=${this.hass.localize(\n \"ui.panel.config.scene.editor.devices.delete\"\n )}\n .device_address=${device.address}\n @click=${this._deleteDevice}\n ></ha-icon-button>\n </h1>\n ${!device.entities\n ? html` <ha-form .schema=${sceneDataSchema}></ha-form> `\n : device.entities.map(\n (entity) =>\n html`\n <paper-icon-item class=\"device-entity\">\n <ha-checkbox\n .checked=${entity.is_in_scene}\n @change=${this._toggleSelection}\n .device_address=${device.address}\n .group=${entity.data3}\n ></ha-checkbox>\n <paper-item-body\n @click=${this._showSetOnLevel}\n .device_address=${device.address}\n .group=${entity.data3}\n >\n ${entity.name}\n </paper-item-body>\n <ha-switch\n .checked=${entity.data1 > 0}\n @change=${this._toggleOnLevel}\n .device_address=${device.address}\n .group=${entity.data3}\n ></ha-switch>\n </paper-icon-item>\n `\n )};\n </ha-card>\n `\n )}\n\n <ha-card\n outlined\n .header=${this.insteon.localize(\"scenes.scene.devices.add\")}\n >\n <div class=\"card-content\">\n <insteon-device-picker\n @value-changed=${this._devicePicked}\n .hass=${this.hass}\n .insteon=${this.insteon}\n .label=${this.insteon.localize(\"scenes.scene.devices.add\")}\n .excludedDomains=${SCENE_IGNORED_DOMAINS}\n ></insteon-device-picker>\n </div>\n </ha-card>\n </ha-config-section>`;\n }\n\n private _setSceneDevices(): InsteonSceneDevice[] {\n const outputDevices: InsteonSceneDevice[] = [];\n if (!this._scene) {\n return [];\n }\n for (const [address, links] of Object.entries(this._scene.devices)) {\n const haDevice = this._insteonToHaDeviceMap[address] || undefined;\n const deviceEntities = haDevice.entities || {};\n const theseEntities: InsteonSceneEntity[] = [];\n let thisDevice: InsteonSceneDevice | undefined = undefined;\n\n for (const [group, entity] of Object.entries(deviceEntities)) {\n const insteonEntityData: InsteonSceneDeviceData | undefined =\n links.find((link) => link.data3 == +group);\n const data1 = insteonEntityData?.data1 || 0;\n const data2 = insteonEntityData?.data2 || 28;\n const data3 = insteonEntityData?.data3 || group;\n const is_in_scene = insteonEntityData ? true : false;\n theseEntities.push({\n entity_id: entity.entity_id,\n name:\n computeStateName(this.hass.states[entity.entity_id]) ||\n \"Device button \" + group,\n is_in_scene: is_in_scene,\n data1: data1,\n data2: data2,\n data3: +data3,\n });\n thisDevice = {\n address: address,\n device_id: haDevice.device.id,\n name: computeDeviceName(\n haDevice.device,\n this.hass,\n this._deviceEntityLookup[haDevice.device.id]\n ),\n entities: theseEntities,\n };\n }\n if (thisDevice) {\n outputDevices.push(thisDevice);\n }\n }\n return outputDevices;\n }\n\n protected firstUpdated(\n _changedProperties: Map<string | number | symbol, unknown>\n ): void {\n super.firstUpdated(_changedProperties);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n this.hassSubscribe();\n\n if (!this._scene && this.sceneId) {\n this._loadScene();\n } else {\n this._initNewScene();\n }\n\n //Copied from ha-panel-config to retain consistancy\n this.style.setProperty(\n \"--app-header-background-color\",\n \"var(--sidebar-background-color)\"\n );\n this.style.setProperty(\n \"--app-header-text-color\",\n \"var(--sidebar-text-color)\"\n );\n this.style.setProperty(\n \"--app-header-border-bottom\",\n \"1px solid var(--divider-color)\"\n );\n this.style.setProperty(\n \"--ha-card-border-radius\",\n \"var(--ha-config-card-border-radius, 8px)\"\n );\n }\n\n protected updated(changedProps: PropertyValues): void {\n super.updated(changedProps);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n\n if (\n changedProps.has(\"_deviceRegistryEntries\") ||\n changedProps.has(\"_entityRegistryEntries\")\n ) {\n this._mapDeviceEntities();\n }\n }\n\n private _initNewScene() {\n this._dirty = false;\n const initData = getSceneEditorInitData();\n this._scene = {\n name: this.insteon.localize(\"scenes.scene.default_name\"),\n devices: {},\n group: -1,\n };\n // if (initData?.areaId) {\n // this._updatedAreaId = initData.areaId;\n // }\n this._dirty =\n initData !== undefined &&\n (initData.areaId !== undefined || initData.config !== undefined);\n }\n\n private _mapDeviceEntities() {\n this._insteonToHaDeviceMap = {};\n this._haToinsteonDeviceMap = {};\n this._deviceRegistryEntries.map((haDevice) => {\n const address: string = haDevice.identifiers[0][1];\n const entities: { [group: number]: EntityRegistryEntry } = {};\n this._entityRegistryEntries\n .filter((entity) => entity.device_id == haDevice.id)\n .map((entity) => {\n const stateobj = this.hass.states[entity.entity_id];\n const group = stateobj.attributes.insteon_group;\n entities[group] = entity;\n });\n this._insteonToHaDeviceMap[address] = {\n device: haDevice,\n entities: entities,\n };\n this._haToinsteonDeviceMap[haDevice.id] = address;\n });\n for (const entity of this._entityRegistryEntries) {\n if (\n !entity.device_id ||\n SCENE_IGNORED_DOMAINS.includes(computeDomain(entity.entity_id))\n ) {\n continue;\n }\n if (!(entity.device_id in this._deviceEntityLookup)) {\n this._deviceEntityLookup[entity.device_id] = [];\n }\n if (\n !this._deviceEntityLookup[entity.device_id].includes(entity.entity_id)\n ) {\n this._deviceEntityLookup[entity.device_id].push(entity.entity_id);\n }\n }\n }\n\n private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {\n switch (ev.detail.index) {\n case 0:\n this._deleteTapped();\n break;\n }\n }\n\n private _showSetOnLevel(ev: Event) {\n ev.stopPropagation();\n const address = (ev.currentTarget as any).device_address;\n const group = (ev.currentTarget as any).group;\n const device = this._scene!.devices[address];\n let link = device.find((curr_link) => curr_link.data3 == +group);\n if (!link) {\n this._selectEntity(true, device, group);\n link = device.find((curr_link) => curr_link.data3 == +group);\n }\n const haDevice = this._insteonToHaDeviceMap[address];\n const deviceEntities = haDevice.entities || {};\n const entity = deviceEntities[+group];\n if (DIMMABLE_DOMAINS.includes(computeDomain(entity.entity_id))) {\n this._setOnLevel(\n address,\n group,\n link!.data1,\n link!.data2 == 0 ? 28 : link!.data2\n );\n }\n }\n\n private async _setOnLevel(\n address: string,\n group: number,\n on_level: number,\n ramp_rate: number\n ): Promise<void> {\n showInsteonSetOnLevelDialog(this, {\n hass: this.hass,\n insteon: this.insteon,\n title: this.insteon.localize(\"device.actions.add\"),\n address: address,\n group: group,\n value: on_level,\n ramp_rate: ramp_rate,\n callback: async (address_out, group_out, on_level_out, ramp_rate_out) =>\n this._handleSetOnLevel(\n address_out,\n group_out,\n on_level_out,\n ramp_rate_out\n ),\n });\n history.back();\n }\n\n private _handleSetOnLevel(\n address: string,\n group: number,\n on_level: number,\n ramp_rate: number\n ) {\n const device = this._scene!.devices[address];\n const existing_link = device.find((link) => link.data3 == +group);\n if (existing_link!.data1 != on_level) {\n existing_link!.data1 = on_level;\n this._dirty = true;\n }\n if (existing_link!.data2 != ramp_rate) {\n existing_link!.data2 = ramp_rate;\n this._dirty = true;\n }\n if (this._dirty) {\n this._scene = { ...this._scene! };\n }\n }\n\n private async _loadScene() {\n // let config: SceneConfig;\n this._scene = await fetchInsteonScene(this.hass, +this.sceneId!);\n for (const address in Object.keys(this._scene.devices)) {\n const ha_device = this._deviceRegistryEntries.find(\n (haDevice) => haDevice.identifiers[0][1] === address\n );\n const device_id = ha_device?.id || undefined;\n if (device_id) {\n this._pickDevice(device_id);\n }\n }\n this._dirty = false;\n }\n\n private _pickDevice(deviceId: string) {\n const haDevice = this._deviceRegistryEntries.find((haCurrDevice) => {\n return haCurrDevice.id == deviceId;\n });\n const address = haDevice?.identifiers[0][1];\n if (!address) {\n return;\n }\n if (this._scene!.devices.hasOwnProperty(address)) {\n return;\n }\n const updated_scene: InsteonScene = { ...this._scene! };\n updated_scene.devices[address] = [];\n this._scene = { ...updated_scene };\n this._dirty = true;\n }\n\n private _devicePicked(ev: CustomEvent) {\n const deviceId = ev.detail.value;\n (ev.target as any).value = \"\";\n this._pickDevice(deviceId);\n }\n\n private _deleteDevice(ev: Event) {\n const address = (ev.target as any).device_address;\n const updated_scene: InsteonScene = { ...this._scene! };\n if (updated_scene.devices.hasOwnProperty(address)) {\n delete updated_scene.devices[address];\n }\n this._scene = { ...updated_scene };\n this._dirty = true;\n }\n\n private _toggleSelection(ev: Event) {\n const address = (ev.target as any).device_address;\n const checked = (ev.target as any).checked;\n const group = (ev.target as any).group;\n const device = this._scene!.devices[address];\n this._selectEntity(checked, device, group);\n this._scene = { ...this._scene! };\n this._dirty = true;\n }\n\n private _selectEntity(\n checked: boolean,\n device: InsteonSceneDeviceData[],\n group: number\n ) {\n if (checked) {\n const existing_link = device.find((link) => link.data3 == +group);\n if (existing_link) {\n return;\n }\n const link: InsteonSceneDeviceData = {\n data1: 0,\n data2: 0,\n data3: group,\n has_controller: false,\n has_responder: false,\n };\n device.push(link);\n } else {\n const existing_link = device.findIndex((link) => link.data3 == +group);\n if (existing_link !== -1) {\n device.splice(existing_link, 1);\n }\n }\n this._dirty = true;\n }\n\n private _toggleOnLevel(ev: Event) {\n const address = (ev.target as any).device_address;\n const checked = (ev.target as any).checked;\n const group = (ev.target as any).group;\n const device = this._scene!.devices[address];\n let existing_link = device.find((link) => link.data3 == +group);\n if (!existing_link) {\n this._selectEntity(true, device, +group);\n existing_link = device.find((link) => link.data3 == +group);\n }\n if (checked) {\n existing_link!.data1 = 255;\n const haDevice = this._insteonToHaDeviceMap[address] || undefined;\n const deviceEntities = haDevice.entities || {};\n const entity = deviceEntities[+group];\n if (DIMMABLE_DOMAINS.includes(computeDomain(entity.entity_id))) {\n existing_link!.data2 = 28;\n }\n } else {\n existing_link!.data1 = 0;\n existing_link!.data2 = 0;\n }\n this._scene = { ...this._scene! };\n this._dirty = true;\n }\n\n private _nameChanged(ev: Event) {\n ev.stopPropagation();\n const target = ev.target as any;\n const name = target.name;\n if (!name) {\n return;\n }\n let newVal = (ev as CustomEvent).detail?.value ?? target.value;\n if (target.type === \"number\") {\n newVal = Number(newVal);\n }\n if ((this._scene![name] || \"\") === newVal) {\n return;\n }\n if (!newVal) {\n delete this._scene![name];\n this._scene = { ...this._scene! };\n } else {\n this._scene = { ...this._scene!, [name]: newVal };\n }\n this._scene = { ...this._scene! };\n this._dirty = true;\n }\n\n private _backTapped = async (): Promise<void> => {\n const result = await this.confirmUnsavedChanged();\n if (result) {\n this._goBack();\n }\n };\n\n private _goBack(): void {\n afterNextRender(() => history.back());\n }\n\n private async confirmUnsavedChanged(): Promise<boolean> {\n if (this._dirty) {\n const action = showConfirmationDialog(this, {\n title: this.hass!.localize(\n \"ui.panel.config.scene.editor.unsaved_confirm_title\"\n ),\n text: this.hass!.localize(\n \"ui.panel.config.scene.editor.unsaved_confirm_text\"\n ),\n confirmText: this.hass!.localize(\"ui.common.leave\"),\n dismissText: this.hass!.localize(\"ui.common.stay\"),\n destructive: true,\n });\n history.back();\n return action;\n }\n return true;\n }\n\n private _deleteTapped(): void {\n showConfirmationDialog(this, {\n text: this.hass!.localize(\"ui.panel.config.scene.picker.delete_confirm\"),\n confirmText: this.hass!.localize(\"ui.common.delete\"),\n dismissText: this.hass!.localize(\"ui.common.cancel\"),\n confirm: () => this._delete(),\n });\n history.back();\n }\n\n private async _delete(): Promise<void> {\n this._saving = true;\n const sceneId: number = +this.sceneId!;\n const result = await deleteInsteonScene(this.hass, sceneId!);\n this._saving = false;\n if (!result.result) {\n showAlertDialog(this, {\n text: this.insteon!.localize(\"common.error.scene_write\"),\n confirmText: this.hass!.localize(\"ui.common.close\"),\n });\n history.back();\n }\n history.back();\n }\n\n private async _saveScene(): Promise<void> {\n if (!this._checkDeviceEntitySelections()) {\n showAlertDialog(this, {\n text: this.insteon!.localize(\"common.error.scene_device_no_entities\"),\n confirmText: this.hass!.localize(\"ui.common.close\"),\n });\n history.back();\n return;\n }\n this._saving = true;\n const links: InsteonSceneLinkData[] = [];\n Object.keys(this._scene!.devices).forEach((address) => {\n const link_data = this._scene!.devices[address];\n link_data.forEach((link_info) => {\n const link = {\n address: address,\n data1: link_info.data1,\n data2: link_info.data2,\n data3: link_info.data3,\n };\n links.push(link);\n });\n });\n const result = await saveInsteonScene(\n this.hass,\n this._scene!.group,\n links,\n this._scene!.name\n );\n this._saving = false;\n this._dirty = false;\n if (!result.result) {\n showAlertDialog(this, {\n text: this.insteon!.localize(\"common.error.scene_write\"),\n confirmText: this.hass!.localize(\"ui.common.close\"),\n });\n history.back();\n } else {\n if (!this.sceneId) {\n navigate(`/insteon/scene/${result.scene_id}`, { replace: true });\n }\n }\n }\n\n private _checkDeviceEntitySelections(): boolean {\n for (const [_, links] of Object.entries(this._scene!.devices)) {\n if (links.length == 0) {\n return false;\n }\n }\n return true;\n }\n\n protected handleKeyboardSave() {\n this._saveScene();\n }\n\n static get styles(): CSSResultGroup {\n return [\n haStyle,\n css`\n ha-card {\n overflow: hidden;\n }\n .errors {\n padding: 20px;\n font-weight: bold;\n color: var(--error-color);\n }\n ha-config-section:last-child {\n padding-bottom: 20px;\n }\n .triggers,\n .script {\n margin-top: -16px;\n }\n .triggers ha-card,\n .script ha-card {\n margin-top: 16px;\n }\n .add-card mwc-button {\n display: block;\n text-align: center;\n }\n .card-menu {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 1;\n color: var(--primary-text-color);\n }\n .rtl .card-menu {\n right: auto;\n left: 0;\n }\n .card-menu paper-item {\n cursor: pointer;\n }\n paper-icon-item {\n padding: 8px 16px;\n }\n ha-card ha-icon-button {\n color: var(--secondary-text-color);\n }\n .card-header > ha-icon-button {\n float: right;\n position: relative;\n top: -8px;\n }\n .device-entity {\n cursor: pointer;\n }\n span[slot=\"introduction\"] a {\n color: var(--primary-color);\n }\n ha-fab {\n position: relative;\n bottom: calc(-80px - env(safe-area-inset-bottom));\n transition: bottom 0.3s;\n }\n ha-fab.dirty {\n bottom: 0;\n }\n ha-fab.saving {\n opacity: var(--light-disabled-opacity);\n }\n ha-icon-picker,\n ha-area-picker,\n ha-entity-picker {\n display: block;\n margin-top: 8px;\n }\n ha-textfield {\n display: block;\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"insteon-scene-editor\": InsteonSceneEditor;\n }\n}\n"],"names":[],"sourceRoot":""}
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
inset-inline-end: 0px !important;
|
|
84
84
|
direction: var(--direction);
|
|
85
85
|
}
|
|
86
|
-
`]}]}}),i.M)},8846:(e,t,r)=>{r.d(t,{CL:()=>w,CN:()=>y,Co:()=>a,Cy:()=>l,DT:()=>_,GU:()=>g,Ho:()=>D,Jz:()=>E,Kw:()=>p,N2:()=>f,NC:()=>s,NL:()=>v,Qs:()=>h,SL:()=>d,di:()=>b,i:()=>i,kT:()=>x,o5:()=>n,rW:()=>u,tW:()=>c,tw:()=>m,yq:()=>k,zM:()=>o});const i=e=>e.callWS({type:"insteon/scenes/get"}),n=(e,t)=>e.callWS({type:"insteon/scene/get",scene_id:t}),o=(e,t)=>e.callWS({type:"insteon/device/get",device_id:t}),a=(e,t)=>e.callWS({type:"insteon/aldb/get",device_address:t}),s=(e,t,r)=>e.callWS({type:"insteon/properties/get",device_address:t,show_advanced:r}),l=(e,t,r)=>e.callWS({type:"insteon/aldb/change",device_address:t,record:r}),d=(e,t,r,i)=>e.callWS({type:"insteon/properties/change",device_address:t,name:r,value:i}),c=(e,t,r,i)=>e.callWS({type:"insteon/scene/save",name:i,scene_id:t,links:r}),p=(e,t)=>e.callWS({type:"insteon/scene/delete",scene_id:t}),u=e=>e.callWS({type:"insteon/device/add/cancel"}),f=(e,t,r)=>e.callWS({type:"insteon/aldb/create",device_address:t,record:r}),h=(e,t)=>e.callWS({type:"insteon/aldb/load",device_address:t}),m=(e,t)=>e.callWS({type:"insteon/properties/load",device_address:t}),v=(e,t)=>e.callWS({type:"insteon/aldb/write",device_address:t}),y=(e,t)=>e.callWS({type:"insteon/properties/write",device_address:t}),g=(e,t)=>e.callWS({type:"insteon/aldb/reset",device_address:t}),b=(e,t)=>e.callWS({type:"insteon/properties/reset",device_address:t}),k=(e,t)=>e.callWS({type:"insteon/aldb/add_default_links",device_address:t}),w=e=>[{name:"mode",options:[["c",e.localize("aldb.mode.controller")],["r",e.localize("aldb.mode.responder")]],required:!0,type:"select"},{name:"group",required:!0,type:"integer",valueMin:-1,valueMax:255},{name:"target",required:!0,type:"string"},{name:"data1",required:!0,type:"integer",valueMin:-1,valueMax:255},{name:"data2",required:!0,type:"integer",valueMin:-1,valueMax:255},{name:"data3",required:!0,type:"integer",valueMin:-1,valueMax:255}],_=e=>[{name:"in_use",required:!0,type:"boolean"},...w(e)],E=e=>[{name:"multiple",required:!0,type:"boolean"},{name:"address",required:!1,type:e?"constant":"string"}],x=[{name:"data1",required:!0,type:"integer"},{name:"data2",required:!0,type:"integer"},{name:"data3",required:!0,type:"integer"}],D={name:"ramp_rate",options:[["31","0.1"],["30","0.2"],["29","0.3"],["28","0.5"],["27","2"],["26","4.5"],["25","6.5"],["24","8.5"],["23","19"],["22","21.5"],["21","23.5"],["20","26"],["19","28"],["18","30"],["17","32"],["16","34"],["15","38.5"],["14","43"],["13","47"],["12","60"],["11","90"],["10","120"],["9","150"],["8","180"],["7","210"],["6","240"],["5","270"],["4","300"],["3","360"],["2","420"],["1","480"]],required:!0,type:"select"}},9502:(e,t,r)=>{r.r(t);var i=r(7500),n=r(7626),o=(r(8348),r(9828)),a=r(9950),s=r(8846),l=r(8652);r(9663);function d(){d=function(){return e};var e={elementsDefinitionOrder:[["method"],["field"]],initializeInstanceElements:function(e,t){["method","field"].forEach((function(r){t.forEach((function(t){t.kind===r&&"own"===t.placement&&this.defineClassElement(e,t)}),this)}),this)},initializeClassElements:function(e,t){var r=e.prototype;["method","field"].forEach((function(i){t.forEach((function(t){var n=t.placement;if(t.kind===i&&("static"===n||"prototype"===n)){var o="static"===n?e:r;this.defineClassElement(o,t)}}),this)}),this)},defineClassElement:function(e,t){var r=t.descriptor;if("field"===t.kind){var i=t.initializer;r={enumerable:r.enumerable,writable:r.writable,configurable:r.configurable,value:void 0===i?void 0:i.call(e)}}Object.defineProperty(e,t.key,r)},decorateClass:function(e,t){var r=[],i=[],n={static:[],prototype:[],own:[]};if(e.forEach((function(e){this.addElementPlacement(e,n)}),this),e.forEach((function(e){if(!u(e))return r.push(e);var t=this.decorateElement(e,n);r.push(t.element),r.push.apply(r,t.extras),i.push.apply(i,t.finishers)}),this),!t)return{elements:r,finishers:i};var o=this.decorateConstructor(r,t);return i.push.apply(i,o.finishers),o.finishers=i,o},addElementPlacement:function(e,t,r){var i=t[e.placement];if(!r&&-1!==i.indexOf(e.key))throw new TypeError("Duplicated element ("+e.key+")");i.push(e.key)},decorateElement:function(e,t){for(var r=[],i=[],n=e.decorators,o=n.length-1;o>=0;o--){var a=t[e.placement];a.splice(a.indexOf(e.key),1);var s=this.fromElementDescriptor(e),l=this.toElementFinisherExtras((0,n[o])(s)||s);e=l.element,this.addElementPlacement(e,t),l.finisher&&i.push(l.finisher);var d=l.extras;if(d){for(var c=0;c<d.length;c++)this.addElementPlacement(d[c],t);r.push.apply(r,d)}}return{element:e,finishers:i,extras:r}},decorateConstructor:function(e,t){for(var r=[],i=t.length-1;i>=0;i--){var n=this.fromClassDescriptor(e),o=this.toClassDescriptor((0,t[i])(n)||n);if(void 0!==o.finisher&&r.push(o.finisher),void 0!==o.elements){e=o.elements;for(var a=0;a<e.length-1;a++)for(var s=a+1;s<e.length;s++)if(e[a].key===e[s].key&&e[a].placement===e[s].placement)throw new TypeError("Duplicated element ("+e[a].key+")")}}return{elements:e,finishers:r}},fromElementDescriptor:function(e){var t={kind:e.kind,key:e.key,placement:e.placement,descriptor:e.descriptor};return Object.defineProperty(t,Symbol.toStringTag,{value:"Descriptor",configurable:!0}),"field"===e.kind&&(t.initializer=e.initializer),t},toElementDescriptors:function(e){var t;if(void 0!==e)return(t=e,function(e){if(Array.isArray(e))return e}(t)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(t)||function(e,t){if(e){if("string"==typeof e)return v(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?v(e,t):void 0}}(t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()).map((function(e){var t=this.toElementDescriptor(e);return this.disallowProperty(e,"finisher","An element descriptor"),this.disallowProperty(e,"extras","An element descriptor"),t}),this)},toElementDescriptor:function(e){var t=String(e.kind);if("method"!==t&&"field"!==t)throw new TypeError('An element descriptor\'s .kind property must be either "method" or "field", but a decorator created an element descriptor with .kind "'+t+'"');var r=m(e.key),i=String(e.placement);if("static"!==i&&"prototype"!==i&&"own"!==i)throw new TypeError('An element descriptor\'s .placement property must be one of "static", "prototype" or "own", but a decorator created an element descriptor with .placement "'+i+'"');var n=e.descriptor;this.disallowProperty(e,"elements","An element descriptor");var o={kind:t,key:r,placement:i,descriptor:Object.assign({},n)};return"field"!==t?this.disallowProperty(e,"initializer","A method descriptor"):(this.disallowProperty(n,"get","The property descriptor of a field descriptor"),this.disallowProperty(n,"set","The property descriptor of a field descriptor"),this.disallowProperty(n,"value","The property descriptor of a field descriptor"),o.initializer=e.initializer),o},toElementFinisherExtras:function(e){return{element:this.toElementDescriptor(e),finisher:h(e,"finisher"),extras:this.toElementDescriptors(e.extras)}},fromClassDescriptor:function(e){var t={kind:"class",elements:e.map(this.fromElementDescriptor,this)};return Object.defineProperty(t,Symbol.toStringTag,{value:"Descriptor",configurable:!0}),t},toClassDescriptor:function(e){var t=String(e.kind);if("class"!==t)throw new TypeError('A class descriptor\'s .kind property must be "class", but a decorator created a class descriptor with .kind "'+t+'"');this.disallowProperty(e,"key","A class descriptor"),this.disallowProperty(e,"placement","A class descriptor"),this.disallowProperty(e,"descriptor","A class descriptor"),this.disallowProperty(e,"initializer","A class descriptor"),this.disallowProperty(e,"extras","A class descriptor");var r=h(e,"finisher");return{elements:this.toElementDescriptors(e.elements),finisher:r}},runClassFinishers:function(e,t){for(var r=0;r<t.length;r++){var i=(0,t[r])(e);if(void 0!==i){if("function"!=typeof i)throw new TypeError("Finishers must return a constructor.");e=i}}return e},disallowProperty:function(e,t,r){if(void 0!==e[t])throw new TypeError(r+" can't have a ."+t+" property.")}};return e}function c(e){var t,r=m(e.key);"method"===e.kind?t={value:e.value,writable:!0,configurable:!0,enumerable:!1}:"get"===e.kind?t={get:e.value,configurable:!0,enumerable:!1}:"set"===e.kind?t={set:e.value,configurable:!0,enumerable:!1}:"field"===e.kind&&(t={configurable:!0,writable:!0,enumerable:!0});var i={kind:"field"===e.kind?"field":"method",key:r,placement:e.static?"static":"field"===e.kind?"own":"prototype",descriptor:t};return e.decorators&&(i.decorators=e.decorators),"field"===e.kind&&(i.initializer=e.value),i}function p(e,t){void 0!==e.descriptor.get?t.descriptor.get=e.descriptor.get:t.descriptor.set=e.descriptor.set}function u(e){return e.decorators&&e.decorators.length}function f(e){return void 0!==e&&!(void 0===e.value&&void 0===e.writable)}function h(e,t){var r=e[t];if(void 0!==r&&"function"!=typeof r)throw new TypeError("Expected '"+t+"' to be a function");return r}function m(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var i=r.call(e,t||"default");if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}function v(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,i=new Array(t);r<t;r++)i[r]=e[r];return i}!function(e,t,r,i){var n=d();if(i)for(var o=0;o<i.length;o++)n=i[o](n);var a=t((function(e){n.initializeInstanceElements(e,s.elements)}),r),s=n.decorateClass(function(e){for(var t=[],r=function(e){return"method"===e.kind&&e.key===o.key&&e.placement===o.placement},i=0;i<e.length;i++){var n,o=e[i];if("method"===o.kind&&(n=t.find(r)))if(f(o.descriptor)||f(n.descriptor)){if(u(o)||u(n))throw new ReferenceError("Duplicated methods ("+o.key+") can't be decorated.");n.descriptor=o.descriptor}else{if(u(o)){if(u(n))throw new ReferenceError("Decorators can't be placed on different accessors with for the same property ("+o.key+").");n.decorators=o.decorators}p(o,n)}else t.push(o)}return t}(a.d.map(c)),e);n.initializeClassElements(a.F,s.elements),n.runClassFinishers(a.F,s.finishers)}([(0,n.Mo)("dialog-insteon-add-device")],(function(e,t){return{F:class extends t{constructor(...t){super(...t),e(this)}},d:[{kind:"field",decorators:[(0,n.Cb)({attribute:!1})],key:"hass",value:void 0},{kind:"field",decorators:[(0,n.Cb)({attribute:!1})],key:"insteon",value:void 0},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"isWide",value:void 0},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"narrow",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_title",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_callback",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_errors",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_formData",value:()=>({multiple:!1,address:""})},{kind:"field",decorators:[(0,n.SB)()],key:"_opened",value:()=>!1},{kind:"method",key:"showDialog",value:async function(e){this.hass=e.hass,this.insteon=e.insteon,this._callback=e.callback,this._title=e.title,this._errors={},this._opened=!0,this._formData={multiple:!1,address:""}}},{kind:"method",key:"_schema",value:function(e){return(0,s.Jz)(e)}},{kind:"method",key:"render",value:function(){var e;return this._opened?i.dy`
|
|
86
|
+
`]}]}}),i.M)},8846:(e,t,r)=>{r.d(t,{CL:()=>w,CN:()=>y,Co:()=>a,Cy:()=>l,DT:()=>_,GU:()=>g,Ho:()=>D,Jz:()=>E,Kw:()=>p,N2:()=>f,NC:()=>s,NL:()=>v,Qs:()=>h,SL:()=>d,di:()=>b,i:()=>i,kT:()=>x,o5:()=>n,rW:()=>u,tW:()=>c,tw:()=>m,yq:()=>k,zM:()=>o});const i=e=>e.callWS({type:"insteon/scenes/get"}),n=(e,t)=>e.callWS({type:"insteon/scene/get",scene_id:t}),o=(e,t)=>e.callWS({type:"insteon/device/get",device_id:t}),a=(e,t)=>e.callWS({type:"insteon/aldb/get",device_address:t}),s=(e,t,r)=>e.callWS({type:"insteon/properties/get",device_address:t,show_advanced:r}),l=(e,t,r)=>e.callWS({type:"insteon/aldb/change",device_address:t,record:r}),d=(e,t,r,i)=>e.callWS({type:"insteon/properties/change",device_address:t,name:r,value:i}),c=(e,t,r,i)=>e.callWS({type:"insteon/scene/save",name:i,scene_id:t,links:r}),p=(e,t)=>e.callWS({type:"insteon/scene/delete",scene_id:t}),u=e=>e.callWS({type:"insteon/device/add/cancel"}),f=(e,t,r)=>e.callWS({type:"insteon/aldb/create",device_address:t,record:r}),h=(e,t)=>e.callWS({type:"insteon/aldb/load",device_address:t}),m=(e,t)=>e.callWS({type:"insteon/properties/load",device_address:t}),v=(e,t)=>e.callWS({type:"insteon/aldb/write",device_address:t}),y=(e,t)=>e.callWS({type:"insteon/properties/write",device_address:t}),g=(e,t)=>e.callWS({type:"insteon/aldb/reset",device_address:t}),b=(e,t)=>e.callWS({type:"insteon/properties/reset",device_address:t}),k=(e,t)=>e.callWS({type:"insteon/aldb/add_default_links",device_address:t}),w=e=>[{name:"mode",options:[["c",e.localize("aldb.mode.controller")],["r",e.localize("aldb.mode.responder")]],required:!0,type:"select"},{name:"group",required:!0,type:"integer",valueMin:-1,valueMax:255},{name:"target",required:!0,type:"string"},{name:"data1",required:!0,type:"integer",valueMin:-1,valueMax:255},{name:"data2",required:!0,type:"integer",valueMin:-1,valueMax:255},{name:"data3",required:!0,type:"integer",valueMin:-1,valueMax:255}],_=e=>[{name:"in_use",required:!0,type:"boolean"},...w(e)],E=e=>[{name:"multiple",required:!0,type:"boolean"},{name:"device_address",required:!1,type:e?"constant":"string"}],x=[{name:"data1",required:!0,type:"integer"},{name:"data2",required:!0,type:"integer"},{name:"data3",required:!0,type:"integer"}],D={name:"ramp_rate",options:[["31","0.1"],["30","0.2"],["29","0.3"],["28","0.5"],["27","2"],["26","4.5"],["25","6.5"],["24","8.5"],["23","19"],["22","21.5"],["21","23.5"],["20","26"],["19","28"],["18","30"],["17","32"],["16","34"],["15","38.5"],["14","43"],["13","47"],["12","60"],["11","90"],["10","120"],["9","150"],["8","180"],["7","210"],["6","240"],["5","270"],["4","300"],["3","360"],["2","420"],["1","480"]],required:!0,type:"select"}},9502:(e,t,r)=>{r.r(t);var i=r(7500),n=r(7626),o=(r(8348),r(9828)),a=r(9950),s=r(8846),l=r(8652);r(9663);function d(){d=function(){return e};var e={elementsDefinitionOrder:[["method"],["field"]],initializeInstanceElements:function(e,t){["method","field"].forEach((function(r){t.forEach((function(t){t.kind===r&&"own"===t.placement&&this.defineClassElement(e,t)}),this)}),this)},initializeClassElements:function(e,t){var r=e.prototype;["method","field"].forEach((function(i){t.forEach((function(t){var n=t.placement;if(t.kind===i&&("static"===n||"prototype"===n)){var o="static"===n?e:r;this.defineClassElement(o,t)}}),this)}),this)},defineClassElement:function(e,t){var r=t.descriptor;if("field"===t.kind){var i=t.initializer;r={enumerable:r.enumerable,writable:r.writable,configurable:r.configurable,value:void 0===i?void 0:i.call(e)}}Object.defineProperty(e,t.key,r)},decorateClass:function(e,t){var r=[],i=[],n={static:[],prototype:[],own:[]};if(e.forEach((function(e){this.addElementPlacement(e,n)}),this),e.forEach((function(e){if(!u(e))return r.push(e);var t=this.decorateElement(e,n);r.push(t.element),r.push.apply(r,t.extras),i.push.apply(i,t.finishers)}),this),!t)return{elements:r,finishers:i};var o=this.decorateConstructor(r,t);return i.push.apply(i,o.finishers),o.finishers=i,o},addElementPlacement:function(e,t,r){var i=t[e.placement];if(!r&&-1!==i.indexOf(e.key))throw new TypeError("Duplicated element ("+e.key+")");i.push(e.key)},decorateElement:function(e,t){for(var r=[],i=[],n=e.decorators,o=n.length-1;o>=0;o--){var a=t[e.placement];a.splice(a.indexOf(e.key),1);var s=this.fromElementDescriptor(e),l=this.toElementFinisherExtras((0,n[o])(s)||s);e=l.element,this.addElementPlacement(e,t),l.finisher&&i.push(l.finisher);var d=l.extras;if(d){for(var c=0;c<d.length;c++)this.addElementPlacement(d[c],t);r.push.apply(r,d)}}return{element:e,finishers:i,extras:r}},decorateConstructor:function(e,t){for(var r=[],i=t.length-1;i>=0;i--){var n=this.fromClassDescriptor(e),o=this.toClassDescriptor((0,t[i])(n)||n);if(void 0!==o.finisher&&r.push(o.finisher),void 0!==o.elements){e=o.elements;for(var a=0;a<e.length-1;a++)for(var s=a+1;s<e.length;s++)if(e[a].key===e[s].key&&e[a].placement===e[s].placement)throw new TypeError("Duplicated element ("+e[a].key+")")}}return{elements:e,finishers:r}},fromElementDescriptor:function(e){var t={kind:e.kind,key:e.key,placement:e.placement,descriptor:e.descriptor};return Object.defineProperty(t,Symbol.toStringTag,{value:"Descriptor",configurable:!0}),"field"===e.kind&&(t.initializer=e.initializer),t},toElementDescriptors:function(e){var t;if(void 0!==e)return(t=e,function(e){if(Array.isArray(e))return e}(t)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(t)||function(e,t){if(e){if("string"==typeof e)return v(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?v(e,t):void 0}}(t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()).map((function(e){var t=this.toElementDescriptor(e);return this.disallowProperty(e,"finisher","An element descriptor"),this.disallowProperty(e,"extras","An element descriptor"),t}),this)},toElementDescriptor:function(e){var t=String(e.kind);if("method"!==t&&"field"!==t)throw new TypeError('An element descriptor\'s .kind property must be either "method" or "field", but a decorator created an element descriptor with .kind "'+t+'"');var r=m(e.key),i=String(e.placement);if("static"!==i&&"prototype"!==i&&"own"!==i)throw new TypeError('An element descriptor\'s .placement property must be one of "static", "prototype" or "own", but a decorator created an element descriptor with .placement "'+i+'"');var n=e.descriptor;this.disallowProperty(e,"elements","An element descriptor");var o={kind:t,key:r,placement:i,descriptor:Object.assign({},n)};return"field"!==t?this.disallowProperty(e,"initializer","A method descriptor"):(this.disallowProperty(n,"get","The property descriptor of a field descriptor"),this.disallowProperty(n,"set","The property descriptor of a field descriptor"),this.disallowProperty(n,"value","The property descriptor of a field descriptor"),o.initializer=e.initializer),o},toElementFinisherExtras:function(e){return{element:this.toElementDescriptor(e),finisher:h(e,"finisher"),extras:this.toElementDescriptors(e.extras)}},fromClassDescriptor:function(e){var t={kind:"class",elements:e.map(this.fromElementDescriptor,this)};return Object.defineProperty(t,Symbol.toStringTag,{value:"Descriptor",configurable:!0}),t},toClassDescriptor:function(e){var t=String(e.kind);if("class"!==t)throw new TypeError('A class descriptor\'s .kind property must be "class", but a decorator created a class descriptor with .kind "'+t+'"');this.disallowProperty(e,"key","A class descriptor"),this.disallowProperty(e,"placement","A class descriptor"),this.disallowProperty(e,"descriptor","A class descriptor"),this.disallowProperty(e,"initializer","A class descriptor"),this.disallowProperty(e,"extras","A class descriptor");var r=h(e,"finisher");return{elements:this.toElementDescriptors(e.elements),finisher:r}},runClassFinishers:function(e,t){for(var r=0;r<t.length;r++){var i=(0,t[r])(e);if(void 0!==i){if("function"!=typeof i)throw new TypeError("Finishers must return a constructor.");e=i}}return e},disallowProperty:function(e,t,r){if(void 0!==e[t])throw new TypeError(r+" can't have a ."+t+" property.")}};return e}function c(e){var t,r=m(e.key);"method"===e.kind?t={value:e.value,writable:!0,configurable:!0,enumerable:!1}:"get"===e.kind?t={get:e.value,configurable:!0,enumerable:!1}:"set"===e.kind?t={set:e.value,configurable:!0,enumerable:!1}:"field"===e.kind&&(t={configurable:!0,writable:!0,enumerable:!0});var i={kind:"field"===e.kind?"field":"method",key:r,placement:e.static?"static":"field"===e.kind?"own":"prototype",descriptor:t};return e.decorators&&(i.decorators=e.decorators),"field"===e.kind&&(i.initializer=e.value),i}function p(e,t){void 0!==e.descriptor.get?t.descriptor.get=e.descriptor.get:t.descriptor.set=e.descriptor.set}function u(e){return e.decorators&&e.decorators.length}function f(e){return void 0!==e&&!(void 0===e.value&&void 0===e.writable)}function h(e,t){var r=e[t];if(void 0!==r&&"function"!=typeof r)throw new TypeError("Expected '"+t+"' to be a function");return r}function m(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var i=r.call(e,t||"default");if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}function v(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,i=new Array(t);r<t;r++)i[r]=e[r];return i}!function(e,t,r,i){var n=d();if(i)for(var o=0;o<i.length;o++)n=i[o](n);var a=t((function(e){n.initializeInstanceElements(e,s.elements)}),r),s=n.decorateClass(function(e){for(var t=[],r=function(e){return"method"===e.kind&&e.key===o.key&&e.placement===o.placement},i=0;i<e.length;i++){var n,o=e[i];if("method"===o.kind&&(n=t.find(r)))if(f(o.descriptor)||f(n.descriptor)){if(u(o)||u(n))throw new ReferenceError("Duplicated methods ("+o.key+") can't be decorated.");n.descriptor=o.descriptor}else{if(u(o)){if(u(n))throw new ReferenceError("Decorators can't be placed on different accessors with for the same property ("+o.key+").");n.decorators=o.decorators}p(o,n)}else t.push(o)}return t}(a.d.map(c)),e);n.initializeClassElements(a.F,s.elements),n.runClassFinishers(a.F,s.finishers)}([(0,n.Mo)("dialog-insteon-add-device")],(function(e,t){return{F:class extends t{constructor(...t){super(...t),e(this)}},d:[{kind:"field",decorators:[(0,n.Cb)({attribute:!1})],key:"hass",value:void 0},{kind:"field",decorators:[(0,n.Cb)({attribute:!1})],key:"insteon",value:void 0},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"isWide",value:void 0},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"narrow",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_title",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_callback",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_errors",value:void 0},{kind:"field",decorators:[(0,n.SB)()],key:"_formData",value:()=>({multiple:!1,device_address:""})},{kind:"field",decorators:[(0,n.SB)()],key:"_opened",value:()=>!1},{kind:"method",key:"showDialog",value:async function(e){this.hass=e.hass,this.insteon=e.insteon,this._callback=e.callback,this._title=e.title,this._errors={},this._opened=!0,this._formData={multiple:!1,device_address:""}}},{kind:"method",key:"_schema",value:function(e){return(0,s.Jz)(e)}},{kind:"method",key:"render",value:function(){var e;return this._opened?i.dy`
|
|
87
87
|
<ha-dialog
|
|
88
88
|
open
|
|
89
89
|
@closed="${this._close}"
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
</mwc-button>
|
|
108
108
|
</div>
|
|
109
109
|
</ha-dialog>
|
|
110
|
-
`:i.dy``}},{kind:"method",key:"_dismiss",value:function(){this._close()}},{kind:"method",key:"_computeLabel",value:function(e){return t=>e("device.fields."+t.name)||t.name}},{kind:"method",key:"_submit",value:async function(){if(this._checkData()){console.info("Should be calling callback"),this._close();const e=""==this._formData.
|
|
110
|
+
`:i.dy``}},{kind:"method",key:"_dismiss",value:function(){this._close()}},{kind:"method",key:"_computeLabel",value:function(e){return t=>e("device.fields."+t.name)||t.name}},{kind:"method",key:"_submit",value:async function(){if(this._checkData()){console.info("Should be calling callback"),this._close();const e=""==this._formData.device_address?void 0:this._formData.device_address;await this._callback(e,this._formData.multiple)}else this._errors.base=this.insteon.localize("common.error.base")}},{kind:"method",key:"_close",value:function(){this._opened=!1}},{kind:"method",key:"_valueChanged",value:function(e){this._formData=e.detail.value}},{kind:"method",key:"_checkData",value:function(){return!(""!=this._formData.device_address&&!(0,l.z)(this._formData.device_address))||(this._errors={},this._errors.device_address=this.insteon.localize("common.error.address"),!1)}},{kind:"get",static:!0,key:"styles",value:function(){return[a.yu,i.iv`
|
|
111
111
|
table {
|
|
112
112
|
width: 100%;
|
|
113
113
|
}
|
|
@@ -118,4 +118,4 @@
|
|
|
118
118
|
width: 200px;
|
|
119
119
|
}
|
|
120
120
|
`]}}]}}),i.oi)},8652:(e,t,r)=>{r.d(t,{z:()=>i});const i=e=>{const t=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];e=e.replace(".","").replace(".","").toLocaleLowerCase();const r=[...e];if(6!=r.length)return!1;for(let e=0;e<r.length;e++)if(!t.includes(r[e]))return!1;return!0}}}]);
|
|
121
|
-
//# sourceMappingURL=
|
|
121
|
+
//# sourceMappingURL=36f999eb.js.map
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"
|
|
1
|
+
{"version":3,"file":"36f999eb.js","mappings":";AAeA;;AAEA;AAhBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2HA;;;ACpEA;AACA;;;;AAIA;AACA;AACA;AACA;AACA;;;;AAIA;AACA;;AAEA;AACA;;;;AAtBA;;;;;;;;;;AA0FA","sources":["webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-dialog.ts","webpack://insteon-panel-frontend/./src/device/dialog-insteon-add-device.ts"],"sourcesContent":["import { DialogBase } from \"@material/mwc-dialog/mwc-dialog-base\";\nimport { styles } from \"@material/mwc-dialog/mwc-dialog.css\";\nimport { mdiClose } from \"@mdi/js\";\nimport { css, html, TemplateResult } from \"lit\";\nimport { customElement } from \"lit/decorators\";\nimport { FOCUS_TARGET } from \"../dialogs/make-dialog-manager\";\nimport type { HomeAssistant } from \"../types\";\nimport \"./ha-icon-button\";\n\nconst SUPPRESS_DEFAULT_PRESS_SELECTOR = [\"button\"];\n\nexport const createCloseHeading = (\n hass: HomeAssistant,\n title: string | TemplateResult\n) => html`\n <div class=\"header_title\">${title}</div>\n <ha-icon-button\n .label=${hass.localize(\"ui.dialogs.generic.close\")}\n .path=${mdiClose}\n dialogAction=\"close\"\n class=\"header_button\"\n ></ha-icon-button>\n`;\n\n@customElement(\"ha-dialog\")\nexport class HaDialog extends DialogBase {\n protected readonly [FOCUS_TARGET];\n\n public scrollToPos(x: number, y: number) {\n this.contentElement?.scrollTo(x, y);\n }\n\n protected renderHeading() {\n return html`<slot name=\"heading\"> ${super.renderHeading()} </slot>`;\n }\n\n protected firstUpdated(): void {\n super.firstUpdated();\n this.suppressDefaultPressSelector = [\n this.suppressDefaultPressSelector,\n SUPPRESS_DEFAULT_PRESS_SELECTOR,\n ].join(\", \");\n }\n\n static override styles = [\n styles,\n css`\n .mdc-dialog {\n --mdc-dialog-scroll-divider-color: var(--divider-color);\n z-index: var(--dialog-z-index, 7);\n -webkit-backdrop-filter: var(--dialog-backdrop-filter, none);\n backdrop-filter: var(--dialog-backdrop-filter, none);\n --mdc-dialog-box-shadow: var(--dialog-box-shadow, none);\n --mdc-typography-headline6-font-weight: 400;\n --mdc-typography-headline6-font-size: 1.574rem;\n }\n .mdc-dialog__actions {\n justify-content: var(--justify-action-buttons, flex-end);\n padding-bottom: max(env(safe-area-inset-bottom), 24px);\n }\n .mdc-dialog__actions span:nth-child(1) {\n flex: var(--secondary-action-button-flex, unset);\n }\n .mdc-dialog__actions span:nth-child(2) {\n flex: var(--primary-action-button-flex, unset);\n }\n .mdc-dialog__container {\n align-items: var(--vertical-align-dialog, center);\n }\n .mdc-dialog__title {\n padding: 24px 24px 0 24px;\n }\n .mdc-dialog__actions {\n padding: 0 24px 24px 24px;\n }\n .mdc-dialog__title::before {\n display: block;\n height: 0px;\n }\n .mdc-dialog .mdc-dialog__content {\n position: var(--dialog-content-position, relative);\n padding: var(--dialog-content-padding, 24px);\n }\n :host([hideactions]) .mdc-dialog .mdc-dialog__content {\n padding-bottom: max(\n var(--dialog-content-padding, 24px),\n env(safe-area-inset-bottom)\n );\n }\n .mdc-dialog .mdc-dialog__surface {\n position: var(--dialog-surface-position, relative);\n top: var(--dialog-surface-top);\n margin-top: var(--dialog-surface-margin-top);\n min-height: var(--mdc-dialog-min-height, auto);\n border-radius: var(--ha-dialog-border-radius, 28px);\n }\n :host([flexContent]) .mdc-dialog .mdc-dialog__content {\n display: flex;\n flex-direction: column;\n }\n .header_button {\n position: absolute;\n right: 16px;\n top: 14px;\n text-decoration: none;\n color: inherit;\n }\n .header_title {\n margin-right: 32px;\n margin-inline-end: 32px;\n margin-inline-start: initial;\n direction: var(--direction);\n }\n .header_button {\n inset-inline-start: initial;\n inset-inline-end: 16px;\n direction: var(--direction);\n }\n .dialog-actions {\n inset-inline-start: initial !important;\n inset-inline-end: 0px !important;\n direction: var(--direction);\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-dialog\": HaDialog;\n }\n}\n","import { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators\";\nimport \"../../homeassistant-frontend/src/components/ha-code-editor\";\nimport { createCloseHeading } from \"../../homeassistant-frontend/src/components/ha-dialog\";\nimport { haStyleDialog } from \"../../homeassistant-frontend/src/resources/styles\";\nimport { HomeAssistant } from \"../../homeassistant-frontend/src/types\";\nimport { Insteon, addDeviceSchema } from \"../data/insteon\";\nimport { check_address } from \"../tools/check_address\";\nimport \"../../homeassistant-frontend/src/components/ha-form/ha-form\";\nimport type { HaFormSchema } from \"../../homeassistant-frontend/src/components/ha-form/types\";\nimport { InsteonAddDeviceDialogParams } from \"./show-dialog-insteon-add-device\";\n\n@customElement(\"dialog-insteon-add-device\")\nclass DialogInsteonAddDevice extends LitElement {\n @property({ attribute: false }) public hass?: HomeAssistant;\n\n @property({ attribute: false }) public insteon?: Insteon;\n\n @property({ type: Boolean }) public isWide?: boolean;\n\n @property({ type: Boolean }) public narrow?: boolean;\n\n @state() private _title?: string;\n\n @state() private _callback?: (\n device_address: string | undefined,\n multiple: boolean\n ) => Promise<void>;\n\n @state() private _errors?: { [key: string]: string };\n\n @state() private _formData = { multiple: false, device_address: \"\" };\n\n @state() private _opened = false;\n\n public async showDialog(params: InsteonAddDeviceDialogParams): Promise<void> {\n this.hass = params.hass;\n this.insteon = params.insteon;\n this._callback = params.callback;\n this._title = params.title;\n this._errors = {};\n this._opened = true;\n this._formData = { multiple: false, device_address: \"\" };\n }\n\n private _schema(multiple: boolean): HaFormSchema[] {\n return addDeviceSchema(multiple);\n }\n\n protected render(): TemplateResult {\n if (!this._opened) {\n return html``;\n }\n return html`\n <ha-dialog\n open\n @closed=\"${this._close}\"\n .heading=${createCloseHeading(this.hass!, this._title!)}\n >\n <div class=\"form\">\n <ha-form\n .data=${this._formData}\n .schema=${this._schema(this._formData.multiple)}\n .error=${this._errors}\n @value-changed=${this._valueChanged}\n .computeLabel=${this._computeLabel(this.insteon?.localize)}\n ></ha-form>\n </div>\n <div class=\"buttons\">\n <mwc-button @click=${this._dismiss} slot=\"secondaryAction\">\n ${this.hass!.localize(\"ui.dialogs.generic.cancel\")}\n </mwc-button>\n <mwc-button @click=${this._submit} slot=\"primaryAction\">\n ${this.hass!.localize(\"ui.dialogs.generic.ok\")}\n </mwc-button>\n </div>\n </ha-dialog>\n `;\n }\n\n private _dismiss(): void {\n this._close();\n }\n\n private _computeLabel(localize) {\n // Returns a callback for ha-form to calculate labels per schema object\n return (schema) => localize(\"device.fields.\" + schema.name) || schema.name;\n }\n\n private async _submit(): Promise<void> {\n if (this._checkData()) {\n // eslint-disable-next-line no-console\n console.info(\"Should be calling callback\");\n this._close();\n const device_address =\n this._formData.device_address == \"\"\n ? undefined\n : this._formData.device_address;\n await this._callback!(device_address, this._formData.multiple);\n } else {\n this._errors!.base = this.insteon!.localize(\"common.error.base\");\n }\n }\n\n private _close(): void {\n this._opened = false;\n }\n\n private _valueChanged(ev: CustomEvent) {\n this._formData = ev.detail.value;\n }\n\n private _checkData(): boolean {\n if (\n this._formData.device_address == \"\" ||\n check_address(this._formData.device_address)\n )\n return true;\n\n this._errors = {};\n this._errors.device_address = this.insteon!.localize(\n \"common.error.address\"\n );\n return false;\n }\n\n static get styles(): CSSResultGroup[] {\n return [\n haStyleDialog,\n css`\n table {\n width: 100%;\n }\n ha-combo-box {\n width: 20px;\n }\n .title {\n width: 200px;\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"dialog-insteon-add-device\": DialogInsteonAddDevice;\n }\n}\n"],"names":[],"sourceRoot":""}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! For license information please see
|
|
1
|
+
/*! For license information please see 6bdb6d31.js.LICENSE.txt */
|
|
2
2
|
"use strict";(self.webpackChunkinsteon_panel_frontend=self.webpackChunkinsteon_panel_frontend||[]).push([[1668],{4672:(e,t,r)=>{r.d(t,{p:()=>i});const i=e=>e.substr(e.indexOf(".")+1)},2733:(e,t,r)=>{r.d(t,{C:()=>n});var i=r(4672);const n=e=>{return t=e.entity_id,void 0===(r=e.attributes).friendly_name?(0,i.p)(t).replace(/_/g," "):r.friendly_name||"";var t,r}},8858:(e,t,r)=>{r.d(t,{$:()=>s,f:()=>l});var i=r(4516);const n=(0,i.Z)((e=>new Intl.Collator(e))),o=(0,i.Z)((e=>new Intl.Collator(e,{sensitivity:"accent"}))),a=(e,t)=>e<t?-1:e>t?1:0,s=(e,t,r)=>{var i;return null!==(i=Intl)&&void 0!==i&&i.Collator?n(r).compare(e,t):a(e,t)},l=(e,t,r)=>{var i;return null!==(i=Intl)&&void 0!==i&&i.Collator?o(r).compare(e,t):a(e.toLowerCase(),t.toLowerCase())}},5878:(e,t,r)=>{r(4479);var i=r(7500),n=r(7626),o=r(5815);function a(){a=function(){return e};var e={elementsDefinitionOrder:[["method"],["field"]],initializeInstanceElements:function(e,t){["method","field"].forEach((function(r){t.forEach((function(t){t.kind===r&&"own"===t.placement&&this.defineClassElement(e,t)}),this)}),this)},initializeClassElements:function(e,t){var r=e.prototype;["method","field"].forEach((function(i){t.forEach((function(t){var n=t.placement;if(t.kind===i&&("static"===n||"prototype"===n)){var o="static"===n?e:r;this.defineClassElement(o,t)}}),this)}),this)},defineClassElement:function(e,t){var r=t.descriptor;if("field"===t.kind){var i=t.initializer;r={enumerable:r.enumerable,writable:r.writable,configurable:r.configurable,value:void 0===i?void 0:i.call(e)}}Object.defineProperty(e,t.key,r)},decorateClass:function(e,t){var r=[],i=[],n={static:[],prototype:[],own:[]};if(e.forEach((function(e){this.addElementPlacement(e,n)}),this),e.forEach((function(e){if(!c(e))return r.push(e);var t=this.decorateElement(e,n);r.push(t.element),r.push.apply(r,t.extras),i.push.apply(i,t.finishers)}),this),!t)return{elements:r,finishers:i};var o=this.decorateConstructor(r,t);return i.push.apply(i,o.finishers),o.finishers=i,o},addElementPlacement:function(e,t,r){var i=t[e.placement];if(!r&&-1!==i.indexOf(e.key))throw new TypeError("Duplicated element ("+e.key+")");i.push(e.key)},decorateElement:function(e,t){for(var r=[],i=[],n=e.decorators,o=n.length-1;o>=0;o--){var a=t[e.placement];a.splice(a.indexOf(e.key),1);var s=this.fromElementDescriptor(e),l=this.toElementFinisherExtras((0,n[o])(s)||s);e=l.element,this.addElementPlacement(e,t),l.finisher&&i.push(l.finisher);var c=l.extras;if(c){for(var d=0;d<c.length;d++)this.addElementPlacement(c[d],t);r.push.apply(r,c)}}return{element:e,finishers:i,extras:r}},decorateConstructor:function(e,t){for(var r=[],i=t.length-1;i>=0;i--){var n=this.fromClassDescriptor(e),o=this.toClassDescriptor((0,t[i])(n)||n);if(void 0!==o.finisher&&r.push(o.finisher),void 0!==o.elements){e=o.elements;for(var a=0;a<e.length-1;a++)for(var s=a+1;s<e.length;s++)if(e[a].key===e[s].key&&e[a].placement===e[s].placement)throw new TypeError("Duplicated element ("+e[a].key+")")}}return{elements:e,finishers:r}},fromElementDescriptor:function(e){var t={kind:e.kind,key:e.key,placement:e.placement,descriptor:e.descriptor};return Object.defineProperty(t,Symbol.toStringTag,{value:"Descriptor",configurable:!0}),"field"===e.kind&&(t.initializer=e.initializer),t},toElementDescriptors:function(e){var t;if(void 0!==e)return(t=e,function(e){if(Array.isArray(e))return e}(t)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(t)||function(e,t){if(e){if("string"==typeof e)return f(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?f(e,t):void 0}}(t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()).map((function(e){var t=this.toElementDescriptor(e);return this.disallowProperty(e,"finisher","An element descriptor"),this.disallowProperty(e,"extras","An element descriptor"),t}),this)},toElementDescriptor:function(e){var t=String(e.kind);if("method"!==t&&"field"!==t)throw new TypeError('An element descriptor\'s .kind property must be either "method" or "field", but a decorator created an element descriptor with .kind "'+t+'"');var r=u(e.key),i=String(e.placement);if("static"!==i&&"prototype"!==i&&"own"!==i)throw new TypeError('An element descriptor\'s .placement property must be one of "static", "prototype" or "own", but a decorator created an element descriptor with .placement "'+i+'"');var n=e.descriptor;this.disallowProperty(e,"elements","An element descriptor");var o={kind:t,key:r,placement:i,descriptor:Object.assign({},n)};return"field"!==t?this.disallowProperty(e,"initializer","A method descriptor"):(this.disallowProperty(n,"get","The property descriptor of a field descriptor"),this.disallowProperty(n,"set","The property descriptor of a field descriptor"),this.disallowProperty(n,"value","The property descriptor of a field descriptor"),o.initializer=e.initializer),o},toElementFinisherExtras:function(e){return{element:this.toElementDescriptor(e),finisher:p(e,"finisher"),extras:this.toElementDescriptors(e.extras)}},fromClassDescriptor:function(e){var t={kind:"class",elements:e.map(this.fromElementDescriptor,this)};return Object.defineProperty(t,Symbol.toStringTag,{value:"Descriptor",configurable:!0}),t},toClassDescriptor:function(e){var t=String(e.kind);if("class"!==t)throw new TypeError('A class descriptor\'s .kind property must be "class", but a decorator created a class descriptor with .kind "'+t+'"');this.disallowProperty(e,"key","A class descriptor"),this.disallowProperty(e,"placement","A class descriptor"),this.disallowProperty(e,"descriptor","A class descriptor"),this.disallowProperty(e,"initializer","A class descriptor"),this.disallowProperty(e,"extras","A class descriptor");var r=p(e,"finisher");return{elements:this.toElementDescriptors(e.elements),finisher:r}},runClassFinishers:function(e,t){for(var r=0;r<t.length;r++){var i=(0,t[r])(e);if(void 0!==i){if("function"!=typeof i)throw new TypeError("Finishers must return a constructor.");e=i}}return e},disallowProperty:function(e,t,r){if(void 0!==e[t])throw new TypeError(r+" can't have a ."+t+" property.")}};return e}function s(e){var t,r=u(e.key);"method"===e.kind?t={value:e.value,writable:!0,configurable:!0,enumerable:!1}:"get"===e.kind?t={get:e.value,configurable:!0,enumerable:!1}:"set"===e.kind?t={set:e.value,configurable:!0,enumerable:!1}:"field"===e.kind&&(t={configurable:!0,writable:!0,enumerable:!0});var i={kind:"field"===e.kind?"field":"method",key:r,placement:e.static?"static":"field"===e.kind?"own":"prototype",descriptor:t};return e.decorators&&(i.decorators=e.decorators),"field"===e.kind&&(i.initializer=e.value),i}function l(e,t){void 0!==e.descriptor.get?t.descriptor.get=e.descriptor.get:t.descriptor.set=e.descriptor.set}function c(e){return e.decorators&&e.decorators.length}function d(e){return void 0!==e&&!(void 0===e.value&&void 0===e.writable)}function p(e,t){var r=e[t];if(void 0!==r&&"function"!=typeof r)throw new TypeError("Expected '"+t+"' to be a function");return r}function u(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var i=r.call(e,t||"default");if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}function f(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,i=new Array(t);r<t;r++)i[r]=e[r];return i}function h(){return h="undefined"!=typeof Reflect&&Reflect.get?Reflect.get.bind():function(e,t,r){var i=function(e,t){for(;!Object.prototype.hasOwnProperty.call(e,t)&&null!==(e=m(e)););return e}(e,t);if(i){var n=Object.getOwnPropertyDescriptor(i,t);return n.get?n.get.call(arguments.length<3?e:r):n.value}},h.apply(this,arguments)}function m(e){return m=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)},m(e)}!function(e,t,r,i){var n=a();if(i)for(var o=0;o<i.length;o++)n=i[o](n);var p=t((function(e){n.initializeInstanceElements(e,u.elements)}),r),u=n.decorateClass(function(e){for(var t=[],r=function(e){return"method"===e.kind&&e.key===o.key&&e.placement===o.placement},i=0;i<e.length;i++){var n,o=e[i];if("method"===o.kind&&(n=t.find(r)))if(d(o.descriptor)||d(n.descriptor)){if(c(o)||c(n))throw new ReferenceError("Duplicated methods ("+o.key+") can't be decorated.");n.descriptor=o.descriptor}else{if(c(o)){if(c(n))throw new ReferenceError("Decorators can't be placed on different accessors with for the same property ("+o.key+").");n.decorators=o.decorators}l(o,n)}else t.push(o)}return t}(p.d.map(s)),e);n.initializeClassElements(p.F,u.elements),n.runClassFinishers(p.F,u.finishers)}([(0,n.Mo)("ha-button-menu")],(function(e,t){class r extends t{constructor(...t){super(...t),e(this)}}return{F:r,d:[{kind:"field",key:o.gA,value:void 0},{kind:"field",decorators:[(0,n.Cb)()],key:"corner",value:()=>"TOP_START"},{kind:"field",decorators:[(0,n.Cb)()],key:"menuCorner",value:()=>"START"},{kind:"field",decorators:[(0,n.Cb)({type:Number})],key:"x",value:()=>null},{kind:"field",decorators:[(0,n.Cb)({type:Number})],key:"y",value:()=>null},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"multi",value:()=>!1},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"activatable",value:()=>!1},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"disabled",value:()=>!1},{kind:"field",decorators:[(0,n.Cb)({type:Boolean})],key:"fixed",value:()=>!1},{kind:"field",decorators:[(0,n.IO)("mwc-menu",!0)],key:"_menu",value:void 0},{kind:"get",key:"items",value:function(){var e;return null===(e=this._menu)||void 0===e?void 0:e.items}},{kind:"get",key:"selected",value:function(){var e;return null===(e=this._menu)||void 0===e?void 0:e.selected}},{kind:"method",key:"focus",value:function(){var e,t;null!==(e=this._menu)&&void 0!==e&&e.open?this._menu.focusItemAtIndex(0):null===(t=this._triggerButton)||void 0===t||t.focus()}},{kind:"method",key:"render",value:function(){return i.dy`
|
|
3
3
|
<div @click=${this._handleClick}>
|
|
4
4
|
<slot name="trigger" @slotchange=${this._setTriggerAria}></slot>
|
|
@@ -246,4 +246,4 @@
|
|
|
246
246
|
right: auto;
|
|
247
247
|
}
|
|
248
248
|
`,l.Qx]}}]}}),i.oi)}}]);
|
|
249
|
-
//# sourceMappingURL=
|
|
249
|
+
//# sourceMappingURL=6bdb6d31.js.map
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"451cad84.js","mappings":";;AAgDA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AAKA;;;;;;;;AA+CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCA;AAIA;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACqBA;;AC0FA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;AAIA;;AAEA;;;;;AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+FA","sources":["webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-button-menu.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-card.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/layouts/ha-app-layout.js","webpack://insteon-panel-frontend/./src/insteon-devices-panel.ts"],"sourcesContent":["import type { Button } from \"@material/mwc-button\";\nimport \"@material/mwc-menu\";\nimport type { Corner, Menu, MenuCorner } from \"@material/mwc-menu\";\nimport { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property, query } from \"lit/decorators\";\nimport { FOCUS_TARGET } from \"../dialogs/make-dialog-manager\";\nimport type { HaIconButton } from \"./ha-icon-button\";\n\n@customElement(\"ha-button-menu\")\nexport class HaButtonMenu extends LitElement {\n protected readonly [FOCUS_TARGET];\n\n @property() public corner: Corner = \"TOP_START\";\n\n @property() public menuCorner: MenuCorner = \"START\";\n\n @property({ type: Number }) public x: number | null = null;\n\n @property({ type: Number }) public y: number | null = null;\n\n @property({ type: Boolean }) public multi = false;\n\n @property({ type: Boolean }) public activatable = false;\n\n @property({ type: Boolean }) public disabled = false;\n\n @property({ type: Boolean }) public fixed = false;\n\n @query(\"mwc-menu\", true) private _menu?: Menu;\n\n public get items() {\n return this._menu?.items;\n }\n\n public get selected() {\n return this._menu?.selected;\n }\n\n public override focus() {\n if (this._menu?.open) {\n this._menu.focusItemAtIndex(0);\n } else {\n this._triggerButton?.focus();\n }\n }\n\n protected render(): TemplateResult {\n return html`\n <div @click=${this._handleClick}>\n <slot name=\"trigger\" @slotchange=${this._setTriggerAria}></slot>\n </div>\n <mwc-menu\n .corner=${this.corner}\n .menuCorner=${this.menuCorner}\n .fixed=${this.fixed}\n .multi=${this.multi}\n .activatable=${this.activatable}\n .y=${this.y}\n .x=${this.x}\n >\n <slot></slot>\n </mwc-menu>\n `;\n }\n\n protected firstUpdated(changedProps): void {\n super.firstUpdated(changedProps);\n\n if (document.dir === \"rtl\") {\n this.updateComplete.then(() => {\n this.querySelectorAll(\"mwc-list-item\").forEach((item) => {\n const style = document.createElement(\"style\");\n style.innerHTML =\n \"span.material-icons:first-of-type { margin-left: var(--mdc-list-item-graphic-margin, 32px) !important; margin-right: 0px !important;}\";\n item!.shadowRoot!.appendChild(style);\n });\n });\n }\n }\n\n private _handleClick(): void {\n if (this.disabled) {\n return;\n }\n this._menu!.anchor = this;\n this._menu!.show();\n }\n\n private get _triggerButton() {\n return this.querySelector(\n 'ha-icon-button[slot=\"trigger\"], mwc-button[slot=\"trigger\"]'\n ) as HaIconButton | Button | null;\n }\n\n private _setTriggerAria() {\n if (this._triggerButton) {\n this._triggerButton.ariaHasPopup = \"menu\";\n }\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n display: inline-block;\n position: relative;\n }\n ::slotted([disabled]) {\n color: var(--disabled-text-color);\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-button-menu\": HaButtonMenu;\n }\n}\n","import { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\n\n@customElement(\"ha-card\")\nexport class HaCard extends LitElement {\n @property() public header?: string;\n\n @property({ type: Boolean, reflect: true }) public raised = false;\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n background: var(\n --ha-card-background,\n var(--card-background-color, white)\n );\n box-shadow: var(--ha-card-box-shadow, none);\n box-sizing: border-box;\n border-radius: var(--ha-card-border-radius, 12px);\n border-width: var(--ha-card-border-width, 1px);\n border-style: solid;\n border-color: var(\n --ha-card-border-color,\n var(--divider-color, #e0e0e0)\n );\n color: var(--primary-text-color);\n display: block;\n transition: all 0.3s ease-out;\n position: relative;\n }\n\n :host([raised]) {\n border: none;\n box-shadow: var(\n --ha-card-box-shadow,\n 0px 2px 1px -1px rgba(0, 0, 0, 0.2),\n 0px 1px 1px 0px rgba(0, 0, 0, 0.14),\n 0px 1px 3px 0px rgba(0, 0, 0, 0.12)\n );\n }\n\n .card-header,\n :host ::slotted(.card-header) {\n color: var(--ha-card-header-color, --primary-text-color);\n font-family: var(--ha-card-header-font-family, inherit);\n font-size: var(--ha-card-header-font-size, 24px);\n letter-spacing: -0.012em;\n line-height: 48px;\n padding: 12px 16px 16px;\n display: block;\n margin-block-start: 0px;\n margin-block-end: 0px;\n font-weight: normal;\n }\n\n :host ::slotted(.card-content:not(:first-child)),\n slot:not(:first-child)::slotted(.card-content) {\n padding-top: 0px;\n margin-top: -8px;\n }\n\n :host ::slotted(.card-content) {\n padding: 16px;\n }\n\n :host ::slotted(.card-actions) {\n border-top: 1px solid var(--divider-color, #e8e8e8);\n padding: 5px 16px;\n }\n `;\n }\n\n protected render(): TemplateResult {\n return html`\n ${this.header\n ? html`<h1 class=\"card-header\">${this.header}</h1>`\n : html``}\n <slot></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-card\": HaCard;\n }\n}\n","/* eslint-plugin-disable lit */\n/**\n@license\nCopyright (c) 2015 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n/*\nThis code is copied from app-header-layout.\n'fullbleed' support is removed as Home Assisstant doesn't use it.\ntransform: translate(0) is added.\n*/\n/*\n FIXME(polymer-modulizer): the above comments were extracted\n from HTML and may be out of place here. Review them and\n then delete this comment!\n*/\nimport \"@polymer/app-layout/app-header-layout/app-header-layout\";\nimport { html } from \"@polymer/polymer/lib/utils/html-tag\";\nimport \"@polymer/polymer/polymer-element\";\n\nclass HaAppLayout extends customElements.get(\"app-header-layout\") {\n static get template() {\n return html`\n <style>\n :host {\n display: block;\n /**\n * Force app-header-layout to have its own stacking context so that its parent can\n * control the stacking of it relative to other elements (e.g. app-drawer-layout).\n * This could be done using \\`isolation: isolate\\`, but that's not well supported\n * across browsers.\n */\n position: relative;\n z-index: 0;\n }\n\n #wrapper ::slotted([slot=\"header\"]) {\n @apply --layout-fixed-top;\n z-index: 1;\n }\n\n #wrapper.initializing ::slotted([slot=\"header\"]) {\n position: relative;\n }\n\n :host([has-scrolling-region]) {\n height: 100%;\n }\n\n :host([has-scrolling-region]) #wrapper ::slotted([slot=\"header\"]) {\n position: absolute;\n }\n\n :host([has-scrolling-region])\n #wrapper.initializing\n ::slotted([slot=\"header\"]) {\n position: relative;\n }\n\n :host([has-scrolling-region]) #wrapper #contentContainer {\n @apply --layout-fit;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n }\n\n :host([has-scrolling-region]) #wrapper.initializing #contentContainer {\n position: relative;\n }\n\n #contentContainer {\n /* Create a stacking context here so that all children appear below the header. */\n position: relative;\n z-index: 0;\n /* Using 'transform' will cause 'position: fixed' elements to behave like\n 'position: absolute' relative to this element. */\n transform: translate(0);\n margin-left: env(safe-area-inset-left);\n margin-right: env(safe-area-inset-right);\n padding-top: env(safe-area-inset-top);\n padding-bottom: env(safe-area-inset-bottom);\n }\n\n @media print {\n :host([has-scrolling-region]) #wrapper #contentContainer {\n overflow-y: visible;\n }\n }\n </style>\n\n <div id=\"wrapper\" class=\"initializing\">\n <slot id=\"headerSlot\" name=\"header\"></slot>\n\n <div id=\"contentContainer\"><slot></slot></div>\n <slot id=\"fab\" name=\"fab\"></slot>\n </div>\n `;\n }\n}\ncustomElements.define(\"ha-app-layout\", HaAppLayout);\n","import { mdiPlus } from \"@mdi/js\";\nimport { UnsubscribeFunc } from \"home-assistant-js-websocket\";\nimport { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\nimport memoizeOne from \"memoize-one\";\nimport \"../homeassistant-frontend/src/components/data-table/ha-data-table\";\nimport \"../homeassistant-frontend/src/components/ha-fab\";\nimport {\n DataTableRowData,\n RowClickedEvent,\n} from \"../homeassistant-frontend/src/components/data-table/ha-data-table\";\nimport \"../homeassistant-frontend/src/components/ha-card\";\nimport \"../homeassistant-frontend/src/components/ha-button-menu\";\n// import \"../homeassistant-frontend/src/layouts/hass-subpage\";\nimport \"../homeassistant-frontend/src/layouts/ha-app-layout\";\nimport \"../homeassistant-frontend/src/layouts/hass-tabs-subpage-data-table\";\nimport { haStyle } from \"../homeassistant-frontend/src/resources/styles\";\nimport { HomeAssistant, Route } from \"../homeassistant-frontend/src/types\";\nimport {\n subscribeDeviceRegistry,\n DeviceRegistryEntry,\n} from \"../homeassistant-frontend/src/data/device_registry\";\nimport { Insteon } from \"./data/insteon\";\nimport { navigate } from \"../homeassistant-frontend/src/common/navigate\";\nimport { HASSDomEvent } from \"../homeassistant-frontend/src/common/dom/fire_event\";\nimport {\n AreaRegistryEntry,\n subscribeAreaRegistry,\n} from \"../homeassistant-frontend/src/data/area_registry\";\nimport { showInsteonAddDeviceDialog } from \"./device/show-dialog-insteon-add-device\";\nimport { showInsteonAddingDeviceDialog } from \"./device/show-dialog-adding-device\";\nimport { insteonMainTabs } from \"./insteon-router\";\nimport \"../homeassistant-frontend/src/components/ha-fab\";\n\ninterface DeviceRowData extends DataTableRowData {\n id: string;\n name: string;\n address: string;\n description: string;\n model: string;\n area: string;\n}\n\n@customElement(\"insteon-devices-panel\")\nexport class InsteonDevicesPanel extends LitElement {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property({ type: Object }) public insteon!: Insteon;\n\n @property({ type: Object }) public route!: Route;\n\n @property({ type: Boolean }) public narrow = false;\n\n @property({ type: Array }) private _devices: DeviceRegistryEntry[] = [];\n\n private _areas: AreaRegistryEntry[] = [];\n\n private _unsubs?: UnsubscribeFunc[];\n\n public firstUpdated(changedProperties) {\n super.firstUpdated(changedProperties);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n if (!this._unsubs) {\n this._getDevices();\n }\n }\n\n public updated(changedProperties) {\n super.updated(changedProperties);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n if (!this._unsubs) {\n this._getDevices();\n }\n }\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n if (this._unsubs) {\n while (this._unsubs.length) {\n this._unsubs.pop()!();\n }\n this._unsubs = undefined;\n }\n }\n\n private _getDevices() {\n if (!this.insteon || !this.hass) {\n return;\n }\n\n this._unsubs = [\n subscribeAreaRegistry(this.hass.connection, (areas) => {\n this._areas = areas;\n }),\n subscribeDeviceRegistry(this.hass.connection, (entries) => {\n this._devices = entries.filter(\n (device) =>\n device.config_entries &&\n device.config_entries.includes(this.insteon.config_entry.entry_id)\n );\n }),\n ];\n }\n\n private _columns = memoizeOne((narrow: boolean) =>\n narrow\n ? {\n name: {\n title: \"Device\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n grows: true,\n },\n address: {\n title: \"Address\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"5hv\",\n },\n }\n : {\n name: {\n title: \"Device\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n grows: true,\n },\n address: {\n title: \"Address\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"20%\",\n },\n description: {\n title: \"Description\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"15%\",\n },\n model: {\n title: \"Model\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"15%\",\n },\n area: {\n title: \"Area\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"15%\",\n },\n }\n );\n\n private _insteonDevices = memoizeOne((devices: DeviceRegistryEntry[]) => {\n const areaLookup: { [areaId: string]: AreaRegistryEntry } = {};\n for (const area of this._areas) {\n areaLookup[area.area_id] = area;\n }\n\n const insteonDevices: DeviceRowData[] = devices.map((device) => {\n const deviceRowdata: DeviceRowData = {\n id: device.id,\n name: device.name_by_user || device.name || \"No device name\",\n address: device.name?.substring(device.name.length - 8) || \"\",\n description: device.name?.substring(0, device.name.length - 8) || \"\",\n model: device.model || \"\",\n area: device.area_id ? areaLookup[device.area_id].name : \"\",\n };\n return deviceRowdata;\n });\n return insteonDevices;\n });\n\n protected render(): TemplateResult | void {\n return html`\n <hass-tabs-subpage-data-table\n .hass=${this.hass}\n .narrow=${this.narrow}\n .tabs=${insteonMainTabs}\n .route=${this.route}\n .data=${this._insteonDevices(this._devices)}\n .columns=${this._columns(this.narrow)}\n @row-click=${this._handleRowClicked}\n clickable\n .localizeFunc=${this.insteon.localize}\n .mainPage=${true}\n .hasFab=${true}\n >\n <ha-fab\n slot=\"fab\"\n .label=${this.insteon.localize(\"devices.add_device\")}\n extended\n @click=${this._addDevice}\n >\n <ha-svg-icon slot=\"icon\" .path=${mdiPlus}></ha-svg-icon>\n </ha-fab>\n </hass-tabs-subpage-data-table>\n `;\n }\n\n private async _addDevice(): Promise<void> {\n showInsteonAddDeviceDialog(this, {\n hass: this.hass,\n insteon: this.insteon,\n title: this.insteon.localize(\"device.actions.add\"),\n callback: async (address, multiple) => this._handleDeviceAdd(address, multiple),\n });\n }\n\n private async _handleDeviceAdd(address: string, multiple: boolean) {\n showInsteonAddingDeviceDialog(this, {\n hass: this.hass,\n insteon: this.insteon,\n multiple: multiple,\n address: address,\n title: \"Adding Insteon Device\",\n });\n }\n\n private async _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>): Promise<void> {\n // eslint-disable-next-line no-console\n // console.info(\"Row clicked received\");\n const id = ev.detail.id;\n navigate(\"/insteon/device/properties/\" + id);\n }\n\n static get styles(): CSSResultGroup {\n return [\n css`\n ha-data-table {\n width: 100%;\n height: 100%;\n --data-table-border-width: 0;\n }\n :host(:not([narrow])) ha-data-table {\n height: calc(100vh - 1px - var(--header-height));\n display: block;\n }\n :host([narrow]) hass-tabs-subpage {\n --main-title-margin: 0;\n }\n .table-header {\n display: flex;\n align-items: center;\n --mdc-shape-small: 0;\n height: 56px;\n }\n .search-toolbar {\n display: flex;\n align-items: center;\n color: var(--secondary-text-color);\n }\n search-input {\n --mdc-text-field-fill-color: var(--sidebar-background-color);\n --mdc-text-field-idle-line-color: var(--divider-color);\n --text-field-overflow: visible;\n z-index: 5;\n }\n .table-header search-input {\n display: block;\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n }\n .search-toolbar search-input {\n display: block;\n width: 100%;\n color: var(--secondary-text-color);\n --mdc-ripple-color: transparant;\n }\n #fab {\n position: fixed;\n right: calc(16px + env(safe-area-inset-right));\n bottom: calc(16px + env(safe-area-inset-bottom));\n z-index: 1;\n }\n :host([narrow]) #fab.tabs {\n bottom: calc(84px + env(safe-area-inset-bottom));\n }\n #fab[is-wide] {\n bottom: 24px;\n right: 24px;\n }\n :host([rtl]) #fab {\n right: auto;\n left: calc(16px + env(safe-area-inset-left));\n }\n :host([rtl][is-wide]) #fab {\n bottom: 24px;\n left: 24px;\n right: auto;\n }\n `,\n haStyle,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"insteon-devices-panel\": InsteonDevicesPanel;\n }\n}\n"],"names":[],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"6bdb6d31.js","mappings":";;AAgDA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AAKA;;;;;;;;AA+CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCA;AAIA;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACqBA;;AC0FA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;AAIA;;AAEA;;;;;AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+FA","sources":["webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-button-menu.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/components/ha-card.ts","webpack://insteon-panel-frontend/./homeassistant-frontend/src/layouts/ha-app-layout.js","webpack://insteon-panel-frontend/./src/insteon-devices-panel.ts"],"sourcesContent":["import type { Button } from \"@material/mwc-button\";\nimport \"@material/mwc-menu\";\nimport type { Corner, Menu, MenuCorner } from \"@material/mwc-menu\";\nimport { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property, query } from \"lit/decorators\";\nimport { FOCUS_TARGET } from \"../dialogs/make-dialog-manager\";\nimport type { HaIconButton } from \"./ha-icon-button\";\n\n@customElement(\"ha-button-menu\")\nexport class HaButtonMenu extends LitElement {\n protected readonly [FOCUS_TARGET];\n\n @property() public corner: Corner = \"TOP_START\";\n\n @property() public menuCorner: MenuCorner = \"START\";\n\n @property({ type: Number }) public x: number | null = null;\n\n @property({ type: Number }) public y: number | null = null;\n\n @property({ type: Boolean }) public multi = false;\n\n @property({ type: Boolean }) public activatable = false;\n\n @property({ type: Boolean }) public disabled = false;\n\n @property({ type: Boolean }) public fixed = false;\n\n @query(\"mwc-menu\", true) private _menu?: Menu;\n\n public get items() {\n return this._menu?.items;\n }\n\n public get selected() {\n return this._menu?.selected;\n }\n\n public override focus() {\n if (this._menu?.open) {\n this._menu.focusItemAtIndex(0);\n } else {\n this._triggerButton?.focus();\n }\n }\n\n protected render(): TemplateResult {\n return html`\n <div @click=${this._handleClick}>\n <slot name=\"trigger\" @slotchange=${this._setTriggerAria}></slot>\n </div>\n <mwc-menu\n .corner=${this.corner}\n .menuCorner=${this.menuCorner}\n .fixed=${this.fixed}\n .multi=${this.multi}\n .activatable=${this.activatable}\n .y=${this.y}\n .x=${this.x}\n >\n <slot></slot>\n </mwc-menu>\n `;\n }\n\n protected firstUpdated(changedProps): void {\n super.firstUpdated(changedProps);\n\n if (document.dir === \"rtl\") {\n this.updateComplete.then(() => {\n this.querySelectorAll(\"mwc-list-item\").forEach((item) => {\n const style = document.createElement(\"style\");\n style.innerHTML =\n \"span.material-icons:first-of-type { margin-left: var(--mdc-list-item-graphic-margin, 32px) !important; margin-right: 0px !important;}\";\n item!.shadowRoot!.appendChild(style);\n });\n });\n }\n }\n\n private _handleClick(): void {\n if (this.disabled) {\n return;\n }\n this._menu!.anchor = this;\n this._menu!.show();\n }\n\n private get _triggerButton() {\n return this.querySelector(\n 'ha-icon-button[slot=\"trigger\"], mwc-button[slot=\"trigger\"]'\n ) as HaIconButton | Button | null;\n }\n\n private _setTriggerAria() {\n if (this._triggerButton) {\n this._triggerButton.ariaHasPopup = \"menu\";\n }\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n display: inline-block;\n position: relative;\n }\n ::slotted([disabled]) {\n color: var(--disabled-text-color);\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-button-menu\": HaButtonMenu;\n }\n}\n","import { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\n\n@customElement(\"ha-card\")\nexport class HaCard extends LitElement {\n @property() public header?: string;\n\n @property({ type: Boolean, reflect: true }) public raised = false;\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n background: var(\n --ha-card-background,\n var(--card-background-color, white)\n );\n box-shadow: var(--ha-card-box-shadow, none);\n box-sizing: border-box;\n border-radius: var(--ha-card-border-radius, 12px);\n border-width: var(--ha-card-border-width, 1px);\n border-style: solid;\n border-color: var(\n --ha-card-border-color,\n var(--divider-color, #e0e0e0)\n );\n color: var(--primary-text-color);\n display: block;\n transition: all 0.3s ease-out;\n position: relative;\n }\n\n :host([raised]) {\n border: none;\n box-shadow: var(\n --ha-card-box-shadow,\n 0px 2px 1px -1px rgba(0, 0, 0, 0.2),\n 0px 1px 1px 0px rgba(0, 0, 0, 0.14),\n 0px 1px 3px 0px rgba(0, 0, 0, 0.12)\n );\n }\n\n .card-header,\n :host ::slotted(.card-header) {\n color: var(--ha-card-header-color, --primary-text-color);\n font-family: var(--ha-card-header-font-family, inherit);\n font-size: var(--ha-card-header-font-size, 24px);\n letter-spacing: -0.012em;\n line-height: 48px;\n padding: 12px 16px 16px;\n display: block;\n margin-block-start: 0px;\n margin-block-end: 0px;\n font-weight: normal;\n }\n\n :host ::slotted(.card-content:not(:first-child)),\n slot:not(:first-child)::slotted(.card-content) {\n padding-top: 0px;\n margin-top: -8px;\n }\n\n :host ::slotted(.card-content) {\n padding: 16px;\n }\n\n :host ::slotted(.card-actions) {\n border-top: 1px solid var(--divider-color, #e8e8e8);\n padding: 5px 16px;\n }\n `;\n }\n\n protected render(): TemplateResult {\n return html`\n ${this.header\n ? html`<h1 class=\"card-header\">${this.header}</h1>`\n : html``}\n <slot></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ha-card\": HaCard;\n }\n}\n","/* eslint-plugin-disable lit */\n/**\n@license\nCopyright (c) 2015 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n/*\nThis code is copied from app-header-layout.\n'fullbleed' support is removed as Home Assisstant doesn't use it.\ntransform: translate(0) is added.\n*/\n/*\n FIXME(polymer-modulizer): the above comments were extracted\n from HTML and may be out of place here. Review them and\n then delete this comment!\n*/\nimport \"@polymer/app-layout/app-header-layout/app-header-layout\";\nimport { html } from \"@polymer/polymer/lib/utils/html-tag\";\nimport \"@polymer/polymer/polymer-element\";\n\nclass HaAppLayout extends customElements.get(\"app-header-layout\") {\n static get template() {\n return html`\n <style>\n :host {\n display: block;\n /**\n * Force app-header-layout to have its own stacking context so that its parent can\n * control the stacking of it relative to other elements (e.g. app-drawer-layout).\n * This could be done using \\`isolation: isolate\\`, but that's not well supported\n * across browsers.\n */\n position: relative;\n z-index: 0;\n }\n\n #wrapper ::slotted([slot=\"header\"]) {\n @apply --layout-fixed-top;\n z-index: 1;\n }\n\n #wrapper.initializing ::slotted([slot=\"header\"]) {\n position: relative;\n }\n\n :host([has-scrolling-region]) {\n height: 100%;\n }\n\n :host([has-scrolling-region]) #wrapper ::slotted([slot=\"header\"]) {\n position: absolute;\n }\n\n :host([has-scrolling-region])\n #wrapper.initializing\n ::slotted([slot=\"header\"]) {\n position: relative;\n }\n\n :host([has-scrolling-region]) #wrapper #contentContainer {\n @apply --layout-fit;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n }\n\n :host([has-scrolling-region]) #wrapper.initializing #contentContainer {\n position: relative;\n }\n\n #contentContainer {\n /* Create a stacking context here so that all children appear below the header. */\n position: relative;\n z-index: 0;\n /* Using 'transform' will cause 'position: fixed' elements to behave like\n 'position: absolute' relative to this element. */\n transform: translate(0);\n margin-left: env(safe-area-inset-left);\n margin-right: env(safe-area-inset-right);\n padding-top: env(safe-area-inset-top);\n padding-bottom: env(safe-area-inset-bottom);\n }\n\n @media print {\n :host([has-scrolling-region]) #wrapper #contentContainer {\n overflow-y: visible;\n }\n }\n </style>\n\n <div id=\"wrapper\" class=\"initializing\">\n <slot id=\"headerSlot\" name=\"header\"></slot>\n\n <div id=\"contentContainer\"><slot></slot></div>\n <slot id=\"fab\" name=\"fab\"></slot>\n </div>\n `;\n }\n}\ncustomElements.define(\"ha-app-layout\", HaAppLayout);\n","import { mdiPlus } from \"@mdi/js\";\nimport { UnsubscribeFunc } from \"home-assistant-js-websocket\";\nimport { css, CSSResultGroup, html, LitElement, TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators\";\nimport memoizeOne from \"memoize-one\";\nimport \"../homeassistant-frontend/src/components/data-table/ha-data-table\";\nimport \"../homeassistant-frontend/src/components/ha-fab\";\nimport {\n DataTableRowData,\n RowClickedEvent,\n} from \"../homeassistant-frontend/src/components/data-table/ha-data-table\";\nimport \"../homeassistant-frontend/src/components/ha-card\";\nimport \"../homeassistant-frontend/src/components/ha-button-menu\";\n// import \"../homeassistant-frontend/src/layouts/hass-subpage\";\nimport \"../homeassistant-frontend/src/layouts/ha-app-layout\";\nimport \"../homeassistant-frontend/src/layouts/hass-tabs-subpage-data-table\";\nimport { haStyle } from \"../homeassistant-frontend/src/resources/styles\";\nimport { HomeAssistant, Route } from \"../homeassistant-frontend/src/types\";\nimport {\n subscribeDeviceRegistry,\n DeviceRegistryEntry,\n} from \"../homeassistant-frontend/src/data/device_registry\";\nimport { Insteon } from \"./data/insteon\";\nimport { navigate } from \"../homeassistant-frontend/src/common/navigate\";\nimport { HASSDomEvent } from \"../homeassistant-frontend/src/common/dom/fire_event\";\nimport {\n AreaRegistryEntry,\n subscribeAreaRegistry,\n} from \"../homeassistant-frontend/src/data/area_registry\";\nimport { showInsteonAddDeviceDialog } from \"./device/show-dialog-insteon-add-device\";\nimport { showInsteonAddingDeviceDialog } from \"./device/show-dialog-adding-device\";\nimport { insteonMainTabs } from \"./insteon-router\";\nimport \"../homeassistant-frontend/src/components/ha-fab\";\n\ninterface DeviceRowData extends DataTableRowData {\n id: string;\n name: string;\n address: string;\n description: string;\n model: string;\n area: string;\n}\n\n@customElement(\"insteon-devices-panel\")\nexport class InsteonDevicesPanel extends LitElement {\n @property({ attribute: false }) public hass!: HomeAssistant;\n\n @property({ type: Object }) public insteon!: Insteon;\n\n @property({ type: Object }) public route!: Route;\n\n @property({ type: Boolean }) public narrow = false;\n\n @property({ type: Array }) private _devices: DeviceRegistryEntry[] = [];\n\n private _areas: AreaRegistryEntry[] = [];\n\n private _unsubs?: UnsubscribeFunc[];\n\n public firstUpdated(changedProperties) {\n super.firstUpdated(changedProperties);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n if (!this._unsubs) {\n this._getDevices();\n }\n }\n\n public updated(changedProperties) {\n super.updated(changedProperties);\n\n if (!this.hass || !this.insteon) {\n return;\n }\n if (!this._unsubs) {\n this._getDevices();\n }\n }\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n if (this._unsubs) {\n while (this._unsubs.length) {\n this._unsubs.pop()!();\n }\n this._unsubs = undefined;\n }\n }\n\n private _getDevices() {\n if (!this.insteon || !this.hass) {\n return;\n }\n\n this._unsubs = [\n subscribeAreaRegistry(this.hass.connection, (areas) => {\n this._areas = areas;\n }),\n subscribeDeviceRegistry(this.hass.connection, (entries) => {\n this._devices = entries.filter(\n (device) =>\n device.config_entries &&\n device.config_entries.includes(this.insteon.config_entry.entry_id)\n );\n }),\n ];\n }\n\n private _columns = memoizeOne((narrow: boolean) =>\n narrow\n ? {\n name: {\n title: \"Device\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n grows: true,\n },\n address: {\n title: \"Address\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"5hv\",\n },\n }\n : {\n name: {\n title: \"Device\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n grows: true,\n },\n address: {\n title: \"Address\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"20%\",\n },\n description: {\n title: \"Description\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"15%\",\n },\n model: {\n title: \"Model\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"15%\",\n },\n area: {\n title: \"Area\",\n sortable: true,\n filterable: true,\n direction: \"asc\",\n width: \"15%\",\n },\n }\n );\n\n private _insteonDevices = memoizeOne((devices: DeviceRegistryEntry[]) => {\n const areaLookup: { [areaId: string]: AreaRegistryEntry } = {};\n for (const area of this._areas) {\n areaLookup[area.area_id] = area;\n }\n\n const insteonDevices: DeviceRowData[] = devices.map((device) => {\n const deviceRowdata: DeviceRowData = {\n id: device.id,\n name: device.name_by_user || device.name || \"No device name\",\n address: device.name?.substring(device.name.length - 8) || \"\",\n description: device.name?.substring(0, device.name.length - 8) || \"\",\n model: device.model || \"\",\n area: device.area_id ? areaLookup[device.area_id].name : \"\",\n };\n return deviceRowdata;\n });\n return insteonDevices;\n });\n\n protected render(): TemplateResult | void {\n return html`\n <hass-tabs-subpage-data-table\n .hass=${this.hass}\n .narrow=${this.narrow}\n .tabs=${insteonMainTabs}\n .route=${this.route}\n .data=${this._insteonDevices(this._devices)}\n .columns=${this._columns(this.narrow)}\n @row-click=${this._handleRowClicked}\n clickable\n .localizeFunc=${this.insteon.localize}\n .mainPage=${true}\n .hasFab=${true}\n >\n <ha-fab\n slot=\"fab\"\n .label=${this.insteon.localize(\"devices.add_device\")}\n extended\n @click=${this._addDevice}\n >\n <ha-svg-icon slot=\"icon\" .path=${mdiPlus}></ha-svg-icon>\n </ha-fab>\n </hass-tabs-subpage-data-table>\n `;\n }\n\n private async _addDevice(): Promise<void> {\n showInsteonAddDeviceDialog(this, {\n hass: this.hass,\n insteon: this.insteon,\n title: this.insteon.localize(\"device.actions.add\"),\n callback: async (address, multiple) => this._handleDeviceAdd(address, multiple),\n });\n }\n\n private async _handleDeviceAdd(address: string, multiple: boolean) {\n showInsteonAddingDeviceDialog(this, {\n hass: this.hass,\n insteon: this.insteon,\n multiple: multiple,\n address: address,\n title: \"Adding Insteon Device\",\n });\n }\n\n private async _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>): Promise<void> {\n // eslint-disable-next-line no-console\n // console.info(\"Row clicked received\");\n const id = ev.detail.id;\n navigate(\"/insteon/device/properties/\" + id);\n }\n\n static get styles(): CSSResultGroup {\n return [\n css`\n ha-data-table {\n width: 100%;\n height: 100%;\n --data-table-border-width: 0;\n }\n :host(:not([narrow])) ha-data-table {\n height: calc(100vh - 1px - var(--header-height));\n display: block;\n }\n :host([narrow]) hass-tabs-subpage {\n --main-title-margin: 0;\n }\n .table-header {\n display: flex;\n align-items: center;\n --mdc-shape-small: 0;\n height: 56px;\n }\n .search-toolbar {\n display: flex;\n align-items: center;\n color: var(--secondary-text-color);\n }\n search-input {\n --mdc-text-field-fill-color: var(--sidebar-background-color);\n --mdc-text-field-idle-line-color: var(--divider-color);\n --text-field-overflow: visible;\n z-index: 5;\n }\n .table-header search-input {\n display: block;\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n }\n .search-toolbar search-input {\n display: block;\n width: 100%;\n color: var(--secondary-text-color);\n --mdc-ripple-color: transparant;\n }\n #fab {\n position: fixed;\n right: calc(16px + env(safe-area-inset-right));\n bottom: calc(16px + env(safe-area-inset-bottom));\n z-index: 1;\n }\n :host([narrow]) #fab.tabs {\n bottom: calc(84px + env(safe-area-inset-bottom));\n }\n #fab[is-wide] {\n bottom: 24px;\n right: 24px;\n }\n :host([rtl]) #fab {\n right: auto;\n left: calc(16px + env(safe-area-inset-left));\n }\n :host([rtl][is-wide]) #fab {\n bottom: 24px;\n left: 24px;\n right: auto;\n }\n `,\n haStyle,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"insteon-devices-panel\": InsteonDevicesPanel;\n }\n}\n"],"names":[],"sourceRoot":""}
|