设备管理
This commit is contained in:
parent
f7d4af5d9c
commit
3b691766d0
357
frontend/src/components/ManageDevice.js
Normal file
357
frontend/src/components/ManageDevice.js
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
import getWeb3 from '../utils/web3';
|
||||||
|
import DeviceManager, { getDefaultAccount } from '../DeviceManager';
|
||||||
|
import { addHexPrefix } from 'ethereumjs-util';
|
||||||
|
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Tag, Button, Input, Card, Timeline, Divider, Spin, Alert, Icon, notification, message } from 'antd';
|
||||||
|
|
||||||
|
const openNotificationWithIcon = (type, message, description) => {
|
||||||
|
notification[type]({
|
||||||
|
message,
|
||||||
|
description
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const eventsToSave = ['DeviceCreated', 'DevicePropertyUpdated', 'DeviceTransfered', 'DeviceSigned', 'SignatureRevoked'];
|
||||||
|
|
||||||
|
class ManageDevice extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
deviceId: this.props.match.params.deviceId,
|
||||||
|
loading: true,
|
||||||
|
showError: false,
|
||||||
|
showEditIdentifier: false,
|
||||||
|
showEditMetadata: false,
|
||||||
|
showEditFirmware: false,
|
||||||
|
showEditOwner: false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.commonChange = this.commonChange.bind(this);
|
||||||
|
this.watchForChanges = this.watchForChanges.bind(this);
|
||||||
|
this.updateDeviceData = this.updateDeviceData.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps({ match }) {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
showError: false,
|
||||||
|
deviceId: match.params.deviceId
|
||||||
|
}, () => this.updateDeviceData());
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillMount() {
|
||||||
|
try {
|
||||||
|
let web3 = (await getWeb3).web3;
|
||||||
|
let instance = await DeviceManager;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
web3,
|
||||||
|
instance
|
||||||
|
});
|
||||||
|
|
||||||
|
this.updateDeviceData();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
//message.error(error.message);
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
showError: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateDeviceData() {
|
||||||
|
try {
|
||||||
|
const { instance, deviceId } = this.state;
|
||||||
|
let device = await instance.devices(deviceId);
|
||||||
|
let signatureCount = await instance.deviceSignatureCount(deviceId);
|
||||||
|
let allEvents = instance.allEvents({ fromBlock: 0, toBlock: 'latest' });
|
||||||
|
allEvents.get((error, logs) => {
|
||||||
|
let filteredData = logs.filter(el => eventsToSave.includes(el.event) && el.args.deviceId.toNumber() === parseInt(deviceId, 10));
|
||||||
|
if (!error) {
|
||||||
|
this.setState({
|
||||||
|
data: filteredData,
|
||||||
|
loading: false,
|
||||||
|
owner: device[0],
|
||||||
|
identifier: device[1],
|
||||||
|
metadataHash: device[2],
|
||||||
|
firmwareHash: device[3],
|
||||||
|
signatureCount: signatureCount.toNumber()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let { identifier, metadataHash, firmwareHash, owner } = this.state;
|
||||||
|
this.setState({
|
||||||
|
identifierNew: identifier,
|
||||||
|
metadataHashNew: metadataHash,
|
||||||
|
firmwareHashNew: firmwareHash,
|
||||||
|
ownerNew: owner
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
//message.error(error.message);
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
showError: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleEdit(property) {
|
||||||
|
const { showEditFirmware, showEditIdentifier, showEditMetadata, showEditOwner } = this.state;
|
||||||
|
|
||||||
|
switch (property) {
|
||||||
|
case 'identifier':
|
||||||
|
this.setState({
|
||||||
|
showEditIdentifier: !showEditIdentifier
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'metadata':
|
||||||
|
this.setState({
|
||||||
|
showEditMetadata: !showEditMetadata
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'firmware':
|
||||||
|
this.setState({
|
||||||
|
showEditFirmware: !showEditFirmware
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'transfer':
|
||||||
|
this.setState({
|
||||||
|
showEditOwner: !showEditOwner
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watchForChanges(property) {
|
||||||
|
let filter = this.state.web3.eth.filter('latest', (error, result) => {
|
||||||
|
if (!error) {
|
||||||
|
openNotificationWithIcon('success', 'Transaction mined', `Property ${property} has been updated.`);
|
||||||
|
this.state.filter.stopWatching();
|
||||||
|
this.updateDeviceData();
|
||||||
|
} else {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
filter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveData(property) {
|
||||||
|
const { instance, deviceId, identifier, identifierNew, metadataHash, metadataHashNew, firmwareHash, firmwareHashNew, owner, ownerNew } = this.state;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (property) {
|
||||||
|
case 'identifier':
|
||||||
|
if (identifier !== identifierNew) {
|
||||||
|
await instance.updateIdentifier(deviceId, addHexPrefix(identifierNew), { from: getDefaultAccount() });
|
||||||
|
this.watchForChanges(property);
|
||||||
|
openNotificationWithIcon('info', 'Transaction sent', 'Once mined, identifier for this device will be updated.');
|
||||||
|
this.setState({
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'metadata':
|
||||||
|
if (metadataHash !== metadataHashNew) {
|
||||||
|
await instance.updateMetadataHash(deviceId, addHexPrefix(metadataHashNew), { from: getDefaultAccount() });
|
||||||
|
this.watchForChanges(property + ' hash');
|
||||||
|
openNotificationWithIcon('info', 'Transaction sent', 'Once mined, metadata hash for this device will be updated.');
|
||||||
|
this.setState({
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'firmware':
|
||||||
|
if (firmwareHash !== firmwareHashNew) {
|
||||||
|
await instance.updateFirmwareHash(deviceId, addHexPrefix(firmwareHashNew), { from: getDefaultAccount() });
|
||||||
|
this.watchForChanges(property + ' hash');
|
||||||
|
openNotificationWithIcon('info', 'Transaction sent', 'Once mined, firmware hash for this device will be updated.');
|
||||||
|
this.setState({
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'transfer':
|
||||||
|
if (owner !== ownerNew) {
|
||||||
|
await instance.transferDevice(deviceId, addHexPrefix(ownerNew), { from: getDefaultAccount() });
|
||||||
|
this.watchForChanges('owner');
|
||||||
|
openNotificationWithIcon('info', 'Transaction sent', 'Once mined, owner for this device will be updated.');
|
||||||
|
this.setState({
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toggleEdit(property);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
message.error(error.message);
|
||||||
|
this.toggleEdit(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
commonChange(e) {
|
||||||
|
this.setState({
|
||||||
|
[e.target.name]: e.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { web3, loading, showError, owner, identifier, metadataHash, firmwareHash, signatureCount, showEditFirmware, showEditIdentifier, showEditMetadata, showEditOwner } = this.state;
|
||||||
|
|
||||||
|
let identifierContent = () => {
|
||||||
|
if (showEditIdentifier) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input name="identifierNew" value={this.state.identifierNew} onChange={this.commonChange} maxLength="66" />
|
||||||
|
<Button type="primary" style={{ marginTop: '10px' }} onClick={() => this.saveData('identifier')}>Save</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Identifier {identifier}
|
||||||
|
{owner === getDefaultAccount() &&
|
||||||
|
<a><Icon type="edit" onClick={() => this.toggleEdit('identifier')} /></a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadataContent = () => {
|
||||||
|
if (showEditMetadata) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input name="metadataHashNew" value={this.state.metadataHashNew} onChange={this.commonChange} maxLength="66" />
|
||||||
|
<Button type="primary" style={{ marginTop: '10px' }} onClick={() => this.saveData('metadata')}>Save</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Metadata hash {metadataHash.length > 0 ? metadataHash : 'empty'}
|
||||||
|
{owner === getDefaultAccount() &&
|
||||||
|
<a><Icon type="edit" onClick={() => this.toggleEdit('metadata')} /></a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let firmwareContent = () => {
|
||||||
|
if (showEditFirmware) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input name="firmwareHashNew" value={this.state.firmwareHashNew} onChange={this.commonChange} maxLength="66" />
|
||||||
|
<Button type="primary" style={{ marginTop: '10px' }} onClick={() => this.saveData('firmware')}>Save</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Firmware hash {firmwareHash.length > 0 ? firmwareHash : 'empty'}
|
||||||
|
{owner === getDefaultAccount() &&
|
||||||
|
<a><Icon type="edit" onClick={() => this.toggleEdit('firmware')} /></a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let transferContent = () => {
|
||||||
|
if (showEditOwner) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input name="ownerNew" value={this.state.ownerNew} onChange={this.commonChange} maxLength="66" />
|
||||||
|
<Button type="primary" style={{ marginTop: '10px' }} onClick={() => this.saveData('transfer')}>Save</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{owner === getDefaultAccount() &&
|
||||||
|
<Button type="dashed" onClick={() => this.toggleEdit('transfer')}> Transfer ownership</Button>
|
||||||
|
}
|
||||||
|
{owner !== getDefaultAccount() &&
|
||||||
|
<div>
|
||||||
|
Owned by <Link to={"/lookup-entity/" + owner}><Tag>{owner}</Tag></Link>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Spin spinning={loading} className="loading-spin">
|
||||||
|
{loading === false && showError === false && typeof metadataHash !== 'undefined' &&
|
||||||
|
<div>
|
||||||
|
<h3><div style={{ marginBottom: '20px' }}>{identifierContent()}</div></h3>
|
||||||
|
<Divider />
|
||||||
|
<div style={{ marginBottom: '20px' }}>{metadataContent()}</div>
|
||||||
|
<div style={{ marginBottom: '20px' }}>{firmwareContent()}</div>
|
||||||
|
{transferContent()}
|
||||||
|
<Divider />
|
||||||
|
{signatureCount > 0 &&
|
||||||
|
<div>
|
||||||
|
<div>This device has <strong>{signatureCount}</strong> active signature(s). Devices that have been signed can't be updated.</div>
|
||||||
|
<Divider />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<Card title={'Historical events for device (oldest to newest)'}>
|
||||||
|
{this.state.data.length !== 0 ?
|
||||||
|
<div>
|
||||||
|
<p style={{ marginBottom: '20px' }}>Events that are filtered are {eventsToSave.join(', ')} </p>
|
||||||
|
<Timeline style={{ marginTop: '10px' }}>
|
||||||
|
{this.state.data.map(el => {
|
||||||
|
if (el.event === 'DeviceCreated')
|
||||||
|
return <Timeline.Item color='green'>Device created by <Link to={"/lookup-entity/" + el.args.owner}><Tag>{el.args.owner}</Tag></Link>with <Link to={"/manage-device/" + el.args.deviceId.toNumber()}><Tag>ID {el.args.deviceId.toNumber()}</Tag></Link>, identifier <code>{el.args.identifier}</code>, metadata hash <code>{el.args.metadataHash}</code> and firmware hash <code>{el.args.firmwareHash}</code></Timeline.Item>
|
||||||
|
if (el.event === 'DevicePropertyUpdated')
|
||||||
|
return <Timeline.Item>Property {web3.toUtf8(el.args.property)} updated to <code>{el.args.newValue}</code></Timeline.Item>
|
||||||
|
if (el.event === 'DeviceTransfered')
|
||||||
|
return <Timeline.Item color='orange'>Device transfered to <Link to={"/lookup-entity/" + el.args.newOwner}><Tag>{el.args.newOwner}</Tag></Link></Timeline.Item>
|
||||||
|
if (el.event === 'DeviceSigned')
|
||||||
|
return <Timeline.Item color='purple'>Signature with <Link to={"/check-signature/" + el.args.signatureId.toNumber()}><Tag>ID {el.args.signatureId.toNumber()}</Tag></Link>created by {el.args.signer}</Timeline.Item>
|
||||||
|
if (el.event === 'SignatureRevoked')
|
||||||
|
return <Timeline.Item color='purple'>Signature with <Link to={"/check-signature/" + el.args.signatureId.toNumber()}><Tag>ID {el.args.signatureId.toNumber()}</Tag></Link>revoked</Timeline.Item>
|
||||||
|
else
|
||||||
|
return null
|
||||||
|
})}
|
||||||
|
</Timeline>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<p><em>empty</em></p>
|
||||||
|
}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{/*
|
||||||
|
{loading === false && owner !== getDefaultAccount() &&
|
||||||
|
<Alert message="You don't own this device." type="error" showIcon />
|
||||||
|
}
|
||||||
|
*/}
|
||||||
|
{loading === false && showError &&
|
||||||
|
<Alert
|
||||||
|
message="Error"
|
||||||
|
description="Error loading device: invalid ID format or device doesn't exist."
|
||||||
|
type="error"
|
||||||
|
showIcon
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Spin >
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ManageDevice;
|
78
frontend/src/components/ManageDevices.js
Normal file
78
frontend/src/components/ManageDevices.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import DeviceManager, { getDefaultAccount } from '../DeviceManager';
|
||||||
|
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Spin, List, message } from 'antd';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
class ManageDevices extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
instance: null,
|
||||||
|
devices: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
try {
|
||||||
|
let instance = await DeviceManager;
|
||||||
|
let deviceIds = (await instance.getDevicesByOwner(getDefaultAccount())).map(el => el.toNumber());
|
||||||
|
|
||||||
|
let devicePromises = [];
|
||||||
|
for (let deviceId of deviceIds) {
|
||||||
|
let devicePromise = instance.devices(deviceId);
|
||||||
|
devicePromises.push(devicePromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
let devices = await Promise.all(devicePromises);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
instance,
|
||||||
|
devices,
|
||||||
|
deviceIds,
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
message.error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { devices, loading } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Spin spinning={loading} className="loading-spin">
|
||||||
|
{devices.length > 0 && !loading &&
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Below you can find your devices. Click to see more details and manage.
|
||||||
|
</p>
|
||||||
|
<List
|
||||||
|
bordered={true}
|
||||||
|
itemLayout="horizontal"
|
||||||
|
dataSource={devices}
|
||||||
|
renderItem={(device, index) => (
|
||||||
|
<List.Item>
|
||||||
|
<List.Item.Meta
|
||||||
|
/*avatar={<Icon type="profile" style={{ fontSize: 36 }} />}*/
|
||||||
|
title={<Link to={`/manage-device/${this.state.deviceIds[index]}`}>{`Device ID ${this.state.deviceIds[index]}`}</Link>}
|
||||||
|
description={`Identifier ${device[1]}`}
|
||||||
|
/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{devices.length === 0 && !loading &&
|
||||||
|
<p>You don't have any devices registered.</p>
|
||||||
|
}
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ManageDevices;
|
Loading…
Reference in New Issue
Block a user