mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 03:06:41 +00:00
commit
f5b3a82922
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20190917.1",
|
version="20190917.2",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
property,
|
property,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { SubscribeMixin } from "../../../src/mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
||||||
|
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
@ -68,7 +68,6 @@ export interface DataTabelColumnData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface DataTabelRowData {
|
export interface DataTabelRowData {
|
||||||
id: string;
|
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,9 +401,7 @@ export class HaDataTable extends BaseElement {
|
|||||||
const rowId = (ev.target as HTMLElement)
|
const rowId = (ev.target as HTMLElement)
|
||||||
.closest("tr")!
|
.closest("tr")!
|
||||||
.getAttribute("data-row-id")!;
|
.getAttribute("data-row-id")!;
|
||||||
fireEvent(this, "row-click", {
|
fireEvent(this, "row-click", { id: rowId }, { bubbles: false });
|
||||||
id: rowId,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setRowChecked(rowId: string, checked: boolean) {
|
private _setRowChecked(rowId: string, checked: boolean) {
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
PropertyDeclarations,
|
PropertyDeclarations,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
export interface HassSubscribeElement {
|
export interface HassSubscribeElement {
|
||||||
hassSubscribe(): UnsubscribeFunc[];
|
hassSubscribe(): UnsubscribeFunc[];
|
||||||
@ -16,6 +17,7 @@ export const SubscribeMixin = <T extends LitElement>(
|
|||||||
): Constructor<T & HassSubscribeElement> =>
|
): Constructor<T & HassSubscribeElement> =>
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
class extends superClass {
|
class extends superClass {
|
||||||
|
private hass?: HomeAssistant;
|
||||||
/* tslint:disable-next-line */
|
/* tslint:disable-next-line */
|
||||||
private __unsubs?: UnsubscribeFunc[];
|
private __unsubs?: UnsubscribeFunc[];
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ export const SubscribeMixin = <T extends LitElement>(
|
|||||||
if (
|
if (
|
||||||
this.__unsubs !== undefined ||
|
this.__unsubs !== undefined ||
|
||||||
!((this as unknown) as Element).isConnected ||
|
!((this as unknown) as Element).isConnected ||
|
||||||
super.hass === undefined
|
this.hass === undefined
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,17 @@ class HaConfigDashboard extends NavigateMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
<ha-icon-next></ha-icon-next>
|
<ha-icon-next></ha-icon-next>
|
||||||
</paper-item>
|
</paper-item>
|
||||||
</a>
|
</a>
|
||||||
|
<a href='/config/devices/dashboard' tabindex="-1">
|
||||||
|
<paper-item>
|
||||||
|
<paper-item-body two-line>
|
||||||
|
[[localize('ui.panel.config.devices.caption')]]
|
||||||
|
<div secondary>
|
||||||
|
[[localize('ui.panel.config.devices.description')]]
|
||||||
|
</div>
|
||||||
|
</paper-item-body>
|
||||||
|
<ha-icon-next></ha-icon-next>
|
||||||
|
</paper-item>
|
||||||
|
</a>
|
||||||
|
|
||||||
<a href='/config/users' tabindex="-1">
|
<a href='/config/users' tabindex="-1">
|
||||||
<paper-item>
|
<paper-item>
|
||||||
|
80
src/panels/config/devices/ha-config-device-page.ts
Normal file
80
src/panels/config/devices/ha-config-device-page.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { property, LitElement, html, customElement } from "lit-element";
|
||||||
|
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
|
||||||
|
import "../../../layouts/hass-subpage";
|
||||||
|
import "../../../layouts/hass-error-screen";
|
||||||
|
|
||||||
|
import "./ha-device-card";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { ConfigEntry } from "../../../data/config_entries";
|
||||||
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
|
import {
|
||||||
|
DeviceRegistryEntry,
|
||||||
|
updateDeviceRegistryEntry,
|
||||||
|
} from "../../../data/device_registry";
|
||||||
|
import { AreaRegistryEntry } from "../../../data/area_registry";
|
||||||
|
import {
|
||||||
|
loadDeviceRegistryDetailDialog,
|
||||||
|
showDeviceRegistryDetailDialog,
|
||||||
|
} from "../../../dialogs/device-registry-detail/show-dialog-device-registry-detail";
|
||||||
|
|
||||||
|
@customElement("ha-config-device-page")
|
||||||
|
export class HaConfigDevicePage extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
@property() public devices!: DeviceRegistryEntry[];
|
||||||
|
@property() public entries!: ConfigEntry[];
|
||||||
|
@property() public entities!: EntityRegistryEntry[];
|
||||||
|
@property() public areas!: AreaRegistryEntry[];
|
||||||
|
@property() public deviceId!: string;
|
||||||
|
|
||||||
|
private _device = memoizeOne(
|
||||||
|
(
|
||||||
|
deviceId: string,
|
||||||
|
devices: DeviceRegistryEntry[]
|
||||||
|
): DeviceRegistryEntry | undefined =>
|
||||||
|
devices ? devices.find((device) => device.id === deviceId) : undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
loadDeviceRegistryDetailDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
const device = this._device(this.deviceId, this.devices);
|
||||||
|
|
||||||
|
if (!device) {
|
||||||
|
return html`
|
||||||
|
<hass-error-screen error="Device not found."></hass-error-screen>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<hass-subpage .header=${device.name_by_user || device.name}>
|
||||||
|
<paper-icon-button
|
||||||
|
slot="toolbar-icon"
|
||||||
|
icon="hass:settings"
|
||||||
|
@click=${this._showSettings}
|
||||||
|
></paper-icon-button>
|
||||||
|
<ha-device-card
|
||||||
|
.hass=${this.hass}
|
||||||
|
.areas=${this.areas}
|
||||||
|
.devices=${this.devices}
|
||||||
|
.device=${device}
|
||||||
|
.entities=${this.entities}
|
||||||
|
hide-settings
|
||||||
|
></ha-device-card>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _showSettings() {
|
||||||
|
showDeviceRegistryDetailDialog(this, {
|
||||||
|
device: this._device(this.deviceId, this.devices)!,
|
||||||
|
updateEntry: async (updates) => {
|
||||||
|
await updateDeviceRegistryEntry(this.hass, this.deviceId, updates);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
238
src/panels/config/devices/ha-config-devices-dashboard.ts
Normal file
238
src/panels/config/devices/ha-config-devices-dashboard.ts
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
|
import "@material/mwc-button";
|
||||||
|
import "@polymer/iron-icon/iron-icon";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-item/paper-item-body";
|
||||||
|
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-data-table";
|
||||||
|
import "../../../components/entity/ha-state-icon";
|
||||||
|
import "../../../layouts/hass-subpage";
|
||||||
|
import "../../../resources/ha-style";
|
||||||
|
import "../../../components/ha-icon-next";
|
||||||
|
|
||||||
|
import "../ha-config-section";
|
||||||
|
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
|
||||||
|
import {
|
||||||
|
LitElement,
|
||||||
|
html,
|
||||||
|
TemplateResult,
|
||||||
|
property,
|
||||||
|
customElement,
|
||||||
|
} from "lit-element";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
// tslint:disable-next-line
|
||||||
|
import {
|
||||||
|
DataTabelColumnContainer,
|
||||||
|
RowClickedEvent,
|
||||||
|
DataTabelRowData,
|
||||||
|
} from "../../../components/ha-data-table";
|
||||||
|
// tslint:disable-next-line
|
||||||
|
import { DeviceRegistryEntry } from "../../../data/device_registry";
|
||||||
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
|
import { ConfigEntry } from "../../../data/config_entries";
|
||||||
|
import { AreaRegistryEntry } from "../../../data/area_registry";
|
||||||
|
import { navigate } from "../../../common/navigate";
|
||||||
|
|
||||||
|
interface DeviceRowData extends DeviceRegistryEntry {
|
||||||
|
device?: DeviceRowData;
|
||||||
|
area?: string;
|
||||||
|
integration?: string;
|
||||||
|
battery_entity?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("ha-config-devices-dashboard")
|
||||||
|
export class HaConfigDeviceDashboard extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
@property() public narrow = false;
|
||||||
|
@property() public devices!: DeviceRegistryEntry[];
|
||||||
|
@property() public entries!: ConfigEntry[];
|
||||||
|
@property() public entities!: EntityRegistryEntry[];
|
||||||
|
@property() public areas!: AreaRegistryEntry[];
|
||||||
|
@property() public domain!: string;
|
||||||
|
|
||||||
|
private _devices = memoizeOne(
|
||||||
|
(
|
||||||
|
devices: DeviceRegistryEntry[],
|
||||||
|
entries: ConfigEntry[],
|
||||||
|
entities: EntityRegistryEntry[],
|
||||||
|
areas: AreaRegistryEntry[],
|
||||||
|
domain: string
|
||||||
|
) => {
|
||||||
|
let outputDevices: DeviceRowData[] = devices;
|
||||||
|
if (domain) {
|
||||||
|
outputDevices = outputDevices.filter(
|
||||||
|
(device) =>
|
||||||
|
entries.find((entry) =>
|
||||||
|
device.config_entries.includes(entry.entry_id)
|
||||||
|
)!.domain === domain
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
outputDevices = outputDevices.map((device) => {
|
||||||
|
const output = { ...device };
|
||||||
|
output.name = device.name_by_user || device.name || "No name";
|
||||||
|
|
||||||
|
output.area =
|
||||||
|
!areas || !device || !device.area_id
|
||||||
|
? "No area"
|
||||||
|
: areas.find((area) => area.area_id === device.area_id)!.name;
|
||||||
|
|
||||||
|
output.integration =
|
||||||
|
!entries || !device || !device.config_entries
|
||||||
|
? "No integration"
|
||||||
|
: entries.find((entry) =>
|
||||||
|
device.config_entries.includes(entry.entry_id)
|
||||||
|
)!.domain;
|
||||||
|
|
||||||
|
output.battery_entity = this._batteryEntity(device, entities);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
});
|
||||||
|
|
||||||
|
return outputDevices;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
private _columns = memoizeOne(
|
||||||
|
(narrow: boolean): DataTabelColumnContainer =>
|
||||||
|
narrow
|
||||||
|
? {
|
||||||
|
device: {
|
||||||
|
title: "Device",
|
||||||
|
sortable: true,
|
||||||
|
filterKey: "name",
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
template: (device: DeviceRowData) => {
|
||||||
|
const battery = device.battery_entity
|
||||||
|
? this.hass.states[device.battery_entity]
|
||||||
|
: undefined;
|
||||||
|
// Have to work on a nice layout for mobile
|
||||||
|
return html`
|
||||||
|
${device.name_by_user || device.name}<br />
|
||||||
|
${device.area} | ${device.integration}<br />
|
||||||
|
${battery
|
||||||
|
? html`
|
||||||
|
${battery.state}%
|
||||||
|
<ha-state-icon
|
||||||
|
.hass=${this.hass!}
|
||||||
|
.stateObj=${battery}
|
||||||
|
></ha-state-icon>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
device_name: {
|
||||||
|
title: "Device",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
},
|
||||||
|
manufacturer: {
|
||||||
|
title: "Manufacturer",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
title: "Model",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
area: {
|
||||||
|
title: "Area",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
integration: {
|
||||||
|
title: "Integration",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
battery: {
|
||||||
|
title: "Battery",
|
||||||
|
sortable: true,
|
||||||
|
type: "numeric",
|
||||||
|
template: (batteryEntity: string) => {
|
||||||
|
const battery = batteryEntity
|
||||||
|
? this.hass.states[batteryEntity]
|
||||||
|
: undefined;
|
||||||
|
return battery
|
||||||
|
? html`
|
||||||
|
${battery.state}%
|
||||||
|
<ha-state-icon
|
||||||
|
.hass=${this.hass!}
|
||||||
|
.stateObj=${battery}
|
||||||
|
></ha-state-icon>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
n/a
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<hass-subpage
|
||||||
|
header=${this.hass.localize("ui.panel.config.devices.caption")}
|
||||||
|
>
|
||||||
|
<ha-data-table
|
||||||
|
.columns=${this._columns(this.narrow)}
|
||||||
|
.data=${this._devices(
|
||||||
|
this.devices,
|
||||||
|
this.entries,
|
||||||
|
this.entities,
|
||||||
|
this.areas,
|
||||||
|
this.domain
|
||||||
|
).map((device: DeviceRowData) => {
|
||||||
|
// We don't need a lot of this data for mobile view, but kept it for filtering...
|
||||||
|
const data: DataTabelRowData = {
|
||||||
|
device_name: device.name,
|
||||||
|
id: device.id,
|
||||||
|
manufacturer: device.manufacturer,
|
||||||
|
model: device.model,
|
||||||
|
area: device.area,
|
||||||
|
integration: device.integration,
|
||||||
|
};
|
||||||
|
if (this.narrow) {
|
||||||
|
data.device = device;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data.battery = device.battery_entity;
|
||||||
|
return data;
|
||||||
|
})}
|
||||||
|
@row-click=${this._handleRowClicked}
|
||||||
|
></ha-data-table>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _batteryEntity(device, entities): string | undefined {
|
||||||
|
const batteryEntity = entities.find(
|
||||||
|
(entity) =>
|
||||||
|
entity.device_id === device.id &&
|
||||||
|
this.hass.states[entity.entity_id] &&
|
||||||
|
this.hass.states[entity.entity_id].attributes.device_class === "battery"
|
||||||
|
);
|
||||||
|
|
||||||
|
return batteryEntity ? batteryEntity.entity_id : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleRowClicked(ev: CustomEvent) {
|
||||||
|
const deviceId = (ev.detail as RowClickedEvent).id;
|
||||||
|
navigate(this, `/config/devices/device/${deviceId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-config-devices-dashboard": HaConfigDeviceDashboard;
|
||||||
|
}
|
||||||
|
}
|
127
src/panels/config/devices/ha-config-devices.ts
Normal file
127
src/panels/config/devices/ha-config-devices.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import "@polymer/app-route/app-route";
|
||||||
|
|
||||||
|
import "./ha-config-devices-dashboard";
|
||||||
|
import "./ha-config-device-page";
|
||||||
|
import { compare } from "../../../common/string/compare";
|
||||||
|
import {
|
||||||
|
subscribeAreaRegistry,
|
||||||
|
AreaRegistryEntry,
|
||||||
|
} from "../../../data/area_registry";
|
||||||
|
import {
|
||||||
|
HassRouterPage,
|
||||||
|
RouterOptions,
|
||||||
|
} from "../../../layouts/hass-router-page";
|
||||||
|
import { property, customElement, PropertyValues } from "lit-element";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
|
||||||
|
import {
|
||||||
|
EntityRegistryEntry,
|
||||||
|
subscribeEntityRegistry,
|
||||||
|
} from "../../../data/entity_registry";
|
||||||
|
import {
|
||||||
|
DeviceRegistryEntry,
|
||||||
|
subscribeDeviceRegistry,
|
||||||
|
} from "../../../data/device_registry";
|
||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
|
|
||||||
|
@customElement("ha-config-devices")
|
||||||
|
class HaConfigDevices extends HassRouterPage {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
|
protected routerOptions: RouterOptions = {
|
||||||
|
defaultPage: "dashboard",
|
||||||
|
routes: {
|
||||||
|
dashboard: {
|
||||||
|
tag: "ha-config-devices-dashboard",
|
||||||
|
},
|
||||||
|
device: {
|
||||||
|
tag: "ha-config-device-page",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@property() private _configEntries?: ConfigEntry[];
|
||||||
|
@property() private _entityRegistryEntries?: EntityRegistryEntry[];
|
||||||
|
@property() private _deviceRegistryEntries?: DeviceRegistryEntry[];
|
||||||
|
@property() private _areas?: AreaRegistryEntry[];
|
||||||
|
|
||||||
|
private _unsubs?: UnsubscribeFunc[];
|
||||||
|
|
||||||
|
public connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
|
||||||
|
if (!this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
if (this._unsubs) {
|
||||||
|
while (this._unsubs.length) {
|
||||||
|
this._unsubs.pop()!();
|
||||||
|
}
|
||||||
|
this._unsubs = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this.addEventListener("hass-reload-entries", () => {
|
||||||
|
this._loadData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (!this._unsubs && changedProps.has("hass")) {
|
||||||
|
this._loadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updatePageEl(pageEl) {
|
||||||
|
pageEl.hass = this.hass;
|
||||||
|
|
||||||
|
if (this._currentPage === "dashboard") {
|
||||||
|
pageEl.domain = this.routeTail.path.substr(1);
|
||||||
|
} else if (this._currentPage === "device") {
|
||||||
|
pageEl.deviceId = this.routeTail.path.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pageEl.entities = this._entityRegistryEntries;
|
||||||
|
pageEl.entries = this._configEntries;
|
||||||
|
pageEl.devices = this._deviceRegistryEntries;
|
||||||
|
pageEl.areas = this._areas;
|
||||||
|
pageEl.narrow = this.narrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _loadData() {
|
||||||
|
getConfigEntries(this.hass).then((configEntries) => {
|
||||||
|
this._configEntries = configEntries.sort((conf1, conf2) =>
|
||||||
|
compare(conf1.title, conf2.title)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (this._unsubs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._unsubs = [
|
||||||
|
subscribeAreaRegistry(this.hass.connection, (areas) => {
|
||||||
|
this._areas = areas;
|
||||||
|
}),
|
||||||
|
subscribeEntityRegistry(this.hass.connection, (entries) => {
|
||||||
|
this._entityRegistryEntries = entries;
|
||||||
|
}),
|
||||||
|
subscribeDeviceRegistry(this.hass.connection, (entries) => {
|
||||||
|
this._deviceRegistryEntries = entries;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-config-devices": HaConfigDevices;
|
||||||
|
}
|
||||||
|
}
|
@ -6,23 +6,23 @@ import "@polymer/paper-listbox/paper-listbox";
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import "../../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
|
|
||||||
import { EventsMixin } from "../../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import computeStateName from "../../../../common/entity/compute_state_name";
|
import computeStateName from "../../../common/entity/compute_state_name";
|
||||||
import "../../../../components/entity/state-badge";
|
import "../../../components/entity/state-badge";
|
||||||
import { compare } from "../../../../common/string/compare";
|
import { compare } from "../../../common/string/compare";
|
||||||
import {
|
import {
|
||||||
subscribeDeviceRegistry,
|
subscribeDeviceRegistry,
|
||||||
updateDeviceRegistryEntry,
|
updateDeviceRegistryEntry,
|
||||||
} from "../../../../data/device_registry";
|
} from "../../../data/device_registry";
|
||||||
import { subscribeAreaRegistry } from "../../../../data/area_registry";
|
import { subscribeAreaRegistry } from "../../../data/area_registry";
|
||||||
import {
|
import {
|
||||||
loadDeviceRegistryDetailDialog,
|
loadDeviceRegistryDetailDialog,
|
||||||
showDeviceRegistryDetailDialog,
|
showDeviceRegistryDetailDialog,
|
||||||
} from "../../../../dialogs/device-registry-detail/show-dialog-device-registry-detail";
|
} from "../../../dialogs/device-registry-detail/show-dialog-device-registry-detail";
|
||||||
|
|
||||||
function computeEntityName(hass, entity) {
|
function computeEntityName(hass, entity) {
|
||||||
if (entity.name) return entity.name;
|
if (entity.name) return entity.name;
|
||||||
@ -83,11 +83,13 @@ class HaDeviceCard extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
</style>
|
</style>
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
<template is="dom-if" if="[[!hideSettings]]">
|
||||||
<div class="name">[[_deviceName(device)]]</div>
|
<div class="name">[[_deviceName(device)]]</div>
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
icon="hass:settings"
|
icon="hass:settings"
|
||||||
on-click="_gotoSettings"
|
on-click="_gotoSettings"
|
||||||
></paper-icon-button>
|
></paper-icon-button>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
@ -154,6 +156,7 @@ class HaDeviceCard extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
reflectToAttribute: true,
|
reflectToAttribute: true,
|
||||||
},
|
},
|
||||||
|
hideSettings: { type: Boolean, value: false },
|
||||||
_childDevices: {
|
_childDevices: {
|
||||||
type: Array,
|
type: Array,
|
||||||
computed: "_computeChildDevices(device, devices)",
|
computed: "_computeChildDevices(device, devices)",
|
@ -48,6 +48,11 @@ class HaPanelConfig extends HassRouterPage {
|
|||||||
load: () =>
|
load: () =>
|
||||||
import(/* webpackChunkName: "panel-config-core" */ "./core/ha-config-core"),
|
import(/* webpackChunkName: "panel-config-core" */ "./core/ha-config-core"),
|
||||||
},
|
},
|
||||||
|
devices: {
|
||||||
|
tag: "ha-config-devices",
|
||||||
|
load: () =>
|
||||||
|
import(/* webpackChunkName: "panel-config-devices" */ "./devices/ha-config-devices"),
|
||||||
|
},
|
||||||
server_control: {
|
server_control: {
|
||||||
tag: "ha-config-server-control",
|
tag: "ha-config-server-control",
|
||||||
load: () =>
|
load: () =>
|
||||||
|
@ -5,7 +5,7 @@ import "../../../../layouts/hass-error-screen";
|
|||||||
import "../../../../components/entity/state-badge";
|
import "../../../../components/entity/state-badge";
|
||||||
import { compare } from "../../../../common/string/compare";
|
import { compare } from "../../../../common/string/compare";
|
||||||
|
|
||||||
import "./ha-device-card";
|
import "../../devices/ha-device-card";
|
||||||
import "./ha-ce-entities-card";
|
import "./ha-ce-entities-card";
|
||||||
import { showOptionsFlowDialog } from "../../../../dialogs/config-flow/show-dialog-options-flow";
|
import { showOptionsFlowDialog } from "../../../../dialogs/config-flow/show-dialog-options-flow";
|
||||||
import { property, LitElement, CSSResult, css, html } from "lit-element";
|
import { property, LitElement, CSSResult, css, html } from "lit-element";
|
||||||
@ -106,6 +106,7 @@ class HaConfigEntryPage extends LitElement {
|
|||||||
icon="hass:delete"
|
icon="hass:delete"
|
||||||
@click=${this._removeEntry}
|
@click=${this._removeEntry}
|
||||||
></paper-icon-button>
|
></paper-icon-button>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${configEntryDevices.length === 0 && noDeviceEntities.length === 0
|
${configEntryDevices.length === 0 && noDeviceEntities.length === 0
|
||||||
? html`
|
? html`
|
||||||
|
@ -1,235 +0,0 @@
|
|||||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
|
||||||
import "@polymer/paper-tooltip/paper-tooltip";
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import "@polymer/iron-icon/iron-icon";
|
|
||||||
import "@polymer/paper-item/paper-item";
|
|
||||||
import "@polymer/paper-item/paper-item-body";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
|
|
||||||
import "../../../components/ha-card";
|
|
||||||
import "../../../components/ha-fab";
|
|
||||||
import "../../../components/entity/ha-state-icon";
|
|
||||||
import "../../../layouts/hass-subpage";
|
|
||||||
import "../../../resources/ha-style";
|
|
||||||
import "../../../components/ha-icon-next";
|
|
||||||
|
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
|
||||||
import "../ha-config-section";
|
|
||||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
|
||||||
import computeStateName from "../../../common/entity/compute_state_name";
|
|
||||||
import {
|
|
||||||
loadConfigFlowDialog,
|
|
||||||
showConfigFlowDialog,
|
|
||||||
} from "../../../dialogs/config-flow/show-dialog-config-flow";
|
|
||||||
import { localizeConfigFlowTitle } from "../../../data/config_flow";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @appliesMixin LocalizeMixin
|
|
||||||
* @appliesMixin EventsMixin
|
|
||||||
*/
|
|
||||||
class HaConfigManagerDashboard extends LocalizeMixin(
|
|
||||||
EventsMixin(PolymerElement)
|
|
||||||
) {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style include="iron-flex ha-style">
|
|
||||||
ha-card {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
mwc-button {
|
|
||||||
top: 3px;
|
|
||||||
margin-right: -0.57em;
|
|
||||||
}
|
|
||||||
.config-entry-row {
|
|
||||||
display: flex;
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
ha-state-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.configured a {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
ha-fab {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 16px;
|
|
||||||
right: 16px;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-fab[is-wide] {
|
|
||||||
bottom: 24px;
|
|
||||||
right: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-fab[rtl] {
|
|
||||||
right: auto;
|
|
||||||
left: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-fab[rtl][is-wide] {
|
|
||||||
bottom: 24px;
|
|
||||||
right: auto;
|
|
||||||
left: 24px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<hass-subpage
|
|
||||||
header="[[localize('ui.panel.config.integrations.caption')]]"
|
|
||||||
>
|
|
||||||
<template is="dom-if" if="[[progress.length]]">
|
|
||||||
<ha-config-section>
|
|
||||||
<span slot="header"
|
|
||||||
>[[localize('ui.panel.config.integrations.discovered')]]</span
|
|
||||||
>
|
|
||||||
<ha-card>
|
|
||||||
<template is="dom-repeat" items="[[progress]]">
|
|
||||||
<div class="config-entry-row">
|
|
||||||
<paper-item-body>
|
|
||||||
[[_computeActiveFlowTitle(localize, item)]]
|
|
||||||
</paper-item-body>
|
|
||||||
<mwc-button on-click="_continueFlow"
|
|
||||||
>[[localize('ui.panel.config.integrations.configure')]]</mwc-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<ha-config-section class="configured">
|
|
||||||
<span slot="header"
|
|
||||||
>[[localize('ui.panel.config.integrations.configured')]]</span
|
|
||||||
>
|
|
||||||
<ha-card>
|
|
||||||
<template is="dom-if" if="[[!entries.length]]">
|
|
||||||
<div class="config-entry-row">
|
|
||||||
<paper-item-body two-line>
|
|
||||||
<div>[[localize('ui.panel.config.integrations.none')]]</div>
|
|
||||||
</paper-item-body>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template is="dom-repeat" items="[[entries]]">
|
|
||||||
<a href="/config/integrations/config_entry/[[item.entry_id]]">
|
|
||||||
<paper-item>
|
|
||||||
<paper-item-body two-line>
|
|
||||||
<div>
|
|
||||||
[[_computeIntegrationTitle(localize, item.domain)]]:
|
|
||||||
[[item.title]]
|
|
||||||
</div>
|
|
||||||
<div secondary>
|
|
||||||
<template
|
|
||||||
is="dom-repeat"
|
|
||||||
items="[[_computeConfigEntryEntities(hass, item, entities)]]"
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<ha-state-icon state-obj="[[item]]"></ha-state-icon>
|
|
||||||
<paper-tooltip position="bottom"
|
|
||||||
>[[_computeStateName(item)]]</paper-tooltip
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</paper-item-body>
|
|
||||||
<ha-icon-next></ha-icon-next>
|
|
||||||
</paper-item>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
|
||||||
|
|
||||||
<ha-fab
|
|
||||||
icon="hass:plus"
|
|
||||||
title="[[localize('ui.panel.config.integrations.new')]]"
|
|
||||||
on-click="_createFlow"
|
|
||||||
is-wide$="[[isWide]]"
|
|
||||||
rtl$="[[rtl]]"
|
|
||||||
></ha-fab>
|
|
||||||
</hass-subpage>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
hass: Object,
|
|
||||||
isWide: Boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Existing entries.
|
|
||||||
*/
|
|
||||||
entries: Array,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entity Registry entries.
|
|
||||||
*/
|
|
||||||
entities: Array,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current flows that are in progress and have not been started by a user.
|
|
||||||
* For example, can be discovered devices that require more config.
|
|
||||||
*/
|
|
||||||
progress: Array,
|
|
||||||
|
|
||||||
rtl: {
|
|
||||||
type: Boolean,
|
|
||||||
reflectToAttribute: true,
|
|
||||||
computed: "_computeRTL(hass)",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
loadConfigFlowDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
_createFlow() {
|
|
||||||
showConfigFlowDialog(this, {
|
|
||||||
dialogClosedCallback: () => this.fire("hass-reload-entries"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_continueFlow(ev) {
|
|
||||||
showConfigFlowDialog(this, {
|
|
||||||
continueFlowId: ev.model.item.flow_id,
|
|
||||||
dialogClosedCallback: () => this.fire("hass-reload-entries"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeIntegrationTitle(localize, integration) {
|
|
||||||
return localize(`component.${integration}.config.title`);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeActiveFlowTitle(localize, flow) {
|
|
||||||
return localizeConfigFlowTitle(localize, flow);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeConfigEntryEntities(hass, configEntry, entities) {
|
|
||||||
if (!entities) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const states = [];
|
|
||||||
entities.forEach((entity) => {
|
|
||||||
if (
|
|
||||||
entity.config_entry_id === configEntry.entry_id &&
|
|
||||||
entity.entity_id in hass.states
|
|
||||||
) {
|
|
||||||
states.push(hass.states[entity.entity_id]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return states;
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeStateName(stateObj) {
|
|
||||||
return computeStateName(stateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeRTL(hass) {
|
|
||||||
return computeRTL(hass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("ha-config-entries-dashboard", HaConfigManagerDashboard);
|
|
237
src/panels/config/integrations/ha-config-entries-dashboard.ts
Normal file
237
src/panels/config/integrations/ha-config-entries-dashboard.ts
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||||
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
|
import "@material/mwc-button";
|
||||||
|
import "@polymer/iron-icon/iron-icon";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-item/paper-item-body";
|
||||||
|
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-icon-next";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
|
import "../../../components/entity/ha-state-icon";
|
||||||
|
import "../../../layouts/hass-subpage";
|
||||||
|
import "../../../resources/ha-style";
|
||||||
|
import "../../../components/ha-icon";
|
||||||
|
|
||||||
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
|
import "../ha-config-section";
|
||||||
|
|
||||||
|
import computeStateName from "../../../common/entity/compute_state_name";
|
||||||
|
import {
|
||||||
|
loadConfigFlowDialog,
|
||||||
|
showConfigFlowDialog,
|
||||||
|
} from "../../../dialogs/config-flow/show-dialog-config-flow";
|
||||||
|
import { localizeConfigFlowTitle } from "../../../data/config_flow";
|
||||||
|
import {
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
customElement,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { ConfigEntry } from "../../../data/config_entries";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
|
|
||||||
|
@customElement("ha-config-entries-dashboard")
|
||||||
|
export class HaConfigManagerDashboard extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public isWide = false;
|
||||||
|
|
||||||
|
@property() private entries = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity Registry entries.
|
||||||
|
*/
|
||||||
|
@property() private entities: EntityRegistryEntry[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current flows that are in progress and have not been started by a user.
|
||||||
|
* For example, can be discovered devices that require more config.
|
||||||
|
*/
|
||||||
|
@property() private progress = [];
|
||||||
|
|
||||||
|
public connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
loadConfigFlowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<hass-subpage
|
||||||
|
header=${this.hass.localize("ui.panel.config.integrations.caption")}
|
||||||
|
>
|
||||||
|
${this.progress.length
|
||||||
|
? html`
|
||||||
|
<ha-config-section>
|
||||||
|
<span slot="header"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.discovered"
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
<ha-card>
|
||||||
|
${this.progress.map(
|
||||||
|
(flow) => html`
|
||||||
|
<div class="config-entry-row">
|
||||||
|
<paper-item-body>
|
||||||
|
${localizeConfigFlowTitle(this.hass.localize, flow)}
|
||||||
|
</paper-item-body>
|
||||||
|
<mwc-button @click=${this._continueFlow}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.configure"
|
||||||
|
)}</mwc-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-card>
|
||||||
|
</ha-config-section>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
|
||||||
|
<ha-config-section class="configured">
|
||||||
|
<span slot="header"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.configured"
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
<ha-card>
|
||||||
|
${this.entities.length
|
||||||
|
? this.entries.map(
|
||||||
|
(item: any, idx) => html`
|
||||||
|
<a
|
||||||
|
href="/config/integrations/config_entry/${item.entry_id}"
|
||||||
|
>
|
||||||
|
<paper-item data-index=${idx}>
|
||||||
|
<paper-item-body two-line>
|
||||||
|
<div>
|
||||||
|
${this.hass.localize(
|
||||||
|
`component.${item.domain}.config.title`
|
||||||
|
)}:
|
||||||
|
${item.title}
|
||||||
|
</div>
|
||||||
|
<div secondary>
|
||||||
|
${this._getEntities(item).map(
|
||||||
|
(entity) => html`
|
||||||
|
<span>
|
||||||
|
<ha-state-icon
|
||||||
|
.stateObj=${entity}
|
||||||
|
></ha-state-icon>
|
||||||
|
<paper-tooltip position="bottom"
|
||||||
|
>${computeStateName(entity)}</paper-tooltip
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</paper-item-body>
|
||||||
|
<ha-icon-next></ha-icon-next>
|
||||||
|
</paper-item>
|
||||||
|
</a>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
: html`
|
||||||
|
<div class="config-entry-row">
|
||||||
|
<paper-item-body two-line>
|
||||||
|
<div>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.none"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</paper-item-body>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</ha-card>
|
||||||
|
</ha-config-section>
|
||||||
|
|
||||||
|
<ha-fab
|
||||||
|
icon="hass:plus"
|
||||||
|
title=${this.hass.localize("ui.panel.config.integrations.new")}
|
||||||
|
@click=${this._createFlow}
|
||||||
|
?rtl=${computeRTL(this.hass!)}
|
||||||
|
?isWide=${this.isWide}
|
||||||
|
></ha-fab>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createFlow() {
|
||||||
|
showConfigFlowDialog(this, {
|
||||||
|
dialogClosedCallback: () => fireEvent(this, "hass-reload-entries"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _continueFlow(ev) {
|
||||||
|
showConfigFlowDialog(this, {
|
||||||
|
continueFlowId: ev.model.item.flow_id,
|
||||||
|
dialogClosedCallback: () => fireEvent(this, "hass-reload-entries"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getEntities(configEntry: ConfigEntry): HassEntity[] {
|
||||||
|
if (!this.entities) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const states: HassEntity[] = [];
|
||||||
|
this.entities.forEach((entity) => {
|
||||||
|
if (
|
||||||
|
entity.config_entry_id === configEntry.entry_id &&
|
||||||
|
entity.entity_id in this.hass.states
|
||||||
|
) {
|
||||||
|
states.push(this.hass.states[entity.entity_id]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return states;
|
||||||
|
}
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
mwc-button {
|
||||||
|
top: 3px;
|
||||||
|
margin-right: -0.57em;
|
||||||
|
}
|
||||||
|
.config-entry-row {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
ha-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
.configured a {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
ha-fab {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 16px;
|
||||||
|
right: 16px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-fab[is-wide] {
|
||||||
|
bottom: 24px;
|
||||||
|
right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-fab[rtl] {
|
||||||
|
right: auto;
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-fab[rtl][is-wide] {
|
||||||
|
bottom: 24px;
|
||||||
|
right: auto;
|
||||||
|
left: 24px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
@ -137,7 +137,7 @@ documentContainer.innerHTML = `<custom-style>
|
|||||||
--mdc-theme-surface: var(--paper-card-background-color, var(--card-background-color));
|
--mdc-theme-surface: var(--paper-card-background-color, var(--card-background-color));
|
||||||
|
|
||||||
/* mwc text styles */
|
/* mwc text styles */
|
||||||
--mdc-theme-on-primary: var(--primary-text-color);
|
--mdc-theme-on-primary: var(--text-primary-color);
|
||||||
--mdc-theme-on-secondary: var(--text-primary-color);
|
--mdc-theme-on-secondary: var(--text-primary-color);
|
||||||
--mdc-theme-on-surface: var(--primary-text-color);
|
--mdc-theme-on-surface: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
@ -889,6 +889,10 @@
|
|||||||
"description_not_login": "Not logged in",
|
"description_not_login": "Not logged in",
|
||||||
"description_features": "Control away from home, integrate with Alexa and Google Assistant."
|
"description_features": "Control away from home, integrate with Alexa and Google Assistant."
|
||||||
},
|
},
|
||||||
|
"devices": {
|
||||||
|
"caption": "Devices",
|
||||||
|
"description": "Manage connected devices"
|
||||||
|
},
|
||||||
"entity_registry": {
|
"entity_registry": {
|
||||||
"caption": "Entity Registry",
|
"caption": "Entity Registry",
|
||||||
"description": "Overview of all known entities.",
|
"description": "Overview of all known entities.",
|
||||||
@ -920,7 +924,7 @@
|
|||||||
},
|
},
|
||||||
"integrations": {
|
"integrations": {
|
||||||
"caption": "Integrations",
|
"caption": "Integrations",
|
||||||
"description": "Manage connected devices and services",
|
"description": "Manage and setup integrations",
|
||||||
"discovered": "Discovered",
|
"discovered": "Discovered",
|
||||||
"configured": "Configured",
|
"configured": "Configured",
|
||||||
"new": "Set up a new integration",
|
"new": "Set up a new integration",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user