mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Rework ZHA group adds and removes (#5602)
This commit is contained in:
parent
1b2841eef9
commit
577a21fc5c
@ -3,6 +3,7 @@ import { HomeAssistant } from "../types";
|
|||||||
|
|
||||||
export interface ZHAEntityReference extends HassEntity {
|
export interface ZHAEntityReference extends HassEntity {
|
||||||
name: string;
|
name: string;
|
||||||
|
original_name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ZHADevice {
|
export interface ZHADevice {
|
||||||
@ -26,6 +27,12 @@ export interface ZHADevice {
|
|||||||
signature: any;
|
signature: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ZHADeviceEndpoint {
|
||||||
|
device: ZHADevice;
|
||||||
|
endpoint_id: number;
|
||||||
|
entities: ZHAEntityReference[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface Attribute {
|
export interface Attribute {
|
||||||
name: string;
|
name: string;
|
||||||
id: number;
|
id: number;
|
||||||
@ -56,7 +63,12 @@ export interface ReadAttributeServiceData {
|
|||||||
export interface ZHAGroup {
|
export interface ZHAGroup {
|
||||||
name: string;
|
name: string;
|
||||||
group_id: number;
|
group_id: number;
|
||||||
members: ZHADevice[];
|
members: ZHADeviceEndpoint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ZHAGroupMember {
|
||||||
|
ieee: string;
|
||||||
|
endpoint_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reconfigureNode = (
|
export const reconfigureNode = (
|
||||||
@ -213,7 +225,7 @@ export const fetchGroup = (
|
|||||||
|
|
||||||
export const fetchGroupableDevices = (
|
export const fetchGroupableDevices = (
|
||||||
hass: HomeAssistant
|
hass: HomeAssistant
|
||||||
): Promise<ZHADevice[]> =>
|
): Promise<ZHADeviceEndpoint[]> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/devices/groupable",
|
type: "zha/devices/groupable",
|
||||||
});
|
});
|
||||||
@ -221,7 +233,7 @@ export const fetchGroupableDevices = (
|
|||||||
export const addMembersToGroup = (
|
export const addMembersToGroup = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
groupId: number,
|
groupId: number,
|
||||||
membersToAdd: string[]
|
membersToAdd: ZHAGroupMember[]
|
||||||
): Promise<ZHAGroup> =>
|
): Promise<ZHAGroup> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/group/members/add",
|
type: "zha/group/members/add",
|
||||||
@ -232,7 +244,7 @@ export const addMembersToGroup = (
|
|||||||
export const removeMembersFromGroup = (
|
export const removeMembersFromGroup = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
groupId: number,
|
groupId: number,
|
||||||
membersToRemove: string[]
|
membersToRemove: ZHAGroupMember[]
|
||||||
): Promise<ZHAGroup> =>
|
): Promise<ZHAGroup> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/group/members/remove",
|
type: "zha/group/members/remove",
|
||||||
@ -243,7 +255,7 @@ export const removeMembersFromGroup = (
|
|||||||
export const addGroup = (
|
export const addGroup = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
groupName: string,
|
groupName: string,
|
||||||
membersToAdd?: string[]
|
membersToAdd?: ZHAGroupMember[]
|
||||||
): Promise<ZHAGroup> =>
|
): Promise<ZHAGroup> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/group/add",
|
type: "zha/group/add",
|
||||||
|
@ -18,31 +18,31 @@ import type { SelectionChangedEvent } from "../../../components/data-table/ha-da
|
|||||||
import {
|
import {
|
||||||
addGroup,
|
addGroup,
|
||||||
fetchGroupableDevices,
|
fetchGroupableDevices,
|
||||||
ZHADevice,
|
|
||||||
ZHAGroup,
|
ZHAGroup,
|
||||||
|
ZHADeviceEndpoint,
|
||||||
} from "../../../data/zha";
|
} from "../../../data/zha";
|
||||||
import "../../../layouts/hass-error-screen";
|
import "../../../layouts/hass-error-screen";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import type { PolymerChangedEvent } from "../../../polymer-types";
|
import type { PolymerChangedEvent } from "../../../polymer-types";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import "./zha-devices-data-table";
|
import "./zha-device-endpoint-data-table";
|
||||||
import type { ZHADevicesDataTable } from "./zha-devices-data-table";
|
import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table";
|
||||||
|
|
||||||
@customElement("zha-add-group-page")
|
@customElement("zha-add-group-page")
|
||||||
export class ZHAAddGroupPage extends LitElement {
|
export class ZHAAddGroupPage extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property() public devices: ZHADevice[] = [];
|
@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
@property() private _processingAdd = false;
|
@property() private _processingAdd = false;
|
||||||
|
|
||||||
@property() private _groupName = "";
|
@property() private _groupName = "";
|
||||||
|
|
||||||
@query("zha-devices-data-table")
|
@query("zha-device-endpoint-data-table")
|
||||||
private _zhaDevicesDataTable!: ZHADevicesDataTable;
|
private _zhaDevicesDataTable!: ZHADeviceEndpointDataTable;
|
||||||
|
|
||||||
private _firstUpdatedCalled = false;
|
private _firstUpdatedCalled = false;
|
||||||
|
|
||||||
@ -87,14 +87,14 @@ export class ZHAAddGroupPage extends LitElement {
|
|||||||
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<zha-devices-data-table
|
<zha-device-endpoint-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.devices=${this.devices}
|
.deviceEndpoints=${this.deviceEndpoints}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
selectable
|
selectable
|
||||||
@selection-changed=${this._handleAddSelectionChanged}
|
@selection-changed=${this._handleAddSelectionChanged}
|
||||||
>
|
>
|
||||||
</zha-devices-data-table>
|
</zha-device-endpoint-data-table>
|
||||||
|
|
||||||
<div class="paper-dialog-buttons">
|
<div class="paper-dialog-buttons">
|
||||||
<mwc-button
|
<mwc-button
|
||||||
@ -121,7 +121,7 @@ export class ZHAAddGroupPage extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchData() {
|
private async _fetchData() {
|
||||||
this.devices = await fetchGroupableDevices(this.hass!);
|
this.deviceEndpoints = await fetchGroupableDevices(this.hass!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleAddSelectionChanged(
|
private _handleAddSelectionChanged(
|
||||||
@ -132,11 +132,11 @@ export class ZHAAddGroupPage extends LitElement {
|
|||||||
|
|
||||||
private async _createGroup(): Promise<void> {
|
private async _createGroup(): Promise<void> {
|
||||||
this._processingAdd = true;
|
this._processingAdd = true;
|
||||||
const group: ZHAGroup = await addGroup(
|
const members = this._selectedDevicesToAdd.map((member) => {
|
||||||
this.hass,
|
const memberParts = member.split("_");
|
||||||
this._groupName,
|
return { ieee: memberParts[0], endpoint_id: memberParts[1] };
|
||||||
this._selectedDevicesToAdd
|
});
|
||||||
);
|
const group: ZHAGroup = await addGroup(this.hass, this._groupName, members);
|
||||||
this._selectedDevicesToAdd = [];
|
this._selectedDevicesToAdd = [];
|
||||||
this._processingAdd = false;
|
this._processingAdd = false;
|
||||||
this._groupName = "";
|
this._groupName = "";
|
||||||
|
@ -16,6 +16,7 @@ import "../../../components/data-table/ha-data-table";
|
|||||||
import type {
|
import type {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
|
DataTableRowData,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
@ -27,19 +28,19 @@ import type { HomeAssistant, Route } from "../../../types";
|
|||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import { formatAsPaddedHex, sortZHADevices } from "./functions";
|
import { formatAsPaddedHex, sortZHADevices } from "./functions";
|
||||||
|
|
||||||
export interface DeviceRowData extends ZHADevice {
|
export interface DeviceRowData extends DataTableRowData {
|
||||||
device?: DeviceRowData;
|
device?: DeviceRowData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("zha-config-dashboard")
|
@customElement("zha-config-dashboard")
|
||||||
class ZHAConfigDashboard extends LitElement {
|
class ZHAConfigDashboard extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public route!: Route;
|
@property({ type: Object }) public route!: Route;
|
||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property() public isWide!: boolean;
|
@property({ type: Boolean }) public isWide!: boolean;
|
||||||
|
|
||||||
@property() private _devices: ZHADevice[] = [];
|
@property() private _devices: ZHADevice[] = [];
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ class ZHAConfigDashboard extends LitElement {
|
|||||||
title: "IEEE",
|
title: "IEEE",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "25%",
|
width: "30%",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
182
src/panels/config/zha/zha-device-endpoint-data-table.ts
Normal file
182
src/panels/config/zha/zha-device-endpoint-data-table.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import "../../../components/data-table/ha-data-table";
|
||||||
|
import type {
|
||||||
|
DataTableColumnContainer,
|
||||||
|
HaDataTable,
|
||||||
|
DataTableRowData,
|
||||||
|
} from "../../../components/data-table/ha-data-table";
|
||||||
|
import "../../../components/entity/ha-state-icon";
|
||||||
|
import type { ZHADeviceEndpoint, ZHAEntityReference } from "../../../data/zha";
|
||||||
|
import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
|
export interface DeviceEndpointRowData extends DataTableRowData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
model: string;
|
||||||
|
manufacturer: string;
|
||||||
|
endpoint_id: number;
|
||||||
|
entities: ZHAEntityReference[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("zha-device-endpoint-data-table")
|
||||||
|
export class ZHADeviceEndpointDataTable extends LitElement {
|
||||||
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public selectable = false;
|
||||||
|
|
||||||
|
@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
|
@query("ha-data-table") private _dataTable!: HaDataTable;
|
||||||
|
|
||||||
|
private _deviceEndpoints = memoizeOne(
|
||||||
|
(deviceEndpoints: ZHADeviceEndpoint[]) => {
|
||||||
|
const outputDevices: DeviceEndpointRowData[] = [];
|
||||||
|
|
||||||
|
deviceEndpoints.forEach((deviceEndpoint) => {
|
||||||
|
outputDevices.push({
|
||||||
|
name:
|
||||||
|
deviceEndpoint.device.user_given_name || deviceEndpoint.device.name,
|
||||||
|
model: deviceEndpoint.device.model,
|
||||||
|
manufacturer: deviceEndpoint.device.manufacturer,
|
||||||
|
id: deviceEndpoint.device.ieee + "_" + deviceEndpoint.endpoint_id,
|
||||||
|
ieee: deviceEndpoint.device.ieee,
|
||||||
|
endpoint_id: deviceEndpoint.endpoint_id,
|
||||||
|
entities: deviceEndpoint.entities,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return outputDevices;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
private _columns = memoizeOne(
|
||||||
|
(narrow: boolean): DataTableColumnContainer =>
|
||||||
|
narrow
|
||||||
|
? {
|
||||||
|
name: {
|
||||||
|
title: "Devices",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
grows: true,
|
||||||
|
template: (name) => html`
|
||||||
|
<div
|
||||||
|
class="mdc-data-table__cell table-cell-text"
|
||||||
|
@click=${this._handleClicked}
|
||||||
|
style="cursor: pointer;"
|
||||||
|
>
|
||||||
|
${name}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
endpoint_id: {
|
||||||
|
title: "Endpoint",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
name: {
|
||||||
|
title: "Name",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
grows: true,
|
||||||
|
template: (name) => html`
|
||||||
|
<div
|
||||||
|
class="mdc-data-table__cell table-cell-text"
|
||||||
|
@click=${this._handleClicked}
|
||||||
|
style="cursor: pointer;"
|
||||||
|
>
|
||||||
|
${name}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
endpoint_id: {
|
||||||
|
title: "Endpoint",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
entities: {
|
||||||
|
title: "Associated Entities",
|
||||||
|
sortable: false,
|
||||||
|
filterable: false,
|
||||||
|
width: "50%",
|
||||||
|
template: (entities) => html`
|
||||||
|
${entities.length
|
||||||
|
? entities.length > 3
|
||||||
|
? html`${entities.slice(0, 2).map(
|
||||||
|
(entity) =>
|
||||||
|
html`<div
|
||||||
|
style="overflow: hidden; text-overflow: ellipsis;"
|
||||||
|
>
|
||||||
|
${entity.name || entity.original_name}
|
||||||
|
</div>`
|
||||||
|
)}
|
||||||
|
<div>And ${entities.length - 2} more...</div>`
|
||||||
|
: entities.map(
|
||||||
|
(entity) =>
|
||||||
|
html`<div
|
||||||
|
style="overflow: hidden; text-overflow: ellipsis;"
|
||||||
|
>
|
||||||
|
${entity.name || entity.original_name}
|
||||||
|
</div>`
|
||||||
|
)
|
||||||
|
: "This endpoint has no associated entities"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
public clearSelection() {
|
||||||
|
this._dataTable.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<ha-data-table
|
||||||
|
.columns=${this._columns(this.narrow)}
|
||||||
|
.data=${this._deviceEndpoints(this.deviceEndpoints)}
|
||||||
|
.selectable=${this.selectable}
|
||||||
|
auto-height
|
||||||
|
></ha-data-table>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _handleClicked(ev: CustomEvent) {
|
||||||
|
const rowId = ((ev.target as HTMLElement).closest(
|
||||||
|
".mdc-data-table__row"
|
||||||
|
) as any).rowId;
|
||||||
|
const ieee = rowId.substring(0, rowId.indexOf("_"));
|
||||||
|
showZHADeviceInfoDialog(this, { ieee });
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
css`
|
||||||
|
.table-cell-text {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zha-device-endpoint-data-table": ZHADeviceEndpointDataTable;
|
||||||
|
}
|
||||||
|
}
|
@ -1,124 +0,0 @@
|
|||||||
import {
|
|
||||||
customElement,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
property,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import "../../../components/data-table/ha-data-table";
|
|
||||||
import type {
|
|
||||||
DataTableColumnContainer,
|
|
||||||
HaDataTable,
|
|
||||||
} from "../../../components/data-table/ha-data-table";
|
|
||||||
import "../../../components/entity/ha-state-icon";
|
|
||||||
import type { ZHADevice } from "../../../data/zha";
|
|
||||||
import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info";
|
|
||||||
import type { HomeAssistant } from "../../../types";
|
|
||||||
|
|
||||||
export interface DeviceRowData extends ZHADevice {
|
|
||||||
device?: DeviceRowData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("zha-devices-data-table")
|
|
||||||
export class ZHADevicesDataTable extends LitElement {
|
|
||||||
@property() public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@property() public narrow = false;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public selectable = false;
|
|
||||||
|
|
||||||
@property() public devices: ZHADevice[] = [];
|
|
||||||
|
|
||||||
@query("ha-data-table") private _dataTable!: HaDataTable;
|
|
||||||
|
|
||||||
private _devices = memoizeOne((devices: ZHADevice[]) => {
|
|
||||||
let outputDevices: DeviceRowData[] = devices;
|
|
||||||
|
|
||||||
outputDevices = outputDevices.map((device) => {
|
|
||||||
return {
|
|
||||||
...device,
|
|
||||||
name: device.user_given_name || device.name,
|
|
||||||
model: device.model,
|
|
||||||
manufacturer: device.manufacturer,
|
|
||||||
id: device.ieee,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return outputDevices;
|
|
||||||
});
|
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
|
||||||
(narrow: boolean): DataTableColumnContainer =>
|
|
||||||
narrow
|
|
||||||
? {
|
|
||||||
name: {
|
|
||||||
title: "Devices",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
direction: "asc",
|
|
||||||
grows: true,
|
|
||||||
template: (name) => html`
|
|
||||||
<div @click=${this._handleClicked} style="cursor: pointer;">
|
|
||||||
${name}
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
name: {
|
|
||||||
title: "Name",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
direction: "asc",
|
|
||||||
grows: true,
|
|
||||||
template: (name) => html`
|
|
||||||
<div @click=${this._handleClicked} style="cursor: pointer;">
|
|
||||||
${name}
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
manufacturer: {
|
|
||||||
title: "Manufacturer",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
width: "20%",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
title: "Model",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
width: "20%",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
public clearSelection() {
|
|
||||||
this._dataTable.clearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-data-table
|
|
||||||
.columns=${this._columns(this.narrow)}
|
|
||||||
.data=${this._devices(this.devices)}
|
|
||||||
.selectable=${this.selectable}
|
|
||||||
auto-height
|
|
||||||
></ha-data-table>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _handleClicked(ev: CustomEvent) {
|
|
||||||
const ieee = ((ev.target as HTMLElement).closest(
|
|
||||||
".mdc-data-table__row"
|
|
||||||
) as any).rowId;
|
|
||||||
showZHADeviceInfoDialog(this, { ieee });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"zha-devices-data-table": ZHADevicesDataTable;
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,8 +9,8 @@ import {
|
|||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
|
query,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
||||||
@ -20,8 +20,8 @@ import {
|
|||||||
fetchGroupableDevices,
|
fetchGroupableDevices,
|
||||||
removeGroups,
|
removeGroups,
|
||||||
removeMembersFromGroup,
|
removeMembersFromGroup,
|
||||||
ZHADevice,
|
|
||||||
ZHAGroup,
|
ZHAGroup,
|
||||||
|
ZHADeviceEndpoint,
|
||||||
} from "../../../data/zha";
|
} from "../../../data/zha";
|
||||||
import "../../../layouts/hass-error-screen";
|
import "../../../layouts/hass-error-screen";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
@ -29,37 +29,40 @@ import { HomeAssistant } from "../../../types";
|
|||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import { formatAsPaddedHex } from "./functions";
|
import { formatAsPaddedHex } from "./functions";
|
||||||
import "./zha-device-card";
|
import "./zha-device-card";
|
||||||
import "./zha-devices-data-table";
|
import "./zha-device-endpoint-data-table";
|
||||||
|
import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table";
|
||||||
|
|
||||||
@customElement("zha-group-page")
|
@customElement("zha-group-page")
|
||||||
export class ZHAGroupPage extends LitElement {
|
export class ZHAGroupPage extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public group?: ZHAGroup;
|
@property({ type: Object }) public group?: ZHAGroup;
|
||||||
|
|
||||||
@property() public groupId!: number;
|
@property({ type: Number }) public groupId!: number;
|
||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property() public isWide!: boolean;
|
@property({ type: Boolean }) public isWide!: boolean;
|
||||||
|
|
||||||
@property() public devices: ZHADevice[] = [];
|
@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
@property() private _processingAdd = false;
|
@property() private _processingAdd = false;
|
||||||
|
|
||||||
@property() private _processingRemove = false;
|
@property() private _processingRemove = false;
|
||||||
|
|
||||||
@property() private _filteredDevices: ZHADevice[] = [];
|
@property() private _filteredDeviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
@property() private _selectedDevicesToAdd: string[] = [];
|
@property() private _selectedDevicesToAdd: string[] = [];
|
||||||
|
|
||||||
@property() private _selectedDevicesToRemove: string[] = [];
|
@property() private _selectedDevicesToRemove: string[] = [];
|
||||||
|
|
||||||
private _firstUpdatedCalled = false;
|
@query("#addMembers")
|
||||||
|
private _zhaAddMembersDataTable!: ZHADeviceEndpointDataTable;
|
||||||
|
|
||||||
private _members = memoizeOne(
|
@query("#removeMembers")
|
||||||
(group: ZHAGroup): ZHADevice[] => group.members
|
private _zhaRemoveMembersDataTable!: ZHADeviceEndpointDataTable;
|
||||||
);
|
|
||||||
|
private _firstUpdatedCalled = false;
|
||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
@ -74,8 +77,8 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
this._processingRemove = false;
|
this._processingRemove = false;
|
||||||
this._selectedDevicesToRemove = [];
|
this._selectedDevicesToRemove = [];
|
||||||
this._selectedDevicesToAdd = [];
|
this._selectedDevicesToAdd = [];
|
||||||
this.devices = [];
|
this.deviceEndpoints = [];
|
||||||
this._filteredDevices = [];
|
this._filteredDeviceEndpoints = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||||
@ -97,8 +100,6 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const members = this._members(this.group);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage .header=${this.group.name}>
|
<hass-subpage .header=${this.group.name}>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
@ -122,13 +123,13 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
${this.hass.localize("ui.panel.config.zha.groups.members")}
|
${this.hass.localize("ui.panel.config.zha.groups.members")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${members.length
|
${this.group.members.length
|
||||||
? members.map(
|
? this.group.members.map(
|
||||||
(member) => html`
|
(member) => html`
|
||||||
<zha-device-card
|
<zha-device-card
|
||||||
class="card"
|
class="card"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.device=${member}
|
.device=${member.device}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.showActions=${false}
|
.showActions=${false}
|
||||||
.showEditableInfo=${false}
|
.showEditableInfo=${false}
|
||||||
@ -140,7 +141,7 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
This group has no members
|
This group has no members
|
||||||
</p>
|
</p>
|
||||||
`}
|
`}
|
||||||
${members.length
|
${this.group.members.length
|
||||||
? html`
|
? html`
|
||||||
<div class="header">
|
<div class="header">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -148,14 +149,15 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<zha-devices-data-table
|
<zha-device-endpoint-data-table
|
||||||
|
id="removeMembers"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.devices=${members}
|
.deviceEndpoints=${this.group.members}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
selectable
|
selectable
|
||||||
@selection-changed=${this._handleRemoveSelectionChanged}
|
@selection-changed=${this._handleRemoveSelectionChanged}
|
||||||
>
|
>
|
||||||
</zha-devices-data-table>
|
</zha-device-endpoint-data-table>
|
||||||
|
|
||||||
<div class="paper-dialog-buttons">
|
<div class="paper-dialog-buttons">
|
||||||
<mwc-button
|
<mwc-button
|
||||||
@ -182,14 +184,15 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<zha-devices-data-table
|
<zha-device-endpoint-data-table
|
||||||
|
id="addMembers"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.devices=${this._filteredDevices}
|
.deviceEndpoints=${this._filteredDeviceEndpoints}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
selectable
|
selectable
|
||||||
@selection-changed=${this._handleAddSelectionChanged}
|
@selection-changed=${this._handleAddSelectionChanged}
|
||||||
>
|
>
|
||||||
</zha-devices-data-table>
|
</zha-device-endpoint-data-table>
|
||||||
|
|
||||||
<div class="paper-dialog-buttons">
|
<div class="paper-dialog-buttons">
|
||||||
<mwc-button
|
<mwc-button
|
||||||
@ -218,16 +221,22 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
if (this.groupId !== null && this.groupId !== undefined) {
|
if (this.groupId !== null && this.groupId !== undefined) {
|
||||||
this.group = await fetchGroup(this.hass!, this.groupId);
|
this.group = await fetchGroup(this.hass!, this.groupId);
|
||||||
}
|
}
|
||||||
this.devices = await fetchGroupableDevices(this.hass!);
|
this.deviceEndpoints = await fetchGroupableDevices(this.hass!);
|
||||||
// filter the groupable devices so we only show devices that aren't already in the group
|
// filter the groupable devices so we only show devices that aren't already in the group
|
||||||
this._filterDevices();
|
this._filterDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _filterDevices() {
|
private _filterDevices() {
|
||||||
// filter the groupable devices so we only show devices that aren't already in the group
|
// filter the groupable devices so we only show devices that aren't already in the group
|
||||||
this._filteredDevices = this.devices.filter((device) => {
|
this._filteredDeviceEndpoints = this.deviceEndpoints.filter(
|
||||||
return !this.group!.members.some((member) => member.ieee === device.ieee);
|
(deviceEndpoint) => {
|
||||||
});
|
return !this.group!.members.some(
|
||||||
|
(member) =>
|
||||||
|
member.device.ieee === deviceEndpoint.device.ieee &&
|
||||||
|
member.endpoint_id === deviceEndpoint.endpoint_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleAddSelectionChanged(
|
private _handleAddSelectionChanged(
|
||||||
@ -244,25 +253,27 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
|
|
||||||
private async _addMembersToGroup(): Promise<void> {
|
private async _addMembersToGroup(): Promise<void> {
|
||||||
this._processingAdd = true;
|
this._processingAdd = true;
|
||||||
this.group = await addMembersToGroup(
|
const members = this._selectedDevicesToAdd.map((member) => {
|
||||||
this.hass,
|
const memberParts = member.split("_");
|
||||||
this.groupId,
|
return { ieee: memberParts[0], endpoint_id: memberParts[1] };
|
||||||
this._selectedDevicesToAdd
|
});
|
||||||
);
|
this.group = await addMembersToGroup(this.hass, this.groupId, members);
|
||||||
this._filterDevices();
|
this._filterDevices();
|
||||||
this._selectedDevicesToAdd = [];
|
this._selectedDevicesToAdd = [];
|
||||||
|
this._zhaAddMembersDataTable.clearSelection();
|
||||||
this._processingAdd = false;
|
this._processingAdd = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _removeMembersFromGroup(): Promise<void> {
|
private async _removeMembersFromGroup(): Promise<void> {
|
||||||
this._processingRemove = true;
|
this._processingRemove = true;
|
||||||
this.group = await removeMembersFromGroup(
|
const members = this._selectedDevicesToRemove.map((member) => {
|
||||||
this.hass,
|
const memberParts = member.split("_");
|
||||||
this.groupId,
|
return { ieee: memberParts[0], endpoint_id: memberParts[1] };
|
||||||
this._selectedDevicesToRemove
|
});
|
||||||
);
|
this.group = await removeMembersFromGroup(this.hass, this.groupId, members);
|
||||||
this._filterDevices();
|
this._filterDevices();
|
||||||
this._selectedDevicesToRemove = [];
|
this._selectedDevicesToRemove = [];
|
||||||
|
this._zhaRemoveMembersDataTable.clearSelection();
|
||||||
this._processingRemove = false;
|
this._processingRemove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user