Skip to content

Commit

Permalink
First version of improved Z-Wave integration UI
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre-Gilles committed Nov 13, 2019
1 parent 5bf6928 commit 4281c50
Show file tree
Hide file tree
Showing 24 changed files with 532 additions and 180 deletions.
247 changes: 124 additions & 123 deletions front/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"leaflet": "^1.4.0",
"linkstate": "^1.1.1",
"moment": "^2.24.0",
"preact": "^10.0.1",
"preact": "^10.0.5",
"preact-cli-plugin-fast-async": "^1.0.1",
"preact-i18n": "^2.0.0-preactx.2",
"preact-router": "^3.1.0",
Expand Down
7 changes: 3 additions & 4 deletions front/src/components/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import ZwaveNodePage from '../routes/integration/all/zwave/node-page';
import ZwaveNetworkPage from '../routes/integration/all/zwave/network-page';
import ZwaveSettingsPage from '../routes/integration/all/zwave/settings-page';
import ZwaveSetupPage from '../routes/integration/all/zwave/setup-page';
import ZwaveNodeOperationPage from '../routes/integration/all/zwave/node-operation-page';
import RtspCameraPage from '../routes/integration/all/rtsp-camera';
import XiaomiPage from '../routes/integration/all/xiaomi';
import EditXiaomiPage from '../routes/integration/all/xiaomi/edit-page';
Expand Down Expand Up @@ -158,6 +159,7 @@ const AppRouter = connect(
<ZwaveNetworkPage path="/dashboard/integration/device/zwave/network" />
<ZwaveSettingsPage path="/dashboard/integration/device/zwave/settings" />
<ZwaveSetupPage path="/dashboard/integration/device/zwave/setup" />
<ZwaveNodeOperationPage path="/dashboard/integration/device/zwave/node-operation" />
<RtspCameraPage path="/dashboard/integration/device/rtsp-camera" />
<MqttDevicePage path="/dashboard/integration/device/mqtt" />
<MqttDeviceSetupPage path="/dashboard/integration/device/mqtt/edit" />
Expand Down Expand Up @@ -188,10 +190,7 @@ const AppRouter = connect(
</div>
));

@connect(
'',
actions
)
@connect('', actions)
class MainApp extends Component {
componentWillMount() {
this.props.checkSession();
Expand Down
15 changes: 14 additions & 1 deletion front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,20 @@
"description": "To use Z-Wave in Gladys, you need to have a Z-Wave USB Stick connected to your Gladys instance.",
"zwaveUsbDriverPathLabel": "Select the USB port where your Z-Wave stick is connected",
"connectButton": "Connect",
"disconnectButton": "Disconnect"
"disconnectButton": "Disconnect",
"refreshButton": "Refresh USB list",
"notConnected": "Gladys is not connected to any Z-Wave USB stick.",
"connectedWithSuccess": "Z-Wave USB stick connected with success.",
"connecting": "Trying to connect to Z-Wave USB stick...",
"driverFailedError": "An error occured while trying to connect to Z-Wave USB stick."
},
"nodeOperation": {
"addNodeInstructions": "You can now include your device following instructions in your device manual.",
"removeNodeInstructions": "You can now exclude your device following instructions in your device manual.",
"addNodeTitle": "Inclusion Mode",
"removeNodeTitle": "Exclusion Mode",
"seconds": "seconds remaining",
"cancelButton": "Cancel"
}
},
"darkSky": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Text } from 'preact-i18n';

const AddNode = ({ children, ...props }) => (
<div class="card">
<div class="card-header">
<h3 class="card-title">
{props.action === 'remove' ? (
<Text id="integration.zwave.nodeOperation.removeNodeTitle" />
) : (
<Text id="integration.zwave.nodeOperation.addNodeTitle" />
)}
</h3>
<div class="card-options">
<button class="btn btn-danger" onClick={props.cancel}>
<Text id="integration.zwave.nodeOperation.cancelButton" />
</button>
</div>
</div>
<div class="card-body">
<div class="text-center">
<h1>
{props.remainingTimeInSeconds} <Text id="integration.zwave.nodeOperation.seconds" />
</h1>
<p>
{props.action === 'remove' ? (
<Text id="integration.zwave.nodeOperation.removeNodeInstructions" />
) : (
<Text id="integration.zwave.nodeOperation.addNodeInstructions" />
)}
</p>
</div>
</div>
</div>
);

export default AddNode;
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { RequestStatus } from '../../../../../utils/consts';

const actions = store => {
const actions = {
async addNode(state, e, secure = false) {
if (e) {
e.preventDefault();
}
store.setState({
zwaveAddNodeStatus: RequestStatus.Getting
});
try {
await state.httpClient.post('/api/v1/service/zwave/node/add', {
secure
});
store.setState({
zwaveAddNodeStatus: RequestStatus.Success
});
} catch (e) {
store.setState({
zwaveAddNodeStatus: RequestStatus.Error
});
}
},
async addNodeSecure(state, e) {
actions.addNode(state, e, true);
},
async cancelZwaveCommand(state) {
store.setState({
zwaveCancelZwaveCommandStatus: RequestStatus.Getting
});
try {
await state.httpClient.post('/api/v1/service/zwave/cancel');
store.setState({
zwaveCancelZwaveCommandStatus: RequestStatus.Success
});
} catch (e) {
store.setState({
zwaveCancelZwaveCommandStatus: RequestStatus.Error
});
}
},
async removeNode(state, secure = false) {
store.setState({
zwaveRemoveNodeStatus: RequestStatus.Getting
});
try {
await state.httpClient.post('/api/v1/service/zwave/node/remove');
store.setState({
zwaveRemoveNodeStatus: RequestStatus.Success
});
} catch (e) {
store.setState({
zwaveRemoveNodeStatus: RequestStatus.Error
});
}
}
};

return actions;
};

export default actions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Component } from 'preact';
import { connect } from 'unistore/preact';
import { route } from 'preact-router';
import actions from './actions';
import ZwavePage from '../ZwavePage';
import NodeOperationPage from './AddRemoveNode';

@connect('session,user,zwaveDevices,houses,getZwaveDevicesStatus', actions)
class ZwaveNodeOperationPage extends Component {
decrementTimer = () => {
this.setState(prevState => {
return { remainingTimeInSeconds: prevState.remainingTimeInSeconds - 1 };
});
if (this.state.remainingTimeInSeconds > 1) {
setTimeout(this.decrementTimer, 1000);
} else {
route('/dashboard/integration/device/zwave/setup');
}
};
addNode = () => {
this.props.addNode();
setTimeout(this.decrementTimer, 1000);
};
addNodeSecure = () => {
this.props.addNodeSecure();
setTimeout(this.decrementTimer, 1000);
};
removeNode = () => {
this.props.removeNode();
setTimeout(this.decrementTimer, 1000);
};
cancel = () => {
this.props.cancelZwaveCommand();
route('/dashboard/integration/device/zwave/setup');
};
constructor(props) {
super(props);
this.state = {
remainingTimeInSeconds: 60
};
}
componentWillMount() {
switch (this.props.action) {
case 'add':
this.addNode();
break;
case 'add-secure':
this.addNodeSecure();
break;
case 'remove':
this.removeNode();
break;
}
}

render(props, { remainingTimeInSeconds }) {
return (
<ZwavePage>
<NodeOperationPage {...props} remainingTimeInSeconds={remainingTimeInSeconds} cancel={this.cancel} />
</ZwavePage>
);
}
}

export default ZwaveNodeOperationPage;
32 changes: 18 additions & 14 deletions front/src/routes/integration/all/zwave/node-page/NodeTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,24 @@ const NodeTab = ({ children, ...props }) => (
<div class="loader" />
<div class="dimmer-content">
{props.getZwaveDevicesStatus === RequestStatus.Getting && <div class={style.emptyDiv} />}
<div class="row">
{props.zwaveDevices &&
props.zwaveDevices.map((zwaveDevice, index) => (
<Device
device={zwaveDevice}
deviceIndex={index}
houses={props.houses}
updateDeviceProperty={props.updateDeviceProperty}
saveDevice={props.saveDevice}
deleteDevice={props.deleteDevice}
/>
))}
{props.zwaveDevices && props.zwaveDevices.length === 0 && <Text id="integration.zwave.device.noDevices" />}
</div>
{props.getZwaveDevicesStatus !== RequestStatus.Getting && (
<div class="row">
{props.zwaveDevices &&
props.zwaveDevices.map((zwaveDevice, index) => (
<Device
device={zwaveDevice}
deviceIndex={index}
houses={props.houses}
updateDeviceProperty={props.updateDeviceProperty}
saveDevice={props.saveDevice}
deleteDevice={props.deleteDevice}
/>
))}
{props.zwaveDevices && props.zwaveDevices.length === 0 && (
<Text id="integration.zwave.device.noDevices" />
)}
</div>
)}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,47 @@
import { Text } from 'preact-i18n';
import get from 'get-value';
import cx from 'classnames';

const SettingsTab = ({ children, ...props }) => (
<div class="card">
<div class="card-header">
<h2 class="card-title">
<Text id="integration.zwave.settings.title" />
</h2>
<div class="page-options d-flex">
<button class="btn btn-info" onClick={props.getUsbPorts}>
<Text id="integration.zwave.settings.refreshButton" />
</button>
</div>
</div>
<div class="card-body">
<div class="dimmer">
<div
class={cx('dimmer', {
active: props.loading
})}
>
<div class="loader" />
<div class="dimmer-content">
<h3>
<Text id="integration.zwave.settings.ino" />
</h3>
{get(props, 'zwaveStatus.ready') && (
<div class="alert alert-success">
<Text id="integration.zwave.settings.connectedWithSuccess" />
</div>
)}
{!get(props, 'zwaveStatus.ready') && (
<div class="alert alert-warning">
<Text id="integration.zwave.settings.notConnected" />
</div>
)}
{props.zwaveConnectionInProgress && (
<div class="alert alert-info">
<Text id="integration.zwave.settings.connecting" />
</div>
)}
{props.zwaveDriverFailed && (
<div class="alert alert-danger">
<Text id="integration.zwave.settings.driverFailedError" />
</div>
)}
<p>
<Text id="integration.zwave.settings.description" />
</p>
Expand Down
31 changes: 29 additions & 2 deletions front/src/routes/integration/all/zwave/settings-page/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,17 @@ const actions = store => {
},
async saveDriverPathAndConnect(state) {
store.setState({
connectZwaveStatus: RequestStatus.Getting
connectZwaveStatus: RequestStatus.Getting,
zwaveDriverFailed: false
});
try {
await state.httpClient.post('/api/v1/service/zwave/variable/ZWAVE_DRIVER_PATH', {
value: state.zwaveDriverPath
});
await state.httpClient.post('/api/v1/service/zwave/connect');
store.setState({
connectZwaveStatus: RequestStatus.Success
connectZwaveStatus: RequestStatus.Success,
zwaveConnectionInProgress: true
});
} catch (e) {
store.setState({
Expand Down Expand Up @@ -79,6 +81,7 @@ const actions = store => {
});
try {
await state.httpClient.post('/api/v1/service/zwave/disconnect');
await actions.getStatus(store.getState());
store.setState({
zwaveDisconnectStatus: RequestStatus.Success
});
Expand All @@ -87,6 +90,30 @@ const actions = store => {
zwaveDisconnectStatus: RequestStatus.Error
});
}
},
async getStatus(state) {
store.setState({
zwaveGetStatusStatus: RequestStatus.Getting
});
try {
const zwaveStatus = await state.httpClient.get('/api/v1/service/zwave/status');
store.setState({
zwaveStatus,
zwaveConnectionInProgress: false,
zwaveGetStatusStatus: RequestStatus.Success
});
} catch (e) {
store.setState({
zwaveGetStatusStatus: RequestStatus.Error,
zwaveConnectionInProgress: false
});
}
},
driverFailed(state) {
store.setState({
zwaveDriverFailed: true,
zwaveConnectionInProgress: false
});
}
};

Expand Down
Loading

0 comments on commit 4281c50

Please sign in to comment.