Merge branch 'master' into HEAD
This commit is contained in:
318
app/index.html
318
app/index.html
@@ -1,181 +1,197 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" />
|
|
||||||
<title>MQTT Explorer</title>
|
|
||||||
<script src="./bugtracking.bundle.js"></script>
|
|
||||||
|
|
||||||
<style>
|
<head>
|
||||||
body,
|
<meta charset="UTF-8" />
|
||||||
html {
|
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" />
|
||||||
margin: 0;
|
<title>MQTT Explorer</title>
|
||||||
padding: 0;
|
<script src="./bugtracking.bundle.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body,
|
||||||
|
html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tabindex] {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes updateDark {
|
||||||
|
0% {
|
||||||
|
background-color: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
[tabindex] {
|
25% {
|
||||||
outline: none;
|
background-color: #595585;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes updateDark {
|
50% {
|
||||||
0% {
|
background-color: #595585;
|
||||||
background-color: none;
|
|
||||||
}
|
|
||||||
25% {
|
|
||||||
background-color: #595585;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: #595585;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-color: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes updateLight {
|
100% {
|
||||||
0% {
|
background-color: none;
|
||||||
background-color: none;
|
}
|
||||||
color: inherit;
|
}
|
||||||
}
|
|
||||||
25% {
|
@keyframes updateLight {
|
||||||
background-color: #c0c8c0;
|
0% {
|
||||||
}
|
background-color: none;
|
||||||
50% {
|
color: inherit;
|
||||||
background-color: #c0c8c0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-color: none;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
25% {
|
||||||
width: 8px;
|
background-color: #c0c8c0;
|
||||||
height: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-corner {
|
50% {
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: #c0c8c0;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
100% {
|
||||||
-webkit-box-shadow: inset 0 0 6px rgba(60, 60, 60, 0.5);
|
background-color: none;
|
||||||
background-color: rgba(140, 140, 140, 0.1);
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar {
|
||||||
background-color: rgba(140, 140, 140, 0.8);
|
width: 8px;
|
||||||
}
|
height: 8px;
|
||||||
</style>
|
}
|
||||||
<style>
|
|
||||||
.Resizer {
|
|
||||||
background: rgba(200, 200, 200, 0);
|
|
||||||
z-index: 10;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-moz-background-clip: padding;
|
|
||||||
-webkit-background-clip: padding;
|
|
||||||
background-clip: padding-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Resizer:hover {
|
::-webkit-scrollbar-corner {
|
||||||
-webkit-transition: all 0.3s ease-out;
|
background-color: rgba(0, 0, 0, 0);
|
||||||
transition: all 0.3s ease-out;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.Resizer.horizontal {
|
::-webkit-scrollbar-track {
|
||||||
height: 10px;
|
-webkit-box-shadow: inset 0 0 6px rgba(60, 60, 60, 0.5);
|
||||||
margin: -10px 0 0 0;
|
background-color: rgba(140, 140, 140, 0.1);
|
||||||
border-top: 5px solid rgba(255, 255, 255, 0);
|
}
|
||||||
border-bottom: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
cursor: row-resize;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Resizer.horizontal::before {
|
::-webkit-scrollbar-thumb {
|
||||||
content: '•••';
|
background-color: rgba(140, 140, 140, 0.8);
|
||||||
display: inline-block;
|
}
|
||||||
vertical-align: middle;
|
</style>
|
||||||
text-align: center;
|
<style>
|
||||||
width: 100%;
|
.Resizer {
|
||||||
margin-top: -22px;
|
background: rgba(200, 200, 200, 0);
|
||||||
color: #aaa;
|
z-index: 10;
|
||||||
opacity: 1;
|
-moz-box-sizing: border-box;
|
||||||
}
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-moz-background-clip: padding;
|
||||||
|
-webkit-background-clip: padding;
|
||||||
|
background-clip: padding-box;
|
||||||
|
}
|
||||||
|
|
||||||
.Resizer.horizontal:hover {
|
.Resizer:hover {
|
||||||
border-top: 5px solid rgba(120, 120, 120, 0.3);
|
-webkit-transition: all 0.3s ease-out;
|
||||||
border-bottom: 5px solid rgba(120, 120, 120, 0.3);
|
transition: all 0.3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Resizer.vertical {
|
.Resizer.horizontal {
|
||||||
width: 2px;
|
height: 10px;
|
||||||
margin: 0px -8px 0px 0px;
|
margin: -10px 0 0 0;
|
||||||
border-left: 0px solid rgba(128, 128, 128, 0);
|
border-top: 5px solid rgba(255, 255, 255, 0);
|
||||||
border-right: 8px solid rgba(128, 128, 128, 0);
|
border-bottom: 5px solid rgba(255, 255, 255, 0);
|
||||||
cursor: col-resize;
|
cursor: row-resize;
|
||||||
}
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.Resizer.vertical::before {
|
.Resizer.horizontal::before {
|
||||||
content: '•••';
|
content: '•••';
|
||||||
margin-left: -11px;
|
display: inline-block;
|
||||||
height: 3em;
|
vertical-align: middle;
|
||||||
margin-top: calc(50vh - 32px);
|
text-align: center;
|
||||||
display: inline-block;
|
width: 100%;
|
||||||
vertical-align: middle;
|
margin-top: -22px;
|
||||||
text-align: center;
|
color: #aaa;
|
||||||
color: #aaa;
|
opacity: 1;
|
||||||
opacity: 1;
|
}
|
||||||
writing-mode: vertical-lr;
|
|
||||||
text-orientation: sideways;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Resizer.vertical:hover {
|
.Resizer.horizontal:hover {
|
||||||
border-left: 0px solid rgba(130, 130, 130, 0.3);
|
border-top: 5px solid rgba(120, 120, 120, 0.3);
|
||||||
border-right: 8px solid rgba(140, 140, 140, 0.3);
|
border-bottom: 5px solid rgba(120, 120, 120, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.Resizer.disabled {
|
.Resizer.vertical {
|
||||||
cursor: not-allowed;
|
width: 2px;
|
||||||
}
|
margin: 0px -8px 0px 0px;
|
||||||
.Resizer.disabled:hover {
|
border-left: 0px solid rgba(128, 128, 128, 0);
|
||||||
border-color: transparent;
|
border-right: 8px solid rgba(128, 128, 128, 0);
|
||||||
}
|
cursor: col-resize;
|
||||||
|
}
|
||||||
|
|
||||||
.example-enter {
|
.Resizer.vertical::before {
|
||||||
opacity: 0;
|
content: '•••';
|
||||||
}
|
margin-left: -11px;
|
||||||
.example-enter-active {
|
height: 3em;
|
||||||
opacity: 1;
|
margin-top: calc(50vh - 32px);
|
||||||
transition: opacity 300ms ease-in;
|
display: inline-block;
|
||||||
}
|
vertical-align: middle;
|
||||||
.example-exit {
|
text-align: center;
|
||||||
opacity: 1;
|
color: #aaa;
|
||||||
}
|
opacity: 1;
|
||||||
.example-exit-active {
|
writing-mode: vertical-lr;
|
||||||
opacity: 0;
|
text-orientation: sideways;
|
||||||
transition: opacity 300ms ease-in;
|
}
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app" style="font: -webkit-control;"></div>
|
|
||||||
<script>
|
|
||||||
function loadScript(path) {
|
|
||||||
var script = document.createElement('script')
|
|
||||||
script.src = path
|
|
||||||
document.head.appendChild(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', onLoad(), false)
|
.Resizer.vertical:hover {
|
||||||
function onLoad() {
|
border-left: 0px solid rgba(130, 130, 130, 0.3);
|
||||||
// <% _.forEach(htmlWebpackPlugin.files.js, function(file) { %>loadScript("<%- file %>");<% }); %>
|
border-right: 8px solid rgba(140, 140, 140, 0.3);
|
||||||
// loadScript("<%= JSON.stringify(htmlWebpackPlugin) %>")
|
}
|
||||||
}
|
|
||||||
</script>
|
.Resizer.disabled {
|
||||||
<% _.forEach(htmlWebpackPlugin.files.js, function(file) { %>
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Resizer.disabled:hover {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-enter {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-enter-active {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 300ms ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-exit {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-exit-active {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 300ms ease-in;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
global = globalThis //<- this should be enough
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app" style="font: -webkit-control;"></div>
|
||||||
|
<script>
|
||||||
|
function loadScript(path) {
|
||||||
|
var script = document.createElement('script')
|
||||||
|
script.src = path
|
||||||
|
document.head.appendChild(script)
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', onLoad(), false)
|
||||||
|
function onLoad() {
|
||||||
|
// <% _.forEach(htmlWebpackPlugin.files.js, function(file) { %>loadScript("<%- file %>");<% }); %>
|
||||||
|
// loadScript("<%= JSON.stringify(htmlWebpackPlugin) %>")
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<% _.forEach(htmlWebpackPlugin.files.js, function(file) { %>
|
||||||
<script src="<%- file %>"></script>
|
<script src="<%- file %>"></script>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -4,29 +4,30 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn rebuild && webpack --mode production",
|
"build": "webpack --mode production",
|
||||||
"dev": "node_modules/.bin/webpack-dev-server --mode development --progress",
|
"dev": "node_modules/.bin/webpack-dev-server --mode development --progress",
|
||||||
"rebuild": "cd node_modules/heapdump && node-gyp rebuild --target=7.1.1 --arch=x64 --dist-url=https://atom.io/download/electron || echo Could not build heapdump; cd -",
|
|
||||||
"test": "cross-env TS_NODE_PROJECT=test/tsconfig.json yarn mochatest",
|
"test": "cross-env TS_NODE_PROJECT=test/tsconfig.json yarn mochatest",
|
||||||
"mochatest": "mocha --require ts-node/register src/**/*.spec.ts"
|
"mochatest": "mocha --require ts-node/register src/**/*.spec.ts"
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "16"
|
||||||
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "CC-BY-ND-4.0",
|
"license": "CC-BY-ND-4.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4",
|
"@material-ui/core": "4.12",
|
||||||
"@material-ui/icons": "^4",
|
"@material-ui/icons": "^4",
|
||||||
"@material-ui/lab": "^4.0.0-alpha",
|
"@material-ui/lab": "^4.0.0-alpha",
|
||||||
"@material-ui/styles": "^4",
|
"@material-ui/styles": "4.11",
|
||||||
"@types/react-transition-group": "^4",
|
"@types/react-transition-group": "^4",
|
||||||
"ace-builds": "^1.4.11",
|
"ace-builds": "^1.4.11",
|
||||||
"axios": "^0.19.0",
|
"axios": "^0.26.0",
|
||||||
"compare-versions": "^3.5.0",
|
"compare-versions": "^3.5.0",
|
||||||
"copy-text-to-clipboard": "^2.1.0",
|
"copy-text-to-clipboard": "^2.1.0",
|
||||||
"d3": "^5.9.7",
|
"d3": "^5.9.7",
|
||||||
"d3-shape": "^1.3.5",
|
"d3-shape": "^1.3.5",
|
||||||
"diff": "^4.0.1",
|
"diff": "^4.0.1",
|
||||||
"dot-prop": "^5.0.0",
|
"dot-prop": "^5.0.0",
|
||||||
"electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git#dist",
|
|
||||||
"file-loader": "6",
|
"file-loader": "6",
|
||||||
"get-value": "^3.0.1",
|
"get-value": "^3.0.1",
|
||||||
"immutable": "^4.0.0-rc.12",
|
"immutable": "^4.0.0-rc.12",
|
||||||
@@ -35,7 +36,6 @@
|
|||||||
"json-to-ast": "^2.1.0",
|
"json-to-ast": "^2.1.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"moment": "^2.24.0",
|
|
||||||
"moving-average": "^1.0.0",
|
"moving-average": "^1.0.0",
|
||||||
"number-abbreviate": "^2.0.0",
|
"number-abbreviate": "^2.0.0",
|
||||||
"parse-duration": "^0.1.1",
|
"parse-duration": "^0.1.1",
|
||||||
@@ -56,6 +56,7 @@
|
|||||||
"uuid": "7"
|
"uuid": "7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/runtime": "^7.17.2",
|
||||||
"@types/d3": "^5.7.2",
|
"@types/d3": "^5.7.2",
|
||||||
"@types/diff": "^4.0.1",
|
"@types/diff": "^4.0.1",
|
||||||
"@types/get-value": "^3.0.1",
|
"@types/get-value": "^3.0.1",
|
||||||
@@ -69,24 +70,24 @@
|
|||||||
"@types/socket.io-client": "^1.4.32",
|
"@types/socket.io-client": "^1.4.32",
|
||||||
"@types/uuid": "^7.0.2",
|
"@types/uuid": "^7.0.2",
|
||||||
"@types/vis": "^4.21.9",
|
"@types/vis": "^4.21.9",
|
||||||
"awesome-typescript-loader": "^5.2.1",
|
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"css-loader": "^3.0.0",
|
"css-loader": "^3.0.0",
|
||||||
"hard-source-webpack-plugin": "^0.13.1",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"heapdump": "^0.3.12",
|
"lodash": "^4.17.21",
|
||||||
"html-webpack-plugin": "^4.0.0-beta.5",
|
"mocha": "^9.2.1",
|
||||||
"mocha": "^7.1.1",
|
"moment": "^2.29.1",
|
||||||
"node-loader": "^0.6.0",
|
"node-loader": "^0.6.0",
|
||||||
"source-map-loader": "^0.2.4",
|
"source-map-loader": "^0.2.4",
|
||||||
"style-loader": "^1",
|
"style-loader": "^1",
|
||||||
"typescript": "^3.6.3",
|
"ts-loader": "^9.2.6",
|
||||||
"webpack": "^4.28.2",
|
"typescript": "^4.5.5",
|
||||||
"webpack-bundle-analyzer": "^3.0.3",
|
"webpack": "^5.69.1",
|
||||||
"webpack-cli": "^3.3.6",
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
"webpack-dev-server": "^3.1.14"
|
"webpack-cli": "^4.9.2",
|
||||||
|
"webpack-dev-server": "^4.7.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"electron": "^5.0.5"
|
"electron": "^17"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,13 @@ import {
|
|||||||
import { default as persistentStorage, StorageIdentifier } from '../utils/PersistentStorage'
|
import { default as persistentStorage, StorageIdentifier } from '../utils/PersistentStorage'
|
||||||
import { Dispatch } from 'redux'
|
import { Dispatch } from 'redux'
|
||||||
import { showError } from './Global'
|
import { showError } from './Global'
|
||||||
import { remote } from 'electron'
|
|
||||||
import { promises as fsPromise } from 'fs'
|
import { promises as fsPromise } from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { ActionTypes, Action } from '../reducers/ConnectionManager'
|
import { ActionTypes, Action } from '../reducers/ConnectionManager'
|
||||||
import { Subscription } from '../../../backend/src/DataSource/MqttSource'
|
import { Subscription } from '../../../backend/src/DataSource/MqttSource'
|
||||||
import { connectionsMigrator } from './migrations/Connection'
|
import { connectionsMigrator } from './migrations/Connection'
|
||||||
|
import { rendererRpc } from '../../../events'
|
||||||
|
import { makeOpenDialogRpc } from '../../../events/OpenDialogRequest'
|
||||||
|
|
||||||
export interface ConnectionDictionary {
|
export interface ConnectionDictionary {
|
||||||
[s: string]: ConnectionOptions
|
[s: string]: ConnectionOptions
|
||||||
@@ -72,7 +73,7 @@ async function openCertificate(): Promise<CertificateParameters> {
|
|||||||
certificateSizeDoesNotMatch: 'Certificate size larger/smaller then expected.',
|
certificateSizeDoesNotMatch: 'Certificate size larger/smaller then expected.',
|
||||||
}
|
}
|
||||||
|
|
||||||
const openDialogReturnValue = await remote.dialog.showOpenDialog(remote.getCurrentWindow(), {
|
const openDialogReturnValue = await rendererRpc.call(makeOpenDialogRpc(), {
|
||||||
properties: ['openFile'],
|
properties: ['openFile'],
|
||||||
securityScopedBookmarks: true,
|
securityScopedBookmarks: true,
|
||||||
})
|
})
|
||||||
@@ -83,7 +84,7 @@ async function openCertificate(): Promise<CertificateParameters> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await fsPromise.readFile(selectedFile)
|
const data = await fsPromise.readFile(selectedFile)
|
||||||
if (data.length > 16_384 || data.length < 128) {
|
if (data.length > 16_384 || data.length < 64) {
|
||||||
throw rejectReasons.certificateSizeDoesNotMatch
|
throw rejectReasons.certificateSizeDoesNotMatch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ActionTypes, ConfirmationRequest } from '../reducers/Global'
|
import { ActionTypes, ConfirmationRequest } from '../reducers/Global'
|
||||||
import { Dispatch } from 'redux'
|
import { Dispatch } from 'redux'
|
||||||
|
|
||||||
export const showError = (error?: string) => ({
|
export const showError = (error?: string | unknown) => ({
|
||||||
error,
|
error,
|
||||||
type: ActionTypes.showError,
|
type: ActionTypes.showError,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import { connect } from 'react-redux'
|
|||||||
import { globalActions, settingsActions } from '../actions'
|
import { globalActions, settingsActions } from '../actions'
|
||||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||||
|
|
||||||
|
(window as any).global = window
|
||||||
|
|
||||||
const Settings = React.lazy(() => import('./SettingsDrawer/Settings'))
|
const Settings = React.lazy(() => import('./SettingsDrawer/Settings'))
|
||||||
const ContentView = React.lazy(() => import('./Layout/ContentView'))
|
const ContentView = React.lazy(() => import('./Layout/ContentView'))
|
||||||
|
|
||||||
@@ -66,6 +68,8 @@ class App extends React.PureComponent<Props, {}> {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const anyProps: any = {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={centerContent}>
|
<div className={centerContent}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
@@ -73,7 +77,7 @@ class App extends React.PureComponent<Props, {}> {
|
|||||||
<ConfirmationDialog confirmationRequests={this.props.confirmationRequests} />
|
<ConfirmationDialog confirmationRequests={this.props.confirmationRequests} />
|
||||||
{this.renderNotification()}
|
{this.renderNotification()}
|
||||||
<React.Suspense fallback={<div></div>}>
|
<React.Suspense fallback={<div></div>}>
|
||||||
<Settings />
|
<Settings {...anyProps} />
|
||||||
</React.Suspense>
|
</React.Suspense>
|
||||||
<div className={centerContent}>
|
<div className={centerContent}>
|
||||||
<div className={`${settingsVisible ? contentShift : content}`}>
|
<div className={`${settingsVisible ? contentShift : content}`}>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import Add from '@material-ui/icons/Add'
|
|
||||||
import ClearAdornment from '../helper/ClearAdornment'
|
import ClearAdornment from '../helper/ClearAdornment'
|
||||||
import Delete from '@material-ui/icons/Delete'
|
|
||||||
import Lock from '@material-ui/icons/Lock'
|
import Lock from '@material-ui/icons/Lock'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { Button, Theme, Tooltip, Typography } from '@material-ui/core'
|
import { Button, Theme, Tooltip, Typography } from '@material-ui/core'
|
||||||
|
|||||||
@@ -43,15 +43,15 @@ class Demo extends React.Component<{ classes: any }, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
;(window as any).demo.enableMouse = () => {
|
; (window as any).demo.enableMouse = () => {
|
||||||
this.setState({ enabled: true })
|
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 stepSizeX = Math.abs(this.state.position.x - x) / (animationTime / this.frameInterval)
|
||||||
const stepSizeY = Math.abs(this.state.position.y - y) / (animationTime / this.frameInterval)
|
const stepSizeY = Math.abs(this.state.position.y - y) / (animationTime / this.frameInterval)
|
||||||
this.setState({ stepSizeX, stepSizeY, enabled: true, target: { x, y } })
|
this.setState({ stepSizeX, stepSizeY, enabled: true, target: { x, y } })
|
||||||
this.moveCloser()
|
this.moveCloser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ let heapdump: any
|
|||||||
|
|
||||||
function writeHeapdump(path?: string) {
|
function writeHeapdump(path?: string) {
|
||||||
if (!heapdump) {
|
if (!heapdump) {
|
||||||
heapdump = require('heapdump')
|
//<heapdump = require('heapdump')
|
||||||
}
|
}
|
||||||
|
|
||||||
heapdump.writeSnapshot(path || `${Date.now()}.heapsnapshot`)
|
heapdump.writeSnapshot(path || `${Date.now()}.heapsnapshot`)
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
;(window as any).demo = {
|
; (window as any).demo = {
|
||||||
writeHeapdump,
|
writeHeapdump,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import * as React from 'react'
|
|||||||
import PersistentStorage from '../utils/PersistentStorage'
|
import PersistentStorage from '../utils/PersistentStorage'
|
||||||
import SentimentDissatisfied from '@material-ui/icons/SentimentDissatisfied'
|
import SentimentDissatisfied from '@material-ui/icons/SentimentDissatisfied'
|
||||||
import Warning from '@material-ui/icons/Warning'
|
import Warning from '@material-ui/icons/Warning'
|
||||||
import { electronRendererTelemetry } from 'electron-telemetry'
|
|
||||||
import { Theme, withStyles } from '@material-ui/core/styles'
|
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'
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ class ErrorBoundary extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public componentDidCatch(error: Error, errorInfo: any) {
|
public componentDidCatch(error: Error, errorInfo: any) {
|
||||||
electronRendererTelemetry.trackError(error)
|
// electronRendererTelemetry.trackError(error)
|
||||||
console.log('did catch', error)
|
console.log('did catch', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,17 @@ import DateFormatter from '../helper/DateFormatter'
|
|||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { Input, InputLabel, MenuItem, Select, StyleRulesCallback, Theme } from '@material-ui/core'
|
import { Input, InputLabel, MenuItem, Select, Theme } from '@material-ui/core'
|
||||||
import { settingsActions } from '../../actions'
|
import { settingsActions } from '../../actions'
|
||||||
import { withStyles } from '@material-ui/styles'
|
import { withStyles } from '@material-ui/styles'
|
||||||
import * as moment from 'moment'
|
|
||||||
|
function importAll(r: any) {
|
||||||
|
r.keys().forEach(r);
|
||||||
|
}
|
||||||
|
// @ts-expect-error -- webpack require
|
||||||
|
importAll(require.context('moment/locale', true, /\.js$/));
|
||||||
|
|
||||||
|
const moment = require('moment')
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ const EditorMode = memo(function EditorMode(props: {
|
|||||||
const str = JSON.stringify(JSON.parse(props.payload), undefined, ' ')
|
const str = JSON.stringify(JSON.parse(props.payload), undefined, ' ')
|
||||||
updatePayload(str)
|
updatePayload(str)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
props.globalActions.showError(`Format error: ${error.message}`)
|
props.globalActions.showError(`Format error: ${(error as Error)?.message}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [props.payload])
|
}, [props.payload])
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { Theme, withStyles } from '@material-ui/core/styles'
|
|||||||
import { updateNotifierActions } from '../actions'
|
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'
|
||||||
|
import { rendererRpc, getAppVersion } from '../../../events'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
showUpdateNotification: boolean
|
showUpdateNotification: boolean
|
||||||
@@ -50,18 +51,21 @@ class UpdateNotifier extends React.PureComponent<Props, State> {
|
|||||||
super(props)
|
super(props)
|
||||||
this.state = { newerVersions: [] }
|
this.state = { newerVersions: [] }
|
||||||
|
|
||||||
const ownVersion = electron.remote.app.getVersion()
|
this.checkForUpdates()
|
||||||
this.fetchReleases().then(releases => {
|
}
|
||||||
const newerVersions = releases
|
|
||||||
.filter(release => this.allowPrereleaseIfOwnVersionIsBeta(release, ownVersion))
|
|
||||||
.filter(release => compareVersions(release.tag_name, ownVersion) > 0)
|
|
||||||
.sort((a, b) => compareVersions(b.tag_name, a.tag_name))
|
|
||||||
|
|
||||||
if (newerVersions.length > 0) {
|
private async checkForUpdates() {
|
||||||
this.setState({ newerVersions })
|
const ownVersion = await rendererRpc.call(getAppVersion, undefined, 10000);
|
||||||
this.props.actions.showUpdateNotification(true)
|
const releases = await this.fetchReleases();
|
||||||
}
|
const newerVersions = releases
|
||||||
})
|
.filter(release => this.allowPrereleaseIfOwnVersionIsBeta(release, ownVersion))
|
||||||
|
.filter(release => compareVersions(release.tag_name, ownVersion) > 0)
|
||||||
|
.sort((a, b) => compareVersions(b.tag_name, a.tag_name))
|
||||||
|
|
||||||
|
if (newerVersions.length > 0) {
|
||||||
|
this.setState({ newerVersions })
|
||||||
|
this.props.actions.showUpdateNotification(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private allowPrereleaseIfOwnVersionIsBeta(release: GithubRelease, ownVersion: string) {
|
private allowPrereleaseIfOwnVersionIsBeta(release: GithubRelease, ownVersion: string) {
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { rendererEvents } from '../../../events'
|
import { rendererRpc } from '../../../events'
|
||||||
import { v4 } from 'uuid'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
storageStoreEvent,
|
storageStoreEvent,
|
||||||
makeStorageResponseEvent,
|
|
||||||
storageLoadEvent,
|
storageLoadEvent,
|
||||||
storageClearEvent,
|
storageClearEvent,
|
||||||
makeStorageAcknowledgementEvent,
|
|
||||||
} from '../../../events/StorageEvents'
|
} from '../../../events/StorageEvents'
|
||||||
|
|
||||||
export interface StorageIdentifier<Model> {
|
export interface StorageIdentifier<Model> {
|
||||||
@@ -20,71 +17,23 @@ export interface PersistentStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class RemoteStorage implements PersistentStorage {
|
class RemoteStorage implements PersistentStorage {
|
||||||
private timeoutCallback(event: any, callback: any, reject: any) {
|
|
||||||
setTimeout(() => {
|
|
||||||
reject('remote storage timeout')
|
|
||||||
rendererEvents.unsubscribe(event, callback)
|
|
||||||
}, 10000)
|
|
||||||
}
|
|
||||||
|
|
||||||
private expectAck(transactionId: string): Promise<void> {
|
|
||||||
const ack = makeStorageAcknowledgementEvent(transactionId)
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
const callback = (msg: any) => {
|
|
||||||
if (msg && msg.error) {
|
|
||||||
reject(msg.error)
|
|
||||||
} else {
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
rendererEvents.unsubscribe(ack, callback)
|
|
||||||
}
|
|
||||||
rendererEvents.subscribe(ack, callback)
|
|
||||||
this.timeoutCallback(ack, callback, reject)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public store<Model>(identifier: StorageIdentifier<Model>, data: Model): Promise<void> {
|
public store<Model>(identifier: StorageIdentifier<Model>, data: Model): Promise<void> {
|
||||||
const transactionId = v4()
|
return rendererRpc.call(storageStoreEvent, {
|
||||||
const expectation = this.expectAck(transactionId)
|
|
||||||
rendererEvents.emit(storageStoreEvent, {
|
|
||||||
data,
|
data,
|
||||||
transactionId,
|
|
||||||
store: identifier.id,
|
store: identifier.id,
|
||||||
})
|
})
|
||||||
return expectation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public load<Model>(identifier: StorageIdentifier<Model>): Promise<Model | undefined> {
|
public async load<Model>(identifier: StorageIdentifier<Model>): Promise<Model | undefined> {
|
||||||
const transactionId = v4()
|
const result = await rendererRpc.call(storageLoadEvent, {
|
||||||
const responseEvent = makeStorageResponseEvent(transactionId)
|
|
||||||
|
|
||||||
const promise = new Promise<Model>((resolve, reject) => {
|
|
||||||
const callback = (msg: any) => {
|
|
||||||
if (msg.error) {
|
|
||||||
reject(msg.error)
|
|
||||||
} else {
|
|
||||||
resolve(msg.data)
|
|
||||||
}
|
|
||||||
rendererEvents.unsubscribe(responseEvent, callback)
|
|
||||||
}
|
|
||||||
rendererEvents.subscribe(responseEvent, callback)
|
|
||||||
this.timeoutCallback(responseEvent, callback, reject)
|
|
||||||
})
|
|
||||||
|
|
||||||
rendererEvents.emit(storageLoadEvent, {
|
|
||||||
transactionId,
|
|
||||||
store: identifier.id,
|
store: identifier.id,
|
||||||
})
|
}, 10000)
|
||||||
|
|
||||||
return promise
|
return (result as any).data
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear(): Promise<void> {
|
public clear(): Promise<void> {
|
||||||
const transactionId = v4()
|
return rendererRpc.call(storageClearEvent, undefined, 10000)
|
||||||
const expectation = this.expectAck(transactionId)
|
|
||||||
|
|
||||||
rendererEvents.emit(storageClearEvent, { transactionId })
|
|
||||||
return expectation
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { electronRendererTelemetry } from 'electron-telemetry'
|
// import { electronRendererTelemetry } from 'electron-telemetry'
|
||||||
|
|
||||||
const telemetry = electronRendererTelemetry
|
// const telemetry = electronRendererTelemetry
|
||||||
electronRendererTelemetry.registerErrorHandler()
|
// electronRendererTelemetry.registerErrorHandler()
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import { electronRendererTelemetry } from 'electron-telemetry'
|
// import { electronRendererTelemetry } from 'electron-telemetry'
|
||||||
|
|
||||||
// Used to determine long-time-stability and memory leaks
|
// Used to determine long-time-stability and memory leaks
|
||||||
function trackProcessStatistics() {
|
// function trackProcessStatistics() {
|
||||||
setInterval(() => {
|
// setInterval(() => {
|
||||||
try {
|
// try {
|
||||||
electronRendererTelemetry.trackCustomEvent({
|
// electronRendererTelemetry.trackCustomEvent({
|
||||||
name: 'heapStatistics',
|
// name: 'heapStatistics',
|
||||||
payload: process.getHeapStatistics(),
|
// payload: process.getHeapStatistics(),
|
||||||
})
|
// })
|
||||||
electronRendererTelemetry.trackCustomEvent({
|
// electronRendererTelemetry.trackCustomEvent({
|
||||||
name: 'cpuUsage',
|
// name: 'cpuUsage',
|
||||||
payload: process.getCPUUsage(),
|
// payload: process.getCPUUsage(),
|
||||||
})
|
// })
|
||||||
electronRendererTelemetry.trackCustomEvent({
|
// electronRendererTelemetry.trackCustomEvent({
|
||||||
name: 'runningSince',
|
// name: 'runningSince',
|
||||||
payload: performance.now(),
|
// payload: performance.now(),
|
||||||
})
|
// })
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error(error)
|
// console.error(error)
|
||||||
}
|
// }
|
||||||
}, 60 * 1000)
|
// }, 60 * 1000)
|
||||||
}
|
// }
|
||||||
trackProcessStatistics()
|
// trackProcessStatistics()
|
||||||
|
|
||||||
// Log reducer event names to determine what functionality is used and how to reproduce reported errors
|
// Log reducer event names to determine what functionality is used and how to reproduce reported errors
|
||||||
export function trackEvent(name: string) {
|
export function trackEvent(name: string) {
|
||||||
@@ -30,6 +30,6 @@ export function trackEvent(name: string) {
|
|||||||
}
|
}
|
||||||
const blacklist = ['CONNECTION_SET_HEALTH']
|
const blacklist = ['CONNECTION_SET_HEALTH']
|
||||||
if (blacklist.indexOf(name) === -1) {
|
if (blacklist.indexOf(name) === -1) {
|
||||||
electronRendererTelemetry.trackEvent(name)
|
// electronRendererTelemetry.trackEvent(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,30 @@
|
|||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"lib": ["es2017", "dom"],
|
"lib": [
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"outDir": "./build/",
|
"outDir": "./build/",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"types": ["react"],
|
"types": [
|
||||||
"allowSyntheticDefaultImports": true
|
"react"
|
||||||
|
],
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"include": ["./src/**/*"],
|
"include": [
|
||||||
"exclude": ["**/*.d.ts", ".src/**/*.png"],
|
"./src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/*.d.ts",
|
||||||
|
".src/**/*.png",
|
||||||
|
"./node_modules"
|
||||||
|
],
|
||||||
"awesomeTypescriptLoaderOptions": {
|
"awesomeTypescriptLoaderOptions": {
|
||||||
"useCache": true,
|
"useCache": true,
|
||||||
"transpileModule": true,
|
"transpileModule": true,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
@@ -18,12 +17,11 @@ module.exports = {
|
|||||||
splitChunks: {
|
splitChunks: {
|
||||||
chunks: 'all',
|
chunks: 'all',
|
||||||
minSize: 30000,
|
minSize: 30000,
|
||||||
maxSize: 0,
|
|
||||||
minChunks: 1,
|
minChunks: 1,
|
||||||
maxAsyncRequests: 5,
|
maxAsyncRequests: 5,
|
||||||
maxInitialRequests: 3,
|
maxInitialRequests: 3,
|
||||||
automaticNameDelimiter: '~',
|
automaticNameDelimiter: '~',
|
||||||
name: true,
|
// name: true,
|
||||||
cacheGroups: {
|
cacheGroups: {
|
||||||
vendors: {
|
vendors: {
|
||||||
test: /[\\/]node_modules[\\/](react|react-dom|@material-ui|popper\.js|react|react-redux|prop-types|jss|redux|scheduler|react-transition-group)[\\/]/,
|
test: /[\\/]node_modules[\\/](react|react-dom|@material-ui|popper\.js|react|react-redux|prop-types|jss|redux|scheduler|react-transition-group)[\\/]/,
|
||||||
@@ -32,6 +30,7 @@ module.exports = {
|
|||||||
priority: -10,
|
priority: -10,
|
||||||
},
|
},
|
||||||
default: {
|
default: {
|
||||||
|
name: 'default',
|
||||||
minChunks: 2,
|
minChunks: 2,
|
||||||
priority: -20,
|
priority: -20,
|
||||||
reuseExistingChunk: true,
|
reuseExistingChunk: true,
|
||||||
@@ -55,13 +54,7 @@ module.exports = {
|
|||||||
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
|
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
|
||||||
{
|
{
|
||||||
test: /\.tsx?$/,
|
test: /\.tsx?$/,
|
||||||
loader: 'awesome-typescript-loader',
|
loader: 'ts-loader',
|
||||||
options: {
|
|
||||||
reportFiles: [
|
|
||||||
"src/**/*.{ts,tsx}",
|
|
||||||
"../backend/src/**/*.{ts,tsx}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
|
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
|
||||||
{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' },
|
{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' },
|
||||||
@@ -78,15 +71,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
test: /\.node$/,
|
|
||||||
use: {
|
|
||||||
loader: 'node-loader',
|
|
||||||
options: {
|
|
||||||
modules: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
test: /\.proto$/,
|
test: /\.proto$/,
|
||||||
use: [
|
use: [
|
||||||
@@ -98,18 +82,26 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// test: /\.node$/,
|
||||||
|
// use: {
|
||||||
|
// loader: 'node-loader',
|
||||||
|
// options: {
|
||||||
|
// modules: true,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
// node: { global: true },
|
||||||
plugins: [
|
plugins: [
|
||||||
new HtmlWebpackPlugin({ template: './index.html', file: './build/index.html', inject: false }),
|
new HtmlWebpackPlugin({ template: './index.html', file: './build/index.html', inject: false }),
|
||||||
// new BundleAnalyzerPlugin(),
|
// new BundleAnalyzerPlugin(),
|
||||||
new HardSourceWebpackPlugin(),
|
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
new webpack.IgnorePlugin({
|
// new webpack.IgnorePlugin({
|
||||||
resourceRegExp: /\.\/build\/Debug\/addon/,
|
// resourceRegExp: /\.\/build\/Debug\/addon/,
|
||||||
contextRegExp: /heapdump$/
|
// contextRegExp: /heapdump$/
|
||||||
}),
|
// }),
|
||||||
],
|
],
|
||||||
|
|
||||||
// When importing a module whose path matches one of the following, just
|
// When importing a module whose path matches one of the following, just
|
||||||
|
|||||||
6508
app/yarn.lock
6508
app/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ cache:
|
|||||||
- '%LOCALAPPDATA%\electron-builder\cache'
|
- '%LOCALAPPDATA%\electron-builder\cache'
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- ps: Install-Product node 10
|
- ps: Install-Product node 16
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- yarn
|
- yarn
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
"debug": "ts-node --inspect ./src/index.ts",
|
"debug": "ts-node --inspect ./src/index.ts",
|
||||||
"postinstall": "yarn build"
|
"postinstall": "yarn build"
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "16"
|
||||||
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "CC-BY-ND-4.0",
|
"license": "CC-BY-ND-4.0",
|
||||||
"nyc": {
|
"nyc": {
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ import * as FileAsync from 'lowdb/adapters/FileAsync'
|
|||||||
import * as fs from 'fs-extra'
|
import * as fs from 'fs-extra'
|
||||||
import * as lowdb from 'lowdb'
|
import * as lowdb from 'lowdb'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { backendEvents } from '../../events'
|
import { backendRpc } from '../../events'
|
||||||
import {
|
import {
|
||||||
makeStorageAcknowledgementEvent,
|
|
||||||
makeStorageResponseEvent,
|
|
||||||
storageClearEvent,
|
storageClearEvent,
|
||||||
storageLoadEvent,
|
storageLoadEvent,
|
||||||
storageStoreEvent,
|
storageStoreEvent,
|
||||||
@@ -32,56 +30,26 @@ export default class ConfigStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async init() {
|
public async init() {
|
||||||
backendEvents.subscribe(storageStoreEvent, async event => {
|
backendRpc.on(storageStoreEvent, async event => {
|
||||||
const ack = makeStorageAcknowledgementEvent(event.transactionId)
|
const db = await this.getDb()
|
||||||
try {
|
await db.set(event.store, event.data).write()
|
||||||
const db = await this.getDb()
|
return
|
||||||
await db.set(event.store, event.data).write()
|
})
|
||||||
backendEvents.emit(ack, undefined)
|
|
||||||
} catch (error) {
|
backendRpc.on(storageLoadEvent, async event => {
|
||||||
backendEvents.emit(ack, {
|
const db = await this.getDb()
|
||||||
error,
|
const data = await db.get(event.store).value()
|
||||||
transactionId: event.transactionId,
|
return {
|
||||||
store: event.store,
|
data,
|
||||||
})
|
store: event.store,
|
||||||
throw error
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
backendEvents.subscribe(storageLoadEvent, async event => {
|
backendRpc.on(storageClearEvent, async event => {
|
||||||
const responseEvent = makeStorageResponseEvent(event.transactionId)
|
const db = await this.getDb()
|
||||||
try {
|
const keys = await db.keys().value()
|
||||||
const db = await this.getDb()
|
for (const key of keys) {
|
||||||
const data = await db.get(event.store).value()
|
await db.unset(key).write()
|
||||||
backendEvents.emit(responseEvent, {
|
|
||||||
data,
|
|
||||||
transactionId: event.transactionId,
|
|
||||||
store: event.store,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
backendEvents.emit(responseEvent, {
|
|
||||||
error,
|
|
||||||
transactionId: event.transactionId,
|
|
||||||
store: event.store,
|
|
||||||
})
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
backendEvents.subscribe(storageClearEvent, async event => {
|
|
||||||
try {
|
|
||||||
const db = await this.getDb()
|
|
||||||
const keys = await db.keys().value()
|
|
||||||
for (const key of keys) {
|
|
||||||
await db.unset(key).write()
|
|
||||||
}
|
|
||||||
backendEvents.emit(makeStorageAcknowledgementEvent(event.transactionId), undefined)
|
|
||||||
} catch (error) {
|
|
||||||
backendEvents.emit(makeStorageAcknowledgementEvent(event.transactionId), {
|
|
||||||
error,
|
|
||||||
transactionId: event.transactionId,
|
|
||||||
})
|
|
||||||
throw error
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as Url from 'url'
|
import { URL } from 'url'
|
||||||
|
|
||||||
import { Client, connect as mqttConnect } from 'mqtt'
|
import { Client, connect as mqttConnect } from 'mqtt'
|
||||||
import { DataSource, DataSourceStateMachine } from './'
|
import { DataSource, DataSourceStateMachine } from './'
|
||||||
@@ -41,13 +41,14 @@ export class MqttSource implements DataSource<MqttOptions> {
|
|||||||
const urlStr = options.tls ? options.url.replace(/^(mqtt|ws):/, '$1s:') : options.url
|
const urlStr = options.tls ? options.url.replace(/^(mqtt|ws):/, '$1s:') : options.url
|
||||||
let url
|
let url
|
||||||
try {
|
try {
|
||||||
url = Url.parse(urlStr)
|
url = new URL(urlStr)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.stateMachine.setError(error)
|
this.stateMachine.setError(error as Error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = mqttConnect(url, {
|
|
||||||
|
const client = mqttConnect(url.toString(), {
|
||||||
resubscribe: false,
|
resubscribe: false,
|
||||||
rejectUnauthorized: options.certValidation,
|
rejectUnauthorized: options.certValidation,
|
||||||
username: options.username,
|
username: options.username,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeBuffer } from './ChangeBuffer'
|
import { ChangeBuffer } from './ChangeBuffer'
|
||||||
import { Destroyable } from './Destroyable'
|
import { Destroyable } from './Destroyable'
|
||||||
import { EventBusInterface, EventDispatcher, makeConnectionMessageEvent, MqttMessage } from '../../../events'
|
import { EventDispatcher, makeConnectionMessageEvent, MqttMessage, EventBusInterface } from '../../../events'
|
||||||
import { TreeNode } from './'
|
import { TreeNode } from './'
|
||||||
import { TreeNodeFactory } from './TreeNodeFactory'
|
import { TreeNodeFactory } from './TreeNodeFactory'
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export class Tree<ViewModel extends Destroyable> extends TreeNode<ViewModel> {
|
|||||||
if (!this.paused && this.applyChangesHasCompleted) {
|
if (!this.paused && this.applyChangesHasCompleted) {
|
||||||
this.applyChangesHasCompleted = false
|
this.applyChangesHasCompleted = false
|
||||||
if ((window as any).requestIdleCallback) {
|
if ((window as any).requestIdleCallback) {
|
||||||
;(window as any).requestIdleCallback(() => this.applyUnmergedChanges(), { timeout: 500 })
|
; (window as any).requestIdleCallback(() => this.applyUnmergedChanges(), { timeout: 500 })
|
||||||
} else {
|
} else {
|
||||||
this.applyUnmergedChanges()
|
this.applyUnmergedChanges()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
{
|
{
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"skipLibCheck": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"lib": ["es2017", "dom"],
|
"lib": [
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"includes": [
|
"includes": [
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
import { IpcMain, ipcMain, ipcRenderer } from 'electron'
|
|
||||||
|
|
||||||
import { Event } from './Events'
|
|
||||||
import { IpcRendererEventBus } from './IpcRendererEventBus'
|
|
||||||
|
|
||||||
export interface EventBusInterface {
|
|
||||||
subscribe<MessageType>(event: Event<MessageType>, callback: (msg: MessageType) => void): void
|
|
||||||
unsubscribeAll<MessageType>(event: Event<MessageType>): void
|
|
||||||
emit<MessageType>(event: Event<MessageType>, msg: MessageType): void
|
|
||||||
unsubscribe<MessageType>(event: Event<MessageType>, callback: any): void
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CallbackStore {
|
|
||||||
wrappedCallback: any
|
|
||||||
callback: any
|
|
||||||
}
|
|
||||||
|
|
||||||
class IpcMainEventBus implements EventBusInterface {
|
|
||||||
private ipc: IpcMain
|
|
||||||
private client: any
|
|
||||||
constructor(ipc: IpcMain) {
|
|
||||||
this.ipc = ipc
|
|
||||||
}
|
|
||||||
|
|
||||||
public subscribe<MessageType>(subscribeEvent: Event<MessageType>, callback: (msg: MessageType) => void) {
|
|
||||||
console.log('subscribing', subscribeEvent.topic)
|
|
||||||
this.ipc.on(subscribeEvent.topic, (event: any, arg: any) => {
|
|
||||||
this.client = event.sender
|
|
||||||
callback(arg)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsubscribeAll<MessageType>(event: Event<MessageType>) {
|
|
||||||
console.log('unsubscribeAll', event.topic)
|
|
||||||
this.ipc.removeAllListeners(event.topic)
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsubscribe<MessageType>(event: Event<MessageType>, callback: any) {
|
|
||||||
throw new Error('Not implemented') // Todo: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
|
||||||
if (!this.client.isDestroyed()) {
|
|
||||||
this.client.send(event.topic, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const rendererEvents = new IpcRendererEventBus(ipcRenderer)
|
|
||||||
export const backendEvents = new IpcMainEventBus(ipcMain)
|
|
||||||
4
events/EventSystem/CallbackStore.ts
Normal file
4
events/EventSystem/CallbackStore.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface CallbackStore {
|
||||||
|
wrappedCallback: any;
|
||||||
|
callback: any;
|
||||||
|
}
|
||||||
12
events/EventSystem/EventBus.ts
Normal file
12
events/EventSystem/EventBus.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ipcMain, ipcRenderer } from 'electron'
|
||||||
|
|
||||||
|
import { IpcMainEventBus } from './IpcMainEventBus'
|
||||||
|
import { IpcRendererEventBus } from './IpcRendererEventBus'
|
||||||
|
import { Rpc } from './Rpc'
|
||||||
|
|
||||||
|
export const rendererEvents = new IpcRendererEventBus(ipcRenderer)
|
||||||
|
export const backendEvents = new IpcMainEventBus(ipcMain)
|
||||||
|
|
||||||
|
// Preferred way to communicate typesafe
|
||||||
|
export const rendererRpc = new Rpc(rendererEvents)
|
||||||
|
export const backendRpc = new Rpc(backendEvents)
|
||||||
8
events/EventSystem/EventBusInterface.ts
Normal file
8
events/EventSystem/EventBusInterface.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Event } from '../Events';
|
||||||
|
|
||||||
|
export interface EventBusInterface {
|
||||||
|
subscribe<MessageType>(event: Event<MessageType>, callback: (msg: MessageType) => void): void;
|
||||||
|
unsubscribeAll<MessageType>(event: Event<MessageType>): void;
|
||||||
|
emit<MessageType>(event: Event<MessageType>, msg: MessageType): void;
|
||||||
|
unsubscribe<MessageType>(event: Event<MessageType>, callback: any): void;
|
||||||
|
}
|
||||||
34
events/EventSystem/IpcMainEventBus.ts
Normal file
34
events/EventSystem/IpcMainEventBus.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { IpcMain } from 'electron';
|
||||||
|
import { Event } from '../Events';
|
||||||
|
import { EventBusInterface } from "./EventBusInterface";
|
||||||
|
|
||||||
|
export class IpcMainEventBus implements EventBusInterface {
|
||||||
|
private ipc: IpcMain;
|
||||||
|
private client: any;
|
||||||
|
constructor(ipc: IpcMain) {
|
||||||
|
this.ipc = ipc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscribe<MessageType>(subscribeEvent: Event<MessageType>, callback: (msg: MessageType) => void) {
|
||||||
|
console.log('subscribing', subscribeEvent.topic);
|
||||||
|
this.ipc.on(subscribeEvent.topic, (event: any, arg: any) => {
|
||||||
|
this.client = event.sender;
|
||||||
|
callback(arg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsubscribeAll<MessageType>(event: Event<MessageType>) {
|
||||||
|
console.log('unsubscribeAll', event.topic);
|
||||||
|
this.ipc.removeAllListeners(event.topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsubscribe<MessageType>(event: Event<MessageType>, callback: any) {
|
||||||
|
throw new Error('Not implemented'); // Todo: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
||||||
|
if (!this.client.isDestroyed()) {
|
||||||
|
this.client.send(event.topic, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,32 @@
|
|||||||
import { CallbackStore, EventBusInterface } from './EventBus'
|
import { CallbackStore } from "./CallbackStore"
|
||||||
import { Event } from './Events'
|
import { EventBusInterface } from "./EventBusInterface"
|
||||||
|
import { Event } from '../Events'
|
||||||
import { IpcRenderer } from 'electron'
|
import { IpcRenderer } from 'electron'
|
||||||
|
|
||||||
export class IpcRendererEventBus implements EventBusInterface {
|
export class IpcRendererEventBus implements EventBusInterface {
|
||||||
private ipc: IpcRenderer
|
private ipc: IpcRenderer
|
||||||
private callbacks: Array<CallbackStore> = []
|
private callbacks: Array<CallbackStore> = []
|
||||||
|
|
||||||
constructor(ipc: IpcRenderer) {
|
constructor(ipc: IpcRenderer) {
|
||||||
this.ipc = ipc
|
this.ipc = ipc
|
||||||
}
|
}
|
||||||
|
|
||||||
public subscribe<MessageType>(event: Event<MessageType>, callback: (msg: MessageType) => void) {
|
public subscribe<MessageType>(event: Event<MessageType>, callback: (msg: MessageType) => void) {
|
||||||
const wrappedCallback = (_: any, arg: any) => {
|
const wrappedCallback = (_: any, arg: any) => {
|
||||||
callback(arg)
|
callback(arg)
|
||||||
}
|
}
|
||||||
|
console.log("subscribing", event.topic)
|
||||||
this.ipc.on(event.topic, wrappedCallback)
|
this.ipc.on(event.topic, wrappedCallback)
|
||||||
this.callbacks.push({
|
this.callbacks.push({
|
||||||
callback,
|
callback,
|
||||||
wrappedCallback,
|
wrappedCallback,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsubscribeAll<MessageType>(event: Event<MessageType>) {
|
public unsubscribeAll<MessageType>(event: Event<MessageType>) {
|
||||||
this.ipc.removeAllListeners(event.topic)
|
this.ipc.removeAllListeners(event.topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsubscribe<MessageType>(event: Event<MessageType>, callback: any) {
|
public unsubscribe<MessageType>(event: Event<MessageType>, callback: any) {
|
||||||
const item = this.callbacks.find(store => store.callback === callback)
|
const item = this.callbacks.find(store => store.callback === callback)
|
||||||
if (!item) {
|
if (!item) {
|
||||||
@@ -29,6 +35,7 @@ export class IpcRendererEventBus implements EventBusInterface {
|
|||||||
this.ipc.removeListener(event.topic, item.wrappedCallback)
|
this.ipc.removeListener(event.topic, item.wrappedCallback)
|
||||||
this.callbacks = this.callbacks.filter(a => a !== item)
|
this.callbacks = this.callbacks.filter(a => a !== item)
|
||||||
}
|
}
|
||||||
|
|
||||||
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
||||||
this.ipc.send(event.topic, msg)
|
this.ipc.send(event.topic, msg)
|
||||||
}
|
}
|
||||||
53
events/EventSystem/Rpc.ts
Normal file
53
events/EventSystem/Rpc.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { Event } from '../Events';
|
||||||
|
import { EventBusInterface } from './EventBusInterface'
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
export type RpcEvent<RequstType, ResponseType> = {
|
||||||
|
topic: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Rpc {
|
||||||
|
constructor(private participant: EventBusInterface) { }
|
||||||
|
|
||||||
|
async call<RpcRequest, RpcResponse>(event: RpcEvent<RpcRequest, RpcResponse>, request: RpcRequest, timeout: number = 0): Promise<RpcResponse> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let id = v4();
|
||||||
|
|
||||||
|
let responseEvent: Event<any> = { topic: `${event.topic}/response/${id}` };
|
||||||
|
let requestEvent: Event<any> = { topic: `${event.topic}/request` };
|
||||||
|
let callback = (result: { id: string; payload: RpcResponse; error: unknown }) => {
|
||||||
|
this.participant.unsubscribe(responseEvent as any, callback);
|
||||||
|
if (result.error) {
|
||||||
|
reject(result.error)
|
||||||
|
} else {
|
||||||
|
resolve(result.payload);
|
||||||
|
}
|
||||||
|
console.log("received", result)
|
||||||
|
};
|
||||||
|
this.participant.subscribe(responseEvent, callback);
|
||||||
|
this.participant.emit(requestEvent, { id, payload: request });
|
||||||
|
|
||||||
|
if (timeout > 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
reject(new Error(`Did not respond to ${event.topic} within ${timeout}ms`))
|
||||||
|
this.participant.unsubscribe(responseEvent as any, callback);
|
||||||
|
}, 10000)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async on<RpcRequest, RpcResponse>(event: RpcEvent<RpcRequest, RpcResponse>, handler: (request: RpcRequest) => Promise<RpcResponse>) {
|
||||||
|
this.participant.subscribe<RpcRequest>({ topic: `${event.topic}/request` } as RpcEvent<any, any>, async (request) => {
|
||||||
|
let payload;
|
||||||
|
let error;
|
||||||
|
try {
|
||||||
|
payload = await handler((request as any).payload);
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
const id = (request as any).id
|
||||||
|
console.log(`${event.topic}/response/${id}`, payload, error)
|
||||||
|
this.participant.emit({ topic: `${event.topic}/response/${id}` }, { id, payload, error });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Base64Message } from '../backend/src/Model/Base64Message'
|
import { Base64Message } from '../backend/src/Model/Base64Message'
|
||||||
import { DataSourceState, MqttOptions } from '../backend/src/DataSource'
|
import { DataSourceState, MqttOptions } from '../backend/src/DataSource'
|
||||||
import { UpdateInfo } from 'builder-util-runtime'
|
import { UpdateInfo } from 'builder-util-runtime'
|
||||||
|
import { RpcEvent } from './EventSystem/Rpc';
|
||||||
|
|
||||||
export interface Event<MessageType> {
|
export type Event<MessageType> = {
|
||||||
topic: string
|
topic: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,3 +50,7 @@ export function makeConnectionMessageEvent(connectionId: string): Event<MqttMess
|
|||||||
topic: `conn/${connectionId}`,
|
topic: `conn/${connectionId}`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getAppVersion: RpcEvent<void, string> = {
|
||||||
|
topic: `getAppVersion`
|
||||||
|
}
|
||||||
|
|||||||
8
events/OpenDialogRequest.ts
Normal file
8
events/OpenDialogRequest.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { OpenDialogOptions, OpenDialogReturnValue } from 'electron';
|
||||||
|
import { RpcEvent } from './EventSystem/Rpc';
|
||||||
|
|
||||||
|
export function makeOpenDialogRpc(): RpcEvent<OpenDialogOptions, OpenDialogReturnValue> {
|
||||||
|
return {
|
||||||
|
topic: `openDialog`
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,39 +1,22 @@
|
|||||||
import { Event } from './'
|
import { RpcEvent } from './EventSystem/Rpc'
|
||||||
|
|
||||||
interface StorageEvent {
|
export interface StoreCommand {
|
||||||
transactionId: string
|
store: string
|
||||||
|
data: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StoreCommand extends StorageEvent {
|
export interface LoadCommand {
|
||||||
store?: string
|
|
||||||
data?: any
|
|
||||||
error?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoadCommand extends StorageEvent {
|
|
||||||
store: string
|
store: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const storageStoreEvent: Event<StoreCommand> = {
|
export const storageStoreEvent: RpcEvent<StoreCommand, void> = {
|
||||||
topic: 'storage/store',
|
topic: 'storage/store',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const storageLoadEvent: Event<LoadCommand> = {
|
export const storageLoadEvent: RpcEvent<LoadCommand, StoreCommand> = {
|
||||||
topic: 'storage/load',
|
topic: 'storage/load',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeStorageAcknowledgementEvent(transactionId: string): Event<StoreCommand> {
|
export const storageClearEvent: RpcEvent<void, void> = {
|
||||||
return {
|
|
||||||
topic: `storage/ack/${transactionId}`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeStorageResponseEvent(transactionId: string): Event<StoreCommand> {
|
|
||||||
return {
|
|
||||||
topic: `storage/response/${transactionId}`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const storageClearEvent: Event<StorageEvent> = {
|
|
||||||
topic: 'storage/clear',
|
topic: 'storage/clear',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './Events'
|
export * from './Events'
|
||||||
export * from './EventDispatcher'
|
export * from './EventSystem/EventDispatcher'
|
||||||
export * from './EventBus'
|
export * from './EventSystem/EventBus'
|
||||||
|
export * from './EventSystem/EventBusInterface'
|
||||||
40
package.json
40
package.json
@@ -3,6 +3,9 @@
|
|||||||
"version": "0.4.0-beta1",
|
"version": "0.4.0-beta1",
|
||||||
"description": "Explore your message queues",
|
"description": "Explore your message queues",
|
||||||
"main": "dist/src/electron.js",
|
"main": "dist/src/electron.js",
|
||||||
|
"engines": {
|
||||||
|
"node": "16"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron .",
|
"start": "electron .",
|
||||||
"test": "yarn test:app && yarn test:backend",
|
"test": "yarn test:app && yarn test:backend",
|
||||||
@@ -62,14 +65,14 @@
|
|||||||
"buildResources": "res",
|
"buildResources": "res",
|
||||||
"output": "build"
|
"output": "build"
|
||||||
},
|
},
|
||||||
"afterPack": "./dist/scripts/afterPack.js",
|
"afterPack": "./dist/scripts/afterPack.js"
|
||||||
"afterSign": "./scripts/afterSign.js"
|
|
||||||
},
|
},
|
||||||
"author": "Thomas Nordquist",
|
"author": "Thomas Nordquist",
|
||||||
"email": "xxnerowingerxx@gmail.com",
|
"email": "xxnerowingerxx@gmail.com",
|
||||||
"homepage": "https://github.com",
|
"homepage": "https://github.com",
|
||||||
"license": "CC-BY-ND-4.0",
|
"license": "CC-BY-ND-4.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/runtime": "^7.17.2",
|
||||||
"@types/chai": "^4.1.7",
|
"@types/chai": "^4.1.7",
|
||||||
"@types/fs-extra": "8",
|
"@types/fs-extra": "8",
|
||||||
"@types/lowdb": "^1.0.6",
|
"@types/lowdb": "^1.0.6",
|
||||||
@@ -79,12 +82,13 @@
|
|||||||
"@types/node": "^12.6.8",
|
"@types/node": "^12.6.8",
|
||||||
"@types/semver": "7",
|
"@types/semver": "7",
|
||||||
"@types/sha1": "^1.1.1",
|
"@types/sha1": "^1.1.1",
|
||||||
"builder-util-runtime": "^8.2.5",
|
"@types/uuid": "^8.3.4",
|
||||||
|
"builder-util-runtime": "^9",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"cspell": "^4.0.28",
|
"cspell": "^4.0.28",
|
||||||
"electron": "8.2.3",
|
"electron": "17",
|
||||||
"electron-builder": "22.5.1",
|
"electron-builder": "22",
|
||||||
"electron-notarize": "^0.3.0",
|
"electron-notarize": "^1.1.1",
|
||||||
"mocha": "7.1",
|
"mocha": "7.1",
|
||||||
"mustache": "4",
|
"mustache": "4",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
@@ -92,32 +96,26 @@
|
|||||||
"prettier": "2",
|
"prettier": "2",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"source-map-support": "^0.5.9",
|
"source-map-support": "^0.5.9",
|
||||||
"spectron": "10",
|
"spectron": "19",
|
||||||
"ts-node": "^8.2.0",
|
"ts-node": "^10.5.0",
|
||||||
"tslint": "6",
|
"typescript": "^4.5.5",
|
||||||
"tslint-config-airbnb": "^5.11.1",
|
"webdriverio": "7.16"
|
||||||
"tslint-react": "^4.0.0",
|
|
||||||
"tslint-react-recommended": "^1.0.15",
|
|
||||||
"tslint-strict-null-checks": "^1.0.1",
|
|
||||||
"typescript": "^3.2.2",
|
|
||||||
"webdriverio": "6"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"about-window": "^1.12.1",
|
"about-window": "^1.12.1",
|
||||||
"axios": "^0.19.0",
|
"axios": "^0.19.0",
|
||||||
"dot-prop": "^5.0.0",
|
"dot-prop": "^5.0.0",
|
||||||
"electron-log": "4.1.1",
|
"electron-log": "4.4.6",
|
||||||
"electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git#dist",
|
"electron-updater": "^4.6",
|
||||||
"electron-updater": "^4.0.6",
|
|
||||||
"fs-extra": "9",
|
"fs-extra": "9",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"json-to-ast": "^2.1.0",
|
"json-to-ast": "^2.1.0",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"mime": "^2.4.4",
|
"mime": "^2.4.4",
|
||||||
"mqtt": "^3.0.0",
|
"mqtt": "^4.3.6",
|
||||||
"protobufjs": "~6.11.2",
|
"protobufjs": "~6.11.2",
|
||||||
"sha1": "^1.1.1",
|
"sha1": "^1.1.1",
|
||||||
|
"uuid": "^8.3.2",
|
||||||
"yarn-run-all": "^3.1.1"
|
"yarn-run-all": "^3.1.1"
|
||||||
},
|
}
|
||||||
"optionalDependencies": {}
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import * as fs from 'fs-extra'
|
import * as fs from 'fs-extra'
|
||||||
import * as path from 'path'
|
|
||||||
import { chdir } from 'process'
|
import { chdir } from 'process'
|
||||||
import { exec } from './util'
|
import { exec } from './util'
|
||||||
|
|
||||||
|
|||||||
@@ -53,12 +53,12 @@ async function uploadAsset() {
|
|||||||
try {
|
try {
|
||||||
uploadUrl = await createDraft(tag)
|
uploadUrl = await createDraft(tag)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('failed to create draft', error.stack)
|
console.error('failed to create draft', (error as Error).stack)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('failed to find tag release', error.stack)
|
console.error('failed to find tag release', (error as Error).stack)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function redirectOutputFor(child: ChildProcess) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function waitFor(child: ChildProcess) {
|
async function waitFor(child: ChildProcess) {
|
||||||
return new Promise(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
child.once('close', () => resolve())
|
child.once('close', () => resolve())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { autoUpdater, UpdateInfo } from 'electron-updater'
|
import { autoUpdater, UpdateInfo } from 'electron-updater'
|
||||||
import { BuildInfo } from 'electron-telemetry/build/Model'
|
// import { BuildInfo } from 'electron-telemetry/build/Model'
|
||||||
|
|
||||||
export function shouldAutoUpdate(build: BuildInfo) {
|
export function shouldAutoUpdate(build: any) {
|
||||||
return (
|
return (
|
||||||
build.package !== 'portable' &&
|
build.package !== 'portable' &&
|
||||||
build.package !== 'appx' &&
|
build.package !== 'appx' &&
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { BuildInfo } from 'electron-telemetry/build/Model'
|
// import { BuildInfo } from 'electron-telemetry/build/Model'
|
||||||
|
|
||||||
let buildOptions: BuildInfo = {
|
let buildOptions: any = {
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
package: 'unpacked',
|
package: 'unpacked',
|
||||||
} as any
|
} as any
|
||||||
|
|||||||
@@ -1,23 +1,31 @@
|
|||||||
import * as log from 'electron-log'
|
import * as log from 'electron-log'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import ConfigStorage from '../backend/src/ConfigStorage'
|
import ConfigStorage from '../backend/src/ConfigStorage'
|
||||||
import { app, BrowserWindow, Menu } from 'electron'
|
import { app, BrowserWindow, Menu, dialog } from 'electron'
|
||||||
import { autoUpdater } from 'electron-updater'
|
import { autoUpdater } from 'electron-updater'
|
||||||
import { ConnectionManager } from '../backend/src/index'
|
import { ConnectionManager } from '../backend/src/index'
|
||||||
import { electronTelemetryFactory } from 'electron-telemetry'
|
// import { electronTelemetryFactory } from 'electron-telemetry'
|
||||||
import { menuTemplate } from './MenuTemplate'
|
import { menuTemplate } from './MenuTemplate'
|
||||||
import buildOptions from './buildOptions'
|
import buildOptions from './buildOptions'
|
||||||
import { waitForDevServer, isDev, runningUiTestOnCi, loadDevTools } from './development'
|
import { waitForDevServer, isDev, runningUiTestOnCi, loadDevTools } from './development'
|
||||||
import { shouldAutoUpdate, handleAutoUpdate } from './autoUpdater'
|
import { shouldAutoUpdate, handleAutoUpdate } from './autoUpdater'
|
||||||
import { registerCrashReporter } from './registerCrashReporter'
|
import { registerCrashReporter } from './registerCrashReporter'
|
||||||
|
import { makeOpenDialogRpc } from '../events/OpenDialogRequest'
|
||||||
|
import { backendRpc, getAppVersion } from '../events'
|
||||||
|
|
||||||
registerCrashReporter()
|
registerCrashReporter()
|
||||||
|
|
||||||
if (!isDev() && !runningUiTestOnCi()) {
|
// if (!isDev() && !runningUiTestOnCi()) {
|
||||||
const electronTelemetry = electronTelemetryFactory('9b0c8ca04a361eb8160d98c5', buildOptions)
|
// const electronTelemetry = electronTelemetryFactory('9b0c8ca04a361eb8160d98c5', buildOptions)
|
||||||
}
|
// }
|
||||||
|
|
||||||
app.commandLine.appendSwitch('--no-sandbox')
|
app.commandLine.appendSwitch('--no-sandbox')
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
backendRpc.on(makeOpenDialogRpc(), async (request) => {
|
||||||
|
return dialog.showOpenDialog(BrowserWindow.getFocusedWindow() ?? BrowserWindow.getAllWindows()[0], request)
|
||||||
|
})
|
||||||
|
backendRpc.on(getAppVersion, async () => app.getVersion())
|
||||||
|
})
|
||||||
|
|
||||||
autoUpdater.logger = log
|
autoUpdater.logger = log
|
||||||
log.info('App starting...')
|
log.info('App starting...')
|
||||||
@@ -45,6 +53,8 @@ async function createWindow() {
|
|||||||
height: 720,
|
height: 720,
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
|
...({ enableRemoteModule: true } as any),
|
||||||
|
contextIsolation: false,
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
devTools: true,
|
devTools: true,
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { clickOn, expandTopic, moveToCenterOfElement, sleep, writeText } from '../util'
|
import { clickOn, expandTopic, moveToCenterOfElement, sleep, writeText } from '../util'
|
||||||
|
|
||||||
export async function clearOldTopics(browser: Browser) {
|
export async function clearOldTopics(browser: Browser<'async'>) {
|
||||||
const topics = ['hello', 'test 123']
|
const topics = ['hello', 'test 123']
|
||||||
for (const topic of topics) {
|
for (const topic of topics) {
|
||||||
await expandTopic(topic, browser)
|
await expandTopic(topic, browser)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { clickOn, setTextInInput } from '../util'
|
import { clickOn, setTextInInput } from '../util'
|
||||||
|
|
||||||
export async function connectTo(host: string, browser: Browser) {
|
export async function connectTo(host: string, browser: Browser<'async'>) {
|
||||||
await setTextInInput('Host', host, browser)
|
await setTextInInput('Host', host, browser)
|
||||||
|
|
||||||
await browser.saveScreenshot('screen1.png')
|
await browser.saveScreenshot('screen1.png')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser } from 'webdriverio'
|
import { Browser } from 'webdriverio'
|
||||||
import { clickOn } from '../util'
|
import { clickOn } from '../util'
|
||||||
|
|
||||||
export async function copyTopicToClipboard(browser: Browser) {
|
export async function copyTopicToClipboard(browser: Browser<'async'>) {
|
||||||
const copyButton = await browser.$('//span[contains(text(), "Topic")]//button')
|
const copyButton = await browser.$('//span[contains(text(), "Topic")]//button')
|
||||||
await clickOn(copyButton, browser, 1)
|
await clickOn(copyButton, browser, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser } from 'webdriverio'
|
import { Browser } from 'webdriverio'
|
||||||
import { clickOn } from '../util'
|
import { clickOn } from '../util'
|
||||||
|
|
||||||
export async function copyValueToClipboard(browser: Browser) {
|
export async function copyValueToClipboard(browser: Browser<'async'>) {
|
||||||
const copyButton = await browser.$('//span[contains(text(), "Value")]//button')
|
const copyButton = await browser.$('//span[contains(text(), "Value")]//button')
|
||||||
await clickOn(copyButton, browser, 1)
|
await clickOn(copyButton, browser, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { clickOn } from '../util'
|
import { clickOn } from '../util'
|
||||||
|
|
||||||
export async function disconnect(browser: Browser) {
|
export async function disconnect(browser: Browser<'async'>) {
|
||||||
const disconnectButton = await browser.$('//button/span[contains(text(),"Disconnect")]')
|
const disconnectButton = await browser.$('//button/span[contains(text(),"Disconnect")]')
|
||||||
await clickOn(disconnectButton, browser)
|
await clickOn(disconnectButton, browser)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
showText,
|
showText,
|
||||||
} from '../util'
|
} from '../util'
|
||||||
|
|
||||||
export async function publishTopic(browser: Browser) {
|
export async function publishTopic(browser: Browser<'async'>) {
|
||||||
await expandTopic('kitchen/lamp/state', browser)
|
await expandTopic('kitchen/lamp/state', browser)
|
||||||
const topicInput = await browser.$('//input[contains(@value,"kitchen/lamp/state")][1]')
|
const topicInput = await browser.$('//input[contains(@value,"kitchen/lamp/state")][1]')
|
||||||
await clickOn(topicInput, browser)
|
await clickOn(topicInput, browser)
|
||||||
@@ -17,8 +17,7 @@ export async function publishTopic(browser: Browser) {
|
|||||||
await writeText('set', browser, 300)
|
await writeText('set', browser, 300)
|
||||||
|
|
||||||
const payloadInput = await browser.$('//*[contains(@class, "ace_text-input")]')
|
const payloadInput = await browser.$('//*[contains(@class, "ace_text-input")]')
|
||||||
await writeTextPayload(payloadInput, '{"action": "setState", "state": "on" }')
|
await writeTextPayload(payloadInput, 'off')
|
||||||
|
|
||||||
await sleep(500)
|
await sleep(500)
|
||||||
const formatJsonButton = await browser.$('#sidebar-publish-format-json')
|
const formatJsonButton = await browser.$('#sidebar-publish-format-json')
|
||||||
await clickOn(formatJsonButton, browser)
|
await clickOn(formatJsonButton, browser)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { clickOn } from '../util'
|
import { clickOn } from '../util'
|
||||||
|
|
||||||
export async function reconnect(browser: Browser) {
|
export async function reconnect(browser: Browser<'async'>) {
|
||||||
const disconnectButton = await browser.$('//button/span[contains(text(),"Disconnect")]')
|
const disconnectButton = await browser.$('//button/span[contains(text(),"Disconnect")]')
|
||||||
await clickOn(disconnectButton, browser)
|
await clickOn(disconnectButton, browser)
|
||||||
const connectButton = await browser.$('//button/span[contains(text(),"Connect")]')
|
const connectButton = await browser.$('//button/span[contains(text(),"Connect")]')
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { clickOn, deleteTextWithBackspaces, showText, sleep, writeText } from '../util'
|
import { clickOn, deleteTextWithBackspaces, showText, sleep, writeText } from '../util'
|
||||||
|
|
||||||
export async function searchTree(text: string, browser: Browser) {
|
export async function searchTree(text: string, browser: Browser<'async'>) {
|
||||||
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
|
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
|
||||||
await clickOn(searchField, browser, 1)
|
await clickOn(searchField, browser, 1)
|
||||||
await writeText(text, browser, 100)
|
await writeText(text, browser, 100)
|
||||||
await sleep(1500)
|
await sleep(1500)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clearSearch(browser: Browser) {
|
export async function clearSearch(browser: Browser<'async'>) {
|
||||||
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
|
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
|
||||||
await clickOn(searchField, browser, 1)
|
await clickOn(searchField, browser, 1)
|
||||||
await deleteTextWithBackspaces(searchField, browser, 100)
|
await deleteTextWithBackspaces(searchField, browser, 100)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser } from 'webdriverio'
|
import { Browser } from 'webdriverio'
|
||||||
import { clickOn, sleep, setInputText } from '../util'
|
import { clickOn, sleep, setInputText } from '../util'
|
||||||
|
|
||||||
export async function showAdvancedConnectionSettings(browser: Browser) {
|
export async function showAdvancedConnectionSettings(browser: Browser<'async'>) {
|
||||||
const advancedSettingsButton = await browser.$('//button/span[contains(text(),"Advanced")]')
|
const advancedSettingsButton = await browser.$('//button/span[contains(text(),"Advanced")]')
|
||||||
const addButton = await browser.$('//button/span[contains(text(),"Add")]')
|
const addButton = await browser.$('//button/span[contains(text(),"Add")]')
|
||||||
const topicInput = await browser.$('//*[contains(@class, "advanced-connection-settings-topic-input")]//input')
|
const topicInput = await browser.$('//*[contains(@class, "advanced-connection-settings-topic-input")]//input')
|
||||||
@@ -24,7 +24,7 @@ export async function showAdvancedConnectionSettings(browser: Browser) {
|
|||||||
await clickOn(connectButton, browser)
|
await clickOn(connectButton, browser)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteFirstSubscribedTopic(browser: Browser) {
|
async function deleteFirstSubscribedTopic(browser: Browser<'async'>) {
|
||||||
const deleteButton = await browser.$('.advanced-connection-settings-topic-list button')
|
const deleteButton = await browser.$('.advanced-connection-settings-topic-list button')
|
||||||
await clickOn(deleteButton, browser)
|
await clickOn(deleteButton, browser)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { expandTopic, sleep } from '../util'
|
import { expandTopic, sleep } from '../util'
|
||||||
|
|
||||||
export async function showJsonPreview(browser: Browser) {
|
export async function showJsonPreview(browser: Browser<'async'>) {
|
||||||
await expandTopic('actuality/showcase', browser)
|
await expandTopic('actuality/showcase', browser)
|
||||||
await browser.saveScreenshot('screen3.png')
|
await browser.saveScreenshot('screen3.png')
|
||||||
await sleep(1000)
|
await sleep(1000)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser } from 'webdriverio'
|
import { Browser } from 'webdriverio'
|
||||||
import { clickOn, showText, sleep } from '../util'
|
import { clickOn, showText, sleep } from '../util'
|
||||||
|
|
||||||
export async function showMenu(browser: Browser) {
|
export async function showMenu(browser: Browser<'async'>) {
|
||||||
const menuButton = await browser.$('//button[contains(@aria-label, "Menu")]')
|
const menuButton = await browser.$('//button[contains(@aria-label, "Menu")]')
|
||||||
await clickOn(menuButton, browser)
|
await clickOn(menuButton, browser)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { moveToCenterOfElement, clickOn, clickOnHistory, expandTopic, sleep, writeText } from '../util'
|
import { moveToCenterOfElement, clickOn, clickOnHistory, expandTopic, sleep, writeText } from '../util'
|
||||||
|
|
||||||
export async function showNumericPlot(browser: Browser) {
|
export async function showNumericPlot(browser: Browser<'async'>) {
|
||||||
await expandTopic('kitchen/coffee_maker', browser)
|
await expandTopic('kitchen/coffee_maker', browser)
|
||||||
let heater = await valuePreviewGuttersShowChartIcon('heater', browser)
|
let heater = await valuePreviewGuttersShowChartIcon('heater', browser)
|
||||||
await moveToCenterOfElement(heater, browser)
|
await moveToCenterOfElement(heater, browser)
|
||||||
@@ -42,7 +42,7 @@ export async function showNumericPlot(browser: Browser) {
|
|||||||
await clickOnHistory(browser)
|
await clickOnHistory(browser)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function valuePreviewGuttersShowChartIcon(name: string, browser: Browser) {
|
async function valuePreviewGuttersShowChartIcon(name: string, browser: Browser<'async'>) {
|
||||||
for (let retries = 0; retries < 2; retries += 1) {
|
for (let retries = 0; retries < 2; retries += 1) {
|
||||||
try {
|
try {
|
||||||
return await browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
return await browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
||||||
@@ -53,23 +53,23 @@ async function valuePreviewGuttersShowChartIcon(name: string, browser: Browser)
|
|||||||
return browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
return browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chartSettings(name: string, browser: Browser) {
|
async function chartSettings(name: string, browser: Browser<'async'>) {
|
||||||
const settings = await browser.$(`//*[contains(@data-test-type, "ChartSettings")][contains(@data-test, "${name}")]`)
|
const settings = await browser.$(`//*[contains(@data-test-type, "ChartSettings")][contains(@data-test, "${name}")]`)
|
||||||
return clickOn(settings, browser)
|
return clickOn(settings, browser)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickAway(name: string, browser: Browser) {
|
async function clickAway(name: string, browser: Browser<'async'>) {
|
||||||
const settings = await browser.$(`//*[contains(@data-test-type, "ChartPaper")][contains(@data-test, "${name}")]`)
|
const settings = await browser.$(`//*[contains(@data-test-type, "ChartPaper")][contains(@data-test, "${name}")]`)
|
||||||
await moveToCenterOfElement(settings, browser)
|
await moveToCenterOfElement(settings, browser)
|
||||||
await browser.keys(['Escape'])
|
await browser.keys(['Escape'])
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeChart(name: string, browser: Browser) {
|
async function removeChart(name: string, browser: Browser<'async'>) {
|
||||||
const remove = await browser.$(`//*[contains(@data-test-type, "RemoveChart")][contains(@data-test, "${name}")]`)
|
const remove = await browser.$(`//*[contains(@data-test-type, "RemoveChart")][contains(@data-test, "${name}")]`)
|
||||||
return clickOn(remove, browser)
|
return clickOn(remove, browser)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickOnMenuPoint(name: string, browser: Browser) {
|
async function clickOnMenuPoint(name: string, browser: Browser<'async'>) {
|
||||||
const item = await browser.$(`//li/span[contains(text(), "${name}")]`)
|
const item = await browser.$(`//li/span[contains(text(), "${name}")]`)
|
||||||
return clickOn(item, browser)
|
return clickOn(item, browser)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Browser, Element } from 'webdriverio'
|
|||||||
import { clickOn, showText, sleep } from '../util'
|
import { clickOn, showText, sleep } from '../util'
|
||||||
|
|
||||||
// Expects a topic with at least two messages to be selected
|
// Expects a topic with at least two messages to be selected
|
||||||
export async function showOffDiffCapability(browser: Browser) {
|
export async function showOffDiffCapability(browser: Browser<'async'>) {
|
||||||
await showText('Compare messages', 2000, browser, 'top')
|
await showText('Compare messages', 2000, browser, 'top')
|
||||||
|
|
||||||
await showText('Show raw message', 2000, browser, 'bottom')
|
await showText('Show raw message', 2000, browser, 'bottom')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
import { showKeys, showText, sleep } from '../util'
|
import { showKeys, showText, sleep } from '../util'
|
||||||
|
|
||||||
export async function showZoomLevel(browser: Browser) {
|
export async function showZoomLevel(browser: Browser<'async'>) {
|
||||||
await showKeys('Zoom in', 2000, browser, 'top', ['Ctrl', '+'])
|
await showKeys('Zoom in', 2000, browser, 'top', ['Ctrl', '+'])
|
||||||
await sleep(2000)
|
await sleep(2000)
|
||||||
await showKeys('Zoom out', 2000, browser, 'middle', ['Ctrl', '-'])
|
await showKeys('Zoom out', 2000, browser, 'middle', ['Ctrl', '-'])
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { clickOn } from './'
|
import { clickOn } from './'
|
||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser, Element } from 'webdriverio'
|
||||||
|
|
||||||
export async function expandTopic(path: string, browser: Browser) {
|
export async function expandTopic(path: string, browser: Browser<'async'>) {
|
||||||
const originalTopics = path.split('/')
|
const originalTopics = path.split('/')
|
||||||
let topics = path.split('/')
|
let topics = path.split('/')
|
||||||
while (topics.length > 0 && !(await topicMatches(topics, browser))) {
|
while (topics.length > 0 && !(await topicMatches(topics, browser))) {
|
||||||
@@ -18,7 +18,7 @@ export async function expandTopic(path: string, browser: Browser) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function topicMatches(topics: Array<string>, browser: Browser) {
|
async function topicMatches(topics: Array<string>, browser: Browser<'async'>) {
|
||||||
const result = await browser.$(topicSelector(topics))
|
const result = await browser.$(topicSelector(topics))
|
||||||
return result.isExisting()
|
return result.isExisting()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function sleep(ms: number, required = false) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function writeText(text: string, browser: Browser, delay = 0) {
|
export async function writeText(text: string, browser: Browser<'async'>, delay = 0) {
|
||||||
if (fast) {
|
if (fast) {
|
||||||
return browser.keys(text.split(''))
|
return browser.keys(text.split(''))
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ export async function writeText(text: string, browser: Browser, delay = 0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteTextWithBackspaces(element: Element, browser: Browser, delay = 0, count = 0) {
|
export async function deleteTextWithBackspaces(element: Element<'async'>, browser: Browser<'async'>, delay = 0, count = 0) {
|
||||||
const length = count > 0 ? count : (await element.getValue()).length
|
const length = count > 0 ? count : (await element.getValue()).length
|
||||||
for (let i = 0; i < length; i += 1) {
|
for (let i = 0; i < length; i += 1) {
|
||||||
await browser.keys(['Backspace'])
|
await browser.keys(['Backspace'])
|
||||||
@@ -37,13 +37,13 @@ export async function deleteTextWithBackspaces(element: Element, browser: Browse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setInputText(input: Element, text: string, browser: Browser) {
|
export async function setInputText(input: Element<'async'>, text: string, browser: Browser<'async'>) {
|
||||||
await clickOn(input, browser, 1)
|
await clickOn(input, browser, 1)
|
||||||
await deleteTextWithBackspaces(input, browser)
|
await deleteTextWithBackspaces(input, browser)
|
||||||
await input.setValue(text)
|
await input.setValue(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setTextInInput(name: string, text: string, browser: Browser) {
|
export async function setTextInInput(name: string, text: string, browser: Browser<'async'>) {
|
||||||
const input = await browser.$(`//label[contains(text(), "${name}")]/..//input`)
|
const input = await browser.$(`//label[contains(text(), "${name}")]/..//input`)
|
||||||
await clickOn(input, browser, 1)
|
await clickOn(input, browser, 1)
|
||||||
await browser.$(`//label[contains(text(), "${name}")]/..//input`)
|
await browser.$(`//label[contains(text(), "${name}")]/..//input`)
|
||||||
@@ -52,7 +52,7 @@ export async function setTextInInput(name: string, text: string, browser: Browse
|
|||||||
await input.setValue(text)
|
await input.setValue(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function moveToCenterOfElement(element: Element, browser: Browser) {
|
export async function moveToCenterOfElement(element: Element<'async'>, browser: Browser<'async'>) {
|
||||||
const { x, y } = await element.getLocation()
|
const { x, y } = await element.getLocation()
|
||||||
const { width, height } = await element.getSize()
|
const { width, height } = await element.getSize()
|
||||||
|
|
||||||
@@ -69,12 +69,12 @@ export async function moveToCenterOfElement(element: Element, browser: Browser)
|
|||||||
await element.moveTo()
|
await element.moveTo()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clickOnHistory(browser: Browser) {
|
export async function clickOnHistory(browser: Browser<'async'>) {
|
||||||
const messageHistory = await browser.$('//span/*[contains(text(), "History")]')
|
const messageHistory = await browser.$('//span/*[contains(text(), "History")]')
|
||||||
await clickOn(messageHistory, browser)
|
await clickOn(messageHistory, browser)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clickOn(element: Element, browser: Browser, clicks = 1) {
|
export async function clickOn(element: Element<'async'>, browser: Browser<'async'>, clicks = 1) {
|
||||||
await moveToCenterOfElement(element, browser)
|
await moveToCenterOfElement(element, browser)
|
||||||
for (let i = 0; i < clicks; i += 1) {
|
for (let i = 0; i < clicks; i += 1) {
|
||||||
await element.click()
|
await element.click()
|
||||||
@@ -82,7 +82,7 @@ export async function clickOn(element: Element, browser: Browser, clicks = 1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createFakeMousePointer(browser: Browser) {
|
export async function createFakeMousePointer(browser: Browser<'async'>) {
|
||||||
const js = 'window.demo.enableMouse();'
|
const js = 'window.demo.enableMouse();'
|
||||||
|
|
||||||
await browser.execute(js)
|
await browser.execute(js)
|
||||||
@@ -91,7 +91,7 @@ export async function createFakeMousePointer(browser: Browser) {
|
|||||||
export async function showText(
|
export async function showText(
|
||||||
text: string,
|
text: string,
|
||||||
duration: number = 0,
|
duration: number = 0,
|
||||||
browser: Browser,
|
browser: Browser<'async'>,
|
||||||
location: 'top' | 'bottom' | 'middle' = 'bottom',
|
location: 'top' | 'bottom' | 'middle' = 'bottom',
|
||||||
keys = []
|
keys = []
|
||||||
) {
|
) {
|
||||||
@@ -102,7 +102,7 @@ export async function showText(
|
|||||||
|
|
||||||
type HeapDump = any
|
type HeapDump = any
|
||||||
|
|
||||||
export async function getHeapDump(browser: Browser): Promise<HeapDump> {
|
export async function getHeapDump(browser: Browser<'async'>): Promise<HeapDump> {
|
||||||
const filename = 'heapdump.json'
|
const filename = 'heapdump.json'
|
||||||
const js = `window.demo.writeHeapdump('${filename}');`
|
const js = `window.demo.writeHeapdump('${filename}');`
|
||||||
await browser.execute(js)
|
await browser.execute(js)
|
||||||
@@ -125,7 +125,7 @@ export async function countInstancesOf(heapDump: HeapDump, className: ClassNameM
|
|||||||
export async function showKeys(
|
export async function showKeys(
|
||||||
text: string,
|
text: string,
|
||||||
duration: number = 0,
|
duration: number = 0,
|
||||||
browser: Browser,
|
browser: Browser<'async'>,
|
||||||
location: 'top' | 'bottom' | 'middle' = 'bottom',
|
location: 'top' | 'bottom' | 'middle' = 'bottom',
|
||||||
keys: Array<string> = []
|
keys: Array<string> = []
|
||||||
) {
|
) {
|
||||||
@@ -134,7 +134,7 @@ export async function showKeys(
|
|||||||
await browser.execute(js)
|
await browser.execute(js)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function hideText(browser: Browser) {
|
export async function hideText(browser: Browser<'async'>) {
|
||||||
const js = 'window.demo.hideMessage();'
|
const js = 'window.demo.hideMessage();'
|
||||||
await browser.execute(js)
|
await browser.execute(js)
|
||||||
await sleep(600)
|
await sleep(600)
|
||||||
|
|||||||
@@ -8,9 +8,15 @@
|
|||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"sourceRoot": "src/",
|
"sourceRoot": "src/",
|
||||||
"lib": ["es2017", "dom"],
|
"lib": [
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"types": ["node"]
|
"types": [
|
||||||
|
"node"
|
||||||
|
],
|
||||||
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/electron.ts",
|
"src/electron.ts",
|
||||||
@@ -18,5 +24,8 @@
|
|||||||
"src/spec/demoVideo.ts",
|
"src/spec/demoVideo.ts",
|
||||||
"src/spec/leakTest.ts",
|
"src/spec/leakTest.ts",
|
||||||
"scripts/*.ts"
|
"scripts/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user