Re-writes diagnostics UI using React

Re-writes diagnostics UI using React

The existing Ember app was using a 5 year old Ember release, and I am far more comfortable with React in order to further build out this functionality.

From 0fe0124269f80c8305860287897c6595ce9c6139 Mon Sep 17 00:00:00 2001
From: Ben Langfeld <blangfeld@powerhrg.com>
Date: Thu, 6 Dec 2018 18:35:50 -0200
Subject: [PATCH] Re-writes diagnostics UI using React

The existing Ember app was using a 5 year old Ember release, and I am far more comfortable with React in order to further build out this functionality.

diff --git a/CHANGELOG b/CHANGELOG
index 4f0d22f..563052c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+Unreleased
+
+- Re-wrote diagnostics UI using React
+
 30-11-2018
 
 - Version 2.2.0.pre.1
diff --git a/assets/application.handlebars b/assets/application.handlebars
deleted file mode 100644
index 19525f1..0000000
--- a/assets/application.handlebars
+++ /dev/null
@@ -1,7 +0,0 @@
-<header>
-  <h2>Message Bus Diagnostics<h2>
-</header>
-
-<div>
-  {{outlet}}
-</div>
diff --git a/assets/application.js b/assets/application.js
deleted file mode 100644
index f2181e6..0000000
--- a/assets/application.js
+++ /dev/null
@@ -1,79 +0,0 @@
-
-window.App = Ember.Application.createWithMixins({
-  start: function(){
-    MessageBus.start();
-  }
-});
-
-window.App.start();
-
-App.IndexRoute = Ember.Route.extend({
-  setupController: function(controller) {
-    model =  App.IndexModel.create();
-    model.ensureSubscribed();
-    controller.set('content', model);
-  }
-});
-
-App.IndexView = Ember.View.extend({});
-
-App.Process = Ember.View.extend({
-  uniqueId: function(){
-    return this.get('hostname') + this.get('pid');
-  }.property('hostname', 'pid'),
-
-  hup: function(){
-    $.post("/message-bus/_diagnostics/hup/" + this.get('hostname') + "/" + this.get('pid'));
-  }
-});
-
-App.IndexModel = Ember.Object.extend({
-  disabled: function(){
-    return this.get("discovering") ? "disabled" : null;
-  }.property("discovering"),
-
-  ensureSubscribed: function() {
-    var processes;
-    var _this = this;
-    if(this.get("subscribed")) { return; }
-
-    MessageBus.callbackInterval = 500;
-    MessageBus.subscribe("/_diagnostics/process-discovery", function(data){
-      processes = _this.get('processes');
-      processes.pushObject(App.Process.create(data));
-      processes = processes.sort(function(a,b){
-        return a.get('uniqueId') < b.get('uniqueId') ? -1 : 1;
-      });
-      // somewhat odd ...
-      _this.set('processes', null);
-      _this.set('processes', processes);
-    });
-
-    this.set("subscribed", true);
-  },
-
-  discover: function(){
-    var _this = this;
-    this.set('processes', Em.A());
-
-    this.ensureSubscribed();
-
-    this.set("discovering", true);
-    Ember.run.later(function(){
-      _this.set("discovering", false);
-    }, 1 * 1000);
-
-    $.post("/message-bus/_diagnostics/discover");
-  }
-});
-
-
-App.IndexController = Ember.ObjectController.extend({
-  discover: function(){
-    this.get("content").discover();
-  },
-
-  hup: function(process) {
-    process.hup();
-  }
-});
diff --git a/assets/application.jsx b/assets/application.jsx
new file mode 100644
index 0000000..d33625a
--- /dev/null
+++ b/assets/application.jsx
@@ -0,0 +1,121 @@
+'use strict';
+
+class Process extends React.Component {
+  hup() {
+    fetch(
+      `/message-bus/_diagnostics/hup/${this.props.hostname}/${this.props.pid}`,
+      {
+        method: 'POST'
+      }
+    );
+  }
+
+  render() {
+    return (
+      <tr>
+        <td>{this.props.pid}</td>
+        <td>{this.props.full_path}</td>
+        <td>{this.props.hostname}</td>
+        <td>{this.props.uptime} secs</td>
+        <td><button onClick={this.hup.bind(this)}>HUP</button></td>
+      </tr>
+    );
+  }
+};
+
+class DiagnosticsApp extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {processes: []};
+  }
+
+  componentDidMount() {
+    MessageBus.start();
+    this.ensureSubscribed();
+  }
+
+  discover() {
+    this.ensureSubscribed();
+
+    this.setState({discovering: true});
+
+    var _this = this;
+    fetch(
+      "/message-bus/_diagnostics/discover",
+      {
+        method: "POST"
+      }
+    ).then(function() {
+      _this.setState({discovering: false})
+    });
+  }
+
+  ensureSubscribed() {
+    if (this.state.subscribed) { return; }
+
+    MessageBus.callbackInterval = 500;
+
+    MessageBus.subscribe(
+      "/_diagnostics/process-discovery",
+      this.updateProcess.bind(this)
+    );
+
+    this.setState({subscribed: true});
+  }
+
+  updateProcess(data) {
+    const _this = this;
+    const processes = this.state.processes.filter(function(process) {
+      return _this.processUniqueId(process) !== _this.processUniqueId(data);
+    });
+    this.setState({processes: processes.concat([data])});
+  }
+
+  processUniqueId(process) {
+    return process.hostname + process.pid;
+  }
+
+  render() {
+    let disabled = this.state.discovering ? "disabled" : null;
+
+    let _this = this;
+    let processes = this.state.processes.sort(function(a,b) {
+      return _this.processUniqueId(a) < _this.processUniqueId(b) ? -1 : 1;
+    });
+
+    return (
+      <div>
+        <header>
+          <h2>Message Bus Diagnostics</h2>
+        </header>
+
+        <div>
+          <button onClick={this.discover.bind(this)} disabled={disabled}>Discover Processes</button>
+
+          <table>
+            <thead>
+              <tr>
+                <td>pid</td>
+                <td>full_path</td>
+                <td>hostname</td>
+                <td>uptime</td>
+                <td></td>
+              </tr>
+            </thead>
+
+            <tbody>
+              {processes.map(function(process, index){
+                return <Process key={index} {...process} />;
+              })}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    );
+  }
+}
+
+ReactDOM.render(
+  <DiagnosticsApp />,
+  document.getElementById('app')
+);
diff --git a/assets/babel.min.js b/assets/babel.min.js
new file mode 100644
index 0000000..1075776
--- /dev/null
+++ b/assets/babel.min.js
@@ -0,0 +1,25 @@
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Babel=t():e.Babel=t()}(this,function(){return function(e){function t(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return e[n].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var r=t.slice(1),n=e[t[0]];return function(e,t,i){n.apply(this,[e,t,i].concat(r))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,r){"use strict";function n(e,t){return g(t)&&"string"==typeof t[0]?e.hasOwnProperty(t[0])?[e[t[0]]].concat(t.slice(1)):void 0:"string"==typeof t?e[t]:t}function i(e){var t=(e.presets||[]).map(function(e){var t=n(E,e);if(!t)throw new Error('Invalid preset specified in Babel options: "'+e+'"');return g(t)&&"object"===h(t[0])&&t[0].hasOwnProperty("buildPreset")&&(t[0]=d({},t[0],{buildPreset:t[0].buildPreset})),t}),r=(e.plugins||[]).map(function(e){var t=n(b,e);if(!t)throw new Error('Invalid plugin specified in Babel options: "'+e+'"');return t});return d({babelrc:!1},e,{presets:t,plugins:r})}function s(e,t){return y.transform(e,i(t))}function a(e,t,r){return y.transformFromAst(e,t,i(r))}function o(e,t){b.hasOwnProperty(e)&&console.warn('A plugin named "'+e+'" is already registered, it will be overridden'),b[e]=t}function u(e){Object.keys(e).forEach(function(t){return o(t,e[t])})}function l(e,t){E.hasOwnProperty(e)&&console.warn('A preset named "'+e+'" is already registered, it will be overridden'),E[e]=t}function c(e){Object.keys(e).forEach(function(t){return l(t,e[t])})}function f(e){(0,v.runScripts)(s,e)}function p(){window.removeEventListener("DOMContentLoaded",f)}Object.defineProperty(t,"__esModule",{value:!0}),t.version=t.buildExternalHelpers=t.availablePresets=t.availablePlugins=void

GitHub

1 Like