Fix emitter leaks, style, tree swaps
This commit is contained in:
187
app/package-lock.json
generated
187
app/package-lock.json
generated
@@ -12,6 +12,11 @@
|
|||||||
"regenerator-runtime": "^0.12.0"
|
"regenerator-runtime": "^0.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@emotion/hash": {
|
||||||
|
"version": "0.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.1.tgz",
|
||||||
|
"integrity": "sha512-OYpa/Sg+2GDX+jibUfpZVn1YqSVRpYmTLF2eyAfrFTIJSbwyIrc+YscayoykvaOME/wV4BV0Sa0yqdMrgse6mA=="
|
||||||
|
},
|
||||||
"@fimbul/bifrost": {
|
"@fimbul/bifrost": {
|
||||||
"version": "0.17.0",
|
"version": "0.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/@fimbul/bifrost/-/bifrost-0.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@fimbul/bifrost/-/bifrost-0.17.0.tgz",
|
||||||
@@ -53,12 +58,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/core": {
|
"@material-ui/core": {
|
||||||
"version": "3.7.1",
|
"version": "3.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.9.0.tgz",
|
||||||
"integrity": "sha512-CjIGwvzn84BgzXWzC9M/Tz2gDI7AfUe3G1JXkZQAVy+ddPikh+iZwn5snnElfcjuC+ahXxaIyK49ARt3NM49vQ==",
|
"integrity": "sha512-9fxu0B9zx/TfiU0OJmwRFk+I+2J7fcXzTfQl+ZPxqlVRrPDqTHnMZlqWRJjlHCe3AVXlgpJ6/a4QCvGEohEbIQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "7.2.0",
|
"@babel/runtime": "^7.2.0",
|
||||||
"@material-ui/utils": "^3.0.0-alpha.1",
|
"@material-ui/system": "^3.0.0-alpha.0",
|
||||||
|
"@material-ui/utils": "^3.0.0-alpha.2",
|
||||||
"@types/jss": "^9.5.6",
|
"@types/jss": "^9.5.6",
|
||||||
"@types/react-transition-group": "^2.0.8",
|
"@types/react-transition-group": "^2.0.8",
|
||||||
"brcast": "^3.0.1",
|
"brcast": "^3.0.1",
|
||||||
@@ -127,17 +133,66 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/lab": {
|
"@material-ui/styles": {
|
||||||
"version": "3.0.0-alpha.27",
|
"version": "3.0.0-alpha.8",
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-3.0.0-alpha.27.tgz",
|
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-3.0.0-alpha.8.tgz",
|
||||||
"integrity": "sha512-VwUCXEJEo1QkSTDoAg5g8K51f6Re7Fh5d7m5IO9W95B9iEYVJhSGy+WY1/ZQdpJl1F1gPzL9u2asCg6LIazBLA==",
|
"integrity": "sha512-66X0fN9AmXexpnk8wWin2L0p4PzRvIP8Cy2pzXANrbfpHyTgDsURiGECRgv+cgtIBoAjqb/x+NxEE92RYFYFWQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "7.2.0",
|
"@babel/runtime": "^7.2.0",
|
||||||
|
"@emotion/hash": "^0.7.1",
|
||||||
"@material-ui/utils": "^3.0.0-alpha.2",
|
"@material-ui/utils": "^3.0.0-alpha.2",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"keycode": "^2.1.9",
|
"deepmerge": "^3.0.0",
|
||||||
"prop-types": "^15.6.0"
|
"hoist-non-react-statics": "^3.2.1",
|
||||||
|
"jss": "^10.0.0-alpha.7",
|
||||||
|
"jss-plugin-camel-case": "^10.0.0-alpha.7",
|
||||||
|
"jss-plugin-default-unit": "^10.0.0-alpha.7",
|
||||||
|
"jss-plugin-global": "^10.0.0-alpha.7",
|
||||||
|
"jss-plugin-nested": "^10.0.0-alpha.7",
|
||||||
|
"jss-plugin-props-sort": "^10.0.0-alpha.7",
|
||||||
|
"jss-plugin-rule-value-function": "^10.0.0-alpha.7",
|
||||||
|
"jss-plugin-vendor-prefixer": "^10.0.0-alpha.7",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"warning": "^4.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jss": {
|
||||||
|
"version": "10.0.0-alpha.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.8.tgz",
|
||||||
|
"integrity": "sha512-7cNQXMbJ5KQOgTJSaDPfLInBIaU5AD+FYg00PCl9i170NXj3M/CsoIWUMnTGbsWjcIQ7DmlqzrSFdsxSwzHjuA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"is-in-browser": "^1.1.3",
|
||||||
|
"symbol-observable": "^1.2.0",
|
||||||
|
"tiny-warning": "^1.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@material-ui/system": {
|
||||||
|
"version": "3.0.0-alpha.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-3.0.0-alpha.1.tgz",
|
||||||
|
"integrity": "sha512-5EihYa6Ct5mA/shfFSjWO8e/whV+otbXAduYfiL34GH+Mh4vZs+wjcy0P80XA/cDIwSgkQ7vTvvY1x04AgIz4w==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "7.1.2",
|
||||||
|
"deepmerge": "^2.0.1",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"warning": "^4.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==",
|
||||||
|
"requires": {
|
||||||
|
"regenerator-runtime": "^0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deepmerge": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/utils": {
|
"@material-ui/utils": {
|
||||||
@@ -1802,9 +1857,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"deepmerge": {
|
"deepmerge": {
|
||||||
"version": "3.0.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.1.0.tgz",
|
||||||
"integrity": "sha512-a8z8bkgHsAML+uHLqmMS83HHlpy3PvZOOuiTQqaa3wu8ZVg3h0hqHk6aCsGdOnZV2XMM/FRimNGjUh0KCcmHBw=="
|
"integrity": "sha512-/TnecbwXEdycfbsM2++O3eGiatEFHjjNciHEwJclM+T5Kd94qD1AP+2elP/Mq0L5b9VZJao5znR01Mz6eX8Seg=="
|
||||||
},
|
},
|
||||||
"default-gateway": {
|
"default-gateway": {
|
||||||
"version": "2.7.2",
|
"version": "2.7.2",
|
||||||
@@ -4206,6 +4261,75 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jss-plugin-camel-case": {
|
||||||
|
"version": "10.0.0-alpha.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.0-alpha.7.tgz",
|
||||||
|
"integrity": "sha512-Bwrav1ZB0XywdJW6TaEuFhKe1ZpZvUlESh3jsFOvebA9aFTYNCkmHMEqjA5+u9VMxksl3u77nnZHtukpxkzrBA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"hyphenate-style-name": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jss-plugin-default-unit": {
|
||||||
|
"version": "10.0.0-alpha.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.0-alpha.7.tgz",
|
||||||
|
"integrity": "sha512-auuJUbQaWMxoHOVFPrfZNZpZm9ab8PZeDyvey8nMt2lbokkmZ53UyAnM/1kNsg5BdAXTItcLDxDB3I4gwNU84g==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jss-plugin-global": {
|
||||||
|
"version": "10.0.0-alpha.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.0-alpha.7.tgz",
|
||||||
|
"integrity": "sha512-OWeoW4szLDgRUKviST+xfilqa8O5uXJCW+O3YonheCRTRJg6rRzlE/b5pfYPoU9UtwvY9n7JvwBX5r3c1lMsEQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jss-plugin-nested": {
|
||||||
|
"version": "10.0.0-alpha.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.0-alpha.7.tgz",
|
||||||
|
"integrity": "sha512-wsRzuIZXAc6WMjc61mREW9cUrDxgSI7dK/fx5c7a06IDUfSn+83NJ30J/RB4oBnbQW9SijV/muujz7IJqpn9Gw==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"tiny-warning": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jss-plugin-props-sort": {
|
||||||
|
"version": "10.0.0-alpha.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.0-alpha.7.tgz",
|
||||||
|
"integrity": "sha512-KXOCaHUk1+KXqE0z3q66/w1fDoy+VsZvI77gLxOqTsTrvIKFLX0jarwXogW3CDlaPQQFTZ6JykJJXtPRTBlstA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jss-plugin-rule-value-function": {
|
||||||
|
"version": "10.0.0-alpha.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.0-alpha.7.tgz",
|
||||||
|
"integrity": "sha512-ett83hvIM69/LknmrWndrrdiDlfLfP+rneU5qP7gTOWJ7g1P9GuEL1Tc4CWdZUWBX+T58tgIBP0V1pzWCkP0QA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jss-plugin-vendor-prefixer": {
|
||||||
|
"version": "10.0.0-alpha.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.0-alpha.7.tgz",
|
||||||
|
"integrity": "sha512-YbIVgqq+dLimOBOEYggho1Iuc0roz4PJSZYyaok9n8JnXVIqPnxYJbr8+bMbvzJ5CL3eeJij/e7L2IPCceRKrA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"css-vendor": "^1.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"css-vendor": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-pePyROdjdMRjHhGN+xZjBomaR9GXueNQ2ZLkEi0i2A/eVx0m4oCLglltdRsaYCSOpun0GRJWuqmWLIYj6Y/RVQ==",
|
||||||
|
"requires": {
|
||||||
|
"is-in-browser": "^1.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"jss-props-sort": {
|
"jss-props-sort": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz",
|
||||||
@@ -5588,15 +5712,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "16.7.0",
|
"version": "16.8.0-alpha.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-16.8.0-alpha.1.tgz",
|
||||||
"integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==",
|
"integrity": "sha512-vLwwnhM2dXrCsiQmcSxF2UdZVV5xsiXjK5Yetmy8dVqngJhQ3aw3YJhZN/YmyonxwdimH40wVqFQfsl4gSu2RA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"scheduler": "^0.12.0"
|
"scheduler": "^0.13.0-alpha.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"scheduler": {
|
||||||
|
"version": "0.13.0-alpha.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.0-alpha.1.tgz",
|
||||||
|
"integrity": "sha512-W0sH0848sVuPKg+I18vTYQyzVtA4X1lrVgSeXK6KnOPUltFdJcY5nkbTkjGUeS/E0x+eBsNYfSdhJtGjT95njw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.1.0",
|
||||||
|
"object-assign": "^4.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-ace": {
|
"react-ace": {
|
||||||
@@ -5718,9 +5854,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-transition-group": {
|
"react-transition-group": {
|
||||||
"version": "2.5.2",
|
"version": "2.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz",
|
||||||
"integrity": "sha512-vwHP++S+f6KL7rg8V1mfs62+MBKtbMeZDR8KiNmD7v98Gs3UPGsDZDahPJH2PVprFW5YHJfh6cbNim3zPndaSQ==",
|
"integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"dom-helpers": "^3.3.1",
|
"dom-helpers": "^3.3.1",
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
@@ -6949,6 +7085,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tiny-warning": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q=="
|
||||||
|
},
|
||||||
"to-array": {
|
"to-array": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
|
||||||
|
|||||||
@@ -10,14 +10,13 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@material-ui/icons": "^3.0.1",
|
"@material-ui/icons": "^3.0.1",
|
||||||
"@material-ui/lab": "^3.0.0-alpha.27",
|
|
||||||
"@types/react": "^16.7.18",
|
"@types/react": "^16.7.18",
|
||||||
"@types/react-dom": "^16.0.11",
|
"@types/react-dom": "^16.0.11",
|
||||||
"@types/react-redux": "^6.0.12",
|
"@types/react-redux": "^6.0.12",
|
||||||
"css-loader": "^2.1.0",
|
"css-loader": "^2.1.0",
|
||||||
"electron-nucleus": "^1.11.0",
|
"electron-nucleus": "^1.11.0",
|
||||||
"electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git",
|
"electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git",
|
||||||
"react": "^16.7.0",
|
"react": "^16.8.0-alpha.1",
|
||||||
"react-dom": "^16.7.0",
|
"react-dom": "^16.7.0",
|
||||||
"react-redux": "^6.0.0",
|
"react-redux": "^6.0.0",
|
||||||
"react-vis": "^1.11.6",
|
"react-vis": "^1.11.6",
|
||||||
@@ -27,7 +26,8 @@
|
|||||||
"webpack-livereload-plugin": "^2.2.0"
|
"webpack-livereload-plugin": "^2.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^3.7.1",
|
"@material-ui/core": "^3.9.0",
|
||||||
|
"@material-ui/styles": "^3.0.0-alpha.8",
|
||||||
"@types/node": "^10.12.18",
|
"@types/node": "^10.12.18",
|
||||||
"@types/react-resize-detector": "^3.1.0",
|
"@types/react-resize-detector": "^3.1.0",
|
||||||
"@types/sha1": "^1.1.1",
|
"@types/sha1": "^1.1.1",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import ErrorBoundary from './ErrorBoundary'
|
|||||||
interface Props {
|
interface Props {
|
||||||
name: string
|
name: string
|
||||||
connectionId: string
|
connectionId: string
|
||||||
theme: Theme
|
classes: any
|
||||||
settingsVisible: boolean
|
settingsVisible: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,32 +27,66 @@ class App extends React.Component<Props, {}> {
|
|||||||
this.state = { }
|
this.state = { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private getStyles(): {[s: string]: React.CSSProperties} {
|
public render() {
|
||||||
const { theme } = this.props
|
const { settingsVisible } = this.props
|
||||||
|
const { content, contentShift, centerContent, left, right } = this.props.classes
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={centerContent}>
|
||||||
|
<CssBaseline />
|
||||||
|
<ErrorBoundary>
|
||||||
|
<Settings />
|
||||||
|
<div className={settingsVisible ? contentShift : content}>
|
||||||
|
<TitleBar />
|
||||||
|
<div className={centerContent}>
|
||||||
|
<div className={this.props.classes.left}>
|
||||||
|
<Tree />
|
||||||
|
</div>
|
||||||
|
<div className={right}>
|
||||||
|
<Sidebar connectionId={this.props.connectionId} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<UpdateNotifier />
|
||||||
|
<Connection />
|
||||||
|
</ErrorBoundary>
|
||||||
|
</div >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state: AppState) => {
|
||||||
|
return {
|
||||||
|
settingsVisible: state.settings.visible,
|
||||||
|
connectionId: state.connection.connectionId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = (theme: Theme) => {
|
||||||
const drawerWidth = 300
|
const drawerWidth = 300
|
||||||
return {
|
return {
|
||||||
left: {
|
left: {
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
height: 'calc(100vh - 64px)',
|
height: 'calc(100vh - 64px)',
|
||||||
float: 'left',
|
float: 'left' as 'left',
|
||||||
overflowY: 'scroll',
|
overflowY: 'scroll' as 'scroll',
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden' as 'hidden',
|
||||||
display: 'block',
|
display: 'block' as 'block',
|
||||||
width: '60vw',
|
width: '60vw',
|
||||||
},
|
},
|
||||||
right: {
|
right: {
|
||||||
height: 'calc(100vh - 64px)',
|
height: 'calc(100vh - 64px)',
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
float: 'left',
|
float: 'left' as 'left',
|
||||||
width: '40vw',
|
width: '40vw',
|
||||||
overflowY: 'scroll',
|
overflowY: 'scroll' as 'scroll',
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden' as 'hidden',
|
||||||
display: 'block',
|
display: 'block' as 'block',
|
||||||
},
|
},
|
||||||
centerContent: {
|
centerContent: {
|
||||||
width: '100vw',
|
width: '100vw',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden' as 'hidden',
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
@@ -74,39 +108,4 @@ class App extends React.Component<Props, {}> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
export default withStyles(styles)(connect(mapStateToProps)(App))
|
||||||
const { settingsVisible } = this.props
|
|
||||||
const { content, contentShift, centerContent } = this.getStyles()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={centerContent}>
|
|
||||||
<CssBaseline />
|
|
||||||
<ErrorBoundary>
|
|
||||||
<Settings />
|
|
||||||
<div style={settingsVisible ? contentShift : content}>
|
|
||||||
<TitleBar />
|
|
||||||
<div style={centerContent}>
|
|
||||||
<div style={this.getStyles().left}>
|
|
||||||
<Tree />
|
|
||||||
</div>
|
|
||||||
<div style={this.getStyles().right}>
|
|
||||||
<Sidebar connectionId={this.props.connectionId} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<UpdateNotifier />
|
|
||||||
<Connection />
|
|
||||||
</ErrorBoundary>
|
|
||||||
</div >
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = (state: AppState) => {
|
|
||||||
return {
|
|
||||||
settingsVisible: state.settings.visible,
|
|
||||||
connectionId: state.connection.connectionId,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withStyles({}, { withTheme: true })(connect(mapStateToProps)(App))
|
|
||||||
|
|||||||
@@ -224,4 +224,4 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(styles, { withTheme: true })(connect(mapStateToProps, mapDispatchToProps)(UpdateNotifier))
|
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(UpdateNotifier))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Action, ActionTypes, TopicOrder } from '../reducers/Settings'
|
import { Action, ActionTypes, TopicOrder } from '../reducers/Settings'
|
||||||
import { ActionTypes as TreeActionTypes, Action as TreeAction } from '../reducers/Tree'
|
import { ActionTypes as TreeActionTypes } from '../reducers/Tree'
|
||||||
import { Dispatch } from 'redux'
|
import { Dispatch } from 'redux'
|
||||||
|
import { showTree } from './Tree'
|
||||||
import { AppState } from '../reducers'
|
import { AppState } from '../reducers'
|
||||||
import * as q from '../../../backend/src/Model'
|
import * as q from '../../../backend/src/Model'
|
||||||
|
|
||||||
@@ -38,17 +39,22 @@ export const filterTopics = (filterStr: string) => (dispatch: Dispatch<any>, get
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!topicFilter) {
|
if (!topicFilter) {
|
||||||
dispatch({
|
dispatch(showTree(tree))
|
||||||
tree,
|
|
||||||
filter: '',
|
|
||||||
type: TreeActionTypes.TREE_SHOW_TREE,
|
|
||||||
})
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nodeFilter = (node: q.TreeNode): boolean => {
|
||||||
|
const topicMatches = node.path().toLowerCase().indexOf(topicFilter) !== -1
|
||||||
|
if (topicMatches) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageMatches = (node.message && typeof node.message.value === 'string' && node.message.value.toLowerCase().indexOf(filterStr) !== -1)
|
||||||
|
return Boolean(messageMatches)
|
||||||
|
}
|
||||||
|
|
||||||
const resultTree = tree.leafes()
|
const resultTree = tree.leafes()
|
||||||
.filter(leaf => leaf.path().toLowerCase().indexOf(topicFilter) !== -1)
|
.filter(nodeFilter)
|
||||||
.map((node) => {
|
.map((node) => {
|
||||||
const clone = node.unconnectedClone()
|
const clone = node.unconnectedClone()
|
||||||
q.TreeNodeFactory.insertNodeAtPosition(node.path().split('/'), clone)
|
q.TreeNodeFactory.insertNodeAtPosition(node.path().split('/'), clone)
|
||||||
@@ -59,9 +65,10 @@ export const filterTopics = (filterStr: string) => (dispatch: Dispatch<any>, get
|
|||||||
return a
|
return a
|
||||||
}, new q.Tree())
|
}, new q.Tree())
|
||||||
|
|
||||||
dispatch({
|
const nextTree: q.Tree = resultTree as q.Tree
|
||||||
tree: resultTree,
|
if (tree.updateSource && tree.connectionId) {
|
||||||
filter: topicFilter,
|
nextTree.updateWithConnection(tree.updateSource, tree.connectionId, nodeFilter)
|
||||||
type: TreeActionTypes.TREE_SHOW_TREE,
|
}
|
||||||
})
|
|
||||||
|
dispatch(showTree(nextTree))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,17 @@ export const selectTopic = (topic: q.TreeNode) => (dispatch: Dispatch<any>, getS
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showTree = (tree?: q.Tree) => {
|
export const showTree = (tree?: q.Tree) => (dispatch: Dispatch<any>, getState: () => AppState) => {
|
||||||
return {
|
const visibleTree = getState().tree.tree
|
||||||
|
const connectionTree = getState().connection.tree
|
||||||
|
|
||||||
|
// Stop updates of old tree
|
||||||
|
if (visibleTree !== connectionTree && visibleTree) {
|
||||||
|
visibleTree.stopUpdating()
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
tree,
|
tree,
|
||||||
type: ActionTypes.TREE_SHOW_TREE,
|
type: ActionTypes.TREE_SHOW_TREE,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import { connectionActions } from '../../actions'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
classes: {[s: string]: string}
|
classes: {[s: string]: string}
|
||||||
theme: Theme
|
|
||||||
actions: typeof connectionActions,
|
actions: typeof connectionActions,
|
||||||
visible: boolean
|
visible: boolean
|
||||||
connected: boolean
|
connected: boolean
|
||||||
@@ -393,4 +392,4 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(Connection.styles, { withTheme: true })(Connection))
|
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(Connection.styles)(Connection))
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { bindActionCreators } from 'redux'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { settingsActions } from '../actions'
|
import { settingsActions } from '../actions'
|
||||||
import { TopicOrder } from '../reducers/Settings'
|
import { TopicOrder } from '../reducers/Settings'
|
||||||
import Topic from './Sidebar/Topic';
|
|
||||||
|
|
||||||
const styles: StyleRulesCallback = theme => ({
|
const styles: StyleRulesCallback = theme => ({
|
||||||
drawer: {
|
drawer: {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
|
|
||||||
import { Theme, withTheme } from '@material-ui/core/styles'
|
|
||||||
import BarChart from '@material-ui/icons/BarChart'
|
import BarChart from '@material-ui/icons/BarChart'
|
||||||
import DateFormatter from '../DateFormatter'
|
import DateFormatter from '../helper/DateFormatter'
|
||||||
import History from './History'
|
import History from './History'
|
||||||
import PlotHistory from './PlotHistory'
|
import PlotHistory from './PlotHistory'
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ const throttle = require('lodash.throttle')
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
node?: q.TreeNode
|
node?: q.TreeNode
|
||||||
theme: Theme
|
|
||||||
onSelect: (message: q.Message) => void
|
onSelect: (message: q.Message) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +33,7 @@ class MessageHistory extends React.Component<Props, State> {
|
|||||||
nextProps.node && nextProps.node.onMessage.subscribe(this.updateNode)
|
nextProps.node && nextProps.node.onMessage.subscribe(this.updateNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillMount() {
|
public componentDidMount() {
|
||||||
this.props.node && this.props.node.onMessage.subscribe(this.updateNode)
|
this.props.node && this.props.node.onMessage.subscribe(this.updateNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,4 +79,4 @@ class MessageHistory extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withTheme()(MessageHistory)
|
export default MessageHistory
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
const { XYPlot, XAxis, LineMarkSeries, Hint, YAxis, HorizontalGridLines, LineSeries } = require('react-vis')
|
const { XYPlot, XAxis, LineMarkSeries, Hint, YAxis, HorizontalGridLines, LineSeries } = require('react-vis')
|
||||||
import { default as ReactResizeDetector } from 'react-resize-detector'
|
import { default as ReactResizeDetector } from 'react-resize-detector'
|
||||||
|
|
||||||
import DateFormatter from '../DateFormatter'
|
import DateFormatter from '../helper/DateFormatter'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import { withStyles, Theme, StyleRulesCallback } from '@material-ui/core/styles'
|
|
||||||
import 'react-vis/dist/style.css'
|
import 'react-vis/dist/style.css'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -71,4 +70,4 @@ class PlotHistory extends React.Component<Props, Stats> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles({}, { withTheme: true })(PlotHistory)
|
export default PlotHistory
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ import {
|
|||||||
ExpansionPanelDetails,
|
ExpansionPanelDetails,
|
||||||
ExpansionPanelSummary,
|
ExpansionPanelSummary,
|
||||||
Fade,
|
Fade,
|
||||||
Fab,
|
|
||||||
Paper,
|
Paper,
|
||||||
Popper,
|
Popper,
|
||||||
Typography,
|
Typography,
|
||||||
IconButton,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@material-ui/core'
|
} from '@material-ui/core'
|
||||||
import { StyleRulesCallback, Theme, withStyles } from '@material-ui/core/styles'
|
import { StyleRulesCallback, Theme, withStyles } from '@material-ui/core/styles'
|
||||||
@@ -20,7 +18,7 @@ import { sidebarActons } from '../../actions'
|
|||||||
|
|
||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
import Copy from '../Copy'
|
import Copy from '../Copy'
|
||||||
import DateFormatter from '../DateFormatter'
|
import DateFormatter from '../helper/DateFormatter'
|
||||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
import ExpandMore from '@material-ui/icons/ExpandMore'
|
||||||
import Clear from '@material-ui/icons/Clear'
|
import Clear from '@material-ui/icons/Clear'
|
||||||
import MessageHistory from './MessageHistory'
|
import MessageHistory from './MessageHistory'
|
||||||
@@ -37,7 +35,6 @@ interface Props {
|
|||||||
node?: q.TreeNode,
|
node?: q.TreeNode,
|
||||||
actions: typeof sidebarActons,
|
actions: typeof sidebarActons,
|
||||||
classes: any,
|
classes: any,
|
||||||
theme: Theme,
|
|
||||||
connectionId?: string,
|
connectionId?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,22 +55,6 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
this.state = { node: new q.Tree() }
|
this.state = { node: new q.Tree() }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static styles: StyleRulesCallback<string> = (theme: Theme) => {
|
|
||||||
return {
|
|
||||||
drawer: {
|
|
||||||
display: 'block',
|
|
||||||
height: '100%',
|
|
||||||
},
|
|
||||||
valuePaper: {
|
|
||||||
margin: `${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px`,
|
|
||||||
},
|
|
||||||
heading: {
|
|
||||||
fontSize: theme.typography.pxToRem(15),
|
|
||||||
fontWeight: theme.typography.fontWeightRegular,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillReceiveProps(nextProps: Props) {
|
public componentWillReceiveProps(nextProps: Props) {
|
||||||
this.props.node && this.removeUpdateListener(this.props.node)
|
this.props.node && this.removeUpdateListener(this.props.node)
|
||||||
nextProps.node && this.registerUpdateListener(nextProps.node)
|
nextProps.node && this.registerUpdateListener(nextProps.node)
|
||||||
@@ -229,4 +210,20 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(Sidebar.styles, { withTheme: true })(connect(mapStateToProps, mapDispatchToProps)(Sidebar))
|
const styles: StyleRulesCallback<string> = (theme: Theme) => {
|
||||||
|
return {
|
||||||
|
drawer: {
|
||||||
|
display: 'block',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
valuePaper: {
|
||||||
|
margin: `${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px`,
|
||||||
|
},
|
||||||
|
heading: {
|
||||||
|
fontSize: theme.typography.pxToRem(15),
|
||||||
|
fontWeight: theme.typography.fontWeightRegular,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(Sidebar))
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
|
|
||||||
import { makeConnectionMessageEvent, rendererEvents, MqttMessage } from '../../../../events'
|
|
||||||
|
|
||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
import TreeNode from './TreeNode'
|
import TreeNode from './TreeNode'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
@@ -84,11 +82,11 @@ class Tree extends React.Component<Props, {}> {
|
|||||||
lineHeight: '1.1',
|
lineHeight: '1.1',
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
}
|
}
|
||||||
const key = `rootNode-${filter}`
|
|
||||||
return (
|
return (
|
||||||
<div style={style}>
|
<div style={style}>
|
||||||
<TreeNode
|
<TreeNode
|
||||||
key={key}
|
key={tree.hash()}
|
||||||
animateChages={true}
|
animateChages={true}
|
||||||
isRoot={true}
|
isRoot={true}
|
||||||
treeNode={tree}
|
treeNode={tree}
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ class TreeNode extends React.Component<Props, State> {
|
|||||||
private cssAnimationWasSetAt?: number
|
private cssAnimationWasSetAt?: number
|
||||||
|
|
||||||
private willUpdateTime: number = performance.now()
|
private willUpdateTime: number = performance.now()
|
||||||
private titleRef = React.createRef<HTMLDivElement>()
|
private titleRef?: React.RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>()
|
||||||
private topicSelectRef = React.createRef<HTMLDivElement>()
|
private topicSelectRef?: React.RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
private subnodesDidchange = () => {
|
private subnodesDidchange = () => {
|
||||||
this.dirtySubnodes = true
|
this.dirtySubnodes = true
|
||||||
@@ -90,18 +90,52 @@ class TreeNode extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private writeStats(what: string) {
|
||||||
|
const w: any = window
|
||||||
|
if (!w.stats) {
|
||||||
|
w.stats = {}
|
||||||
|
}
|
||||||
|
if (!w.stats[what]) {
|
||||||
|
w.stats[what] = 0
|
||||||
|
}
|
||||||
|
w.stats[what] += 1
|
||||||
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
const { treeNode } = this.props
|
const { treeNode } = this.props
|
||||||
|
this.addSubscriber(treeNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
private addSubscriber(treeNode: q.TreeNode) {
|
||||||
|
this.writeStats('subscribe')
|
||||||
treeNode.onMerge.subscribe(this.subnodesDidchange)
|
treeNode.onMerge.subscribe(this.subnodesDidchange)
|
||||||
treeNode.onEdgesChange.subscribe(this.edgesDidChange)
|
treeNode.onEdgesChange.subscribe(this.edgesDidChange)
|
||||||
treeNode.onMessage.subscribe(this.messageDidChange)
|
treeNode.onMessage.subscribe(this.messageDidChange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private removeSubscriber(treeNode: q.TreeNode) {
|
||||||
|
this.writeStats('unsubscribe')
|
||||||
|
treeNode.onMerge.unsubscribe(this.subnodesDidchange)
|
||||||
|
treeNode.onEdgesChange.unsubscribe(this.edgesDidChange)
|
||||||
|
treeNode.onMessage.unsubscribe(this.messageDidChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillReceiveProps(nextProps: Props) {
|
||||||
|
if (nextProps.treeNode !== this.props.treeNode) {
|
||||||
|
this.removeSubscriber(this.props.treeNode)
|
||||||
|
this.addSubscriber(nextProps.treeNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
|
this.writeStats('unsubscribe')
|
||||||
|
|
||||||
const { treeNode } = this.props
|
const { treeNode } = this.props
|
||||||
treeNode.onMerge.unsubscribe(this.subnodesDidchange)
|
treeNode.onMerge.unsubscribe(this.subnodesDidchange)
|
||||||
treeNode.onEdgesChange.unsubscribe(this.edgesDidChange)
|
treeNode.onEdgesChange.unsubscribe(this.edgesDidChange)
|
||||||
treeNode.onMessage.unsubscribe(this.messageDidChange)
|
treeNode.onMessage.unsubscribe(this.messageDidChange)
|
||||||
|
this.topicSelectRef = undefined
|
||||||
|
this.titleRef = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
private stateHasChanged(newState: State) {
|
private stateHasChanged(newState: State) {
|
||||||
@@ -189,20 +223,20 @@ class TreeNode extends React.Component<Props, State> {
|
|||||||
|
|
||||||
private mouseOver = (event: React.MouseEvent) => {
|
private mouseOver = (event: React.MouseEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
if (this.topicSelectRef.current) {
|
if (this.topicSelectRef && this.topicSelectRef.current) {
|
||||||
this.topicSelectRef.current.style.opacity = '1'
|
this.topicSelectRef.current.style.opacity = '1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private mouseOut = (event: React.MouseEvent) => {
|
private mouseOut = (event: React.MouseEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
if (this.topicSelectRef.current) {
|
if (this.topicSelectRef && this.topicSelectRef.current) {
|
||||||
this.topicSelectRef.current.style.opacity = '0'
|
this.topicSelectRef.current.style.opacity = '0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private didSelectNode = (event: React.MouseEvent) => {
|
private didSelectNode = (event: React.MouseEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
if (this.topicSelectRef.current) {
|
if (this.topicSelectRef && this.topicSelectRef.current) {
|
||||||
this.topicSelectRef.current.style.opacity = '1'
|
this.topicSelectRef.current.style.opacity = '1'
|
||||||
}
|
}
|
||||||
this.props.actions.selectTopic(this.props.treeNode)
|
this.props.actions.selectTopic(this.props.treeNode)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import * as React from 'react'
|
|||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
|
|
||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
import { Theme, withTheme } from '@material-ui/core/styles'
|
|
||||||
|
|
||||||
import TreeNode from './TreeNode'
|
import TreeNode from './TreeNode'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
@@ -14,9 +13,9 @@ export interface Props {
|
|||||||
animateChanges: boolean
|
animateChanges: boolean
|
||||||
treeNode: q.TreeNode
|
treeNode: q.TreeNode
|
||||||
autoExpandLimit: number
|
autoExpandLimit: number
|
||||||
|
filter?: string
|
||||||
collapsed?: boolean | undefined
|
collapsed?: boolean | undefined
|
||||||
didSelectNode?: (node: q.TreeNode) => void
|
didSelectNode?: (node: q.TreeNode) => void
|
||||||
theme: Theme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@@ -76,7 +75,7 @@ class TreeNodeSubnodes extends React.Component<Props, State> {
|
|||||||
|
|
||||||
const nodes = this.sortedNodes().slice(0, this.state.alreadyAdded)
|
const nodes = this.sortedNodes().slice(0, this.state.alreadyAdded)
|
||||||
const listItems = nodes.map(node => (
|
const listItems = nodes.map(node => (
|
||||||
<div key={node.hash()}>
|
<div key={`${node.hash()}-${this.props.filter}`}>
|
||||||
<TreeNode
|
<TreeNode
|
||||||
animateChages={this.props.animateChanges}
|
animateChages={this.props.animateChanges}
|
||||||
treeNode={node}
|
treeNode={node}
|
||||||
@@ -97,7 +96,8 @@ class TreeNodeSubnodes extends React.Component<Props, State> {
|
|||||||
const mapStateToProps = (state: AppState) => {
|
const mapStateToProps = (state: AppState) => {
|
||||||
return {
|
return {
|
||||||
topicOrder: state.settings.topicOrder,
|
topicOrder: state.settings.topicOrder,
|
||||||
|
filter: state.tree.filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withTheme()(connect(mapStateToProps)(TreeNodeSubnodes))
|
export default connect(mapStateToProps)(TreeNodeSubnodes)
|
||||||
|
|||||||
@@ -3,23 +3,20 @@ import { connect } from 'react-redux'
|
|||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { treeActions } from '../../actions'
|
import { treeActions } from '../../actions'
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import { withTheme, Theme } from '@material-ui/core/styles'
|
|
||||||
|
|
||||||
export interface TreeNodeProps extends React.HTMLAttributes<HTMLElement> {
|
export interface TreeNodeProps extends React.HTMLAttributes<HTMLElement> {
|
||||||
treeNode: q.TreeNode
|
treeNode: q.TreeNode
|
||||||
actions: any
|
actions: any
|
||||||
name?: string | undefined
|
name?: string | undefined
|
||||||
collapsed?: boolean | undefined
|
collapsed?: boolean | undefined
|
||||||
theme: Theme
|
|
||||||
lastUpdate: number
|
lastUpdate: number
|
||||||
}
|
}
|
||||||
|
|
||||||
class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
||||||
private getStyles() {
|
private getStyles() {
|
||||||
const { theme } = this.props
|
|
||||||
return {
|
return {
|
||||||
collapsedSubnodes: {
|
collapsedSubnodes: {
|
||||||
color: theme.palette.text.secondary,
|
color: 'white', // theme.palette.text.secondary,
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
display: 'block',
|
display: 'block',
|
||||||
@@ -97,4 +94,4 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withTheme()(connect(null, mapDispatchToProps)(TreeNodeTitle))
|
export default connect(null, mapDispatchToProps)(TreeNodeTitle)
|
||||||
|
|||||||
11
app/src/reducers/Theme.ts
Normal file
11
app/src/reducers/Theme.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { createReducer } from './lib'
|
||||||
|
import { createMuiTheme, Theme } from '@material-ui/core'
|
||||||
|
|
||||||
|
const initialState: Theme = createMuiTheme({
|
||||||
|
palette: {
|
||||||
|
type: 'dark',
|
||||||
|
},
|
||||||
|
typography: { useNextVariants: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
export const theme = createReducer(initialState, {})
|
||||||
@@ -7,6 +7,7 @@ import { PublishState, publishReducer } from './Publish'
|
|||||||
import { ConnectionState, connectionReducer } from './Connection'
|
import { ConnectionState, connectionReducer } from './Connection'
|
||||||
import { SettingsState, settingsReducer } from './Settings'
|
import { SettingsState, settingsReducer } from './Settings'
|
||||||
import { TreeState, treeReducer } from './Tree'
|
import { TreeState, treeReducer } from './Tree'
|
||||||
|
import { theme } from './theme'
|
||||||
|
|
||||||
export enum ActionTypes {
|
export enum ActionTypes {
|
||||||
showUpdateNotification = 'SHOW_UPDATE_NOTIFICATION',
|
showUpdateNotification = 'SHOW_UPDATE_NOTIFICATION',
|
||||||
@@ -64,6 +65,7 @@ const tooBigReducer: Reducer<TooBigOfState | undefined, CustomAction> = (state =
|
|||||||
}
|
}
|
||||||
|
|
||||||
const reducer = combineReducers({
|
const reducer = combineReducers({
|
||||||
|
theme,
|
||||||
tooBigReducer,
|
tooBigReducer,
|
||||||
publish: publishReducer,
|
publish: publishReducer,
|
||||||
connection: connectionReducer,
|
connection: connectionReducer,
|
||||||
|
|||||||
@@ -18,7 +18,14 @@ export class Edge implements Hashable {
|
|||||||
|
|
||||||
public hash(): string {
|
public hash(): string {
|
||||||
if (!this.cachedHash) {
|
if (!this.cachedHash) {
|
||||||
const previousHash = (this.source && this.source.sourceEdge) ? this.source.sourceEdge.hash() : ''
|
let previousHash
|
||||||
|
if (this.source && this.source.sourceEdge) {
|
||||||
|
previousHash = this.source.sourceEdge.hash()
|
||||||
|
} else {
|
||||||
|
// Use the tree hash to distinguish between different trees
|
||||||
|
previousHash = this.source && this.source.isTree ? (this.source as any).hash() : ''
|
||||||
|
}
|
||||||
|
|
||||||
this.cachedHash = `H${sha1(previousHash + this.name)}`
|
this.cachedHash = `H${sha1(previousHash + this.name)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,27 +3,45 @@ import { EventBusInterface, makeConnectionMessageEvent, MqttMessage } from '../.
|
|||||||
import { TreeNodeFactory } from './TreeNodeFactory'
|
import { TreeNodeFactory } from './TreeNodeFactory'
|
||||||
|
|
||||||
export class Tree extends TreeNode {
|
export class Tree extends TreeNode {
|
||||||
private connectionId?: string
|
public connectionId?: string
|
||||||
private updateSource?: EventBusInterface
|
public updateSource?: EventBusInterface
|
||||||
|
public nodeFilter?: (node: TreeNode) => boolean
|
||||||
|
private subscriptionEvent?: any
|
||||||
|
public isTree = true
|
||||||
|
private cachedHash = `${Math.random()}`
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(undefined, undefined)
|
super(undefined, undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateWithConnection(emitter: EventBusInterface, connectionId: string) {
|
public updateWithConnection(emitter: EventBusInterface, connectionId: string, nodeFilter?:(node: TreeNode) => boolean) {
|
||||||
this.updateSource = emitter
|
this.updateSource = emitter
|
||||||
this.updateSource.subscribe(makeConnectionMessageEvent(connectionId), this.handleNewData)
|
this.connectionId = connectionId
|
||||||
|
this.nodeFilter = nodeFilter
|
||||||
|
|
||||||
|
this.subscriptionEvent = makeConnectionMessageEvent(connectionId)
|
||||||
|
this.updateSource.subscribe(this.subscriptionEvent, this.handleNewData)
|
||||||
|
}
|
||||||
|
|
||||||
|
public hash() {
|
||||||
|
return this.cachedHash
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleNewData = (msg: MqttMessage) => {
|
private handleNewData = (msg: MqttMessage) => {
|
||||||
const edges = msg.topic.split('/')
|
const edges = msg.topic.split('/')
|
||||||
const node = TreeNodeFactory.fromEdgesAndValue(edges, msg.payload)
|
const node = TreeNodeFactory.fromEdgesAndValue(edges, msg.payload)
|
||||||
node.mqttMessage = msg
|
node.mqttMessage = msg
|
||||||
|
|
||||||
|
if (this.nodeFilter && !this.nodeFilter(node)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.updateWithNode(node.firstNode())
|
this.updateWithNode(node.firstNode())
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopUpdating() {
|
public stopUpdating() {
|
||||||
if (this.updateSource && this.connectionId) {
|
if (this.subscriptionEvent && this.updateSource) {
|
||||||
this.updateSource.unsubscribeAll(makeConnectionMessageEvent(this.connectionId))
|
console.log(this.updateSource.ipc)
|
||||||
|
this.updateSource.unsubscribe(this.subscriptionEvent, this.handleNewData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export class TreeNode {
|
|||||||
public onMerge = new EventDispatcher<void, TreeNode>(this)
|
public onMerge = new EventDispatcher<void, TreeNode>(this)
|
||||||
public onEdgesChange = new EventDispatcher<void, TreeNode>(this)
|
public onEdgesChange = new EventDispatcher<void, TreeNode>(this)
|
||||||
public onMessage = new EventDispatcher<Message, TreeNode>(this)
|
public onMessage = new EventDispatcher<Message, TreeNode>(this)
|
||||||
|
public isTree = false
|
||||||
private cachedLeafes?: TreeNode[]
|
private cachedLeafes?: TreeNode[]
|
||||||
private cachedLeafMessageCount?: number
|
private cachedLeafMessageCount?: number
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ export interface EventBusInterface {
|
|||||||
subscribe<MessageType>(event: Event<MessageType>, callback:(msg: MessageType) => void): void
|
subscribe<MessageType>(event: Event<MessageType>, callback:(msg: MessageType) => void): void
|
||||||
unsubscribeAll<MessageType>(event: Event<MessageType>): void
|
unsubscribeAll<MessageType>(event: Event<MessageType>): void
|
||||||
emit<MessageType>(event: Event<MessageType>, msg: MessageType): void
|
emit<MessageType>(event: Event<MessageType>, msg: MessageType): void
|
||||||
|
unsubscribe<MessageType>(event: Event<MessageType>, callback: any): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CallbackStore {
|
||||||
|
wrappedCallback: any
|
||||||
|
callback: any
|
||||||
}
|
}
|
||||||
|
|
||||||
class IpcMainEventBus implements EventBusInterface {
|
class IpcMainEventBus implements EventBusInterface {
|
||||||
@@ -27,6 +33,10 @@ class IpcMainEventBus implements EventBusInterface {
|
|||||||
this.ipc.removeAllListeners(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) {
|
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
||||||
if (!this.client.isDestroyed()) {
|
if (!this.client.isDestroyed()) {
|
||||||
this.client.send(event.topic, msg)
|
this.client.send(event.topic, msg)
|
||||||
@@ -36,18 +46,40 @@ class IpcMainEventBus implements EventBusInterface {
|
|||||||
|
|
||||||
class IpcRendererEventBus implements EventBusInterface {
|
class IpcRendererEventBus implements EventBusInterface {
|
||||||
private ipc: IpcRenderer
|
private ipc: IpcRenderer
|
||||||
|
private callbacks: 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) {
|
||||||
this.ipc.on(event.topic, (_event: any, arg: any) => callback(arg))
|
const wrappedCallback = (_event: any, arg: any) => {
|
||||||
|
callback(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ipc.on(event.topic, wrappedCallback)
|
||||||
|
|
||||||
|
this.callbacks.push({
|
||||||
|
callback,
|
||||||
|
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) {
|
||||||
|
debugger
|
||||||
|
const item = this.callbacks.find(store => store.callback === callback)
|
||||||
|
if (!item) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ipc.removeListener(event.topic, item.wrappedCallback)
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user