import * as React from 'react' import { Button, CircularProgress, FormControl, FormControlLabel, Grid, IconButton, Input, InputAdornment, InputLabel, MenuItem, Modal, Paper, Switch, TextField, Toolbar, Typography, } from '@material-ui/core' import { connect } from 'react-redux' import { MqttOptions } from '../../../../backend/src/DataSource' import { StyleRulesCallback, Theme, withStyles } from '@material-ui/core/styles' import Notification from './Notification' import Visibility from '@material-ui/icons/Visibility' import VisibilityOff from '@material-ui/icons/VisibilityOff' import sha1 = require('sha1') import { AppState } from '../../reducers' import { bindActionCreators } from 'redux' import { connectionActions } from '../../actions' interface Props { classes: {[s: string]: string} theme: Theme actions: typeof connectionActions, visible: boolean connected: boolean connecting: boolean error?: string } const protocols = [ 'mqtt://', 'ws://', ] interface State { showPassword: boolean connectionSettings: ConnectionSettings } interface ConnectionSettings { host: string protocol: string port: number tls: boolean certValidation: boolean clientId: string connectionId?: string username: string password: string } declare var window: any class Connection extends React.Component { private randomClientId: string private defaultConnectionSettings: ConnectionSettings = { host: 'iot.eclipse.org', protocol: protocols[0], port: 1883, tls: false, certValidation: true, clientId: '', username: '', password: '', connectionId: undefined, } constructor(props: any) { super(props) const clientIdSha = sha1(`${Math.random()}`).slice(0, 8) this.randomClientId = `mqtt-explorer-${clientIdSha}` this.state = { connectionSettings: this.loadConnectionSettings(), showPassword: false, } } private loadConnectionSettings(): ConnectionSettings { let storedSettings: ConnectionSettings | undefined const storedSettingsString = window.localStorage.getItem('connectionSettings') try { storedSettings = storedSettingsString ? JSON.parse(storedSettingsString) : undefined } catch { window.localStorage.setItem('connectionSettings', undefined) } return storedSettings || this.defaultConnectionSettings } private saveConnectionSettings() { window.localStorage.setItem('connectionSettings', JSON.stringify(this.state.connectionSettings)) } private handleClickShowPassword = () => { this.setState({ showPassword: !this.state.showPassword }) } private optionsFromState(): MqttOptions { const protocol = this.state.connectionSettings.protocol === 'tcp://' ? 'mqtt://' : this.state.connectionSettings.protocol const url = `${protocol}${this.state.connectionSettings.host}:${this.state.connectionSettings.port}` return { url, username: this.state.connectionSettings.username || undefined, password: this.state.connectionSettings.password || undefined, clientId: this.state.connectionSettings.clientId || this.randomClientId, tls: this.state.connectionSettings.tls, certValidation: this.state.connectionSettings.certValidation, } } public static styles: StyleRulesCallback = (theme: Theme) => { return { root: { minWidth: 550, maxWidth: 650, backgroundColor: theme.palette.background.default, margin: '14vh auto auto auto', padding: `${2 * theme.spacing.unit}px`, outline: 'none', }, title: { color: theme.palette.text.primary, }, paper: { padding: theme.spacing.unit * 2, textAlign: 'center', color: theme.palette.text.secondary, }, textField: { width: '100%', }, switch: { marginTop: `${1 * theme.spacing.unit}px`, }, button: { margin: theme.spacing.unit, }, inputFormControl: { marginTop: '16px', }, } } private handleChange = (name: string) => (event: any) => { this.setState({ connectionSettings: { ...this.state.connectionSettings, [name]: event.target.value, }, }) } public render() { const { classes } = this.props const passwordVisibilityButton = ( {this.state.showPassword ? : } ) let renderError = null if (this.props.error) { renderError = ( { this.props.actions.showError(undefined) }} /> ) } return (
{renderError} MQTT Connection
{this.renderProtocols()} Password Client ID } /> {this.renderCertValidationSwitch()} {this.renderTlsSwitch()}
{this.renderConnectButton()}
) } private renderProtocols() { const { classes } = this.props const protocolItems = protocols.map((value: string) => ( {value} )) return ( {protocolItems} ) } private renderCertValidationSwitch() { const { classes } = this.props const certSwitch = ( ) return (
) } private toggleCertValidation = () => this.setState({ connectionSettings: { ...this.state.connectionSettings, certValidation: !this.state.connectionSettings.certValidation, }, }) private renderTlsSwitch() { const { classes } = this.props const tlsSwitch = ( ) return (
) } private toggleTls = () => this.setState({ connectionSettings: { ...this.state.connectionSettings, tls: !this.state.connectionSettings.tls, }, }) private renderConnectButton() { const { classes, actions } = this.props if (this.props.connecting) { return ( ) } return ( ) } private onClickConnect = () => { const connectionId = String(sha1(String(Math.random())).slice(0, 8)) const options = this.optionsFromState() this.props.actions.connect(options, connectionId) } } const mapStateToProps = (state: AppState) => { return { visible: !state.tooBigReducer.connected, connected: state.tooBigReducer.connected, connecting: state.tooBigReducer.connecting, error: state.tooBigReducer.error, } } const mapDispatchToProps = (dispatch: any) => { return { actions: bindActionCreators(connectionActions, dispatch), } } export default connect(mapStateToProps, mapDispatchToProps)(withStyles(Connection.styles, { withTheme: true })(Connection))