Skip to content

Commit

Permalink
added optimizations for the controller page (#53)
Browse files Browse the repository at this point in the history
* added optimizations for the controller page (not dialogs yet)

* apply new translation

* finish off rework of ble dialog on controller page

* finish off rework on controller tab

* re-add the vendor change

* adapt code to correctly handle null/undefined

* throw error if cannot load config

* give max width of 800px to discover dialog
  • Loading branch information
foxriver76 authored Aug 1, 2024
1 parent 164eac3 commit 5e9deff
Show file tree
Hide file tree
Showing 24 changed files with 525 additions and 183 deletions.
33 changes: 27 additions & 6 deletions src-admin/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ class App extends GenericApp<GenericAppProps, AppState> {
this.refreshTimer = setTimeout(() => {
this.refreshTimer = null;
this.refreshBackendSubscription();
}, 60000);
}, 60_000);

this.socket.subscribeOnInstance(`matter.${this.instance}`, 'gui', null, this.onBackendUpdates).then(result => {
if (typeof result === 'object' && result.accepted === false) {
if (result && typeof result === 'object' && result.accepted === false) {
console.error('Subscribe is not accepted');
this.setState({ backendRunning: !!result.accepted });
} else if (!this.state.backendRunning) {
Expand All @@ -151,6 +151,7 @@ class App extends GenericApp<GenericAppProps, AppState> {
this.configHandler && this.configHandler.destroy();
this.configHandler = new ConfigHandler(this.instance, this.socket, this.onChanged, this.onCommissioningChanged);
const matter = await this.configHandler.loadConfig();

const commissioning = this.configHandler.getCommissioning();
matter.controller = matter.controller || { enabled: false };
matter.devices = matter.devices || [];
Expand Down Expand Up @@ -206,7 +207,11 @@ class App extends GenericApp<GenericAppProps, AppState> {
if (update.states) {
const uuids = update.states ? Object.keys(update.states) : [];
for (const uuid of uuids) {
nodeStates[uuid.split('.').pop()] = update.states[uuid];
const nodeId = uuid.split('.').pop();

if (nodeId) {
nodeStates[nodeId] = update.states[uuid];
}
}
}
this.setState({ nodeStates });
Expand Down Expand Up @@ -266,7 +271,11 @@ class App extends GenericApp<GenericAppProps, AppState> {
this.configHandler && this.configHandler.destroy();
}

renderController() {
renderController(): React.ReactNode {
if (!this.configHandler || !this.socket.systemConfig) {
return null;
}

return (
<ControllerTab
registerMessageHandler={(handler: null | ((_message: GUIMessage | null) => void)) =>
Expand All @@ -290,7 +299,11 @@ class App extends GenericApp<GenericAppProps, AppState> {
);
}

renderOptions() {
renderOptions(): React.ReactNode {
if (!this.common) {
return null;
}

return (
<OptionsTab
alive={this.state.alive}
Expand All @@ -306,7 +319,7 @@ class App extends GenericApp<GenericAppProps, AppState> {
);
}

renderBridges() {
renderBridges(): React.ReactNode {
return (
<BridgesTab
alive={this.state.alive}
Expand All @@ -326,6 +339,10 @@ class App extends GenericApp<GenericAppProps, AppState> {
productIDs={productIDs}
matter={this.state.matter}
updateConfig={async config => {
if (!this.configHandler) {
return;
}

await this.configHandler.saveBridgesConfig(config);
await this.onChanged(config);
}}
Expand Down Expand Up @@ -357,6 +374,10 @@ class App extends GenericApp<GenericAppProps, AppState> {
instance={this.instance}
matter={this.state.matter}
updateConfig={async config => {
if (!this.configHandler) {
return;
}

await this.configHandler.saveDevicesConfig(config);
await this.onChanged(config);
}}
Expand Down
46 changes: 45 additions & 1 deletion src-admin/src/Tabs/Bridges.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
disabled={isCommissioned}
value={this.state.editBridgeDialog.name}
onChange={e => {
if (!this.state.editBridgeDialog) {
return;
}

const editBridgeDialog = clone(this.state.editBridgeDialog);
editBridgeDialog.name = e.target.value;
this.setState({ editBridgeDialog });
Expand All @@ -340,6 +344,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
style={{ width: 'calc(50% - 8px)', marginRight: 16, marginTop: 16 }}
value={this.state.editBridgeDialog.vendorID}
onChange={e => {
if (!this.state.editBridgeDialog) {
return;
}

const editBridgeDialog = clone(this.state.editBridgeDialog);
editBridgeDialog.vendorID = e.target.value;
this.setState({ editBridgeDialog });
Expand All @@ -360,6 +368,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
style={{ width: 'calc(50% - 8px)', marginTop: 16 }}
value={this.state.editBridgeDialog.productID}
onChange={e => {
if (!this.state.editBridgeDialog) {
return;
}

const editBridgeDialog = clone(this.state.editBridgeDialog);
editBridgeDialog.productID = e.target.value;
this.setState({ editBridgeDialog });
Expand Down Expand Up @@ -457,6 +469,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
disabled={isCommissioned}
value={this.state.editDeviceDialog.name}
onChange={e => {
if (!this.state.editDeviceDialog) {
return;
}

const editDeviceDialog = clone(this.state.editDeviceDialog);
editDeviceDialog.name = e.target.value;
this.setState({ editDeviceDialog });
Expand All @@ -471,6 +487,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
<Checkbox
checked={this.state.editDeviceDialog.noComposed}
onChange={e => {
if (!this.state.editDeviceDialog) {
return;
}

const editDeviceDialog = clone(this.state.editDeviceDialog);
editDeviceDialog.noComposed = e.target.checked;
this.setState({ editDeviceDialog });
Expand All @@ -493,6 +513,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
disabled={isCommissioned || this.state.editDeviceDialog.auto}
value={this.state.editDeviceDialog.deviceType}
onChange={e => {
if (!this.state.editDeviceDialog) {
return;
}

const editDeviceDialog = clone(this.state.editDeviceDialog);
editDeviceDialog.deviceType = e.target.value as Types;
this.setState({ editDeviceDialog });
Expand Down Expand Up @@ -521,6 +545,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
<Checkbox
checked={this.state.editDeviceDialog.actionAllowedByIdentify}
onChange={e => {
if (!this.state.editDeviceDialog) {
return;
}

const editDeviceDialog = clone(this.state.editDeviceDialog);
editDeviceDialog.actionAllowedByIdentify = e.target.checked;
this.setState({ editDeviceDialog });
Expand All @@ -536,6 +564,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
<Checkbox
checked={this.state.editDeviceDialog.dimmerUseLastLevelForOn}
onChange={e => {
if (!this.state.editDeviceDialog) {
return;
}

const editDeviceDialog = clone(this.state.editDeviceDialog);
editDeviceDialog.dimmerUseLastLevelForOn = e.target.checked;
this.setState({ editDeviceDialog });
Expand All @@ -554,6 +586,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
variant="standard"
value={this.state.editDeviceDialog.dimmerOnLevel}
onChange={e => {
if (!this.state.editDeviceDialog) {
return;
}

const editDeviceDialog = clone(this.state.editDeviceDialog);
editDeviceDialog.dimmerOnLevel = e.target.value as number;
this.setState({ editDeviceDialog });
Expand Down Expand Up @@ -753,7 +789,7 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
/**
* Render dialog to select if devices should be added from state or detected automatically
*/
renderAddDevicesPreDialog(): React.JSX.Element {
renderAddDevicesPreDialog(): React.ReactNode {
if (!this.state.addDevicePreDialog.open) {
return null;
}
Expand Down Expand Up @@ -825,6 +861,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
label={I18n.t('Name')}
value={this.state.addCustomDeviceDialog.name}
onChange={e => {
if (!this.state.addCustomDeviceDialog) {
return;
}

const addCustomDeviceDialog = clone(this.state.addCustomDeviceDialog);
addCustomDeviceDialog.name = e.target.value;
this.setState({ addCustomDeviceDialog });
Expand All @@ -846,6 +886,10 @@ export class Bridges extends BridgesAndDevices<BridgesProps, BridgesState> {
variant="standard"
value={this.state.addCustomDeviceDialog.deviceType}
onChange={e => {
if (!this.state.addCustomDeviceDialog) {
return;
}

const addCustomDeviceDialog = clone(this.state.addCustomDeviceDialog);
addCustomDeviceDialog.deviceType = e.target.value as Types;
this.setState({ addCustomDeviceDialog });
Expand Down
22 changes: 15 additions & 7 deletions src-admin/src/Tabs/BridgesAndDevices.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from 'react';
import QRCode from 'react-qr-code';

import { type AdminConnection, I18n, type IobTheme, type ThemeType, Utils } from '@iobroker/adapter-react-v5';
import {
Close,
ContentCopy,
Expand Down Expand Up @@ -31,8 +32,7 @@ import {
Typography,
} from '@mui/material';
import { SiAmazonalexa, SiApple, SiGoogleassistant, SiSmartthings } from 'react-icons/si';

import { type AdminConnection, I18n, type IobTheme, type ThemeType, Utils } from '@iobroker/adapter-react-v5';
import VENDOR_IDS from '../utils/vendorIDs';

import type {
BridgeDescription,
Expand Down Expand Up @@ -121,7 +121,9 @@ class BridgesAndDevices<TProps extends BridgesAndDevicesProps, TState extends Br
}
}

static getVendorIcon(vendor: string, themeType: ThemeType) {
static getVendorIcon(vendorId: number, themeType: ThemeType) {
const vendor = VENDOR_IDS[vendorId];

if (vendor === 'Amazon Lab126') {
return (
<SiAmazonalexa
Expand Down Expand Up @@ -279,8 +281,8 @@ class BridgesAndDevices<TProps extends BridgesAndDevicesProps, TState extends Br
{data.connectionInfo?.map((info, i) => (
<TableRow key={i}>
<TableCell>
{BridgesAndDevices.getVendorIcon(info.vendor, this.props.themeType) ||
info.vendor}
{BridgesAndDevices.getVendorIcon(info.vendorId, this.props.themeType) ||
info.vendorId}
{info.label ? (
<span
style={{
Expand Down Expand Up @@ -329,7 +331,11 @@ class BridgesAndDevices<TProps extends BridgesAndDevicesProps, TState extends Br
/**
* Render the QR code dialog for pairing
*/
renderQrCodeDialog(): React.JSX.Element {
renderQrCodeDialog(): React.ReactNode {
if (!this.state.showQrCode) {
return null;
}

const uuid = this.state.showQrCode?.uuid;
const nodeState = uuid && this.props.nodeStates[this.state.showQrCode.uuid];
if (nodeState && !nodeState.qrPairingCode) {
Expand All @@ -343,9 +349,11 @@ class BridgesAndDevices<TProps extends BridgesAndDevicesProps, TState extends Br
1_000,
);
}
if (!this.state.showQrCode || !nodeState) {

if (!nodeState) {
return null;
}

return (
<Dialog onClose={() => this.setState({ showQrCode: null })} open={!0} maxWidth="md">
<DialogTitle>{I18n.t('QR Code to connect')}</DialogTitle>
Expand Down
Loading

0 comments on commit 5e9deff

Please sign in to comment.