Update code formatting
This commit is contained in:
@@ -28,7 +28,7 @@ interface Props {
|
||||
class App extends React.PureComponent<Props, {}> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { }
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
private renderNotification() {
|
||||
@@ -41,7 +41,9 @@ class App extends React.PureComponent<Props, {}> {
|
||||
<Notification
|
||||
message={str}
|
||||
type={isError ? 'error' : 'notification'}
|
||||
onClose={() => { isError ? this.props.actions.showError(undefined) : this.props.actions.showNotification(undefined) }}
|
||||
onClose={() => {
|
||||
isError ? this.props.actions.showError(undefined) : this.props.actions.showNotification(undefined)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -65,7 +67,7 @@ class App extends React.PureComponent<Props, {}> {
|
||||
<div className={centerContent}>
|
||||
<CssBaseline />
|
||||
<ErrorBoundary>
|
||||
{this.renderNotification()}
|
||||
{this.renderNotification()}
|
||||
<React.Suspense fallback={<div></div>}>
|
||||
<Settings />
|
||||
</React.Suspense>
|
||||
@@ -75,7 +77,11 @@ class App extends React.PureComponent<Props, {}> {
|
||||
</div>
|
||||
<div className={settingsVisible ? contentShift : content}>
|
||||
<React.Suspense fallback={<div></div>}>
|
||||
<ContentView heightProperty={heightProperty} connectionId={this.props.connectionId} paneDefaults={paneDefaults} />
|
||||
<ContentView
|
||||
heightProperty={heightProperty}
|
||||
connectionId={this.props.connectionId}
|
||||
paneDefaults={paneDefaults}
|
||||
/>
|
||||
</React.Suspense>
|
||||
</div>
|
||||
</div>
|
||||
@@ -149,4 +155,9 @@ const mapStateToProps = (state: AppState) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(App))
|
||||
export default withStyles(styles)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(App)
|
||||
)
|
||||
|
||||
@@ -14,18 +14,9 @@ const styles = (theme: Theme) => ({
|
||||
},
|
||||
})
|
||||
|
||||
export const AddButton = withStyles(styles)((props: {
|
||||
classes: any,
|
||||
action: any,
|
||||
}) => {
|
||||
export const AddButton = withStyles(styles)((props: { classes: any; action: any }) => {
|
||||
return (
|
||||
<Fab
|
||||
size="small"
|
||||
color="secondary"
|
||||
aria-label="Add"
|
||||
className={props.classes.addButton}
|
||||
onClick={props.action}
|
||||
>
|
||||
<Fab size="small" color="secondary" aria-label="Add" className={props.classes.addButton} onClick={props.action}>
|
||||
<Add className={props.classes.addIcon} />
|
||||
</Fab>
|
||||
)
|
||||
|
||||
@@ -56,8 +56,8 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
<ClearAdornment action={this.clearCertificate} value={this.props.connection.selfSignedCertificate.name} />
|
||||
{this.props.connection.selfSignedCertificate.name}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -89,27 +89,26 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
className={classes.fullWidth}
|
||||
label="Subscription"
|
||||
margin="normal"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => this.setState({ subscription: event.target.value })}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
this.setState({ subscription: event.target.value })
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item={true} xs={2} className={classes.gridPadding}>
|
||||
<Button
|
||||
className={classes.button}
|
||||
color="secondary"
|
||||
onClick={() => this.props.managerActions.addSubscription(this.state.subscription, this.props.connection.id)}
|
||||
onClick={() =>
|
||||
this.props.managerActions.addSubscription(this.state.subscription, this.props.connection.id)
|
||||
}
|
||||
variant="contained"
|
||||
>
|
||||
<Add /> Add
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item={true} xs={12} style={{ padding: 0 }}>
|
||||
<List
|
||||
className={`${classes.topicList} advanced-connection-settings-topic-list`}
|
||||
component="nav"
|
||||
>
|
||||
<div className={classes.list}>
|
||||
{this.renderSubscriptions()}
|
||||
</div>
|
||||
<List className={`${classes.topicList} advanced-connection-settings-topic-list`} component="nav">
|
||||
<div className={classes.list}>{this.renderSubscriptions()}</div>
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item={true} xs={7} className={classes.gridPadding}>
|
||||
@@ -151,17 +150,15 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
const Subscription = (props: {
|
||||
subscription: string,
|
||||
deleteAction: any,
|
||||
}) => {
|
||||
const Subscription = (props: { subscription: string; deleteAction: any }) => {
|
||||
return (
|
||||
<ListItem style={{ padding: '0 0 0 8px' }}>
|
||||
<ListItemText>
|
||||
<IconButton onClick={props.deleteAction} style={{ padding: '6px' }}>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
{props.subscription}</ListItemText>
|
||||
{props.subscription}
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
)
|
||||
}
|
||||
@@ -199,4 +196,7 @@ const styles = (theme: Theme) => ({
|
||||
},
|
||||
})
|
||||
|
||||
export default connect(undefined, mapDispatchToProps)(withStyles(styles)(ConnectionSettings))
|
||||
export default connect(
|
||||
undefined,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ConnectionSettings))
|
||||
|
||||
@@ -29,17 +29,14 @@ import ConnectionHealthIndicator from '../helper/ConnectionHealthIndicator'
|
||||
|
||||
interface Props {
|
||||
connection: ConnectionOptions
|
||||
classes: {[s: string]: string}
|
||||
actions: typeof connectionActions,
|
||||
classes: { [s: string]: string }
|
||||
actions: typeof connectionActions
|
||||
managerActions: typeof connectionManagerActions
|
||||
connected: boolean
|
||||
connecting: boolean
|
||||
}
|
||||
|
||||
const protocols = [
|
||||
'mqtt',
|
||||
'ws',
|
||||
]
|
||||
const protocols = ['mqtt', 'ws']
|
||||
|
||||
interface State {
|
||||
showPassword: boolean
|
||||
@@ -127,20 +124,12 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
const { classes, connection } = this.props
|
||||
|
||||
const certSwitch = (
|
||||
<Switch
|
||||
checked={connection.certValidation}
|
||||
onChange={this.toggleCertValidation}
|
||||
color="primary"
|
||||
/>
|
||||
<Switch checked={connection.certValidation} onChange={this.toggleCertValidation} color="primary" />
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={classes.switch}>
|
||||
<FormControlLabel
|
||||
control={certSwitch}
|
||||
label="Validate certificate"
|
||||
labelPlacement="bottom"
|
||||
/>
|
||||
<FormControlLabel control={certSwitch} label="Validate certificate" labelPlacement="bottom" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -154,21 +143,11 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
private renderTlsSwitch() {
|
||||
const { classes, connection } = this.props
|
||||
|
||||
const tlsSwitch = (
|
||||
<Switch
|
||||
checked={connection.encryption}
|
||||
onChange={this.toggleTls}
|
||||
color="primary"
|
||||
/>
|
||||
)
|
||||
const tlsSwitch = <Switch checked={connection.encryption} onChange={this.toggleTls} color="primary" />
|
||||
|
||||
return (
|
||||
<div className={classes.switch}>
|
||||
<FormControlLabel
|
||||
control={tlsSwitch}
|
||||
label="Encryption (tls)"
|
||||
labelPlacement="bottom"
|
||||
/>
|
||||
<FormControlLabel control={tlsSwitch} label="Encryption (tls)" labelPlacement="bottom" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -185,12 +164,13 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
if (this.props.connecting) {
|
||||
return (
|
||||
<Button variant="contained" color="primary" className={classes.button} onClick={actions.disconnect}>
|
||||
<ConnectionHealthIndicator /> Abort
|
||||
<ConnectionHealthIndicator />
|
||||
Abort
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Button variant="contained" color="primary" className={classes.button} onClick={this.onClickConnect}>
|
||||
<Button variant="contained" color="primary" className={classes.button} onClick={this.onClickConnect}>
|
||||
<PowerSettingsNew /> Connect
|
||||
</Button>
|
||||
)
|
||||
@@ -212,10 +192,7 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
|
||||
const passwordVisibilityButton = (
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
aria-label="Toggle password visibility"
|
||||
onClick={this.handleClickShowPassword}
|
||||
>
|
||||
<IconButton aria-label="Toggle password visibility" onClick={this.handleClickShowPassword}>
|
||||
{this.state.showPassword ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
@@ -287,15 +264,28 @@ class ConnectionSettings extends React.Component<Props, State> {
|
||||
<br />
|
||||
<div>
|
||||
<div style={{ float: 'left' }}>
|
||||
<Button variant="contained" className={classes.button} onClick={() => this.props.managerActions.deleteConnection(this.props.connection.id)}>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
onClick={() => this.props.managerActions.deleteConnection(this.props.connection.id)}
|
||||
>
|
||||
Delete <Delete />
|
||||
</Button>
|
||||
<Button variant="contained" className={classes.button} onClick={this.props.managerActions.toggleAdvancedSettings}>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
onClick={this.props.managerActions.toggleAdvancedSettings}
|
||||
>
|
||||
<Settings /> Advanced
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ float : 'right' }}>
|
||||
<Button variant="contained" color="secondary" className={classes.button} onClick={this.props.managerActions.saveConnectionSettings}>
|
||||
<div style={{ float: 'right' }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
className={classes.button}
|
||||
onClick={this.props.managerActions.saveConnectionSettings}
|
||||
>
|
||||
<Save /> Save
|
||||
</Button>
|
||||
{this.renderConnectButton()}
|
||||
@@ -336,4 +326,7 @@ const styles = (theme: Theme) => ({
|
||||
},
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ConnectionSettings))
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ConnectionSettings))
|
||||
|
||||
@@ -7,13 +7,7 @@ import { connect } from 'react-redux'
|
||||
import { connectionManagerActions } from '../../actions'
|
||||
import { ConnectionOptions, toMqttConnection } from '../../model/ConnectionOptions'
|
||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||
import {
|
||||
Modal,
|
||||
Paper,
|
||||
Toolbar,
|
||||
Typography,
|
||||
Collapse,
|
||||
} from '@material-ui/core'
|
||||
import { Modal, Paper, Toolbar, Typography, Collapse } from '@material-ui/core'
|
||||
import AdvancedConnectionSettings from './AdvancedConnectionSettings'
|
||||
|
||||
interface Props {
|
||||
@@ -37,8 +31,12 @@ class ConnectionSetup extends React.Component<Props, {}> {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Collapse in={!showAdvancedSettings}><ConnectionSettings connection={connection} /></Collapse>
|
||||
<Collapse in={showAdvancedSettings}><AdvancedConnectionSettings connection={connection} /></Collapse>
|
||||
<Collapse in={!showAdvancedSettings}>
|
||||
<ConnectionSettings connection={connection} />
|
||||
</Collapse>
|
||||
<Collapse in={showAdvancedSettings}>
|
||||
<AdvancedConnectionSettings connection={connection} />
|
||||
</Collapse>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -54,13 +52,15 @@ class ConnectionSetup extends React.Component<Props, {}> {
|
||||
<div>
|
||||
<Modal open={visible} disableAutoFocus={true}>
|
||||
<Paper className={classes.root}>
|
||||
<div className={classes.left}><ProfileList /></div>
|
||||
<div className={classes.left}>
|
||||
<ProfileList />
|
||||
</div>
|
||||
<div className={classes.right} key={connection && connection.id}>
|
||||
<Toolbar>
|
||||
<Typography className={classes.title} variant="h6" color="inherit">MQTT Connection</Typography>
|
||||
<Typography className={classes.connectionUri}>
|
||||
{mqttConnection && mqttConnection.url}
|
||||
<Typography className={classes.title} variant="h6" color="inherit">
|
||||
MQTT Connection
|
||||
</Typography>
|
||||
<Typography className={classes.connectionUri}>{mqttConnection && mqttConnection.url}</Typography>
|
||||
</Toolbar>
|
||||
{this.renderSettings()}
|
||||
</div>
|
||||
@@ -115,7 +115,9 @@ const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
visible: !state.connection.connected,
|
||||
showAdvancedSettings: state.connectionManager.showAdvancedSettings,
|
||||
connection: state.connectionManager.selected ? state.connectionManager.connections[state.connectionManager.selected] : undefined,
|
||||
connection: state.connectionManager.selected
|
||||
? state.connectionManager.connections[state.connectionManager.selected]
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,4 +127,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ConnectionSetup))
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ConnectionSetup))
|
||||
|
||||
@@ -6,17 +6,12 @@ import { connect } from 'react-redux'
|
||||
import { connectionManagerActions } from '../../actions'
|
||||
import { ConnectionOptions, toMqttConnection } from '../../model/ConnectionOptions'
|
||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||
import {
|
||||
List,
|
||||
ListItem,
|
||||
ListSubheader,
|
||||
Typography,
|
||||
} from '@material-ui/core'
|
||||
import { List, ListItem, ListSubheader, Typography } from '@material-ui/core'
|
||||
|
||||
interface Props {
|
||||
classes: any
|
||||
selected?: string
|
||||
connections: {[s: string]: ConnectionOptions}
|
||||
connections: { [s: string]: ConnectionOptions }
|
||||
actions: any
|
||||
}
|
||||
|
||||
@@ -26,7 +21,11 @@ class ProfileList extends React.Component<Props, {}> {
|
||||
}
|
||||
|
||||
private addConnectionButton() {
|
||||
return <span id="addProfileButton" style={{ marginRight: '12px' }}><AddButton action={this.props.actions.createConnection} /></span>
|
||||
return (
|
||||
<span id="addProfileButton" style={{ marginRight: '12px' }}>
|
||||
<AddButton action={this.props.actions.createConnection} />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
public render() {
|
||||
@@ -37,7 +36,13 @@ class ProfileList extends React.Component<Props, {}> {
|
||||
subheader={<ListSubheader component="div">{this.addConnectionButton()}Connections</ListSubheader>}
|
||||
>
|
||||
<div className={this.props.classes.list}>
|
||||
{Object.values(this.props.connections).map(connection => <ConnectionItem connection={connection} key={connection.id} selected={this.props.selected === connection.id} />)}
|
||||
{Object.values(this.props.connections).map(connection => (
|
||||
<ConnectionItem
|
||||
connection={connection}
|
||||
key={connection.id}
|
||||
selected={this.props.selected === connection.id}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</List>
|
||||
)
|
||||
@@ -59,9 +64,9 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
|
||||
interface ConnectionItemProps {
|
||||
connection: ConnectionOptions,
|
||||
actions: any,
|
||||
selected: boolean,
|
||||
connection: ConnectionOptions
|
||||
actions: any
|
||||
selected: boolean
|
||||
classes: any
|
||||
}
|
||||
|
||||
@@ -91,17 +96,16 @@ const connectionItemRenderer = withStyles(connectionItemStyle)((props: Connectio
|
||||
style={{ display: 'block' }}
|
||||
onClick={() => props.actions.selectConnection(props.connection.id)}
|
||||
>
|
||||
<Typography className={props.classes.name}>
|
||||
{props.connection.name || 'mqtt broker'}
|
||||
</Typography>
|
||||
<Typography className={props.classes.details}>
|
||||
{connection && connection.url}
|
||||
</Typography>
|
||||
<Typography className={props.classes.name}>{props.connection.name || 'mqtt broker'}</Typography>
|
||||
<Typography className={props.classes.details}>{connection && connection.url}</Typography>
|
||||
</ListItem>
|
||||
)
|
||||
})
|
||||
|
||||
const ConnectionItem = connect(null, mapDispatchToProps)(connectionItemRenderer)
|
||||
const ConnectionItem = connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(connectionItemRenderer)
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
@@ -110,4 +114,7 @@ const mapStateToProps = (state: AppState) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ProfileList))
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ProfileList))
|
||||
|
||||
@@ -13,7 +13,6 @@ class Key extends React.Component<Props, {}> {
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
||||
return (
|
||||
<div className={this.props.classes.keyStyle}>
|
||||
<div className={this.props.classes.keyTextStyle}>{this.props.keyboardKey}</div>
|
||||
|
||||
@@ -4,13 +4,13 @@ const cursor = require('./cursor.png')
|
||||
|
||||
interface State {
|
||||
enabled: boolean
|
||||
target: {x: number, y: number}
|
||||
position: {x: number, y: number}
|
||||
stepSizeX: number,
|
||||
stepSizeY: number,
|
||||
target: { x: number; y: number }
|
||||
position: { x: number; y: number }
|
||||
stepSizeX: number
|
||||
stepSizeY: number
|
||||
}
|
||||
|
||||
class Demo extends React.Component<{classes: any}, State> {
|
||||
class Demo extends React.Component<{ classes: any }, State> {
|
||||
private timer: any
|
||||
private frameInterval = 20
|
||||
|
||||
@@ -32,8 +32,8 @@ class Demo extends React.Component<{classes: any}, State> {
|
||||
|
||||
this.setState({
|
||||
position: {
|
||||
x: this.state.position.x + (dirX * steSizeX),
|
||||
y: this.state.position.y + (dirY * steSizeY),
|
||||
x: this.state.position.x + dirX * steSizeX,
|
||||
y: this.state.position.y + dirY * steSizeY,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -43,10 +43,10 @@ class Demo extends React.Component<{classes: any}, State> {
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
(window as any).demo.enableMouse = () => {
|
||||
;(window as any).demo.enableMouse = () => {
|
||||
this.setState({ enabled: true })
|
||||
}
|
||||
(window as any).demo.moveMouse = (x: number, y: number, animationTime: number) => {
|
||||
;(window as any).demo.moveMouse = (x: number, y: number, animationTime: number) => {
|
||||
const stepSizeX = Math.abs(this.state.position.x - x) / (animationTime / this.frameInterval)
|
||||
const stepSizeY = Math.abs(this.state.position.y - y) / (animationTime / this.frameInterval)
|
||||
this.setState({ stepSizeX, stepSizeY, enabled: true, target: { x, y } })
|
||||
@@ -64,9 +64,7 @@ class Demo extends React.Component<{classes: any}, State> {
|
||||
top: this.state.position.y + 2,
|
||||
}
|
||||
|
||||
return (
|
||||
<img src={cursor} style={cursorStyle} className={this.props.classes.cursor} />
|
||||
)
|
||||
return <img src={cursor} style={cursorStyle} className={this.props.classes.cursor} />
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ interface State {
|
||||
location: string
|
||||
}
|
||||
|
||||
class Demo extends React.Component<{classes: any}, State> {
|
||||
class Demo extends React.Component<{ classes: any }, State> {
|
||||
private timer: any
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
@@ -20,20 +20,24 @@ class Demo extends React.Component<{classes: any}, State> {
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
(window as any).demo.showMessage = (message: string, location: string, duration: number, keys: Array<string> = []) => {
|
||||
;(window as any).demo.showMessage = (
|
||||
message: string,
|
||||
location: string,
|
||||
duration: number,
|
||||
keys: Array<string> = []
|
||||
) => {
|
||||
this.clearTimer()
|
||||
this.setState({ message, location, keys })
|
||||
this.timer = setTimeout(() => this.setState({ message: undefined }), duration)
|
||||
}
|
||||
|
||||
(window as any).demo.hideMessage = () => {
|
||||
;(window as any).demo.hideMessage = () => {
|
||||
this.clearTimer()
|
||||
this.setState({ message: undefined })
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const positions: {[s: string]: number} = {
|
||||
const positions: { [s: string]: number } = {
|
||||
top: 0,
|
||||
bottom: -65,
|
||||
middle: -32,
|
||||
@@ -52,7 +56,6 @@ class Demo extends React.Component<{classes: any}, State> {
|
||||
color: 'white',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
||||
borderRadius: '16px',
|
||||
|
||||
}
|
||||
|
||||
if (!this.state.message) {
|
||||
@@ -61,7 +64,8 @@ class Demo extends React.Component<{classes: any}, State> {
|
||||
|
||||
let keys: Array<any> = []
|
||||
if (this.state.keys.length > 0) {
|
||||
keys = this.state.keys.map(key => [<Key key={key} keyboardKey={key} />])
|
||||
keys = this.state.keys
|
||||
.map(key => [<Key key={key} keyboardKey={key} />])
|
||||
.reduce((prev, current) => {
|
||||
return [prev, '+' as any, current]
|
||||
})
|
||||
|
||||
@@ -12,7 +12,7 @@ function writeHeapdump(path?: string) {
|
||||
return path
|
||||
}
|
||||
|
||||
(window as any).demo = {
|
||||
;(window as any).demo = {
|
||||
writeHeapdump,
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,7 @@ import SentimentDissatisfied from '@material-ui/icons/SentimentDissatisfied'
|
||||
import Warning from '@material-ui/icons/Warning'
|
||||
import { electronRendererTelementry } from 'electron-telemetry'
|
||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
Paper,
|
||||
Toolbar,
|
||||
Typography,
|
||||
} from '@material-ui/core'
|
||||
import { Button, Modal, Paper, Toolbar, Typography } from '@material-ui/core'
|
||||
|
||||
interface State {
|
||||
error?: Error
|
||||
@@ -21,7 +15,6 @@ interface Props {
|
||||
}
|
||||
|
||||
class ErrorBoundary extends React.Component<Props, State> {
|
||||
|
||||
public static getDerivedStateFromError(error: Error) {
|
||||
return { error }
|
||||
}
|
||||
@@ -54,23 +47,36 @@ class ErrorBoundary extends React.Component<Props, State> {
|
||||
<Modal open={true} disableAutoFocus={true}>
|
||||
<Paper className={classes.root}>
|
||||
<Toolbar style={{ padding: '0' }}>
|
||||
<Typography className={classes.title} variant="h6" color="inherit"><Warning /> Oooooops!</Typography>
|
||||
<Typography className={classes.title} variant="h6" color="inherit">
|
||||
<Warning /> Oooooops!
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
<Typography className={classes.centered}>I hoped that you would never see this window, but MQTT-Explorer had an unexpected error.</Typography>
|
||||
<Typography className={classes.centered}><SentimentDissatisfied /></Typography>
|
||||
<Typography className={classes.centered}>
|
||||
I hoped that you would never see this window, but MQTT-Explorer had an unexpected error.
|
||||
</Typography>
|
||||
<Typography className={classes.centered}>
|
||||
<SentimentDissatisfied />
|
||||
</Typography>
|
||||
<pre className={classes.textColor} style={{ maxHeight: '35vh', overflow: 'scroll' }}>
|
||||
<code className={classes.textColor}>
|
||||
{this.state.error.stack}
|
||||
</code>
|
||||
<code className={classes.textColor}>{this.state.error.stack}</code>
|
||||
</pre>
|
||||
<Typography>
|
||||
Please report this issue with a short description of what happened to
|
||||
<span> <a className={classes.textColor} href="https://github.com/thomasnordquist/MQTT-Explorer/issues">https://github.com/thomasnordquist/MQTT-Explorer/issues</a></span>
|
||||
<span>
|
||||
{' '}
|
||||
<a className={classes.textColor} href="https://github.com/thomasnordquist/MQTT-Explorer/issues">
|
||||
https://github.com/thomasnordquist/MQTT-Explorer/issues
|
||||
</a>
|
||||
</span>
|
||||
</Typography>
|
||||
<div>
|
||||
<div className={classes.buttonPositioning}>
|
||||
<Button className={classes.button} variant="contained" color="secondary" onClick={this.clearStorage}>Start Fresh</Button>
|
||||
<Button className={classes.button} variant="contained" color="primary" onClick={this.restart}>Restart</Button>
|
||||
<Button className={classes.button} variant="contained" color="secondary" onClick={this.clearStorage}>
|
||||
Start Fresh
|
||||
</Button>
|
||||
<Button className={classes.button} variant="contained" color="primary" onClick={this.restart}>
|
||||
Restart
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Paper>
|
||||
|
||||
@@ -3,7 +3,7 @@ import ReactSplitPane from 'react-split-pane'
|
||||
import { Sidebar } from '../Sidebar'
|
||||
import Tree from '../Tree/Tree'
|
||||
|
||||
export default function ContentView(props: {heightProperty: any, paneDefaults: any, connectionId: any}) {
|
||||
export default function ContentView(props: { heightProperty: any; paneDefaults: any; connectionId: any }) {
|
||||
return (
|
||||
<ReactSplitPane
|
||||
step={20}
|
||||
|
||||
@@ -22,13 +22,13 @@ const styles = (theme: Theme) => ({
|
||||
interface Props {
|
||||
classes: any
|
||||
actions: {
|
||||
tree: typeof treeActions,
|
||||
tree: typeof treeActions
|
||||
}
|
||||
paused: boolean
|
||||
tree?: q.Tree<any>
|
||||
}
|
||||
|
||||
class PauseButton extends React.Component<Props, {changes: number}> {
|
||||
class PauseButton extends React.Component<Props, { changes: number }> {
|
||||
private timer?: any
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
@@ -42,7 +42,8 @@ class PauseButton extends React.Component<Props, {changes: number}> {
|
||||
|
||||
return (
|
||||
<span className={this.props.classes.bufferStats}>
|
||||
{this.state.changes} changes<br />
|
||||
{this.state.changes} changes
|
||||
<br />
|
||||
buffer at {Math.round(this.props.tree.unmergedChanges().fillState() * 10000) / 100}%
|
||||
</span>
|
||||
)
|
||||
@@ -66,12 +67,18 @@ class PauseButton extends React.Component<Props, {changes: number}> {
|
||||
}
|
||||
|
||||
public render() {
|
||||
const message = this.props.paused ? 'Resumes updating the tree, after applying all recorded changes' : 'Stops all updates, records changes until the buffer is full.'
|
||||
const message = this.props.paused
|
||||
? 'Resumes updating the tree, after applying all recorded changes'
|
||||
: 'Stops all updates, records changes until the buffer is full.'
|
||||
return (
|
||||
<div style={{ display: 'inline-flex' }}>
|
||||
<span>
|
||||
<CustomIconButton onClick={this.props.actions.tree.togglePause} tooltip={message}>
|
||||
{this.props.paused ? <Resume className={this.props.classes.icon} /> : <Pause className={this.props.classes.icon} />}
|
||||
{this.props.paused ? (
|
||||
<Resume className={this.props.classes.icon} />
|
||||
) : (
|
||||
<Pause className={this.props.classes.icon} />
|
||||
)}
|
||||
</CustomIconButton>
|
||||
</span>
|
||||
{this.props.paused ? this.renderBufferStats() : null}
|
||||
@@ -95,4 +102,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(PauseButton))
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(PauseButton))
|
||||
|
||||
@@ -11,14 +11,7 @@ import { connect } from 'react-redux'
|
||||
import { connectionActions, globalActions, settingsActions } from '../../actions'
|
||||
import { fade } from '@material-ui/core/styles/colorManipulator'
|
||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||
import {
|
||||
AppBar,
|
||||
Button,
|
||||
IconButton,
|
||||
InputBase,
|
||||
Toolbar,
|
||||
Typography,
|
||||
} from '@material-ui/core'
|
||||
import { AppBar, Button, IconButton, InputBase, Toolbar, Typography } from '@material-ui/core'
|
||||
|
||||
const styles = (theme: Theme) => ({
|
||||
title: {
|
||||
@@ -92,9 +85,9 @@ const styles = (theme: Theme) => ({
|
||||
interface Props {
|
||||
classes: any
|
||||
actions: {
|
||||
settings: typeof settingsActions,
|
||||
connection: typeof connectionActions,
|
||||
global: typeof globalActions,
|
||||
settings: typeof settingsActions
|
||||
connection: typeof connectionActions
|
||||
global: typeof globalActions
|
||||
}
|
||||
topicFilter?: string
|
||||
}
|
||||
@@ -102,7 +95,7 @@ interface Props {
|
||||
class TitleBar extends React.Component<Props, {}> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { }
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
private renderSearch() {
|
||||
@@ -117,7 +110,11 @@ class TitleBar extends React.Component<Props, {}> {
|
||||
value={topicFilter}
|
||||
onChange={this.onFilterChange}
|
||||
placeholder="Search…"
|
||||
endAdornment={<div style={{ width: '24px', paddingRight: '8px' }}><ClearAdornment variant="primary" action={this.clearFilter} value={topicFilter} /></div>}
|
||||
endAdornment={
|
||||
<div style={{ width: '24px', paddingRight: '8px' }}>
|
||||
<ClearAdornment variant="primary" action={this.clearFilter} value={topicFilter} />
|
||||
</div>
|
||||
}
|
||||
classes={{ root: classes.inputRoot, input: classes.inputInput }}
|
||||
/>
|
||||
</div>
|
||||
@@ -138,10 +135,17 @@ class TitleBar extends React.Component<Props, {}> {
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu" onClick={actions.global.toggleSettingsVisibility}>
|
||||
<IconButton
|
||||
className={classes.menuButton}
|
||||
color="inherit"
|
||||
aria-label="Menu"
|
||||
onClick={actions.global.toggleSettingsVisibility}
|
||||
>
|
||||
<Menu />
|
||||
</IconButton>
|
||||
<Typography className={classes.title} variant="h6" color="inherit">MQTT Explorer</Typography>
|
||||
<Typography className={classes.title} variant="h6" color="inherit">
|
||||
MQTT Explorer
|
||||
</Typography>
|
||||
{this.renderSearch()}
|
||||
<PauseButton />
|
||||
<Button className={classes.disconnect} onClick={actions.connection.disconnect}>
|
||||
@@ -170,4 +174,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(TitleBar))
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(TitleBar))
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import * as React from 'react'
|
||||
import {
|
||||
InputLabel,
|
||||
Switch,
|
||||
Theme,
|
||||
Tooltip
|
||||
} from '@material-ui/core'
|
||||
import { InputLabel, Switch, Theme, Tooltip } from '@material-ui/core'
|
||||
import { withStyles } from '@material-ui/styles'
|
||||
const sha1 = require('sha1')
|
||||
|
||||
function BooleanSwitch(props: {title: string, value: boolean, tooltip: string, action: () => void, classes: any}) {
|
||||
function BooleanSwitch(props: { title: string; value: boolean; tooltip: string; action: () => void; classes: any }) {
|
||||
const { tooltip, value, action, title, classes } = props
|
||||
|
||||
const clickHandler = (e: React.MouseEvent) => {
|
||||
@@ -20,21 +15,12 @@ function BooleanSwitch(props: {title: string, value: boolean, tooltip: string, a
|
||||
return (
|
||||
<div style={{ padding: '8px', display: 'flex' }}>
|
||||
<Tooltip title={tooltip}>
|
||||
<InputLabel
|
||||
htmlFor={`toggle-${sha1(title)}`}
|
||||
onClick={clickHandler}
|
||||
className={classes.label}
|
||||
>
|
||||
<InputLabel htmlFor={`toggle-${sha1(title)}`} onClick={clickHandler} className={classes.label}>
|
||||
{title}
|
||||
</InputLabel>
|
||||
</Tooltip>
|
||||
<Tooltip title={tooltip}>
|
||||
<Switch
|
||||
name={`toggle-${sha1(title)}`}
|
||||
checked={value}
|
||||
onChange={action}
|
||||
color="primary"
|
||||
/>
|
||||
<Switch name={`toggle-${sha1(title)}`} checked={value} onChange={action} color="primary" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -112,13 +112,17 @@ class BrokerStatistics extends React.Component<Props, {}> {
|
||||
}
|
||||
|
||||
const str = node.message.value ? Base64Message.toUnicodeString(node.message.value) : ''
|
||||
let value = (node.message && node.message.value) ? parseFloat(str) : NaN
|
||||
let value = node.message && node.message.value ? parseFloat(str) : NaN
|
||||
value = !isNaN(value) ? abbreviate(value) : str
|
||||
|
||||
return (
|
||||
<div key={stat.title}>
|
||||
<Typography><b>{stat.title}</b></Typography>
|
||||
<Typography style={{ paddingLeft: '8px' }}><i>{value}</i></Typography>
|
||||
<Typography>
|
||||
<b>{stat.title}</b>
|
||||
</Typography>
|
||||
<Typography style={{ paddingLeft: '8px' }}>
|
||||
<i>{value}</i>
|
||||
</Typography>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,25 +23,32 @@ import {
|
||||
Tooltip,
|
||||
} from '@material-ui/core'
|
||||
|
||||
export const autoExpandLimitSet = [{
|
||||
limit: 0,
|
||||
name: 'Collapsed',
|
||||
}, {
|
||||
limit: 2,
|
||||
name: 'Few',
|
||||
}, {
|
||||
limit: 5,
|
||||
name: 'Some',
|
||||
}, {
|
||||
limit: 15,
|
||||
name: 'Most',
|
||||
}, {
|
||||
limit: 30,
|
||||
name: 'Most',
|
||||
}, {
|
||||
limit: 1E6,
|
||||
name: 'All',
|
||||
}]
|
||||
export const autoExpandLimitSet = [
|
||||
{
|
||||
limit: 0,
|
||||
name: 'Collapsed',
|
||||
},
|
||||
{
|
||||
limit: 2,
|
||||
name: 'Few',
|
||||
},
|
||||
{
|
||||
limit: 5,
|
||||
name: 'Some',
|
||||
},
|
||||
{
|
||||
limit: 15,
|
||||
name: 'Most',
|
||||
},
|
||||
{
|
||||
limit: 30,
|
||||
name: 'Most',
|
||||
},
|
||||
{
|
||||
limit: 1e6,
|
||||
name: 'All',
|
||||
},
|
||||
]
|
||||
|
||||
const styles = (theme: Theme) => ({
|
||||
drawer: {
|
||||
@@ -70,8 +77,8 @@ const styles = (theme: Theme) => ({
|
||||
|
||||
interface Props {
|
||||
actions: {
|
||||
settings: typeof settingsActions,
|
||||
global: typeof globalActions,
|
||||
settings: typeof settingsActions
|
||||
global: typeof globalActions
|
||||
}
|
||||
autoExpandLimit: number
|
||||
classes: any
|
||||
@@ -96,29 +103,56 @@ class Settings extends React.Component<Props, {}> {
|
||||
private renderHighlightTopicUpdates() {
|
||||
const { highlightTopicUpdates, actions } = this.props
|
||||
|
||||
return <BooleanSwitch title="Show Activity" tooltip="Topics blink when a new message arrives" value={highlightTopicUpdates} action={actions.settings.toggleHighlightTopicUpdates}/>
|
||||
return (
|
||||
<BooleanSwitch
|
||||
title="Show Activity"
|
||||
tooltip="Topics blink when a new message arrives"
|
||||
value={highlightTopicUpdates}
|
||||
action={actions.settings.toggleHighlightTopicUpdates}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private selectTopicsOnMouseOver() {
|
||||
const { actions, selectTopicWithMouseOver } = this.props
|
||||
const toggle = () => actions.settings.selectTopicWithMouseOver(!selectTopicWithMouseOver)
|
||||
|
||||
return <BooleanSwitch title="Quick Preview" tooltip="Select topics on mouse over" value={selectTopicWithMouseOver} action={toggle} />
|
||||
return (
|
||||
<BooleanSwitch
|
||||
title="Quick Preview"
|
||||
tooltip="Select topics on mouse over"
|
||||
value={selectTopicWithMouseOver}
|
||||
action={toggle}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private toggleTheme() {
|
||||
const { actions, theme } = this.props
|
||||
|
||||
return <BooleanSwitch title="Dark Mode" tooltip="Enable dark theme" value={theme === 'dark'} action={actions.settings.toggleTheme} />
|
||||
return (
|
||||
<BooleanSwitch
|
||||
title="Dark Mode"
|
||||
tooltip="Enable dark theme"
|
||||
value={theme === 'dark'}
|
||||
action={actions.settings.toggleTheme}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private renderAutoExpand() {
|
||||
const { classes, autoExpandLimit } = this.props
|
||||
|
||||
const limits = autoExpandLimitSet.map(limit => <MenuItem key={limit.limit} value={limit.limit}>{limit.limit < 10000 && limit.limit > 0 ? `≤ ${limit.limit} topics` : limit.name}</MenuItem>)
|
||||
const limits = autoExpandLimitSet.map(limit => (
|
||||
<MenuItem key={limit.limit} value={limit.limit}>
|
||||
{limit.limit < 10000 && limit.limit > 0 ? `≤ ${limit.limit} topics` : limit.name}
|
||||
</MenuItem>
|
||||
))
|
||||
return (
|
||||
<div style={{ padding: '8px', display: 'flex' }}>
|
||||
<InputLabel htmlFor="auto-expand" style={{ flex: '1', marginTop: '8px' }}>Auto Expand</InputLabel>
|
||||
<InputLabel htmlFor="auto-expand" style={{ flex: '1', marginTop: '8px' }}>
|
||||
Auto Expand
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={autoExpandLimit}
|
||||
onChange={this.onChangeAutoExpand}
|
||||
@@ -133,7 +167,7 @@ class Settings extends React.Component<Props, {}> {
|
||||
)
|
||||
}
|
||||
|
||||
private onChangeAutoExpand = (e: React.ChangeEvent<{value: unknown}>) => {
|
||||
private onChangeAutoExpand = (e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
this.props.actions.settings.setAutoExpandLimit(parseInt(String(e.target.value), 10))
|
||||
}
|
||||
|
||||
@@ -142,7 +176,9 @@ class Settings extends React.Component<Props, {}> {
|
||||
|
||||
return (
|
||||
<div style={{ padding: '8px', display: 'flex' }}>
|
||||
<InputLabel htmlFor="auto-expand" style={{ flex: '1', marginTop: '8px' }}>Topic Order</InputLabel>
|
||||
<InputLabel htmlFor="auto-expand" style={{ flex: '1', marginTop: '8px' }}>
|
||||
Topic Order
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={topicOrder}
|
||||
onChange={this.onChangeSorting}
|
||||
@@ -152,32 +188,26 @@ class Settings extends React.Component<Props, {}> {
|
||||
className={classes.input}
|
||||
style={{ flex: '1' }}
|
||||
>
|
||||
<MenuItem value={TopicOrder.none}><em>default</em></MenuItem>
|
||||
<MenuItem value={TopicOrder.none}>
|
||||
<em>default</em>
|
||||
</MenuItem>
|
||||
<MenuItem value={TopicOrder.abc}>a-z</MenuItem>
|
||||
<MenuItem value={TopicOrder.messages}>{TopicOrder.messages}</MenuItem>
|
||||
<MenuItem value={TopicOrder.topics}>{TopicOrder.topics}</MenuItem>
|
||||
</Select>
|
||||
</div>)
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private onChangeSorting = (e: React.ChangeEvent<{value: unknown}>) => {
|
||||
private onChangeSorting = (e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
this.props.actions.settings.setTopicOrder(e.target.value as TopicOrder)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { classes, actions, visible } = this.props
|
||||
return (
|
||||
<Drawer
|
||||
anchor="left"
|
||||
className={classes.drawer}
|
||||
open={visible}
|
||||
variant="persistent"
|
||||
>
|
||||
<div
|
||||
className={classes.paper}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
<Drawer anchor="left" className={classes.drawer} open={visible} variant="persistent">
|
||||
<div className={classes.paper} tabIndex={0} role="button">
|
||||
<Typography className={classes.title} variant="h6" color="inherit">
|
||||
<IconButton onClick={actions.global.toggleSettingsVisibility}>
|
||||
<ChevronRight />
|
||||
@@ -225,4 +255,9 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(Settings))
|
||||
export default withStyles(styles)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Settings)
|
||||
)
|
||||
|
||||
@@ -3,14 +3,7 @@ import DateFormatter from '../helper/DateFormatter'
|
||||
import { AppState } from '../../reducers'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
Input,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
StyleRulesCallback,
|
||||
Theme
|
||||
} from '@material-ui/core'
|
||||
import { Input, InputLabel, MenuItem, Select, StyleRulesCallback, Theme } from '@material-ui/core'
|
||||
import { settingsActions } from '../../actions'
|
||||
import { withStyles } from '@material-ui/styles'
|
||||
const moment = require('moment/min/moment-with-locales')
|
||||
@@ -18,7 +11,7 @@ const moment = require('moment/min/moment-with-locales')
|
||||
interface Props {
|
||||
actions: {
|
||||
settings: typeof settingsActions
|
||||
},
|
||||
}
|
||||
timeLocale: string
|
||||
classes: any
|
||||
}
|
||||
@@ -29,26 +22,33 @@ function TimeLocaleSettings(props: Props) {
|
||||
const date = new Date()
|
||||
const localeMenuItems = locales.map((l: string) => (
|
||||
<MenuItem key={l} value={l}>
|
||||
<div>Locale: <b>{l}</b>, Format: <b><DateFormatter date={date} overrideLocale={l} /></b></div>
|
||||
<div>
|
||||
Locale: <b>{l}</b>, Format:{' '}
|
||||
<b>
|
||||
<DateFormatter date={date} overrideLocale={l} />
|
||||
</b>
|
||||
</div>
|
||||
</MenuItem>
|
||||
))
|
||||
|
||||
function updateLocale(e: React.ChangeEvent<{value: unknown}>) {
|
||||
function updateLocale(e: React.ChangeEvent<{ value: unknown }>) {
|
||||
const locale = e.target.value ? String(e.target.value) : ''
|
||||
actions.settings.setTimeLocale(locale)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '8px', display: 'flex' }}>
|
||||
<InputLabel htmlFor="time-locale" style={{ flex: '1', marginTop: '8px' }}>Time Locale</InputLabel>
|
||||
<InputLabel htmlFor="time-locale" style={{ flex: '1', marginTop: '8px' }}>
|
||||
Time Locale
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={timeLocale}
|
||||
onChange={updateLocale}
|
||||
input={<Input name="time-locale" id="time-locale-label-placeholder" />}
|
||||
name="time-locale"
|
||||
className={classes.input}
|
||||
renderValue={v => <span>{String(v)}</span>}
|
||||
style={{ flex: '1' }}
|
||||
value={timeLocale}
|
||||
onChange={updateLocale}
|
||||
input={<Input name="time-locale" id="time-locale-label-placeholder" />}
|
||||
name="time-locale"
|
||||
className={classes.input}
|
||||
renderValue={v => <span>{String(v)}</span>}
|
||||
style={{ flex: '1' }}
|
||||
>
|
||||
{localeMenuItems}
|
||||
</Select>
|
||||
@@ -82,4 +82,9 @@ const styles = (theme: Theme) => ({
|
||||
},
|
||||
})
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(TimeLocaleSettings))
|
||||
export default withStyles(styles)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TimeLocaleSettings)
|
||||
)
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import * as React from 'react'
|
||||
import { Theme } from '@material-ui/core';
|
||||
import { Theme } from '@material-ui/core'
|
||||
import { withStyles } from '@material-ui/styles'
|
||||
|
||||
interface Props {
|
||||
changes: Array<Diff.Change>
|
||||
classes: {[s: string]: any}
|
||||
classes: { [s: string]: any }
|
||||
nameOfCompareMessage: string
|
||||
}
|
||||
|
||||
function changeAmount(props: Props) {
|
||||
const additions = props.changes.map(change => (change.added === true) ? (change.count || 0) : 0).reduce((a, b) => a + b)
|
||||
const deletions = props.changes.map(change => (change.removed === true) ? (change.count || 0) : 0).reduce((a, b) => a + b)
|
||||
const additions = props.changes.map(change => (change.added === true ? change.count || 0 : 0)).reduce((a, b) => a + b)
|
||||
const deletions = props.changes
|
||||
.map(change => (change.removed === true ? change.count || 0 : 0))
|
||||
.reduce((a, b) => a + b)
|
||||
if (additions === 0 && deletions === 0) {
|
||||
return null
|
||||
}
|
||||
@@ -19,9 +21,13 @@ function changeAmount(props: Props) {
|
||||
<span style={{ display: 'block', marginBottom: '8px', float: 'right' }}>
|
||||
<span>
|
||||
Comparing with <b>{props.nameOfCompareMessage}</b> message:
|
||||
|
||||
<span className={props.classes.additions}>+ {additions} line{additions === 1 ? '' : 's'}</span>
|
||||
, <span className={props.classes.deletions}>- {deletions} line{deletions === 1 ? '' : 's'}</span>
|
||||
<span className={props.classes.additions}>
|
||||
+ {additions} line{additions === 1 ? '' : 's'}
|
||||
</span>
|
||||
,{' '}
|
||||
<span className={props.classes.deletions}>
|
||||
- {deletions} line{deletions === 1 ? '' : 's'}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -5,19 +5,13 @@ import Add from '@material-ui/icons/Add'
|
||||
import Remove from '@material-ui/icons/Remove'
|
||||
import ShowChart from '@material-ui/icons/ShowChart'
|
||||
import TopicPlot from '../TopicPlot'
|
||||
import {
|
||||
Fade,
|
||||
Paper,
|
||||
Popper,
|
||||
Theme,
|
||||
Tooltip
|
||||
} from '@material-ui/core'
|
||||
import { Fade, Paper, Popper, Theme, Tooltip } from '@material-ui/core'
|
||||
import { JsonPropertyLocation } from '../../../../../backend/src/JsonAstParser'
|
||||
import { lineChangeStyle, trimNewlineRight } from './util'
|
||||
import { withStyles } from '@material-ui/styles'
|
||||
|
||||
interface Props {
|
||||
changes: Array<diff.Change>,
|
||||
changes: Array<diff.Change>
|
||||
literalPositions: Array<JsonPropertyLocation>
|
||||
classes: any
|
||||
className: string
|
||||
@@ -58,32 +52,32 @@ const style = (theme: Theme) => {
|
||||
}
|
||||
}
|
||||
|
||||
function ChartIcon(props: { messageHistory: q.MessageHistory, classes: any, literal: JsonPropertyLocation }) {
|
||||
function ChartIcon(props: { messageHistory: q.MessageHistory; classes: any; literal: JsonPropertyLocation }) {
|
||||
const chartIconRef = React.useRef(null)
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
const mouseOver = React.useCallback((event: React.MouseEvent<Element>) => {
|
||||
setOpen(true)
|
||||
}, [props.literal.path])
|
||||
const mouseOver = React.useCallback(
|
||||
(event: React.MouseEvent<Element>) => {
|
||||
setOpen(true)
|
||||
},
|
||||
[props.literal.path]
|
||||
)
|
||||
|
||||
const mouseOut = React.useCallback(() => {
|
||||
setOpen(false)
|
||||
}, [])
|
||||
|
||||
return (<span>
|
||||
<ShowChart ref={chartIconRef} className={props.classes.icon} onMouseEnter={mouseOver} onMouseLeave={mouseOut} />
|
||||
<Popper
|
||||
open={open}
|
||||
anchorEl={chartIconRef.current}
|
||||
placement="left-end"
|
||||
>
|
||||
<Fade in={open} timeout={300}>
|
||||
<Paper style={{ width: '300px' }}>
|
||||
{open ? <TopicPlot history={props.messageHistory} dotPath={props.literal.path} /> : <span/>}
|
||||
</Paper>
|
||||
</Fade>
|
||||
</Popper>
|
||||
</span>
|
||||
return (
|
||||
<span>
|
||||
<ShowChart ref={chartIconRef} className={props.classes.icon} onMouseEnter={mouseOver} onMouseLeave={mouseOut} />
|
||||
<Popper open={open} anchorEl={chartIconRef.current} placement="left-end">
|
||||
<Fade in={open} timeout={300}>
|
||||
<Paper style={{ width: '300px' }}>
|
||||
{open ? <TopicPlot history={props.messageHistory} dotPath={props.literal.path} /> : <span />}
|
||||
</Paper>
|
||||
</Fade>
|
||||
</Popper>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -95,9 +89,19 @@ function tokensForLine(change: diff.Change, line: number, props: Props) {
|
||||
let chartIcon = null
|
||||
if (literal) {
|
||||
if (hasEnoughDataToDisplayDiagrams) {
|
||||
chartIcon = <ChartIcon messageHistory={props.messageHistory} classes={{ icon: props.classes.iconButton }} literal={literal} />
|
||||
chartIcon = (
|
||||
<ChartIcon
|
||||
messageHistory={props.messageHistory}
|
||||
classes={{ icon: props.classes.iconButton }}
|
||||
literal={literal}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
chartIcon = <Tooltip title="Not enough data"><ShowChart className={props.classes.iconDisabled} style={{ color: '#aaa' }} /></Tooltip>
|
||||
chartIcon = (
|
||||
<Tooltip title="Not enough data">
|
||||
<ShowChart className={props.classes.iconDisabled} style={{ color: '#aaa' }} />
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,28 +110,39 @@ function tokensForLine(change: diff.Change, line: number, props: Props) {
|
||||
} else if (change.removed) {
|
||||
return [<Remove key="remove" className={classes.icon} />]
|
||||
} else {
|
||||
return [chartIcon, <div key="placeholder" style={{ width: '12px', display: 'inline-block' }} dangerouslySetInnerHTML={{ __html: ' ' }} />]
|
||||
return [
|
||||
chartIcon,
|
||||
<div
|
||||
key="placeholder"
|
||||
style={{ width: '12px', display: 'inline-block' }}
|
||||
dangerouslySetInnerHTML={{ __html: ' ' }}
|
||||
/>,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function Gutters(props: Props) {
|
||||
let currentLine = -1
|
||||
const gutters = props.changes.map((change, key) => {
|
||||
return trimNewlineRight(change.value)
|
||||
.split('\n')
|
||||
.map((_, idx) => {
|
||||
currentLine = !change.removed ? currentLine + 1 : currentLine
|
||||
return (
|
||||
<div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={props.classes.gutterLine}>
|
||||
{tokensForLine(change, currentLine, props)}
|
||||
</div>
|
||||
)
|
||||
const gutters = props.changes
|
||||
.map((change, key) => {
|
||||
return trimNewlineRight(change.value)
|
||||
.split('\n')
|
||||
.map((_, idx) => {
|
||||
currentLine = !change.removed ? currentLine + 1 : currentLine
|
||||
return (
|
||||
<div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={props.classes.gutterLine}>
|
||||
{tokensForLine(change, currentLine, props)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
})
|
||||
}).reduce((a, b) => a.concat(b), [])
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
|
||||
return <span>
|
||||
<pre className={props.className}>{gutters}</pre>
|
||||
</span>
|
||||
return (
|
||||
<span>
|
||||
<pre className={props.className}>{gutters}</pre>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default withStyles(style)(Gutters)
|
||||
|
||||
@@ -40,35 +40,46 @@ class CodeDiff extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
private plottableLiteralsIndexedWithLineNumbers() {
|
||||
const allLiterals = this.isValidJson(this.props.current) ? (literalsMappedByLines(this.props.current) || []) : []
|
||||
const allLiterals = this.isValidJson(this.props.current) ? literalsMappedByLines(this.props.current) || [] : []
|
||||
|
||||
return allLiterals
|
||||
.map((l: JsonPropertyLocation) => isPlottable(l.value) ? l : undefined) as Array<JsonPropertyLocation>
|
||||
return allLiterals.map((l: JsonPropertyLocation) => (isPlottable(l.value) ? l : undefined)) as Array<
|
||||
JsonPropertyLocation
|
||||
>
|
||||
}
|
||||
|
||||
private renderStyledCodeLines(changes: Array<Diff.Change>) {
|
||||
const styledLines = Prism.highlight(this.props.current, Prism.languages.json, 'json').split('\n')
|
||||
let lineNumber = 0
|
||||
|
||||
return changes.map((change, key) => {
|
||||
const hasStyledCode = change.removed !== true
|
||||
const changedLines = change.count || 0
|
||||
if (hasStyledCode && this.props.language === 'json') {
|
||||
const currentLines = styledLines.slice(lineNumber, lineNumber + changedLines)
|
||||
const lines = currentLines.map((html: string, idx: number) => {
|
||||
return <div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={this.props.classes.line}><span dangerouslySetInnerHTML={{ __html: html }} /></div>
|
||||
})
|
||||
lineNumber += changedLines
|
||||
return changes
|
||||
.map((change, key) => {
|
||||
const hasStyledCode = change.removed !== true
|
||||
const changedLines = change.count || 0
|
||||
if (hasStyledCode && this.props.language === 'json') {
|
||||
const currentLines = styledLines.slice(lineNumber, lineNumber + changedLines)
|
||||
const lines = currentLines.map((html: string, idx: number) => {
|
||||
return (
|
||||
<div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={this.props.classes.line}>
|
||||
<span dangerouslySetInnerHTML={{ __html: html }} />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
lineNumber += changedLines
|
||||
|
||||
return [<div key={key}>{lines}</div>]
|
||||
}
|
||||
return [<div key={key}>{lines}</div>]
|
||||
}
|
||||
|
||||
return trimNewlineRight(change.value)
|
||||
.split('\n')
|
||||
.map((line, idx) => {
|
||||
return <div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={this.props.classes.line}><span>{line}</span></div>
|
||||
})
|
||||
}).reduce((a, b) => a.concat(b), [])
|
||||
return trimNewlineRight(change.value)
|
||||
.split('\n')
|
||||
.map((line, idx) => {
|
||||
return (
|
||||
<div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={this.props.classes.line}>
|
||||
<span>{line}</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
})
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
}
|
||||
|
||||
public render() {
|
||||
@@ -83,7 +94,8 @@ class CodeDiff extends React.Component<Props, State> {
|
||||
className={this.props.classes.gutters}
|
||||
changes={changes}
|
||||
messageHistory={this.props.messageHistory}
|
||||
literalPositions={literalPositions} />
|
||||
literalPositions={literalPositions}
|
||||
/>
|
||||
<pre className={this.props.classes.codeBlock}>{code}</pre>
|
||||
</div>
|
||||
<DiffCount changes={changes} nameOfCompareMessage={this.props.nameOfCompareMessage} />
|
||||
|
||||
@@ -38,7 +38,9 @@ class HistoryDrawer extends React.Component<Props, State> {
|
||||
|
||||
public renderHistory() {
|
||||
const style = (element: HistoryItem) => ({
|
||||
backgroundColor: element.selected ? this.props.theme.palette.action.selected : this.props.theme.palette.action.hover,
|
||||
backgroundColor: element.selected
|
||||
? this.props.theme.palette.action.selected
|
||||
: this.props.theme.palette.action.hover,
|
||||
margin: '8px',
|
||||
padding: '8px 8px 0 8px',
|
||||
cursor: this.props.onClick ? 'pointer' : 'inherit',
|
||||
@@ -50,11 +52,16 @@ class HistoryDrawer extends React.Component<Props, State> {
|
||||
key={element.key}
|
||||
style={style(element)}
|
||||
onClick={(event: React.MouseEvent) => this.props.onClick && this.props.onClick(index, event.target)}
|
||||
tabIndex={0} onKeyDown={this.handleCtrlA}
|
||||
tabIndex={0}
|
||||
onKeyDown={this.handleCtrlA}
|
||||
>
|
||||
<div><i>{element.title}</i></div>
|
||||
<div>
|
||||
<i>{element.title}</i>
|
||||
</div>
|
||||
<div style={messageStyle}>
|
||||
<span><pre>{element.value}</pre></span>
|
||||
<span>
|
||||
<pre>{element.value}</pre>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
@@ -63,11 +70,7 @@ class HistoryDrawer extends React.Component<Props, State> {
|
||||
|
||||
return (
|
||||
<div className={this.props.classes.main}>
|
||||
<Typography
|
||||
component={'span'}
|
||||
onClick={this.toggle}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
<Typography component={'span'} onClick={this.toggle} style={{ cursor: 'pointer' }}>
|
||||
<Badge
|
||||
classes={{ badge: this.props.classes.badge }}
|
||||
invisible={!visible}
|
||||
@@ -78,7 +81,7 @@ class HistoryDrawer extends React.Component<Props, State> {
|
||||
</Badge>
|
||||
<div style={{ float: 'right' }}>{this.state.collapsed ? this.props.contentTypeIndicator : null}</div>
|
||||
</Typography>
|
||||
<div style={{ maxHeight: '230px', overflowY: 'scroll' }}>
|
||||
<div style={{ maxHeight: '230px', overflowY: 'scroll' }}>
|
||||
{this.state.collapsed ? null : this.props.children}
|
||||
{this.state.collapsed ? null : elements}
|
||||
</div>
|
||||
@@ -87,13 +90,7 @@ class HistoryDrawer extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
style={{ display: 'block', width: '100%' }}
|
||||
>
|
||||
{this.renderHistory()}
|
||||
</div>
|
||||
)
|
||||
return <div style={{ display: 'block', width: '100%' }}>{this.renderHistory()}</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ const { XYPlot, LineMarkSeries, Hint, XAxis, YAxis, HorizontalGridLines } = requ
|
||||
const abbreviate = require('number-abbreviate')
|
||||
|
||||
interface Props {
|
||||
data: Array<{x: number, y: number}>
|
||||
data: Array<{ x: number; y: number }>
|
||||
}
|
||||
// const configuredCurve = d3Shape.curveBundle.beta(1)
|
||||
|
||||
@@ -51,10 +51,7 @@ class PlotHistory extends React.Component<Props, Stats> {
|
||||
<XYPlot width={this.state.width} height={180}>
|
||||
<HorizontalGridLines />
|
||||
<XAxis />
|
||||
<YAxis
|
||||
width={45}
|
||||
tickFormat={(num: number) => abbreviate(num)}
|
||||
/>
|
||||
<YAxis width={45} tickFormat={(num: number) => abbreviate(num)} />
|
||||
<LineMarkSeries
|
||||
onValueMouseOver={this._rememberValue}
|
||||
onValueMouseOut={this._forgetValue}
|
||||
|
||||
@@ -53,7 +53,6 @@ interface State {
|
||||
}
|
||||
|
||||
class Publish extends React.Component<Props, State> {
|
||||
|
||||
private editorOptions = {
|
||||
showLineNumbers: false,
|
||||
tabSize: 2,
|
||||
@@ -108,18 +107,18 @@ class Publish extends React.Component<Props, State> {
|
||||
return (
|
||||
<div>
|
||||
<FormControl style={{ width: '100%' }}>
|
||||
<InputLabel htmlFor="publish-topic">Topic</InputLabel>
|
||||
<Input
|
||||
id="publish-topic"
|
||||
value={topicStr}
|
||||
startAdornment={<span/>}
|
||||
endAdornment={<ClearAdornment action={this.clearTopic} value={topicStr} />}
|
||||
onBlur={this.onTopicBlur}
|
||||
onChange={this.updateTopic}
|
||||
multiline={true}
|
||||
placeholder="example/topic"
|
||||
/>
|
||||
</FormControl>
|
||||
<InputLabel htmlFor="publish-topic">Topic</InputLabel>
|
||||
<Input
|
||||
id="publish-topic"
|
||||
value={topicStr}
|
||||
startAdornment={<span />}
|
||||
endAdornment={<ClearAdornment action={this.clearTopic} value={topicStr} />}
|
||||
onBlur={this.onTopicBlur}
|
||||
onChange={this.updateTopic}
|
||||
multiline={true}
|
||||
placeholder="example/topic"
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -132,13 +131,7 @@ class Publish extends React.Component<Props, State> {
|
||||
|
||||
private publishButton() {
|
||||
return (
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
color="primary"
|
||||
onClick={this.publish}
|
||||
id="publish-button"
|
||||
>
|
||||
<Button variant="contained" size="small" color="primary" onClick={this.publish} id="publish-button">
|
||||
<Navigation style={{ marginRight: '8px' }} /> Publish
|
||||
</Button>
|
||||
)
|
||||
@@ -162,7 +155,11 @@ class Publish extends React.Component<Props, State> {
|
||||
|
||||
return (
|
||||
<Tooltip title="Format JSON">
|
||||
<Fab style={{ width: '36px', height: '36px', marginLeft: '8px' }} onClick={this.formatJson} id="sidebar-publish-format-json">
|
||||
<Fab
|
||||
style={{ width: '36px', height: '36px', marginLeft: '8px' }}
|
||||
onClick={this.formatJson}
|
||||
id="sidebar-publish-format-json"
|
||||
>
|
||||
<FormatAlignLeft style={{ fontSize: '20px' }} />
|
||||
</Fab>
|
||||
</Tooltip>
|
||||
@@ -175,9 +172,7 @@ class Publish extends React.Component<Props, State> {
|
||||
<div style={{ width: '100%', lineHeight: '64px' }}>
|
||||
{this.renderEditorModeSelection()}
|
||||
{this.renderFormatJson()}
|
||||
<div style={{ float: 'right', marginRight: '16px' }}>
|
||||
{this.publishButton()}
|
||||
</div>
|
||||
<div style={{ float: 'right', marginRight: '16px' }}>{this.publishButton()}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -239,30 +234,36 @@ class Publish extends React.Component<Props, State> {
|
||||
onChange={this.onChangeQoS}
|
||||
>
|
||||
<MenuItem key={0} value={0} style={itemStyle}>
|
||||
<Tooltip title="At most once"><div style={tooltipStyle}>0</div></Tooltip>
|
||||
<Tooltip title="At most once">
|
||||
<div style={tooltipStyle}>0</div>
|
||||
</Tooltip>
|
||||
</MenuItem>
|
||||
<MenuItem key={1} value={1} style={itemStyle}>
|
||||
<Tooltip title="At least once"><div style={tooltipStyle}>1</div></Tooltip>
|
||||
<Tooltip title="At least once">
|
||||
<div style={tooltipStyle}>1</div>
|
||||
</Tooltip>
|
||||
</MenuItem>
|
||||
<MenuItem key={2} value={2} style={itemStyle}>
|
||||
<Tooltip title="Exactly once"><div style={tooltipStyle}>2</div></Tooltip>
|
||||
<Tooltip title="Exactly once">
|
||||
<div style={tooltipStyle}>2</div>
|
||||
</Tooltip>
|
||||
</MenuItem>
|
||||
</TextField>
|
||||
)
|
||||
return (
|
||||
<div style={{ marginTop: '8px', clear: 'both' }}>
|
||||
<div style={{ width: '100%', textAlign: 'right' }}>
|
||||
<FormControlLabel
|
||||
style={labelStyle}
|
||||
control={qosSelect}
|
||||
label="QoS"
|
||||
labelPlacement="start"
|
||||
/>
|
||||
<Tooltip title="Retained messages only appear to be retained, when client subscribes after the initial publish." placement="top">
|
||||
<FormControlLabel style={labelStyle} control={qosSelect} label="QoS" labelPlacement="start" />
|
||||
<Tooltip
|
||||
title="Retained messages only appear to be retained, when client subscribes after the initial publish."
|
||||
placement="top"
|
||||
>
|
||||
<FormControlLabel
|
||||
value="retain"
|
||||
style={labelStyle}
|
||||
control={<Checkbox color="primary" checked={this.props.retain} onChange={this.props.actions.toggleRetain} />}
|
||||
control={
|
||||
<Checkbox color="primary" checked={this.props.retain} onChange={this.props.actions.toggleRetain} />
|
||||
}
|
||||
label="retain"
|
||||
labelPlacement="end"
|
||||
/>
|
||||
@@ -343,4 +344,7 @@ const mapStateToProps = (state: AppState) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(Publish))
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withTheme(Publish))
|
||||
|
||||
@@ -14,13 +14,7 @@ import { settingsActions, sidebarActions } from '../../actions'
|
||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||
import { TopicViewModel } from '../../model/TopicViewModel'
|
||||
|
||||
import {
|
||||
ExpansionPanel,
|
||||
ExpansionPanelDetails,
|
||||
ExpansionPanelSummary,
|
||||
Typography,
|
||||
Badge,
|
||||
} from '@material-ui/core'
|
||||
import { ExpansionPanel, ExpansionPanelDetails, ExpansionPanelSummary, Typography, Badge } from '@material-ui/core'
|
||||
|
||||
const throttle = require('lodash.throttle')
|
||||
|
||||
@@ -76,7 +70,7 @@ class Sidebar extends React.Component<Props, State> {
|
||||
private renderRecursiveTopicDeleteButton() {
|
||||
const deleteLimit = 50
|
||||
const topicCount = this.props.node ? this.props.node.childTopicCount() : 0
|
||||
if ((!this.props.node || topicCount === 0) || (this.props.node.message && topicCount === 1)) {
|
||||
if (!this.props.node || topicCount === 0 || (this.props.node.message && topicCount === 1)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -86,7 +80,10 @@ class Sidebar extends React.Component<Props, State> {
|
||||
badgeContent={<span style={{ whiteSpace: 'nowrap' }}>{topicCount >= deleteLimit ? '50+' : topicCount}</span>}
|
||||
color="secondary"
|
||||
>
|
||||
<CustomIconButton onClick={() => this.deleteTopic(this.props.node, true, deleteLimit)} tooltip={`Deletes up to ${deleteLimit} sub-topics with a single click`}>
|
||||
<CustomIconButton
|
||||
onClick={() => this.deleteTopic(this.props.node, true, deleteLimit)}
|
||||
tooltip={`Deletes up to ${deleteLimit} sub-topics with a single click`}
|
||||
>
|
||||
<Delete style={{ marginTop: '-3px' }} color="action" />
|
||||
</CustomIconButton>
|
||||
</Badge>
|
||||
@@ -112,7 +109,9 @@ class Sidebar extends React.Component<Props, State> {
|
||||
<div>
|
||||
<ExpansionPanel key="topic" defaultExpanded={true} disabled={!Boolean(this.props.node)}>
|
||||
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summaryStyle}>
|
||||
<Typography className={classes.heading}>Topic {copyTopic} {deleteTopic} {deleteRecursiveTopic}</Typography>
|
||||
<Typography className={classes.heading}>
|
||||
Topic {copyTopic} {deleteTopic} {deleteRecursiveTopic}
|
||||
</Typography>
|
||||
</ExpansionPanelSummary>
|
||||
<ExpansionPanelDetails style={this.detailsStyle}>
|
||||
<Topic node={this.props.node} didSelectNode={this.updateNode} />
|
||||
@@ -204,4 +203,9 @@ const styles = (theme: Theme) => ({
|
||||
},
|
||||
})
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(Sidebar))
|
||||
export default withStyles(styles)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Sidebar)
|
||||
)
|
||||
|
||||
@@ -32,30 +32,29 @@ class Topic extends React.Component<Props, {}> {
|
||||
}
|
||||
|
||||
let key = 0
|
||||
const breadCrumps = node.branch()
|
||||
const breadCrumps = node
|
||||
.branch()
|
||||
.map(node => node.sourceEdge)
|
||||
.filter(edge => Boolean(edge))
|
||||
.map(edge =>
|
||||
[(
|
||||
<Button
|
||||
onClick={() => this.props.actions.selectTopic(edge!.target)}
|
||||
size="small"
|
||||
variant={theme.palette.type === 'light' ? 'contained' : undefined}
|
||||
color={theme.palette.type === 'light' ? 'primary' : 'secondary'}
|
||||
className={this.props.classes.button}
|
||||
key={edge!.hash()}
|
||||
>
|
||||
{edge!.name}
|
||||
</Button>
|
||||
)]
|
||||
)
|
||||
.map(edge => [
|
||||
<Button
|
||||
onClick={() => this.props.actions.selectTopic(edge!.target)}
|
||||
size="small"
|
||||
variant={theme.palette.type === 'light' ? 'contained' : undefined}
|
||||
color={theme.palette.type === 'light' ? 'primary' : 'secondary'}
|
||||
className={this.props.classes.button}
|
||||
key={edge!.hash()}
|
||||
>
|
||||
{edge!.name}
|
||||
</Button>,
|
||||
])
|
||||
|
||||
if (breadCrumps.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const joinedBreadCrumps = breadCrumps.reduce((prev, current) =>
|
||||
prev.concat([<span key={key += 1}> / </span>]).concat(current)
|
||||
prev.concat([<span key={(key += 1)}> / </span>]).concat(current)
|
||||
)
|
||||
|
||||
return <span style={{ lineHeight: '2.2em' }}>{joinedBreadCrumps}</span>
|
||||
@@ -68,4 +67,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(withStyles(styles, { withTheme: true })(Topic))
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles, { withTheme: true })(Topic))
|
||||
|
||||
@@ -16,7 +16,8 @@ function nodeToHistory(history: q.MessageHistory) {
|
||||
.map((message: q.Message) => {
|
||||
const value = message.value ? toPlottableValue(Base64Message.toUnicodeString(message.value)) : NaN
|
||||
return { x: message.received.getTime(), y: toPlottableValue(value) }
|
||||
}).filter(data => !isNaN(data.y as any)) as any
|
||||
})
|
||||
.filter(data => !isNaN(data.y as any)) as any
|
||||
}
|
||||
|
||||
function nodeDotPathToHistory(history: q.MessageHistory, dotPath: string) {
|
||||
@@ -31,7 +32,8 @@ function nodeDotPathToHistory(history: q.MessageHistory, dotPath: string) {
|
||||
let value = dotProp.get(json, dotPath)
|
||||
|
||||
return { x: message.received.getTime(), y: toPlottableValue(value) }
|
||||
}).filter(data => !isNaN(data.y as any)) as any
|
||||
})
|
||||
.filter(data => !isNaN(data.y as any)) as any
|
||||
}
|
||||
|
||||
function render(props: Props) {
|
||||
|
||||
@@ -18,7 +18,7 @@ interface Props {
|
||||
}
|
||||
|
||||
interface State {
|
||||
displayMessage?: q.Message,
|
||||
displayMessage?: q.Message
|
||||
anchorEl?: HTMLElement
|
||||
}
|
||||
|
||||
@@ -65,18 +65,28 @@ class MessageHistory extends React.Component<Props, State> {
|
||||
const element = {
|
||||
value,
|
||||
key: `${message.messageNumber}-${message.received}`,
|
||||
title: (<span>
|
||||
<DateFormatter date={message.received} />
|
||||
{previousMessage ? <i>(-<DateFormatter date={message.received} intervalSince={previousMessage.received} />)</i> : null}
|
||||
<div style={{ float: 'right' }}><Copy value={value} /></div>
|
||||
</span>),
|
||||
title: (
|
||||
<span>
|
||||
<DateFormatter date={message.received} />
|
||||
{previousMessage ? (
|
||||
<i>
|
||||
(-
|
||||
<DateFormatter date={message.received} intervalSince={previousMessage.received} />)
|
||||
</i>
|
||||
) : null}
|
||||
<div style={{ float: 'right' }}>
|
||||
<Copy value={value} />
|
||||
</div>
|
||||
</span>
|
||||
),
|
||||
selected: message && message === this.props.selected,
|
||||
}
|
||||
previousMessage = message
|
||||
return element
|
||||
})
|
||||
|
||||
const isMessagePlottable = node.message && node.message.value && isPlottable(Base64Message.toUnicodeString(node.message.value))
|
||||
const isMessagePlottable =
|
||||
node.message && node.message.value && isPlottable(Base64Message.toUnicodeString(node.message.value))
|
||||
return (
|
||||
<div>
|
||||
<History
|
||||
|
||||
@@ -44,7 +44,7 @@ interface State {}
|
||||
class ValuePanel extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = { }
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
private renderValue() {
|
||||
@@ -84,9 +84,7 @@ class ValuePanel extends React.Component<Props, State> {
|
||||
return (
|
||||
<div style={{ width: '100%', display: 'flex', paddingLeft: '8px' }}>
|
||||
<span style={{ marginTop: '2px', flexGrow: 1 }}>{this.renderActionButtons()}</span>
|
||||
<div style={{ flex: 6, textAlign: 'right' }}>
|
||||
{this.props.node.mqttMessage.retain ? retainedButton : null}
|
||||
</div>
|
||||
<div style={{ flex: 6, textAlign: 'right' }}>{this.props.node.mqttMessage.retain ? retainedButton : null}</div>
|
||||
{this.messageMetaInfo()}
|
||||
</div>
|
||||
)
|
||||
@@ -100,7 +98,11 @@ class ValuePanel extends React.Component<Props, State> {
|
||||
return (
|
||||
<span style={{ width: '100%', paddingLeft: '8px', flex: 6 }}>
|
||||
<Typography style={{ textAlign: 'right' }}>QoS: {this.props.node.mqttMessage.qos}</Typography>
|
||||
<Typography style={{ textAlign: 'right' }}><i><DateFormatter date={this.props.node.message.received} /></i></Typography>
|
||||
<Typography style={{ textAlign: 'right' }}>
|
||||
<i>
|
||||
<DateFormatter date={this.props.node.message.received} />
|
||||
</i>
|
||||
</Typography>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -114,15 +116,24 @@ class ValuePanel extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
return (
|
||||
<ToggleButtonGroup id="valueRendererDisplayMode" value={this.props.valueRendererDisplayMode} exclusive={true} onChange={handleValue}>
|
||||
<ToggleButtonGroup
|
||||
id="valueRendererDisplayMode"
|
||||
value={this.props.valueRendererDisplayMode}
|
||||
exclusive={true}
|
||||
onChange={handleValue}
|
||||
>
|
||||
<ToggleButton className={this.props.classes.toggleButton} value="diff" id="valueRendererDisplayMode-diff">
|
||||
<Tooltip title="Show difference between the current and the last message">
|
||||
<span><Code className={this.props.classes.toggleButtonIcon} /></span>
|
||||
<span>
|
||||
<Code className={this.props.classes.toggleButtonIcon} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</ToggleButton>
|
||||
<ToggleButton className={this.props.classes.toggleButton} value="raw" id="valueRendererDisplayMode-raw">
|
||||
<Tooltip title="Raw value">
|
||||
<span><Reorder className={this.props.classes.toggleButtonIcon} /></span>
|
||||
<span>
|
||||
<Reorder className={this.props.classes.toggleButtonIcon} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
@@ -148,7 +159,10 @@ class ValuePanel extends React.Component<Props, State> {
|
||||
const { node, classes } = this.props
|
||||
const { detailsStyle, summaryStyle } = this.panelStyle()
|
||||
|
||||
const copyValue = (node && node.message && node.message.value) ? <Copy value={Base64Message.toUnicodeString(node.message.value)} /> : null
|
||||
const copyValue =
|
||||
node && node.message && node.message.value ? (
|
||||
<Copy value={Base64Message.toUnicodeString(node.message.value)} />
|
||||
) : null
|
||||
|
||||
return (
|
||||
<ExpansionPanel key="value" defaultExpanded={true}>
|
||||
@@ -158,11 +172,15 @@ class ValuePanel extends React.Component<Props, State> {
|
||||
<ExpansionPanelDetails style={detailsStyle}>
|
||||
{this.renderViewOptions()}
|
||||
<div>
|
||||
<React.Suspense fallback={<div>Loading...</div>}>
|
||||
{this.renderValue()}
|
||||
</React.Suspense>
|
||||
<React.Suspense fallback={<div>Loading...</div>}>{this.renderValue()}</React.Suspense>
|
||||
</div>
|
||||
<div>
|
||||
<MessageHistory
|
||||
onSelect={this.handleMessageHistorySelect}
|
||||
selected={this.props.compareMessage}
|
||||
node={this.props.node}
|
||||
/>
|
||||
</div>
|
||||
<div><MessageHistory onSelect={this.handleMessageHistorySelect} selected={this.props.compareMessage} node={this.props.node} /></div>
|
||||
</ExpansionPanelDetails>
|
||||
</ExpansionPanel>
|
||||
)
|
||||
@@ -197,4 +215,7 @@ const styles = (theme: Theme) => ({
|
||||
},
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ValuePanel))
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ValuePanel))
|
||||
|
||||
@@ -77,18 +77,24 @@ class TreeComponent extends React.PureComponent<Props, State> {
|
||||
const timeUntilNextUpdate = updateInterval - (performance.now() - this.renderTime)
|
||||
|
||||
this.updateTimer = setTimeout(() => {
|
||||
window.requestIdleCallback(() => {
|
||||
this.updateTimer && clearTimeout(this.updateTimer)
|
||||
this.updateTimer = undefined
|
||||
this.renderTime = performance.now()
|
||||
window.requestIdleCallback(
|
||||
() => {
|
||||
this.updateTimer && clearTimeout(this.updateTimer)
|
||||
this.updateTimer = undefined
|
||||
this.renderTime = performance.now()
|
||||
|
||||
if (!this.props.paused) {
|
||||
this.props.tree && this.props.tree.applyUnmergedChanges()
|
||||
}
|
||||
window.requestIdleCallback(() => {
|
||||
this.setState({ lastUpdate: this.renderTime })
|
||||
}, { timeout: 100 })
|
||||
}, { timeout: 500 })
|
||||
if (!this.props.paused) {
|
||||
this.props.tree && this.props.tree.applyUnmergedChanges()
|
||||
}
|
||||
window.requestIdleCallback(
|
||||
() => {
|
||||
this.setState({ lastUpdate: this.renderTime })
|
||||
},
|
||||
{ timeout: 100 }
|
||||
)
|
||||
},
|
||||
{ timeout: 500 }
|
||||
)
|
||||
}, Math.max(0, timeUntilNextUpdate))
|
||||
}
|
||||
|
||||
@@ -137,4 +143,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TreeComponent)
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TreeComponent)
|
||||
|
||||
@@ -107,9 +107,11 @@ class TreeNodeComponent extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
private stateHasChanged(newState: State) {
|
||||
return this.state.collapsedOverride !== newState.collapsedOverride
|
||||
|| this.state.mouseOver !== newState.mouseOver
|
||||
|| this.state.selected !== newState.selected
|
||||
return (
|
||||
this.state.collapsedOverride !== newState.collapsedOverride ||
|
||||
this.state.mouseOver !== newState.mouseOver ||
|
||||
this.state.selected !== newState.selected
|
||||
)
|
||||
}
|
||||
|
||||
private toggle() {
|
||||
@@ -137,7 +139,12 @@ class TreeNodeComponent extends React.Component<Props, State> {
|
||||
private mouseOver = (event: React.MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
this.setHover(true)
|
||||
if (this.props.settings.get('selectTopicWithMouseOver') && this.props.treeNode && this.props.treeNode.message && this.props.treeNode.message.value) {
|
||||
if (
|
||||
this.props.settings.get('selectTopicWithMouseOver') &&
|
||||
this.props.treeNode &&
|
||||
this.props.treeNode.message &&
|
||||
this.props.treeNode.message.value
|
||||
) {
|
||||
this.props.didSelectTopic(this.props.treeNode)
|
||||
}
|
||||
}
|
||||
@@ -181,11 +188,13 @@ class TreeNodeComponent extends React.Component<Props, State> {
|
||||
|
||||
public shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||
const shouldRenderToRemoveCssAnimation = this.cssAnimationWasSetAt !== undefined
|
||||
return this.stateHasChanged(nextState)
|
||||
|| this.props.settings !== nextProps.settings
|
||||
|| (this.props.lastUpdate !== nextProps.lastUpdate)
|
||||
|| this.animationDirty
|
||||
|| shouldRenderToRemoveCssAnimation
|
||||
return (
|
||||
this.stateHasChanged(nextState) ||
|
||||
this.props.settings !== nextProps.settings ||
|
||||
this.props.lastUpdate !== nextProps.lastUpdate ||
|
||||
this.animationDirty ||
|
||||
shouldRenderToRemoveCssAnimation
|
||||
)
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
@@ -204,12 +213,19 @@ class TreeNodeComponent extends React.Component<Props, State> {
|
||||
public render() {
|
||||
const { classes } = this.props
|
||||
|
||||
const shouldStartAnimation = (!this.animationDirty) && !this.props.isRoot && this.props.settings.get('highlightTopicUpdates')
|
||||
const shouldStartAnimation =
|
||||
!this.animationDirty && !this.props.isRoot && this.props.settings.get('highlightTopicUpdates')
|
||||
const animationName = this.props.theme.palette.type === 'light' ? 'updateLight' : 'updateDark'
|
||||
const animation = shouldStartAnimation ? { willChange: 'auto', translateZ: 0, animation: `${animationName} 0.5s` } : {}
|
||||
const animation = shouldStartAnimation
|
||||
? { willChange: 'auto', translateZ: 0, animation: `${animationName} 0.5s` }
|
||||
: {}
|
||||
this.animationDirty = shouldStartAnimation
|
||||
|
||||
const highlightClass = this.state.selected ? this.props.classes.selected : (this.state.mouseOver ? this.props.classes.hover : '')
|
||||
const highlightClass = this.state.selected
|
||||
? this.props.classes.selected
|
||||
: this.state.mouseOver
|
||||
? this.props.classes.hover
|
||||
: ''
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -49,13 +49,16 @@ class TreeNodeSubnodes extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
private renderMore() {
|
||||
this.renderMoreAnimationFrame = (window as any).requestIdleCallback(() => {
|
||||
this.setState({ ...this.state, alreadyAdded: this.state.alreadyAdded * 1.5 })
|
||||
}, { timeout: 500 })
|
||||
this.renderMoreAnimationFrame = (window as any).requestIdleCallback(
|
||||
() => {
|
||||
this.setState({ ...this.state, alreadyAdded: this.state.alreadyAdded * 1.5 })
|
||||
},
|
||||
{ timeout: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
(window as any).cancelIdleCallback(this.renderMoreAnimationFrame)
|
||||
;(window as any).cancelIdleCallback(this.renderMoreAnimationFrame)
|
||||
}
|
||||
|
||||
public render() {
|
||||
@@ -69,7 +72,7 @@ class TreeNodeSubnodes extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
const nodes = this.sortedNodes().slice(0, this.state.alreadyAdded)
|
||||
const listItems = nodes.map((node) => {
|
||||
const listItems = nodes.map(node => {
|
||||
return (
|
||||
<TreeNode
|
||||
key={`${node.hash()}-${this.props.filter}`}
|
||||
@@ -82,11 +85,7 @@ class TreeNodeSubnodes extends React.Component<Props, State> {
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<span className={this.props.classes.list}>
|
||||
{listItems}
|
||||
</span>
|
||||
)
|
||||
return <span className={this.props.classes.list}>{listItems}</span>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,17 +14,25 @@ export interface TreeNodeProps extends React.HTMLAttributes<HTMLElement> {
|
||||
}
|
||||
|
||||
class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
||||
|
||||
private renderSourceEdge() {
|
||||
const name = this.props.name || (this.props.treeNode.sourceEdge && this.props.treeNode.sourceEdge.name)
|
||||
|
||||
return <span key="edge" className={this.props.classes.sourceEdge}>{name}</span>
|
||||
return (
|
||||
<span key="edge" className={this.props.classes.sourceEdge}>
|
||||
{name}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
private renderValue() {
|
||||
return this.props.treeNode.message && this.props.treeNode.message.value && this.props.treeNode.message.length > 0
|
||||
? <span key="value" className={this.props.classes.value}> = {Base64Message.toUnicodeString(this.props.treeNode.message.value).slice(0, 120)}</span>
|
||||
: null
|
||||
return this.props.treeNode.message &&
|
||||
this.props.treeNode.message.value &&
|
||||
this.props.treeNode.message.length > 0 ? (
|
||||
<span key="value" className={this.props.classes.value}>
|
||||
{' '}
|
||||
= {Base64Message.toUnicodeString(this.props.treeNode.message.value).slice(0, 120)}
|
||||
</span>
|
||||
) : null
|
||||
}
|
||||
|
||||
private renderExpander() {
|
||||
@@ -32,7 +40,11 @@ class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
||||
return null
|
||||
}
|
||||
|
||||
return <span key="expander" className={this.props.classes.expander} onClick={this.props.toggleCollapsed}>{this.props.collapsed ? '▶' : '▼'}</span>
|
||||
return (
|
||||
<span key="expander" className={this.props.classes.expander} onClick={this.props.toggleCollapsed}>
|
||||
{this.props.collapsed ? '▶' : '▼'}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
private renderMetadata() {
|
||||
@@ -41,16 +53,16 @@ class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
||||
}
|
||||
|
||||
const messages = this.props.treeNode.leafMessageCount()
|
||||
return <span key="metadata" className={this.props.classes.collapsedSubnodes}>{`(${this.props.treeNode.childTopicCount()} topics, ${messages} messages)`}</span>
|
||||
return (
|
||||
<span
|
||||
key="metadata"
|
||||
className={this.props.classes.collapsedSubnodes}
|
||||
>{`(${this.props.treeNode.childTopicCount()} topics, ${messages} messages)`}</span>
|
||||
)
|
||||
}
|
||||
|
||||
public render() {
|
||||
return ([
|
||||
this.renderExpander(),
|
||||
this.renderSourceEdge(),
|
||||
this.renderMetadata(),
|
||||
this.renderValue(),
|
||||
])
|
||||
return [this.renderExpander(), this.renderSourceEdge(), this.renderMetadata(), this.renderValue()]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,15 +12,7 @@ import { green } from '@material-ui/core/colors'
|
||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||
import { updateNotifierActions } from '../actions'
|
||||
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Modal,
|
||||
Paper,
|
||||
Snackbar,
|
||||
SnackbarContent,
|
||||
Typography,
|
||||
} from '@material-ui/core'
|
||||
import { Button, IconButton, Modal, Paper, Snackbar, SnackbarContent, Typography } from '@material-ui/core'
|
||||
|
||||
interface Props {
|
||||
showUpdateNotification: boolean
|
||||
@@ -30,7 +22,7 @@ interface Props {
|
||||
}
|
||||
|
||||
interface GithubRelease {
|
||||
url: string,
|
||||
url: string
|
||||
assets?: Array<GithubAsset>
|
||||
published_at: string // "2019-01-25T20:14:39Z"
|
||||
body_html: string
|
||||
@@ -59,7 +51,7 @@ class UpdateNotifier extends React.Component<Props, State> {
|
||||
this.state = { newerVersions: [] }
|
||||
|
||||
const ownVersion = electron.remote.app.getVersion()
|
||||
this.fetchReleases().then((releases) => {
|
||||
this.fetchReleases().then(releases => {
|
||||
const newerVersions = releases
|
||||
.filter(release => this.allowPrereleaseIfOwnVersionIsBeta(release, ownVersion))
|
||||
.filter(release => compareVersions(release.tag_name, ownVersion) > 0)
|
||||
@@ -131,21 +123,19 @@ class UpdateNotifier extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
private notificationActions() {
|
||||
return [(
|
||||
<Button key="undo" size="small" onClick={this.showDetails}>
|
||||
Details
|
||||
</Button>
|
||||
), (
|
||||
<IconButton
|
||||
key="close"
|
||||
aria-label="Close"
|
||||
color="inherit"
|
||||
className={this.props.classes.close}
|
||||
onClick={this.closeNotification}
|
||||
>
|
||||
<Close />
|
||||
</IconButton>
|
||||
),
|
||||
return [
|
||||
<Button key="undo" size="small" onClick={this.showDetails}>
|
||||
Details
|
||||
</Button>,
|
||||
<IconButton
|
||||
key="close"
|
||||
aria-label="Close"
|
||||
color="inherit"
|
||||
className={this.props.classes.close}
|
||||
onClick={this.closeNotification}
|
||||
>
|
||||
<Close />
|
||||
</IconButton>,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -159,23 +149,20 @@ class UpdateNotifier extends React.Component<Props, State> {
|
||||
.join('<hr />')
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={this.props.showUpdateDetails}
|
||||
disableAutoFocus={true}
|
||||
onClose={this.hideDetails}
|
||||
>
|
||||
<Modal open={this.props.showUpdateDetails} disableAutoFocus={true} onClose={this.hideDetails}>
|
||||
<Paper className={this.props.classes.root}>
|
||||
<Typography variant="h6" className={this.props.classes.title}>Version {latestUpdate.tag_name}</Typography>
|
||||
<Typography variant="h6" className={this.props.classes.title}>
|
||||
Version {latestUpdate.tag_name}
|
||||
</Typography>
|
||||
<Typography className={this.props.classes.title}>Changelog</Typography>
|
||||
<div className={this.props.classes.releaseNotes} dangerouslySetInnerHTML={{ __html: releaseNotes }} />
|
||||
{this.renderDownloads()}
|
||||
<Button
|
||||
className={this.props.classes.download}
|
||||
onClick={this.openHomePage}
|
||||
>
|
||||
<Button className={this.props.classes.download} onClick={this.openHomePage}>
|
||||
Github Page
|
||||
</Button>
|
||||
<Button className={this.props.classes.closeButton} color="secondary" onClick={this.hideDetails}>Close</Button>
|
||||
<Button className={this.props.classes.closeButton} color="secondary" onClick={this.hideDetails}>
|
||||
Close
|
||||
</Button>
|
||||
</Paper>
|
||||
</Modal>
|
||||
)
|
||||
@@ -208,18 +195,14 @@ class UpdateNotifier extends React.Component<Props, State> {
|
||||
return null
|
||||
}
|
||||
|
||||
return latestUpdate.assets
|
||||
.filter(this.assetForCurrentPlatform)
|
||||
.map(asset => (
|
||||
<div>
|
||||
<Button
|
||||
className={this.props.classes.download}
|
||||
onClick={() => this.openUrl(asset.browser_download_url)}
|
||||
>
|
||||
<CloudDownload /> {asset.name}
|
||||
</Button>
|
||||
</div>
|
||||
))
|
||||
return latestUpdate.assets.filter(this.assetForCurrentPlatform).map(asset => (
|
||||
<div>
|
||||
<Button className={this.props.classes.download} onClick={() => this.openUrl(asset.browser_download_url)}>
|
||||
<CloudDownload />
|
||||
{asset.name}
|
||||
</Button>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
public render() {
|
||||
@@ -283,4 +266,9 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(UpdateNotifier))
|
||||
export default withStyles(styles)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(UpdateNotifier)
|
||||
)
|
||||
|
||||
@@ -18,7 +18,10 @@ const styles = (theme: Theme) => ({
|
||||
color: orange[600],
|
||||
},
|
||||
icon: {
|
||||
boxShadow: theme.shadows[2].split('),').map(s => `inset ${s}`).join('),'),
|
||||
boxShadow: theme.shadows[2]
|
||||
.split('),')
|
||||
.map(s => `inset ${s}`)
|
||||
.join('),'),
|
||||
padding: '6px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#eee',
|
||||
|
||||
@@ -37,9 +37,11 @@ class Copy extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
public render() {
|
||||
const icon = !this.state.didCopy
|
||||
? <FileCopy fontSize="inherit" />
|
||||
: <Check fontSize="inherit" style={{ cursor: 'default' }} />
|
||||
const icon = !this.state.didCopy ? (
|
||||
<FileCopy fontSize="inherit" />
|
||||
) : (
|
||||
<Check fontSize="inherit" style={{ cursor: 'default' }} />
|
||||
)
|
||||
|
||||
return (
|
||||
<span>
|
||||
@@ -61,4 +63,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(undefined, mapDispatchToProps)(Copy)
|
||||
export default connect(
|
||||
undefined,
|
||||
mapDispatchToProps
|
||||
)(Copy)
|
||||
|
||||
@@ -28,7 +28,9 @@ class DateFormatter extends React.Component<Props, {}> {
|
||||
}
|
||||
|
||||
private localizedDate(locale: string) {
|
||||
return moment(this.props.date).locale(locale).format('L LTS')
|
||||
return moment(this.props.date)
|
||||
.locale(locale)
|
||||
.format('L LTS')
|
||||
}
|
||||
|
||||
private unitForInterval(milliseconds: number) {
|
||||
|
||||
@@ -6,7 +6,7 @@ export function isElementInViewport(el: any) {
|
||||
return (
|
||||
rect.top >= 0 &&
|
||||
rect.left >= 0 &&
|
||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
|
||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) /*or $(window).height() */ &&
|
||||
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user