Compare commits

...
Author SHA1 Message Date
Thomas Nordquist 68118248c9 Improve ui-test video 2019-06-18 17:26:10 +02:00
Thomas Nordquist f1a2ae16c1 Fix plot theme switch 2019-06-18 17:05:22 +02:00
Thomas Nordquist 7904cb22cf Update @types/node 2019-06-18 16:25:17 +02:00
Thomas Nordquist 0e0fbae8bb Freeze electron package version in package.json 2019-06-18 15:48:50 +02:00
Thomas Nordquist 3b72048b67 Fix linting error 2019-06-18 15:13:44 +02:00
Thomas Nordquist caa54809b4 Show app name on windows tiles 2019-06-18 15:04:39 +02:00
Thomas Nordquist 23f5846122 Prepare release v0.3.0 2019-06-18 14:53:55 +02:00
Thomas Nordquist de7b461b4e Update ui-test video 2019-06-18 14:49:48 +02:00
Thomas Nordquist d92ea0bad7 Remove scene from ui-test video 2019-06-18 14:49:24 +02:00
Thomas Nordquist d7bb4bb55f Fix layout default sizes 2019-06-18 14:48:52 +02:00
Thomas Nordquist 9ed8a3b91e Add ui-test accessibility 2019-06-18 14:48:39 +02:00
Thomas Nordquist dd78b43058 Fix sidebar scroll behavior 2019-06-18 14:48:16 +02:00
Thomas Nordquist cd68e966ab Fix test text input 2019-06-18 10:27:58 +02:00
Thomas Nordquist 6baeafce39 Fix typo 2019-06-18 10:27:42 +02:00
Thomas Nordquist 1d8900d6eb Move chart panel below tree 2019-06-17 23:27:16 +02:00
Thomas Nordquist e82c8c4eb0 Refactor 2019-06-17 21:31:54 +02:00
Thomas Nordquist 449d046ce3 Avoid dotPath confusions 2019-06-17 19:11:58 +02:00
Thomas Nordquist 06ab52bb6b Fix chart panel auto-open 2019-06-17 19:08:40 +02:00
Thomas Nordquist 181575f71f Prepare release v0.3.0-alpha2 2019-06-17 18:29:46 +02:00
Thomas Nordquist 3d5a4af705 Tidy up ui 2019-06-17 18:27:19 +02:00
Thomas Nordquist 4e982be613 Show notification when adding charts 2019-06-17 18:19:26 +02:00
Thomas Nordquist 8c1c6387c9 Add colors and move capability to charts 2019-06-17 18:08:35 +02:00
35 changed files with 1002 additions and 497 deletions
+7 -6
View File
@@ -114,15 +114,16 @@
.Resizer.vertical {
width: 2px;
margin: 0px -8px 0px 0px;
border-left: 4px solid rgba(128, 128, 128, 0);
border-right: 4px solid rgba(128, 128, 128, 0);
border-left: 0px solid rgba(128, 128, 128, 0);
border-right: 8px solid rgba(128, 128, 128, 0);
cursor: col-resize;
}
.Resizer.vertical::before {
content: '•••';
margin-left: -6px;
height: 100%;
margin-left: -11px;
height: 3em;
margin-top: calc(50vh - 32px);
display: inline-block;
vertical-align: middle;
text-align: center;
@@ -133,8 +134,8 @@
}
.Resizer.vertical:hover {
border-left: 4px solid rgba(130, 130, 130, 0.3);
border-right: 4px solid rgba(140, 140, 140, 0.3);
border-left: 0px solid rgba(130, 130, 130, 0.3);
border-right: 8px solid rgba(140, 140, 140, 0.3);
}
.Resizer.disabled {
+15 -1
View File
@@ -2,7 +2,7 @@ import { Action, ActionTypes, ChartParameters } from '../reducers/Charts'
import { AppState } from '../reducers'
import { default as persistentStorage, StorageIdentifier } from '../utils/PersistentStorage'
import { Dispatch } from 'redux'
import { showError } from './Global'
import { showError, showNotification } from './Global'
interface ConnectionViewState {
charts: Array<ChartParameters>
@@ -72,6 +72,7 @@ export const addChart = (chartParameters: ChartParameters) => async (
.find(chart => chart.topic === chartParameters.topic && chart.dotPath === chartParameters.dotPath)
)
if (chartExists) {
dispatch(showNotification('Already added'))
return
}
@@ -80,6 +81,7 @@ export const addChart = (chartParameters: ChartParameters) => async (
chart: chartParameters,
})
dispatch(saveCharts())
dispatch(showNotification('Added to chart panel'))
}
export const updateChart = (chartParameters: ChartParameters) => async (
@@ -106,6 +108,18 @@ export const removeChart = (chartParameters: ChartParameters) => async (
dispatch(saveCharts())
}
export const moveChartUp = (parameters: { topic: string; dotPath?: string }) => async (
dispatch: Dispatch<any>,
getState: () => AppState
) => {
dispatch({
topic: parameters.topic,
dotPath: parameters.dotPath,
type: ActionTypes.CHARTS_MOVE_UP,
})
dispatch(saveCharts())
}
export const setCharts = (charts: Array<ChartParameters>): Action => {
return {
charts,
+50 -81
View File
@@ -1,61 +1,79 @@
import * as q from '../../../../backend/src/Model'
import * as React from 'react'
import Clear from '@material-ui/icons/Clear'
import CustomIconButton from '../helper/CustomIconButton'
import TopicPlot from '../TopicPlot'
import { AppState } from '../../reducers'
import { bindActionCreators } from 'redux'
import { chartActions } from '../../actions'
import { ChartParameters } from '../../reducers/Charts'
import { connect } from 'react-redux'
import { Paper, Theme, Typography, withStyles } from '@material-ui/core'
import { SettingsButton } from './ChartSettings/SettingsButton'
import { Paper } from '@material-ui/core'
import ChartTitle from './ChartTitle'
import { ChartActions } from './ChartActions'
const throttle = require('lodash.throttle')
interface Props {
parameters: ChartParameters
tree?: q.Tree<any>
classes: any
treeNode?: q.TreeNode<any>
actions: {
chart: typeof chartActions
}
}
function Chart(props: Props) {
if (!props.tree) {
return null
}
/**
* Subscribes to onMessage of treeNode
*/
function useMessageSubscriptionToUpdate(treeNode?: q.TreeNode<any>) {
const [lastUpdated, setLastUpdate] = React.useState(0)
function subscribeToMessageUpdates() {
const onUpdateCallback = throttle(() => setLastUpdate(treeNode ? treeNode.lastUpdate : 0), 300)
treeNode && treeNode.onMessage.subscribe(onUpdateCallback)
const { tree, parameters } = props
const initialTreeNode = tree.findNode(parameters.topic)
const [treeNode, setTreeNode] = React.useState<q.TreeNode<any> | undefined>(initialTreeNode)
usePollingToFetchTreeNode(treeNode, tree, parameters, setTreeNode)
return function cleanup() {
treeNode && treeNode.onMessage.unsubscribe(onUpdateCallback)
}
}
React.useEffect(subscribeToMessageUpdates, [treeNode])
}
function Chart(props: Props) {
const { parameters, treeNode } = props
const [freezedHistory, setHistory] = React.useState<q.MessageHistory | undefined>()
useMessageSubscriptionToUpdate(treeNode)
const togglePause = React.useCallback(() => {
if (!props.treeNode) {
return
}
setHistory(freezedHistory ? undefined : props.treeNode.messageHistory.clone())
}, [props.treeNode, freezedHistory])
const onRemove = React.useCallback(() => {
props.actions.chart.removeChart(props.parameters)
}, [props.parameters])
return (
<Paper style={{ padding: '8px' }}>
<div style={{ float: 'right' }}>
<SettingsButton parameters={parameters} />
<CustomIconButton tooltip="Remove chart" onClick={onRemove}>
<Clear />
</CustomIconButton>
<Paper
style={{ padding: '8px' }}
data-test-type="ChartPaper"
data-test={`${props.parameters.topic}-${props.parameters.dotPath || ''}`}
>
<div style={{ display: 'flex' }}>
<div style={{ display: 'flex', flexGrow: 1, overflow: 'hidden' }}>
<ChartTitle parameters={parameters} />
<ChartActions
parameters={parameters}
onRemove={onRemove}
paused={Boolean(freezedHistory)}
togglePause={togglePause}
/>
</div>
</div>
<Typography variant="caption" className={props.classes.topic}>
{parameters.dotPath ? parameters.dotPath : ''}
</Typography>
<br />
<Typography variant="caption" className={props.classes.topic}>
{parameters.topic}
</Typography>
<br />
{treeNode ? (
{props.treeNode ? (
<TopicPlot
color={props.parameters.color}
interpolation={props.parameters.interpolation}
range={props.parameters.range ? [props.parameters.range.from, props.parameters.range.to] : undefined}
history={treeNode.messageHistory}
history={freezedHistory ? freezedHistory : props.treeNode.messageHistory}
dotPath={parameters.dotPath}
/>
) : (
@@ -65,12 +83,6 @@ function Chart(props: Props) {
)
}
const mapStateToProps = (state: AppState) => {
return {
tree: state.connection.tree,
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: {
@@ -79,50 +91,7 @@ const mapDispatchToProps = (dispatch: any) => {
}
}
const styles = (theme: Theme) => ({
topic: {
wordBreak: 'break-all' as 'break-all',
whiteSpace: 'nowrap' as 'nowrap',
overflow: 'hidden' as 'hidden',
textOverflow: 'ellipsis' as 'ellipsis',
},
})
export default connect(
mapStateToProps,
undefined,
mapDispatchToProps
)(withStyles(styles)(Chart))
/**
* If a node is not available when the plot is shown, keep polling until it has been created
*/
function usePollingToFetchTreeNode(
treeNode: q.TreeNode<any> | undefined,
tree: q.Tree<any>,
parameters: ChartParameters,
setTreeNode: React.Dispatch<React.SetStateAction<q.TreeNode<any> | undefined>>
) {
const [lastUpdate, setLastUpdate] = React.useState(0)
function pollForTreeNode() {
const onUpdateCallback = throttle(() => setLastUpdate(treeNode ? treeNode.lastUpdate : 0), 300)
let intervalTimer: any
if (!treeNode) {
intervalTimer = setInterval(() => {
const node = tree.findNode(parameters.topic)
if (node) {
setTreeNode(node)
node.onMessage.subscribe(onUpdateCallback)
clearInterval(intervalTimer)
}
}, 500)
} else {
treeNode.onMessage.subscribe(onUpdateCallback)
}
return function cleanup() {
treeNode && treeNode.onMessage.unsubscribe(onUpdateCallback)
intervalTimer && clearInterval(intervalTimer)
}
}
React.useEffect(pollForTreeNode)
}
)(Chart)
@@ -0,0 +1,26 @@
import * as React from 'react'
import Play from '@material-ui/icons/PlayArrow'
import Pause from '@material-ui/icons/PauseCircleFilled'
import Clear from '@material-ui/icons/Clear'
import CustomIconButton from '../helper/CustomIconButton'
import { ChartParameters } from '../../reducers/Charts'
import { SettingsButton } from './ChartSettings/SettingsButton'
export function ChartActions(props: {
paused: boolean
togglePause: () => void
parameters: ChartParameters
onRemove: () => void
}) {
return (
<div style={{ display: 'flex' }}>
<CustomIconButton tooltip={props.paused ? 'Resume chart' : 'Pause chart'} onClick={props.togglePause}>
{props.paused ? <Play /> : <Pause />}
</CustomIconButton>
<SettingsButton parameters={props.parameters} />
<CustomIconButton tooltip="Remove chart" onClick={props.onRemove}>
<Clear data-test-type="RemoveChart" data-test={`${props.parameters.topic}-${props.parameters.dotPath || ''}`} />
</CustomIconButton>
</div>
)
}
@@ -0,0 +1,71 @@
import * as React from 'react'
import { bindActionCreators } from 'redux'
import { chartActions } from '../../../actions'
import { ChartParameters } from '../../../reducers/Charts'
import { connect } from 'react-redux'
import { Menu, MenuItem } from '@material-ui/core'
import { colors as createColors } from './colors'
function chartParametersForColor(chart: ChartParameters, color?: string) {
return {
color,
topic: chart.topic,
dotPath: chart.dotPath,
}
}
const colors: Array<string> = createColors()
function ColorSettings(props: {
chart: ChartParameters
actions: {
chart: typeof chartActions
}
anchorEl?: Element
open: boolean
close: () => void
}) {
const setColor = React.useCallback(
(color?: string) => props.actions.chart.updateChart(chartParametersForColor(props.chart, color)),
[props.chart]
)
const menuItems = React.useMemo(() => {
return colors.map(color => (
<MenuItem
style={{ minWidth: '8em', minHeight: '36px', backgroundColor: color, textAlign: 'center' }}
key={color}
onClick={() => setColor(color)}
>
{props.chart.color === color ? 'X' : ''}
</MenuItem>
))
}, [colors, props.chart])
return (
<Menu anchorEl={props.anchorEl} open={props.open} onClose={props.close}>
<MenuItem
style={{ minWidth: '8em', minHeight: '36px', textAlign: 'center' }}
key="none"
onClick={() => setColor()}
selected={props.chart.color === undefined}
>
default
</MenuItem>
{menuItems}
</Menu>
)
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: {
chart: bindActionCreators(chartActions, dispatch),
},
}
}
export default connect(
undefined,
mapDispatchToProps
)(ColorSettings)
@@ -23,7 +23,7 @@ function InterpolationSettings(props: {
}
anchorEl?: Element
open: boolean
onClose: () => void
close: () => void
}) {
const callbacks = React.useMemo(() => {
const createCurveCallback = (curve: PlotCurveTypes) => () => {
@@ -46,7 +46,7 @@ function InterpolationSettings(props: {
}, [curves, props.chart])
return (
<Menu id="long-menu" anchorEl={props.anchorEl} open={props.open} onClose={props.onClose}>
<Menu anchorEl={props.anchorEl} open={props.open} onClose={props.close}>
{menuItems}
</Menu>
)
@@ -0,0 +1,35 @@
import * as React from 'react'
import { ChartParameters } from '../../../reducers/Charts'
import { Menu, MenuItem, TextField, Typography } from '@material-ui/core'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { chartActions } from '../../../actions'
function MoveUp(props: { actions: { chart: typeof chartActions }; chart: ChartParameters; close: () => void }) {
const moveUp = React.useCallback(() => {
props.actions.chart.moveChartUp({
topic: props.chart.topic,
dotPath: props.chart.dotPath,
})
props.close()
}, [props.chart])
return (
<MenuItem key="size" onClick={moveUp}>
Move up
</MenuItem>
)
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: {
chart: bindActionCreators(chartActions, dispatch),
},
}
}
export default connect(
undefined,
mapDispatchToProps
)(MoveUp)
@@ -34,13 +34,7 @@ function RangeSettings(props: {
const setFromHandler = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => setRangeFrom(e.target.value), [])
const setToHandler = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => setRangeTo(e.target.value), [])
return (
<Menu
style={{ textAlign: 'center' }}
id="long-menu"
anchorEl={props.anchorEl}
open={props.open}
onClose={props.onClose}
>
<Menu style={{ textAlign: 'center' }} anchorEl={props.anchorEl} open={props.open} onClose={props.onClose}>
<Typography>Define custom ranges for the Y-Axis</Typography>
<div style={{ padding: '0 16px' }}>
<TextField
@@ -19,7 +19,11 @@ export function SettingsButton(props: { parameters: ChartParameters }) {
<span>
<ChartSettings open={visible} close={close} anchorEl={settingsRef} chart={props.parameters} />
<CustomIconButton tooltip="Chart settings" onClick={toggleSettings}>
<MoreVertIcon ref={settingsRef as any} />
<MoreVertIcon
ref={settingsRef as any}
data-test-type="ChartSettings"
data-test={`${props.parameters.topic}-${props.parameters.dotPath || ''}`}
/>
</CustomIconButton>
</span>
)
@@ -0,0 +1,53 @@
import * as React from 'react'
import { ChartParameters } from '../../../reducers/Charts'
import { Menu, MenuItem, TextField, Typography } from '@material-ui/core'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { chartActions } from '../../../actions'
function Size(props: {
actions: { chart: typeof chartActions }
chart: ChartParameters
anchorEl?: Element
open: boolean
close: () => void
}) {
const setChartWidth = (width?: 'big' | 'medium' | 'small') => () => {
props.actions.chart.updateChart({
width,
topic: props.chart.topic,
dotPath: props.chart.dotPath,
})
props.close()
}
return (
<Menu anchorEl={props.anchorEl} open={props.open} onClose={props.close}>
<MenuItem selected={props.chart.width === undefined} onClick={setChartWidth()}>
auto
</MenuItem>
<MenuItem selected={props.chart.width === 'big'} onClick={setChartWidth('big')}>
100% width
</MenuItem>
<MenuItem selected={props.chart.width === 'medium'} onClick={setChartWidth('medium')}>
50% width
</MenuItem>
<MenuItem selected={props.chart.width === 'small'} onClick={setChartWidth('small')}>
33% width
</MenuItem>
</Menu>
)
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: {
chart: bindActionCreators(chartActions, dispatch),
},
}
}
export default connect(
undefined,
mapDispatchToProps
)(Size)
@@ -0,0 +1,46 @@
import {
amber,
orange,
pink,
purple,
deepPurple,
teal,
red,
green,
lime,
indigo,
yellow,
brown,
blueGrey,
} from '@material-ui/core/colors'
export function colors() {
function colorToInt(color: string): [number, number, number] {
const str = color.replace('#', '')
return [parseInt(str.slice(0, 2), 16), parseInt(str.slice(2, 4), 16), parseInt(str.slice(4, 6), 16)]
}
function colorCompare(colorA: string, colorB: string) {
const a = colorToInt(colorA)
const b = colorToInt(colorB)
return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2) + Math.pow(a[2] - b[2], 2))
}
const colors: Array<string> = [
brown,
blueGrey,
amber,
orange,
pink,
purple,
deepPurple,
teal,
red,
green,
lime,
indigo,
yellow,
]
.map(color => [color[200], color[500], color[700]])
.reduce((a, b) => a.concat(b), [])
.sort((a, b) => colorCompare(a, b))
return colors
}
@@ -3,6 +3,9 @@ import InterpolationSettings from './InterpolationSettings'
import { ChartParameters } from '../../../reducers/Charts'
import { Menu, MenuItem } from '@material-ui/core'
import RangeSettings from './RangeSettings'
import Size from './Size'
import MoveUp from './MoveUp'
import ColorSettings from './ColorSettings'
function ChartSettings(props: {
open: boolean
@@ -12,21 +15,37 @@ function ChartSettings(props: {
}) {
const [rangeVisible, setRangeVisible] = React.useState(false)
const [interpolationVisible, setInterpolationVisible] = React.useState(false)
const [sizeVisible, setSizeVisible] = React.useState(false)
const [colorVisible, setColorVisible] = React.useState(false)
const toggleRange = React.useCallback(() => {
if (!rangeVisible && open) {
if (open) {
props.close()
}
setRangeVisible(!rangeVisible)
}, [rangeVisible, open])
const toggleInterpolation = React.useCallback(() => {
if (!interpolationVisible && open) {
if (open) {
props.close()
}
setInterpolationVisible(!interpolationVisible)
}, [interpolationVisible, open])
const toggleSize = React.useCallback(() => {
if (open) {
props.close()
}
setSizeVisible(!sizeVisible)
}, [sizeVisible, open])
const toggleColor = React.useCallback(() => {
if (open) {
props.close()
}
setColorVisible(!colorVisible)
}, [colorVisible, open])
return (
<span>
<Menu id="long-menu" anchorEl={props.anchorEl.current} open={props.open} onClose={props.close}>
@@ -36,14 +55,23 @@ function ChartSettings(props: {
<MenuItem key="interpolation" onClick={toggleInterpolation}>
Curve interpolation
</MenuItem>
<MenuItem key="size" onClick={toggleSize}>
Size
</MenuItem>
<MenuItem key="color" onClick={toggleColor}>
Color
</MenuItem>
<MoveUp chart={props.chart} close={props.close} />
</Menu>
<RangeSettings chart={props.chart} anchorEl={props.anchorEl.current} open={rangeVisible} onClose={toggleRange} />
<InterpolationSettings
chart={props.chart}
anchorEl={props.anchorEl.current}
open={interpolationVisible}
onClose={toggleInterpolation}
close={toggleInterpolation}
/>
<Size chart={props.chart} anchorEl={props.anchorEl.current} open={sizeVisible} close={toggleSize} />
<ColorSettings chart={props.chart} anchorEl={props.anchorEl.current} open={colorVisible} close={toggleColor} />
</span>
)
}
@@ -0,0 +1,29 @@
import * as React from 'react'
import { ChartParameters } from '../../reducers/Charts'
import { Typography, Theme, withStyles } from '@material-ui/core'
function ChartTitle(props: { parameters: ChartParameters; classes: any }) {
const { classes, parameters } = props
return (
<div style={{ flexGrow: 1, overflow: 'hidden', textOverflow: 'ellipsis' }}>
<Typography variant="caption" className={classes.topic}>
{parameters.dotPath ? parameters.dotPath : parameters.topic}
</Typography>
<br />
<Typography variant="caption" className={classes.topic}>
{parameters.dotPath ? parameters.topic : <span dangerouslySetInnerHTML={{ __html: '&nbsp;' }}></span>}
</Typography>
</div>
)
}
const styles = (theme: Theme) => ({
topic: {
wordBreak: 'break-all' as 'break-all',
whiteSpace: 'nowrap' as 'nowrap',
overflow: 'hidden' as 'hidden',
textOverflow: 'ellipsis' as 'ellipsis',
},
})
export default withStyles(styles)(ChartTitle)
@@ -0,0 +1,50 @@
import * as q from '../../../../backend/src/Model'
import * as React from 'react'
import Chart from './Chart'
import { ChartParameters } from '../../reducers/Charts'
interface Props {
tree?: q.Tree<any>
parameters: ChartParameters
}
export function ChartWithTreeNode(props: Props) {
const { tree, parameters } = props
if (!tree) {
return null
}
const initialTreeNode = tree.findNode(parameters.topic)
const [treeNode, setTreeNode] = React.useState<q.TreeNode<any> | undefined>(initialTreeNode)
usePollingToFetchTreeNode(treeNode, tree, parameters.topic, setTreeNode)
return <Chart treeNode={treeNode} parameters={parameters} />
}
/**
* If a node is not available when the plot is shown, keep polling until it has been created
*/
function usePollingToFetchTreeNode(
treeNode: q.TreeNode<any> | undefined,
tree: q.Tree<any>,
path: string,
setTreeNode: React.Dispatch<React.SetStateAction<q.TreeNode<any> | undefined>>
) {
function pollUntilTreeNodeHasBeenFound() {
let intervalTimer: any
if (!treeNode) {
intervalTimer = setInterval(() => {
const node = tree.findNode(path)
if (node) {
setTreeNode(node)
clearInterval(intervalTimer)
}
}, 500)
}
return function cleanup() {
intervalTimer && clearInterval(intervalTimer)
}
}
React.useEffect(pollUntilTreeNodeHasBeenFound, [])
}
+31 -5
View File
@@ -1,10 +1,11 @@
import * as q from '../../../../backend/src/Model'
import * as React from 'react'
import Chart from './Chart'
import ShowChart from '@material-ui/icons/ShowChart'
import { AppState } from '../../reducers'
import { bindActionCreators } from 'redux'
import { chartActions } from '../../actions'
import { ChartParameters } from '../../reducers/Charts'
import { ChartWithTreeNode } from './ChartWithTreeNode'
import { connect } from 'react-redux'
import { Grid, Theme, Typography, withStyles } from '@material-ui/core'
import { List } from 'immutable'
@@ -13,9 +14,11 @@ const { TransitionGroup, CSSTransition } = require('react-transition-group/esm')
interface Props {
charts: List<ChartParameters>
connectionId?: string
tree?: q.Tree<any>
actions: {
chart: typeof chartActions
}
classes: any
}
function spacingForChartCount(count: number): 4 | 6 | 12 {
@@ -28,6 +31,19 @@ function spacingForChartCount(count: number): 4 | 6 | 12 {
}
}
function mapWidth(width: 'big' | 'medium' | 'small' | undefined, calculatedSpacing: 4 | 6 | 12): 4 | 6 | 12 {
switch (width) {
case 'big':
return 12
case 'medium':
return 6
case 'small':
return 4
default:
return calculatedSpacing
}
}
function ChartPanel(props: Props) {
const chartsInView = props.charts.count()
@@ -53,14 +69,14 @@ function ChartPanel(props: Props) {
timeout={{ enter: 500, exit: 500 }}
classNames="example"
>
<Grid item xs={spacing}>
<Chart parameters={chartParameters} />
<Grid item xs={mapWidth(chartParameters.width, spacing)}>
<ChartWithTreeNode tree={props.tree} parameters={chartParameters} />
</Grid>
</CSSTransition>
))
return (
<div style={{ width: '100%', height: '100%', padding: '8px' }}>
<div className={props.classes.container}>
<Grid container spacing={1}>
<TransitionGroup component={null} className="example">
{charts}
@@ -87,6 +103,7 @@ const mapStateToProps = (state: AppState) => {
return {
charts: state.charts.get('charts'),
connectionId: state.connection.connectionId,
tree: state.connection.tree,
}
}
@@ -98,7 +115,16 @@ const mapDispatchToProps = (dispatch: any) => {
}
}
const styles = (theme: Theme) => ({})
const styles = (theme: Theme) => ({
container: {
backgroundColor: theme.palette.background.default,
width: '100%',
height: '100%',
padding: '8px',
flex: 1,
overflow: 'hidden scroll',
},
})
export default connect(
mapStateToProps,
+64 -34
View File
@@ -18,11 +18,29 @@ interface Props {
function ContentView(props: Props) {
const [height, setHeight] = React.useState<string | number>('100%')
const [sidebarWidth, setSidebarWidth] = React.useState<string | number>('40%')
const [detectedHeight, setDetectedHeight] = React.useState(0)
const [detectedSidebarWidth, setDetectedSidebarWidth] = React.useState(0)
const detectSize = React.useCallback((width, newHeight) => {
setDetectedHeight(newHeight)
}, [])
const detectSidebarSize = React.useCallback(width => {
setDetectedSidebarWidth(width)
}, [])
const closeDrawerCompletelyIfItSitsOnTheEdge = React.useCallback(() => {
if (detectedHeight < 30) {
setHeight('100%')
}
}, [detectedHeight])
const closeSidebarCompletelyIfItSitsOnTheEdge = React.useCallback(() => {
if (detectedSidebarWidth < 30) {
setSidebarWidth('0%')
}
}, [detectedSidebarWidth])
// Open chart panel on start and when a new chart is added but the panel is closed
React.useEffect(() => {
const almostClosed = !isNaN(height as any) && detectedHeight < 30
@@ -37,42 +55,54 @@ function ContentView(props: Props) {
return (
<div className={props.paneDefaults}>
<ReactSplitPane
step={10}
split="horizontal"
minSize={0}
size={height}
defaultSize={'100%'}
allowResize={true}
style={{ height: 'calc(100vh - 64px)' }}
pane1Style={{ maxHeight: '100%' }}
pane2Style={{ borderTop: '1px solid #999', overflow: 'hidden scroll' }}
onChange={setHeight}
>
<span>
<ReactSplitPane
step={20}
primary="second"
className={props.heightProperty}
split="vertical"
minSize={250}
defaultSize={500}
allowResize={true}
style={{ height: '100%' }}
pane1Style={{ overflowX: 'hidden' }}
resizerStyle={{ height: '100%' }}
>
<Tree />
<div className={props.paneDefaults} style={{ height: '100%', overflowY: 'auto', overflowX: 'hidden' }}>
<span>
<ReactSplitPane
step={20}
primary="second"
className={props.heightProperty}
split="vertical"
minSize={0}
size={sidebarWidth}
onChange={setSidebarWidth}
onDragFinished={closeSidebarCompletelyIfItSitsOnTheEdge}
allowResize={true}
style={{ height: '100%' }}
pane1Style={{ overflowX: 'hidden' }}
resizerStyle={{ height: '100%' }}
>
<span>
<ReactSplitPane
step={10}
split="horizontal"
minSize={0}
size={height}
allowResize={true}
style={{ height: 'calc(100vh - 64px)' }}
pane1Style={{ maxHeight: '100%' }}
pane2Style={{ borderTop: '1px solid #999', display: 'flex' }}
onChange={setHeight}
onDragFinished={closeDrawerCompletelyIfItSitsOnTheEdge}
>
<Tree />
{/** Passing height constraints via flex options down */}
<div style={{ flex: 1, display: 'flex', height: '100%', width: '100%' }}>
{/** Resize detector must not be in the scroll zone, it needs to detect actual available size */}
<ReactResizeDetector handleHeight={true} onResize={detectSize} />
<ChartPanel />
</div>
</ReactSplitPane>
</span>
<div style={{ height: '100%' }}>
<ReactResizeDetector handleWidth={true} onResize={detectSidebarSize} />
<div
className={props.paneDefaults}
style={{ minWidth: '250px', height: '100%', overflowY: 'auto', overflowX: 'hidden' }}
>
<Sidebar connectionId={props.connectionId} />
</div>
</ReactSplitPane>
</span>
<div>
<ReactResizeDetector handleHeight={true} onResize={detectSize} />
<ChartPanel />
</div>
</ReactSplitPane>
</div>
</ReactSplitPane>
</span>
</div>
)
}
+1 -1
View File
@@ -2,7 +2,7 @@ import * as React from 'react'
import * as q from '../../../../backend/src/Model'
import CustomIconButton from '../helper/CustomIconButton'
import Pause from '@material-ui/icons/PauseCircleFilled'
import Resume from '@material-ui/icons/PlayCircleFilled'
import Resume from '@material-ui/icons/PlayArrow'
import { AppState } from '../../reducers'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
@@ -24,7 +24,7 @@ function ChartPreview(props: Props) {
const onClick = React.useCallback(() => {
props.actions.chart.addChart({
topic: props.treeNode.path(),
dotPath: props.literal.path,
dotPath: props.literal.path !== '' ? props.literal.path : undefined,
})
setOpen(false)
}, [props.literal.path, props.treeNode])
@@ -40,18 +40,26 @@ function ChartPreview(props: Props) {
const hasEnoughDataToDisplayDiagrams = props.treeNode.messageHistory.count() > 1
const addChartToPanelButton = hasEnoughDataToDisplayDiagrams ? (
<Tooltip title="Click to add to chart panel">
<Tooltip title="Add to chart panel">
<ShowChart
ref={chartIconRef}
className={props.classes.icon}
onMouseEnter={mouseOver}
onMouseLeave={mouseOut}
onClick={onClick}
data-test-type="ShowChart"
data-test={props.literal.path}
/>
</Tooltip>
) : (
<Tooltip title="Click to add to chart panel, not enough data for preview">
<ShowChart onClick={onClick} className={props.classes.icon} style={{ color: '#aaa' }} />
<Tooltip title="Add to chart panel, not enough data for preview">
<ShowChart
onClick={onClick}
className={props.classes.icon}
style={{ color: '#aaa' }}
data-test-type="ShowChart"
data-test={props.literal.path}
/>
</Tooltip>
)
+9 -6
View File
@@ -12,6 +12,7 @@ interface Props {
theme: Theme
interpolation?: PlotCurveTypes
range?: [number?, number?]
color?: string
}
function mapCurveType(type: PlotCurveTypes | undefined) {
@@ -58,6 +59,12 @@ export default withTheme((props: Props) => {
? [props.range[0] || calculatedDomain[0], props.range[1] || calculatedDomain[1]]
: calculatedDomain
let color: string =
props.theme.palette.type === 'light' ? props.theme.palette.secondary.dark : props.theme.palette.primary.light
if (props.color) {
color = props.color
}
return (
<div style={{ height: '150px', overflow: 'hidden' }}>
<XYPlot width={width} height={180} yDomain={yDomain}>
@@ -65,11 +72,7 @@ export default withTheme((props: Props) => {
<XAxis />
<YAxis width={45} tickFormat={(num: number) => abbreviate(num)} />
<LineMarkSeries
color={
props.theme.palette.type === 'light'
? props.theme.palette.secondary.dark
: props.theme.palette.primary.light
}
color={color}
onValueMouseOver={showTooltip}
onValueMouseOut={hideTooltip}
size={3}
@@ -81,7 +84,7 @@ export default withTheme((props: Props) => {
<ReactResizeDetector handleWidth={true} onResize={detectResize} />
</div>
)
}, [width, props.data, tooltip, props.interpolation, props.range])
}, [width, props.data, tooltip, props.interpolation, props.range, props.color, props.theme])
})
function domainForData(data: Array<{ x: number; y: number }>): [number, number] {
@@ -11,6 +11,7 @@ import { TopicViewModel } from '../../../model/TopicViewModel'
import { bindActionCreators } from 'redux'
import { chartActions } from '../../../actions'
import { connect } from 'react-redux'
import CustomIconButton from '../../helper/CustomIconButton'
const throttle = require('lodash.throttle')
@@ -109,7 +110,19 @@ class MessageHistory extends React.Component<Props, State> {
<div>
<History
items={historyElements}
contentTypeIndicator={isMessagePlottable ? <ShowChart onClick={this.addNodeToCharts} /> : undefined}
contentTypeIndicator={
isMessagePlottable ? (
<CustomIconButton
style={{ height: '22px', width: '22px' }}
onClick={this.addNodeToCharts}
tooltip="Add to chart panel"
>
<ShowChart style={{ marginTop: '-5px' }} />
</CustomIconButton>
) : (
undefined
)
}
onClick={this.displayMessage}
>
{isMessagePlottable ? <TopicPlot history={node.messageHistory} /> : null}
+2 -1
View File
@@ -11,6 +11,7 @@ interface Props {
dotPath?: string
interpolation?: PlotCurveTypes
range?: [number?, number?]
color?: string
}
function nodeToHistory(history: q.MessageHistory) {
@@ -41,7 +42,7 @@ function nodeDotPathToHistory(history: q.MessageHistory, dotPath: string) {
function render(props: Props) {
const data = props.dotPath ? nodeDotPathToHistory(props.history, props.dotPath) : nodeToHistory(props.history)
return <PlotHistory range={props.range} interpolation={props.interpolation} data={data} />
return <PlotHistory color={props.color} range={props.range} interpolation={props.interpolation} data={data} />
}
export default render
+1
View File
@@ -110,6 +110,7 @@ class TreeComponent extends React.PureComponent<Props, State> {
overflowY: 'scroll',
overflowX: 'hidden',
height: '100%',
width: '100%',
paddingBottom: '16px', // avoid conflict with chart panel Resizer
}
@@ -6,6 +6,7 @@ interface Props {
onClick: any
tooltip: string
classes: any
style?: React.CSSProperties
}
const styles = (theme: Theme) => ({
@@ -32,7 +33,7 @@ class CustomIconButton extends React.Component<Props, {}> {
public render() {
return (
<IconButton className={this.props.classes.button} onClick={this.onClick}>
<IconButton className={this.props.classes.button} style={this.props.style} onClick={this.onClick}>
<Tooltip title={this.props.tooltip} className={this.props.classes.label}>
<span>{this.props.children}</span>
</Tooltip>
+25 -1
View File
@@ -1,6 +1,7 @@
import { Action } from 'redux'
import { createReducer } from './lib'
import { Record, List } from 'immutable'
import MoveUp from '../components/ChartPanel/ChartSettings/MoveUp'
export type PlotCurveTypes = 'curve' | 'linear' | 'cubic_basis_spline' | 'step_after' | 'step_before'
@@ -12,6 +13,8 @@ export interface ChartParameters {
from?: number
to?: number
}
width?: 'big' | 'medium' | 'small'
color?: string
}
export interface ChartsStateModel {
@@ -20,13 +23,14 @@ export interface ChartsStateModel {
export type ChartsState = Record<ChartsStateModel>
export type Action = AddChart | RemoveChart | SetCharts | UpdateChart
export type Action = AddChart | RemoveChart | SetCharts | UpdateChart | MoveUp
export enum ActionTypes {
CHARTS_ADD = 'CHARTS_ADD',
CHARTS_REMOVE = 'CHARTS_REMOVE',
CHARTS_SET = 'CHARTS_SET',
CHARTS_UPDATE = 'CHARTS_UPDATE',
CHARTS_MOVE_UP = 'CHARTS_MOVE_UP',
}
export interface AddChart {
@@ -34,6 +38,12 @@ export interface AddChart {
chart: ChartParameters
}
export interface MoveUp {
type: ActionTypes.CHARTS_ADD
topic: string
dotPath?: string
}
export interface UpdateChart {
type: ActionTypes.CHARTS_ADD
topic: string
@@ -60,12 +70,26 @@ export const chartsReducer = createReducer(initialState(), {
CHARTS_REMOVE: removeChart,
CHARTS_SET: setCharts,
CHARTS_UPDATE: updateChart,
CHARTS_MOVE_UP: moveUp,
})
function addChart(state: ChartsState, action: AddChart) {
return state.set('charts', state.get('charts').push(action.chart))
}
function moveUp(state: ChartsState, action: MoveUp) {
const charts = state.get('charts')
const idx = charts.findIndex(chart => chart.topic === action.topic && chart.dotPath === action.dotPath)
const item = charts.get(idx)
const previousItem = charts.get(idx - 1)
if (idx === 0 || !item || !previousItem) {
return
}
const newlyOrderedCharts = charts.set(idx - 1, item).set(idx, previousItem)
return state.set('charts', newlyOrderedCharts)
}
function updateChart(state: ChartsState, action: UpdateChart) {
const charts = state.get('charts')
const chartIdx = charts.findIndex(chart => chart.topic === action.topic && chart.dotPath === action.dotPath)
+5 -4
View File
@@ -1,6 +1,6 @@
{
"name": "MQTT-Explorer",
"version": "0.3.0-alpha",
"version": "0.3.0",
"description": "Explore your message queues",
"main": "dist/src/electron.js",
"scripts": {
@@ -46,7 +46,8 @@
"identityName": "51031thomas.nordquist.MQTT-Explorer",
"publisherDisplayName": "Thomas Nordquist",
"publisher": "CN=0A6DE643-4AA2-4FF2-9729-6935C9ED8C13",
"backgroundColor": "transparent"
"backgroundColor": "transparent",
"showNameOnTiles": true
},
"directories": {
"app": "./",
@@ -73,8 +74,8 @@
"builder-util-runtime": "^8.2.5",
"chai": "^4.2.0",
"cspell": "^4.0.23",
"electron": "5",
"electron-builder": "^20.38.5",
"electron": "5.0.4",
"electron-builder": "20.44.1",
"fs-extra": "^8.0.1",
"mime": "^2.4.0",
"mocha": "^6.1.4",
+7 -21
View File
@@ -12,7 +12,6 @@ import { disconnect } from './scenarios/disconnect'
import { publishTopic } from './scenarios/publishTopic'
import { SceneBuilder } from './SceneBuilder'
import { showAdvancedConnectionSettings } from './scenarios/showAdvancedConnectionSettings'
import { showJsonFormatting } from './scenarios/showJsonFormatting'
import { showJsonPreview } from './scenarios/showJsonPreview'
import { showMenu } from './scenarios/showMenu'
import { showNumericPlot } from './scenarios/showNumericPlot'
@@ -59,18 +58,11 @@ async function doStuff() {
const scenes = new SceneBuilder()
await scenes.record('connect', async () => {
await connectTo('127.0.0.1', browser)
await sleep(2000)
})
await scenes.record('topic_updates', async () => {
await showText('Topic overview', 1000, browser, 'top')
await sleep(1000)
await showText('Indicate topic updates', 1000, browser, 'middle')
await sleep(1000)
})
await scenes.record('numeric_plots', async () => {
await showText('Plot topic history', 2000, browser)
await showText('Plot topic history', 1500, browser)
await showNumericPlot(browser)
await sleep(2000)
})
@@ -87,20 +79,14 @@ async function doStuff() {
})
await scenes.record('publish_topic', async () => {
await showText('Publish topics', 2000, browser, 'top')
await showText('Publish topics', 1500, browser, 'top')
await clickOnHistory(browser)
await publishTopic(browser)
await sleep(1000)
})
await scenes.record('json_formatting_publish', async () => {
await showText('Write JSON with ease', 2000, browser, 'top')
await showJsonFormatting(browser)
await sleep(1000)
})
await scenes.record('clipboard', async () => {
await showText('Copy to Clipboard', 2000, browser)
await showText('Copy to Clipboard', 1500, browser)
await copyTopicToClipboard(browser)
await hideText(browser)
await copyValueToClipboard(browser)
@@ -119,25 +105,25 @@ async function doStuff() {
await scenes.record('delete_retained_topics', async () => {
await hideText(browser)
await showText('Delete retained topics', 0, browser)
await showText('Delete retained topics', 5000, browser)
await clearOldTopics(browser)
await hideText(browser)
})
await scenes.record('settings', async () => {
await showText('Display Options', 2000, browser)
await showText('Settings', 1500, browser)
await showMenu(browser)
})
await scenes.record('customize_subscriptions', async () => {
await sleep(2000)
await disconnect(browser)
await showText('Customize Subscriptions', 1000, browser, 'top')
await showText('Customize Subscriptions', 1500, browser, 'top')
await showAdvancedConnectionSettings(browser)
})
await scenes.record('keyboard_shortcuts', async () => {
await showText('Keyboard shortcuts', 1750, browser, 'middle')
await showText('Keyboard shortcuts', 1500, browser, 'middle')
await sleep(1750)
await showZoomLevel(browser)
})
+27 -6
View File
@@ -21,8 +21,8 @@ function connectMqtt(): Promise<mqtt.MqttClient> {
})
}
function temperature(base = 18, sineCoefficient = 2, offset = 0) {
const temp = base + Math.sin(Date.now() / 1000 / 5 + offset) * sineCoefficient + Math.random()
function temperature(base = 18, sineCoefficient = 2, offset = 0, speed = 1) {
const temp = base + Math.sin((Date.now() * speed) / 1000 / 5 + offset) * sineCoefficient + Math.random()
return String(Math.round(temp * 100) / 100)
}
@@ -52,7 +52,9 @@ function generateData(client: mqtt.MqttClient) {
retain: true,
qos: 0,
})
intervals.push(setInterval(() => client.publish('livingroom/temperature', temperature()), 1000))
intervals.push(
setInterval(() => client.publish('livingroom/temperature', temperature(), { retain: true, qos: 0 }), 1000)
)
intervals.push(setInterval(() => client.publish('livingroom/humidity', temperature(60, -2, 0)), 1000))
client.publish('livingroom/lamp-1/state', 'on', { retain: true, qos: 0 })
@@ -72,7 +74,7 @@ function generateData(client: mqtt.MqttClient) {
if (topic === 'kitchen/lamp/set') {
setTimeout(
() =>
client.publish('kitchen/lamp/state', payload, {
client.publish('kitchen/lamp/state', JSON.parse(payload.toString()).state, {
retain: true,
qos: 0,
}),
@@ -81,8 +83,27 @@ function generateData(client: mqtt.MqttClient) {
}
})
intervals.push(setInterval(() => client.publish('kitchen/temperature', temperature()), 1500))
intervals.push(setInterval(() => client.publish('kitchen/humidity', temperature(60, -5, 0)), 1800))
const coffeeMaker = {
heater: 'on',
temperature: 92.5,
waterLevel: 0.5,
update: new Date(),
}
intervals.push(
setInterval(() => {
const newTemp = parseFloat(temperature(90.3, -5, 0, 3))
coffeeMaker.heater = newTemp > coffeeMaker.temperature ? 'on' : 'off'
coffeeMaker.temperature = newTemp
client.publish('kitchen/coffee_maker', JSON.stringify(coffeeMaker), { retain: true, qos: 2 })
}, 1500)
)
intervals.push(
setInterval(() => client.publish('kitchen/temperature', temperature(), { retain: true, qos: 0 }), 1500)
)
intervals.push(
setInterval(() => client.publish('kitchen/humidity', temperature(60, -5, 0), { retain: true, qos: 0 }), 1800)
)
client.publish('garden/pump/state', 'off', { retain: true, qos: 0 })
client.publish('garden/water/level', '70%', { retain: true, qos: 0 })
+2 -4
View File
@@ -1,10 +1,8 @@
import { Browser, Element } from 'webdriverio'
import { clickOn, writeTextToInput } from '../util'
import { clickOn, setTextInInput } from '../util'
export async function connectTo(host: string, browser: Browser) {
await writeTextToInput('Host', host, browser)
await writeTextToInput('Username', 'thomas', browser, false)
await writeTextToInput('Password', 'bierbier', browser, false)
await setTextInInput('Host', host, browser)
await browser.saveScreenshot('screen1.png')
+18 -6
View File
@@ -3,7 +3,7 @@ import {
clickOn,
sleep,
writeText,
delteTextWithBackspaces,
deleteTextWithBackspaces,
expandTopic,
moveToCenterOfElement,
showText,
@@ -13,14 +13,15 @@ export async function publishTopic(browser: Browser) {
await expandTopic('kitchen/lamp/state', browser)
const topicInput = await browser.$('//textarea[contains(text(),"kitchen/lamp/state")][1]')
await clickOn(topicInput, browser)
await delteTextWithBackspaces(topicInput, browser, 120, 5)
await deleteTextWithBackspaces(topicInput, browser, 120, 5)
await writeText('set', browser, 300)
const payloadInput = await browser.$('//*[contains(@class, "ace_text-input")]')
await payloadInput.setValue('o')
await sleep(300)
await payloadInput.setValue('n')
await sleep(700)
await writeTextPayload(payloadInput, '{"action": "setState", "state": "on" }')
await sleep(500)
const formatJsonButton = await browser.$('#sidebar-publish-format-json')
await clickOn(formatJsonButton, browser)
const publishButton = await browser.$('#publish-button')
await moveToCenterOfElement(publishButton, browser)
@@ -28,4 +29,15 @@ export async function publishTopic(browser: Browser) {
await sleep(500)
await clickOn(publishButton, browser)
const sidebarDrawer = await browser.$('#Sidebar')
await sidebarDrawer.scrollIntoView()
}
async function writeTextPayload(payloadInput: any, text: string) {
const chars = text.split('')
for (const char of chars) {
await payloadInput.setValue(char)
await sleep(10)
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
import { Browser, Element } from 'webdriverio'
import { clickOn, delteTextWithBackspaces, showText, sleep, writeText } from '../util'
import { clickOn, deleteTextWithBackspaces, showText, sleep, writeText } from '../util'
export async function searchTree(text: string, browser: Browser) {
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
@@ -11,5 +11,5 @@ export async function searchTree(text: string, browser: Browser) {
export async function clearSearch(browser: Browser) {
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
await clickOn(searchField, browser, 1)
await delteTextWithBackspaces(searchField, browser, 100)
await deleteTextWithBackspaces(searchField, browser, 100)
}
@@ -1,15 +1,15 @@
import { Browser, Element } from 'webdriverio'
import { clickOn, sleep, writeTextToInput } from '../util'
import { clickOn, sleep, setTextInInput } from '../util'
export async function showAdvancedConnectionSettings(browser: Browser) {
const advancedSettingsButton = await browser.$('//button/span[contains(text(),"Advanced")]')
const addButton = await browser.$('//button/span[contains(text(),"Add")]')
await clickOn(advancedSettingsButton, browser)
await writeTextToInput('Subscription', 'garden/#', browser, false)
await setTextInInput('Subscription', 'garden/#', browser)
await clickOn(addButton, browser)
await writeTextToInput('Subscription', 'livingroom/#', browser, false)
await setTextInInput('Subscription', 'livingroom/#', browser)
await clickOn(addButton, browser)
await deleteFirstSubscribedTopic(browser)
-30
View File
@@ -1,30 +0,0 @@
import { Browser, Element } from 'webdriverio'
import { clickOn, sleep } from '../util'
export async function showJsonFormatting(browser: Browser) {
const editor = await browser.$('//*[contains(@class, "ace_editor")]')
const formatJsonButton = await browser.$('#sidebar-publish-format-json')
const payloadInput = await browser.$('//*[contains(@class, "ace_text-input")]')
await clickOn(editor, browser)
await browser.keys(['\uE009', 'A']) // Ctrl + A
await sleep(200)
await browser.keys(['\uE000']) // End keyboard modifier
await sleep(200)
await browser.keys(['\uE003']) // Backspace
await sleep(200)
await writeTextPayload(payloadInput, '{"action": "setState", "state": "on" }')
await sleep(300)
await clickOn(formatJsonButton, browser)
await sleep(1200)
const sidebarDrawer = await browser.$('#Sidebar')
await sidebarDrawer.scrollIntoView()
}
async function writeTextPayload(payloadInput: any, text: string) {
const chars = text.split('')
for (const char of chars) {
await payloadInput.setValue(char)
await sleep(10)
}
}
+66 -1
View File
@@ -1,7 +1,39 @@
import { Browser, Element } from 'webdriverio'
import { clickOn, clickOnHistory, expandTopic, sleep, writeText } from '../util'
import { moveToCenterOfElement, clickOn, clickOnHistory, expandTopic, sleep, writeText } from '../util'
export async function showNumericPlot(browser: Browser) {
await expandTopic('kitchen/coffee_maker', browser)
let heater = await valuePreviewGuttersShowChartIcon('heater', browser)
await moveToCenterOfElement(heater, browser)
await sleep(1000)
// Refocus
heater = await valuePreviewGuttersShowChartIcon('heater', browser)
await heater.click()
let temperature = await valuePreviewGuttersShowChartIcon('temperature', browser)
await moveToCenterOfElement(temperature, browser)
temperature = await valuePreviewGuttersShowChartIcon('temperature', browser)
await temperature.click()
await sleep(1000)
await chartSettings('heater', browser)
await clickOnMenuPoint('Curve interpolation', browser)
await clickOnMenuPoint('step after', browser)
await clickAway('heater', browser)
await chartSettings('temperature', browser)
await clickOnMenuPoint('Curve interpolation', browser)
await clickOnMenuPoint('cubic basis spline', browser)
await clickAway('temperature', browser)
await sleep(2500)
await browser.saveScreenshot('screen_chart_panel.png')
await removeChart('heater', browser)
await sleep(750)
await removeChart('temperature', browser)
await sleep(750)
await expandTopic('livingroom/temperature', browser)
await clickOnHistory(browser)
@@ -9,3 +41,36 @@ export async function showNumericPlot(browser: Browser) {
await sleep(1000)
await expandTopic('livingroom/humidity', browser)
}
async function valuePreviewGuttersShowChartIcon(name: string, browser: Browser) {
for (let retries = 0; retries < 2; retries += 1) {
try {
return await browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
} catch {
// ignore
}
}
return browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
}
async function chartSettings(name: string, browser: Browser) {
const settings = await browser.$(`//*[contains(@data-test-type, "ChartSettings")][contains(@data-test, "${name}")]`)
return clickOn(settings, browser)
}
async function clickAway(name: string, browser: Browser) {
const settings = await browser.$(`//*[contains(@data-test-type, "ChartPaper")][contains(@data-test, "${name}")]`)
await moveToCenterOfElement(settings, browser)
const awayClickElement = await browser.$('//div[contains(@role, "presentation")]')
return awayClickElement.click()
}
async function removeChart(name: string, browser: Browser) {
const remove = await browser.$(`//*[contains(@data-test-type, "RemoveChart")][contains(@data-test, "${name}")]`)
return clickOn(remove, browser)
}
async function clickOnMenuPoint(name: string, browser: Browser) {
const item = await browser.$(`//li[contains(text(), "${name}")]`)
return clickOn(item, browser)
}
+4 -6
View File
@@ -29,7 +29,7 @@ export async function writeText(text: string, browser: Browser, delay = 0) {
}
}
export async function delteTextWithBackspaces(element: Element, browser: Browser, delay = 0, count = 0) {
export async function deleteTextWithBackspaces(element: Element, browser: Browser, delay = 0, count = 0) {
const length = count > 0 ? count : (await element.getValue()).length
for (let i = 0; i < length; i += 1) {
await browser.keys(['Backspace'])
@@ -37,13 +37,11 @@ export async function delteTextWithBackspaces(element: Element, browser: Browser
}
}
export async function writeTextToInput(name: string, text: string, browser: Browser, wait: boolean = true) {
export async function setTextInInput(name: string, text: string, browser: Browser) {
const input = await browser.$(`//label[contains(text(), "${name}")]/..//input`)
await clickOn(input, browser, 1)
wait && (await sleep(500))
input.clearValue()
wait && (await sleep(300))
await writeText(text, browser)
await input.clearValue()
await browser.keys(text)
}
export async function moveToCenterOfElement(element: Element, browser: Browser) {
+286 -259
View File
@@ -114,11 +114,28 @@
reflect-metadata "^0.1.12"
tslib "^1.8.1"
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
"@szmarczak/http-timer@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
dependencies:
defer-to-connect "^1.0.1"
"@types/chai@^4.1.7":
version "4.1.7"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a"
integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==
"@types/debug@^4.1.4":
version "4.1.4"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.4.tgz#56eec47706f0fd0b7c694eae2f3172e6b0b769da"
integrity sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==
"@types/fs-extra@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-7.0.0.tgz#9c4ad9e1339e7448a76698829def1f159c1b636c"
@@ -164,9 +181,9 @@
integrity sha512-NelG/dSahlXYtSoVPErrp06tYFrvzj8XLWmKA+X8x0W//4MqbUyZu++giUG/v0bjAT6/Qxa8IjodrfdACyb0Fg==
"@types/node@^12.0.4":
version "12.0.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.4.tgz#46832183115c904410c275e34cf9403992999c32"
integrity sha512-j8YL2C0fXq7IONwl/Ud5Kt0PeXw22zGERt+HSSnwbKOJVsAGkEz3sFCYwaF9IOuoG1HOtE0vKCj6sXF7Q0+Vaw==
version "12.0.8"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.8.tgz#551466be11b2adc3f3d47156758f610bd9f6b1d8"
integrity sha512-b8bbUOTwzIY3V5vDTY1fIJ+ePKDUBqt2hC2woVGotdQQhG/2Sh62HOKHrT7ab+VerXAcPyAiTEipPu/FsreUtg==
"@types/semver@^6.0.0":
version "6.0.0"
@@ -226,12 +243,12 @@ ajv@^6.5.5, ajv@^6.9.2:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ansi-align@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
ansi-align@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
dependencies:
string-width "^2.0.0"
string-width "^3.0.0"
ansi-colors@3.2.3:
version "3.2.3"
@@ -270,31 +287,31 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
app-builder-bin@2.6.6:
version "2.6.6"
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-2.6.6.tgz#904b0576a510047d03f63c8a02c38eef47871180"
integrity sha512-G0Ee6xkbxV+fvM/7xXWIgSDjWAD4E/d/aNbxerq/TVsCyBIau/0VPmrEqBMyZv0NbTwLDW5aF/yHG+0ZEY77kA==
app-builder-bin@2.6.13:
version "2.6.13"
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-2.6.13.tgz#d3b7eb60b5333b0e5c4daf353260f82f7ba01597"
integrity sha512-P8s4wUuSPp4Vuob/RCmCpsAEAdf28HuP2brGjZ3VLxaAZrBnByuDq2c7Ud7xgEPehOMwEV+EXcEg7wnM7a2H9Q==
app-builder-lib@20.41.0, app-builder-lib@~20.41.0:
version "20.41.0"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-20.41.0.tgz#7d81425f1b58c9dbfd44a4a2b2ea8ea0ab9a56a8"
integrity sha512-c/BpNDuyd0xAh2jI2s9ep+NVC4T0lD1mmEpSH0iueOP8TqWXEMYMJsrSFn6CwRsVeFGaYCz0o+IPpsHUohgP+g==
app-builder-lib@20.44.1, app-builder-lib@~20.44.0:
version "20.44.1"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-20.44.1.tgz#02076f950dcd3a75409356948a0fbb6963ffcd88"
integrity sha512-otmaGKhw9LVPgudeyDe3jOkp1BGad/dWtf/HyjvJH4Ep9UQHw1J4mSNLMuDxNKd1W9BOZVzl8ulw/t5JBmsmHw==
dependencies:
"7zip-bin" "~4.1.0"
app-builder-bin "2.6.6"
app-builder-bin "2.6.13"
async-exit-hook "^2.0.1"
bluebird-lst "^1.0.7"
builder-util "10.0.0"
builder-util-runtime "8.2.2"
bluebird-lst "^1.0.9"
builder-util "10.0.4"
builder-util-runtime "8.2.5"
chromium-pickle-js "^0.2.0"
debug "^4.1.1"
ejs "^2.6.1"
electron-osx-sign "0.4.11"
electron-publish "20.41.0"
fs-extra-p "^7.0.1"
electron-publish "20.44.0"
fs-extra-p "^8.0.2"
hosted-git-info "^2.7.1"
is-ci "^2.0.0"
isbinaryfile "^4.0.0"
isbinaryfile "^4.0.1"
js-yaml "^3.13.1"
lazy-val "^1.0.4"
minimatch "^3.0.4"
@@ -302,8 +319,8 @@ app-builder-lib@20.41.0, app-builder-lib@~20.41.0:
plist "^3.0.1"
read-config-file "3.2.2"
sanitize-filename "^1.6.1"
semver "^6.0.0"
temp-file "^3.3.2"
semver "^6.1.1"
temp-file "^3.3.3"
append-transform@^1.0.0:
version "1.0.0"
@@ -478,7 +495,7 @@ bl@^1.0.0, bl@^1.2.2:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
bluebird-lst@^1.0.6, bluebird-lst@^1.0.7, bluebird-lst@^1.0.8:
bluebird-lst@^1.0.6, bluebird-lst@^1.0.7:
version "1.0.8"
resolved "https://registry.yarnpkg.com/bluebird-lst/-/bluebird-lst-1.0.8.tgz#61b572e8b3eb57e0fff676a0e54566d93597e6a4"
integrity sha512-InUDOaBaIjIobOa3O4YRAbFgff907uTJZXW0m0rhk3zhVZ4GvsmdCLEAKC1CTWTtUWCM8iWTTfFX9N/xQR/etw==
@@ -497,17 +514,18 @@ bluebird@^3.5.0, bluebird@^3.5.4, bluebird@^3.5.5:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
boxen@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
boxen@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-3.2.0.tgz#fbdff0de93636ab4450886b6ff45b92d098f45eb"
integrity sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==
dependencies:
ansi-align "^2.0.0"
camelcase "^4.0.0"
chalk "^2.0.1"
cli-boxes "^1.0.0"
string-width "^2.0.0"
ansi-align "^3.0.0"
camelcase "^5.3.1"
chalk "^2.4.2"
cli-boxes "^2.2.0"
string-width "^3.0.0"
term-size "^1.2.0"
type-fest "^0.3.0"
widest-line "^2.0.0"
brace-expansion@^1.1.7:
@@ -566,27 +584,7 @@ buffer@^5.1.0:
base64-js "^1.0.2"
ieee754 "^1.1.4"
builder-util-runtime@8.2.2:
version "8.2.2"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.2.2.tgz#2b4b5c86cfb8b55b5a19ab90f1a39bdd6ac6f33e"
integrity sha512-Z0NKlpa5VQBMVXAcZH9n4dx+CY5Ckyv7a0Yr/is1h5hwCWaJbQ2JN9PGT7g6YzE5gM3FyrgGDB4DTyJlLcRKNw==
dependencies:
bluebird-lst "^1.0.7"
debug "^4.1.1"
fs-extra-p "^7.0.1"
sax "^1.2.4"
builder-util-runtime@^8.2.2, builder-util-runtime@^8.2.3:
version "8.2.3"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.2.3.tgz#e28b7d6b93e939106e862df68cce6fef1dc3cd41"
integrity sha512-uSeijGTt7IgNMWmyKW2qPgO5aw3o0KMbmop+KE1iQNp//reI0lULuaMcwTkx2Uzr0ToEMgOBMr0jGMHwwDFpCw==
dependencies:
bluebird-lst "^1.0.8"
debug "^4.1.1"
fs-extra-p "^8.0.0"
sax "^1.2.4"
builder-util-runtime@^8.2.5:
builder-util-runtime@8.2.5, builder-util-runtime@^8.2.5:
version "8.2.5"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.2.5.tgz#6f19330178345f8ce2c65842b0a9cf6a187d5946"
integrity sha512-YILT+YUlxrE3yNB6mDC1tF+Q24mr1LSYdjP5U861jbBeDZfvy1/VPDzW3boMVrDtzYnDnvkYrzLJnoh6TXA75w==
@@ -606,47 +604,43 @@ builder-util-runtime@~8.1.0:
fs-extra-p "^7.0.0"
sax "^1.2.4"
builder-util@10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-10.0.0.tgz#b80e347cbd21947fd50f7a0225149eeffc7307c0"
integrity sha512-7gBdyDprpb0QpVCCrSIf1nQhOpT8gp//f8f9o40zki00ePrBxJhvGwwkBXoorJfh3vSgIdMgpvHLAbV5xcnolA==
builder-util@10.0.4, builder-util@~10.0.3:
version "10.0.4"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-10.0.4.tgz#06541ffbe7a2f272972accc40124918f148f6cec"
integrity sha512-KEqMNPb6v4sKoHlrIR8KiJQwd9/fqXxpAKwLNz+g7dKYfS2r8B4SVJWRGutevPeOK7nfRrOAukUwPjByBswrtw==
dependencies:
"7zip-bin" "~4.1.0"
app-builder-bin "2.6.6"
bluebird-lst "^1.0.7"
builder-util-runtime "^8.2.2"
"@types/debug" "^4.1.4"
app-builder-bin "2.6.13"
bluebird-lst "^1.0.9"
builder-util-runtime "^8.2.5"
chalk "^2.4.2"
debug "^4.1.1"
fs-extra-p "^7.0.1"
fs-extra-p "^8.0.2"
is-ci "^2.0.0"
js-yaml "^3.13.1"
source-map-support "^0.5.12"
stat-mode "^0.3.0"
temp-file "^3.3.2"
builder-util@~10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-10.0.1.tgz#1606b3baf21f6d23e790d52d9d0cff9b27cc7e24"
integrity sha512-lMZMx4mmZYVRZPIuSWKY9WO1HAsRYFf7R6O2cZv24zApavOPo3iTQw5c6IX4tvYztp3uABmqAqoElKUNQMrtpQ==
dependencies:
"7zip-bin" "~4.1.0"
app-builder-bin "2.6.6"
bluebird-lst "^1.0.8"
builder-util-runtime "^8.2.3"
chalk "^2.4.2"
debug "^4.1.1"
fs-extra-p "^8.0.0"
is-ci "^2.0.0"
js-yaml "^3.13.1"
source-map-support "^0.5.12"
stat-mode "^0.3.0"
temp-file "^3.3.2"
temp-file "^3.3.3"
builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
cacheable-request@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^3.0.0"
lowercase-keys "^2.0.0"
normalize-url "^4.1.0"
responselike "^1.0.2"
caching-transform@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-3.0.2.tgz#601d46b91eca87687a281e71cef99791b0efca70"
@@ -678,21 +672,11 @@ camelcase@^2.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
camelcase@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
camelcase@^5.0.0:
camelcase@^5.0.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
capture-stack-trace@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
@@ -750,20 +734,15 @@ chromium-pickle-js@^0.2.0:
resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205"
integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=
ci-info@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
ci-info@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
cli-boxes@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
cli-boxes@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d"
integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==
cli-cursor@^2.1.0:
version "2.1.0"
@@ -795,6 +774,13 @@ cliui@^5.0.0:
strip-ansi "^5.2.0"
wrap-ansi "^5.1.0"
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
code-error-fragment@0.0.230:
version "0.0.230"
resolved "https://registry.yarnpkg.com/code-error-fragment/-/code-error-fragment-0.0.230.tgz#d736d75c832445342eca1d1fedbf17d9618b14d7"
@@ -884,18 +870,6 @@ concat-stream@1.6.2, concat-stream@^1.6.2:
readable-stream "^2.2.2"
typedarray "^0.0.6"
configstore@^3.0.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
dependencies:
dot-prop "^4.1.0"
graceful-fs "^4.1.2"
make-dir "^1.0.0"
unique-string "^1.0.0"
write-file-atomic "^2.0.0"
xdg-basedir "^3.0.0"
configstore@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7"
@@ -951,13 +925,6 @@ crc@^3.4.4:
dependencies:
buffer "^5.1.0"
create-error-class@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
dependencies:
capture-stack-trace "^1.0.0"
cross-spawn@^4, cross-spawn@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41"
@@ -1272,6 +1239,13 @@ decode-uri-component@^0.2.0:
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
decompress-response@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
dependencies:
mimic-response "^1.0.0"
deep-eql@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
@@ -1301,6 +1275,11 @@ default-require-extensions@^2.0.0:
dependencies:
strip-bom "^3.0.0"
defer-to-connect@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.0.2.tgz#4bae758a314b034ae33902b5aac25a8dd6a8633e"
integrity sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==
define-properties@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -1328,15 +1307,15 @@ diff@^4.0.1:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff"
integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==
dmg-builder@6.6.2:
version "6.6.2"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-6.6.2.tgz#6a25b372ae61820a7f50cae0638950e58910c375"
integrity sha512-o7qD7UknmKW9w0FcRZ+KWBPtFS59LAdwphrA0Q9eMdKBiOY9qZyt34fZizsuJbR+9sX1cVNwH/zFSwsGNet9fQ==
dmg-builder@6.6.5:
version "6.6.5"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-6.6.5.tgz#0907e573bc4587a1f323dc886d3dc2ab0e272293"
integrity sha512-W9OTcBwKG+EoaQ+W8pbyImogcSISPiRoHS5ZTABaTlok2BP5Kc6ZCeCxVa8gDJcLVaZozpAyTz+QaSrPD3Pmxw==
dependencies:
app-builder-lib "~20.41.0"
bluebird-lst "^1.0.7"
builder-util "~10.0.0"
fs-extra-p "^7.0.1"
app-builder-lib "~20.44.0"
bluebird-lst "^1.0.9"
builder-util "~10.0.3"
fs-extra-p "^8.0.2"
iconv-lite "^0.4.24"
js-yaml "^3.13.1"
parse-color "^1.0.0"
@@ -1412,24 +1391,24 @@ ejs@~2.5.6:
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5"
integrity sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ==
electron-builder@^20.38.5:
version "20.41.0"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-20.41.0.tgz#560b214e6496b0086a605e3d479733bf71333a66"
integrity sha512-NgVD3UKyr9AjKumYeLfdLDmefhXj+XwAXan1CvgfjjiR6IZdh8oPPfpNJvpX3CWJi/aEUfZn0B7PcIzzsZT8FQ==
electron-builder@20.44.1:
version "20.44.1"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-20.44.1.tgz#938e590762339b6ecc561a430b8633463ba740a2"
integrity sha512-xA/kj75B9jFm245q+KiYqumg0fpA1LHNTnEUcXDLShwPgJ8JEjlBmPwdjsydxWuoUvxG4Hj3kCnYhYMg4RDtzg==
dependencies:
app-builder-lib "20.41.0"
bluebird-lst "^1.0.7"
builder-util "10.0.0"
builder-util-runtime "8.2.2"
app-builder-lib "20.44.1"
bluebird-lst "^1.0.9"
builder-util "10.0.4"
builder-util-runtime "8.2.5"
chalk "^2.4.2"
dmg-builder "6.6.2"
fs-extra-p "^7.0.1"
dmg-builder "6.6.5"
fs-extra-p "^8.0.2"
is-ci "^2.0.0"
lazy-val "^1.0.4"
read-config-file "3.2.2"
sanitize-filename "^1.6.1"
update-notifier "^2.5.0"
yargs "^13.2.2"
update-notifier "^3.0.0"
yargs "^13.2.4"
electron-chromedriver@~3.0.0:
version "3.0.0"
@@ -1471,18 +1450,18 @@ electron-osx-sign@0.4.11:
minimist "^1.2.0"
plist "^3.0.1"
electron-publish@20.41.0:
version "20.41.0"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-20.41.0.tgz#825828689f6b449f62f24461f61e7bb3a581debc"
integrity sha512-JaNL2zNIcZfwlwyK5sc4FSPslldFvodHi9WaCtV41+L6hvvi7QE6CqFSW/OUY6Fp+BRNu83D/P2t47TOFTDLoA==
electron-publish@20.44.0:
version "20.44.0"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-20.44.0.tgz#4f4c49fabfa085244ebbd9a8d58ec4110a90ec2f"
integrity sha512-lQmNscoql2Wbvon4om7ZiBMJ5NfvoD9W91oKWl1EKaN1PeXWNjgt6+dEso3Rf/0x78WCC/V7eZ1hrARtL8cYNQ==
dependencies:
bluebird-lst "^1.0.7"
builder-util "~10.0.0"
builder-util-runtime "^8.2.2"
bluebird-lst "^1.0.9"
builder-util "~10.0.3"
builder-util-runtime "^8.2.5"
chalk "^2.4.2"
fs-extra-p "^7.0.1"
fs-extra-p "^8.0.2"
lazy-val "^1.0.4"
mime "^2.4.2"
mime "^2.4.4"
"electron-telemetry@git+https://github.com/thomasnordquist/electron-telemetry.git#dist":
version "1.0.0"
@@ -1507,7 +1486,7 @@ electron-updater@^4.0.6:
semver "^5.6.0"
source-map-support "^0.5.9"
electron@5:
electron@5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/electron/-/electron-5.0.4.tgz#2e0d09055363e983f4a73317cde4821c39617b02"
integrity sha512-7QaKorvANvP+azMT7wElx33oLlqw8QxmLs7/outfH7LC5amErk4EUtWDesQ6Zgr+s5pYFbykl8ZtJ4ZGXER05g==
@@ -1837,14 +1816,6 @@ fs-extra-p@^7.0.0, fs-extra-p@^7.0.1:
bluebird-lst "^1.0.7"
fs-extra "^7.0.1"
fs-extra-p@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/fs-extra-p/-/fs-extra-p-8.0.0.tgz#ae1bdee9c6a97c5b552c29f9e2188021bf10c651"
integrity sha512-gP+HIe9Hyc+NuDcDm+wn4+s+0+WUPFFK89Uf9HogsRZeHwwKkyXUJi8FDdxf4bpr2+4/01kB3JUr2O54FS9UlQ==
dependencies:
bluebird-lst "^1.0.8"
fs-extra "^8.0.0"
fs-extra-p@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/fs-extra-p/-/fs-extra-p-8.0.2.tgz#3b8e03ad963358570b70a152b2ee8d1c9eed5bf4"
@@ -1871,7 +1842,7 @@ fs-extra@^7.0.1:
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^8.0.0, fs-extra@^8.0.1:
fs-extra@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.0.1.tgz#90294081f978b1f182f347a440a209154344285b"
integrity sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==
@@ -1932,13 +1903,20 @@ get-stream@^3.0.0:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
get-stream@^4.0.0:
get-stream@^4.0.0, get-stream@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
get-stream@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
dependencies:
pump "^3.0.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
@@ -2015,22 +1993,22 @@ globule@^1.0.0:
lodash "~4.17.10"
minimatch "~3.0.2"
got@^6.7.1:
version "6.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
dependencies:
create-error-class "^3.0.0"
"@sindresorhus/is" "^0.14.0"
"@szmarczak/http-timer" "^1.1.2"
cacheable-request "^6.0.0"
decompress-response "^3.3.0"
duplexer3 "^0.1.4"
get-stream "^3.0.0"
is-redirect "^1.0.0"
is-retry-allowed "^1.0.0"
is-stream "^1.0.0"
lowercase-keys "^1.0.0"
safe-buffer "^5.0.1"
timed-out "^4.0.0"
unzip-response "^2.0.1"
url-parse-lax "^1.0.0"
get-stream "^4.1.0"
lowercase-keys "^1.0.1"
mimic-response "^1.0.1"
p-cancelable "^1.0.0"
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6:
version "4.1.15"
@@ -2093,6 +2071,11 @@ has-symbols@^1.0.0:
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
has-yarn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
has@^1.0.1, has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@@ -2127,6 +2110,11 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.7.1:
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
http-cache-semantics@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5"
integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@@ -2241,13 +2229,6 @@ is-callable@^1.1.4:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
is-ci@^1.0.10:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
dependencies:
ci-info "^1.5.0"
is-ci@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
@@ -2304,10 +2285,10 @@ is-negated-glob@^1.0.0:
resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"
integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=
is-npm@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
is-npm@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-3.0.0.tgz#ec9147bfb629c43f494cf67936a961edec7e8053"
integrity sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==
is-number@^7.0.0:
version "7.0.0"
@@ -2331,11 +2312,6 @@ is-promise@^2.1.0:
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
is-redirect@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
is-regex@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
@@ -2350,12 +2326,7 @@ is-relative@^1.0.0:
dependencies:
is-unc-path "^1.0.0"
is-retry-allowed@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=
is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
@@ -2389,6 +2360,11 @@ is-windows@^1.0.1:
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
is-yarn-global@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
@@ -2406,10 +2382,10 @@ isbinaryfile@^3.0.2:
dependencies:
buffer-alloc "^1.2.0"
isbinaryfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.0.tgz#07d1061c21598b41292b0f5c68add5eab601ad8e"
integrity sha512-RBtmso6l2mCaEsUvXngMTIjg3oheXo0MgYzzfT6sk44RYggPnm9fT+cQJAmzRnJIxPHXg9FZglqDJGW28dvcqA==
isbinaryfile@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.1.tgz#85dadd12ba236c9225fdf4648d6069956eaba640"
integrity sha512-bvJxbNWm72dy/1+qeBm9F8wUM4siDnlzid7NN5Ib4nQcc0tNIx/YWgEih1ZRHXr8xVbpGk1ccLlA9gOSlyx3gw==
isexe@^2.0.0:
version "2.0.0"
@@ -2511,6 +2487,11 @@ jsesc@^2.5.1:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@@ -2580,12 +2561,19 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
latest-version@^3.0.0:
keyv@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
dependencies:
package-json "^4.0.0"
json-buffer "3.0.0"
latest-version@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
dependencies:
package-json "^6.3.0"
lazy-val@^1.0.3, lazy-val@^1.0.4:
version "1.0.4"
@@ -2701,11 +2689,16 @@ lowdb@^1.0.0:
pify "^3.0.0"
steno "^0.4.1"
lowercase-keys@^1.0.0:
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru-cache@^4.0.1:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@@ -2803,11 +2796,16 @@ mime-types@^2.1.12, mime-types@~2.1.19:
dependencies:
mime-db "1.40.0"
mime@^2.4.0, mime@^2.4.2:
mime@^2.4.0:
version "2.4.3"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
mime@^2.4.4:
version "2.4.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
@@ -2818,6 +2816,11 @@ mimic-fn@^2.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^1.0.0, mimic-response@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -2977,6 +2980,11 @@ normalize-path@^2.0.0:
dependencies:
remove-trailing-separator "^1.0.1"
normalize-url@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.3.0.tgz#9c49e10fc1876aeb76dba88bf1b2b5d9fa57b2ee"
integrity sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==
npm-install-package@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125"
@@ -3124,6 +3132,11 @@ os-tmpdir@~1.0.2:
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
p-cancelable@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
@@ -3168,15 +3181,15 @@ package-hash@^3.0.0:
lodash.flattendeep "^4.4.0"
release-zalgo "^1.0.0"
package-json@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
package-json@^6.3.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.4.0.tgz#4f626976604f4a9a41723ce1792b204a60b1b61e"
integrity sha512-bd1T8OBG7hcvMd9c/udgv6u5v9wISP3Oyl9Cm7Weop8EFwrtcQDnS2sb6zhwqus2WslSr5wSTIPiTTpxxmPm7Q==
dependencies:
got "^6.7.1"
registry-auth-token "^3.0.1"
registry-url "^3.0.3"
semver "^5.1.0"
got "^9.6.0"
registry-auth-token "^3.4.0"
registry-url "^5.0.0"
semver "^6.1.1"
pako@^1.0.7, pako@^1.0.8:
version "1.0.10"
@@ -3328,10 +3341,10 @@ plist@^3.0.1:
xmlbuilder "^9.0.7"
xmldom "0.1.x"
prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
prettier@1.18.2:
version "1.18.2"
@@ -3431,7 +3444,7 @@ querystring@0.2.0:
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
rc@^1.0.1, rc@^1.1.6, rc@^1.2.1:
rc@^1.1.6, rc@^1.2.1, rc@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
@@ -3545,7 +3558,7 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
registry-auth-token@^3.0.1:
registry-auth-token@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
@@ -3553,12 +3566,12 @@ registry-auth-token@^3.0.1:
rc "^1.1.6"
safe-buffer "^5.0.1"
registry-url@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
registry-url@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
dependencies:
rc "^1.0.1"
rc "^1.2.8"
reinterval@^1.1.0:
version "1.1.0"
@@ -3642,6 +3655,13 @@ resolve@^1.10.0, resolve@^1.3.2:
dependencies:
path-parse "^1.0.6"
responselike@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
dependencies:
lowercase-keys "^1.0.0"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@@ -3710,7 +3730,7 @@ semver-diff@^2.0.0:
dependencies:
semver "^5.0.3"
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0:
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0:
version "5.7.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
@@ -3720,6 +3740,11 @@ semver@^6.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.0.tgz#e95dc415d45ecf03f2f9f83b264a6b11f49c0cca"
integrity sha512-kCqEOOHoBcFs/2Ccuk4Xarm/KiWRSLEX9CAZF8xkJ6ZPlIoTZ8V5f7J16vYLJqDbR7KrxTJpR2lqjIEm2Qx9cQ==
semver@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.1.tgz#53f53da9b30b2103cd4f15eab3a18ecbcb210c9b"
integrity sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==
serialize-error@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-3.0.0.tgz#80100282b09be33c611536f50033481cb9cc87cf"
@@ -4082,14 +4107,14 @@ tar-stream@^1.5.0:
to-buffer "^1.1.1"
xtend "^4.0.0"
temp-file@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.3.2.tgz#69b6daf1bbe23231d0a5d03844e3d96f3f531aaa"
integrity sha512-FGKccAW0Mux9hC/2bdUIe4bJRv4OyVo4RpVcuplFird1V/YoplIFbnPZjfzbJSf/qNvRZIRB9/4n/RkI0GziuQ==
temp-file@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.3.3.tgz#f843a8b265bb8010d06dc3550320ccc8f3733881"
integrity sha512-ErWJ0vfZwkozaH7dn/5QtYdrGwy6fWID0GG3PEzNb9Vmt6urL4mQ3lKz7NWVi1/kmZsWQzgjTL7/P4mwGx5jqg==
dependencies:
async-exit-hook "^2.0.1"
bluebird-lst "^1.0.6"
fs-extra-p "^7.0.0"
bluebird-lst "^1.0.9"
fs-extra-p "^8.0.2"
term-size@^1.2.0:
version "1.2.0"
@@ -4142,11 +4167,6 @@ through@2, through@^2.3.6, through@~2.3, through@~2.3.1:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
timed-out@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -4172,6 +4192,11 @@ to-fast-properties@^2.0.0:
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
to-readable-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
@@ -4340,6 +4365,11 @@ type-detect@^4.0.0, type-detect@^4.0.5:
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
type-fest@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
@@ -4388,24 +4418,21 @@ universalify@^0.1.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
unzip-response@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
update-notifier@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
update-notifier@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-3.0.0.tgz#e9bbf8f0f5b7a2ce6666ca46334fdb29492e8fab"
integrity sha512-6Xe3oF2bvuoj4YECUc52yxVs94yWrxwqHbzyveDktTS1WhnlTRpNcQMxUshcB7nRVGi1jEXiqL5cW1S5WSyzKg==
dependencies:
boxen "^1.2.1"
boxen "^3.0.0"
chalk "^2.0.1"
configstore "^3.0.0"
configstore "^4.0.0"
has-yarn "^2.1.0"
import-lazy "^2.1.0"
is-ci "^1.0.10"
is-ci "^2.0.0"
is-installed-globally "^0.1.0"
is-npm "^1.0.0"
latest-version "^3.0.0"
is-npm "^3.0.0"
is-yarn-global "^0.3.0"
latest-version "^5.0.0"
semver-diff "^2.0.0"
xdg-basedir "^3.0.0"
@@ -4421,12 +4448,12 @@ urix@^0.1.0:
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
url-parse-lax@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
url-parse-lax@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
dependencies:
prepend-http "^1.0.1"
prepend-http "^2.0.0"
url@~0.11.0:
version "0.11.0"
@@ -4726,7 +4753,7 @@ yargs@^12.0.5:
y18n "^3.2.1 || ^4.0.0"
yargs-parser "^11.1.1"
yargs@^13.2.2:
yargs@^13.2.2, yargs@^13.2.4:
version "13.2.4"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83"
integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==