Pārlūkot izejas kodu

Merge pull request #13264 from GordonSmith/REACT

HPCC-23316 Add React Support

Reviewed-By: Kunal Aswani <kunal.aswani@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 5 gadi atpakaļ
vecāks
revīzija
c28d73d31a

+ 3 - 0
esp/src/CMakeLists.txt

@@ -209,6 +209,9 @@ set ( SRCS
     ${CMAKE_CURRENT_SOURCE_DIR}/src/DataPatterns/PopularPatterns.ts
     ${CMAKE_CURRENT_SOURCE_DIR}/src/DataPatterns/Report.ts
     ${CMAKE_CURRENT_SOURCE_DIR}/src/DataPatterns/StatChart.ts
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/react/index.ts
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/react/render.ts
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/react/wuStatus.tsx
     ${CMAKE_CURRENT_SOURCE_DIR}/src/UserPreferences/EnvironmentTheme.ts
     ${CMAKE_CURRENT_SOURCE_DIR}/src/Clippy.ts
     ${CMAKE_CURRENT_SOURCE_DIR}/src/CodeMirror.ts

+ 5 - 12
esp/src/eclwatch/WUDetailsWidget.js

@@ -10,6 +10,7 @@ define([
     "dijit/registry",
 
     "src/Clippy",
+    "src/react/index",
 
     "hpcc/_TabContainerWidget",
     "src/ESPWorkunit",
@@ -17,8 +18,6 @@ define([
     "src/ESPRequest",
     "src/WsWorkunits",
 
-    "src/WUStatus",
-
     "dojo/text!../templates/WUDetailsWidget.html",
 
     "hpcc/DelayLoadWidget",
@@ -46,8 +45,8 @@ define([
 ], function (declare, lang, i18n, nlsHPCC, dom, domAttr, domClass,
     registry,
     Clippy,
+    srcReact,
     _TabContainerWidget, ESPWorkunit, ESPActivity, ESPRequest, WsWorkunits,
-    WUStatusModule,
     template) {
     return declare("WUDetailsWidget", [_TabContainerWidget], {
         templateString: template,
@@ -120,9 +119,6 @@ define([
             Clippy.attach(this.id + "ClippyButton");
             Clippy.attach(this.id + "ShareWUClippy");
 
-            this.wuStatus = new WUStatusModule.WUStatus()
-                .baseUrl("")
-                ;
         },
 
         startup: function (args) {
@@ -131,6 +127,7 @@ define([
         },
 
         destroy: function (args) {
+            srcReact.unrender(this.statusNode);
             this.zapDialog.destroyRecursive();
             this.inherited(arguments);
         },
@@ -175,7 +172,6 @@ define([
         _onAutoRefresh: function (event) {
             var autoRefresh = this.widget.AutoRefresh.get("checked");
             this.wu.disableMonitor(!autoRefresh);
-            this.wuStatus.disableMonitor(!autoRefresh);
         },
         _onRefresh: function (event) {
             this.wu.refresh(true);
@@ -316,11 +312,8 @@ define([
             this.infoGridWidget.init(params);
             this.checkIfClustersAllowed();
             this.checkThorLogStatus();
-            this.wuStatus
-                .target(this.id + "WUStatus")
-                .wuid(params.Wuid)
-                .lazyRender()
-                ;
+            this.statusNode = dom.byId(this.id + "WUStatus");
+            srcReact.render(srcReact.WUStatus, { wuid: params.Wuid }, this.statusNode);
 
             this.protected.on("change", function (evt) {
                 context._onSave();

+ 323 - 4
esp/src/package-lock.json

@@ -24,6 +24,26 @@
         "js-tokens": "^4.0.0"
       }
     },
+    "@babel/runtime": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz",
+      "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==",
+      "requires": {
+        "regenerator-runtime": "^0.13.2"
+      },
+      "dependencies": {
+        "regenerator-runtime": {
+          "version": "0.13.3",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
+          "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
+        }
+      }
+    },
+    "@emotion/hash": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.4.tgz",
+      "integrity": "sha512-fxfMSBMX3tlIbKUdtGKxqB1fyrH6gVrX39Gsv3y8lRYKUqlgDt3UMqQyGnR1bQMa2B8aGnhLZokZgg8vT0Le+A=="
+    },
     "@hpcc-js/api": {
       "version": "2.8.6",
       "resolved": "https://registry.npmjs.org/@hpcc-js/api/-/api-2.8.6.tgz",
@@ -268,6 +288,78 @@
         "vary": "^1.1.2"
       }
     },
+    "@material-ui/core": {
+      "version": "4.8.3",
+      "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.8.3.tgz",
+      "integrity": "sha512-ZJbfJQmkuZCSQTf0nzpfZwizmDdCq8ruZxnPNFnhoKDqgJpMvV8TJRi8vdI9ls1tMuTqxlhyhw8556fxOpWpFQ==",
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/styles": "^4.8.2",
+        "@material-ui/system": "^4.7.1",
+        "@material-ui/types": "^4.1.1",
+        "@material-ui/utils": "^4.7.1",
+        "@types/react-transition-group": "^4.2.0",
+        "clsx": "^1.0.2",
+        "convert-css-length": "^2.0.1",
+        "hoist-non-react-statics": "^3.2.1",
+        "normalize-scroll-left": "^0.2.0",
+        "popper.js": "^1.14.1",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0",
+        "react-transition-group": "^4.3.0"
+      }
+    },
+    "@material-ui/styles": {
+      "version": "4.8.2",
+      "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.8.2.tgz",
+      "integrity": "sha512-r5U+93pkpwQOmHTmwyn2sqTio6PHd873xvSHiKP6fdybAXXX6CZgVvh3W8saZNbYr/QXsS8OHmFv7sYJLt5Yfg==",
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@emotion/hash": "^0.7.4",
+        "@material-ui/types": "^4.1.1",
+        "@material-ui/utils": "^4.7.1",
+        "clsx": "^1.0.2",
+        "csstype": "^2.5.2",
+        "hoist-non-react-statics": "^3.2.1",
+        "jss": "^10.0.0",
+        "jss-plugin-camel-case": "^10.0.0",
+        "jss-plugin-default-unit": "^10.0.0",
+        "jss-plugin-global": "^10.0.0",
+        "jss-plugin-nested": "^10.0.0",
+        "jss-plugin-props-sort": "^10.0.0",
+        "jss-plugin-rule-value-function": "^10.0.0",
+        "jss-plugin-vendor-prefixer": "^10.0.0",
+        "prop-types": "^15.7.2"
+      }
+    },
+    "@material-ui/system": {
+      "version": "4.7.1",
+      "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.7.1.tgz",
+      "integrity": "sha512-zH02p+FOimXLSKOW/OT2laYkl9bB3dD1AvnZqsHYoseUaq0aVrpbl2BGjQi+vJ5lg8w73uYlt9zOWzb3+1UdMQ==",
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/utils": "^4.7.1",
+        "prop-types": "^15.7.2"
+      }
+    },
+    "@material-ui/types": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-4.1.1.tgz",
+      "integrity": "sha512-AN+GZNXytX9yxGi0JOfxHrRTbhFybjUJ05rnsBVjcB+16e466Z0Xe5IxawuOayVZgTBNDxmPKo5j4V6OnMtaSQ==",
+      "requires": {
+        "@types/react": "*"
+      }
+    },
+    "@material-ui/utils": {
+      "version": "4.7.1",
+      "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.7.1.tgz",
+      "integrity": "sha512-+ux0SlLdlehvzCk2zdQ3KiS3/ylWvuo/JwAGhvb8dFVvwR21K28z0PU9OQW2PGogrMEdvX3miEI5tGxTwwWiwQ==",
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0"
+      }
+    },
     "@types/d3-array": {
       "version": "1.2.6",
       "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.6.tgz",
@@ -386,6 +478,28 @@
         "@types/geojson": "*"
       }
     },
+    "@types/prop-types": {
+      "version": "15.7.3",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
+      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
+    },
+    "@types/react": {
+      "version": "16.9.17",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.17.tgz",
+      "integrity": "sha512-UP27In4fp4sWF5JgyV6pwVPAQM83Fj76JOcg02X5BZcpSu5Wx+fP9RMqc2v0ssBoQIFvD5JdKY41gjJJKmw6Bg==",
+      "requires": {
+        "@types/prop-types": "*",
+        "csstype": "^2.2.0"
+      }
+    },
+    "@types/react-transition-group": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.3.tgz",
+      "integrity": "sha512-Hk8jiuT7iLOHrcjKP/ZVSyCNXK73wJAUz60xm0mVhiRujrdiI++j4duLiL282VGxwAgxetHQFfqA29LgEeSkFA==",
+      "requires": {
+        "@types/react": "*"
+      }
+    },
     "@webassemblyjs/ast": {
       "version": "1.8.5",
       "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
@@ -1342,6 +1456,11 @@
         "wrap-ansi": "^5.1.0"
       }
     },
+    "clsx": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.0.4.tgz",
+      "integrity": "sha512-1mQ557MIZTrL/140j+JVdRM6e31/OA4vTYxXgqIIZlndyfjHpyawKZia1Im05Vp9BWmImkcNrNtFYQMyFcgJDg=="
+    },
     "co": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -1525,6 +1644,11 @@
       "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
       "dev": true
     },
+    "convert-css-length": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/convert-css-length/-/convert-css-length-2.0.1.tgz",
+      "integrity": "sha512-iGpbcvhLPRKUbBc0Quxx7w/bV14AC3ItuBEGMahA5WTYqB8lq9jH0kTXFheCBASsYnqeMFZhiTruNxr1N59Axg=="
+    },
     "cookies": {
       "version": "0.7.3",
       "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.3.tgz",
@@ -1794,12 +1918,26 @@
         }
       }
     },
+    "css-vendor": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.7.tgz",
+      "integrity": "sha512-VS9Rjt79+p7M0WkPqcAza4Yq1ZHrsHrwf7hPL/bjQB+c1lwmAI+1FXxYTYt818D/50fFVflw0XKleiBN5RITkg==",
+      "requires": {
+        "@babel/runtime": "^7.6.2",
+        "is-in-browser": "^1.0.2"
+      }
+    },
     "cssesc": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
       "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
       "dev": true
     },
+    "csstype": {
+      "version": "2.6.8",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.8.tgz",
+      "integrity": "sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA=="
+    },
     "cyclist": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
@@ -2042,6 +2180,15 @@
         "dojo": "1.16.0"
       }
     },
+    "dom-helpers": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.3.tgz",
+      "integrity": "sha512-nZD1OtwfWGRBWlpANxacBEZrEuLa16o1nh7YopFWeoF68Zt8GGEmzHu6Xv4F3XaFIC+YXtTLrzgqKxFgLEe4jw==",
+      "requires": {
+        "@babel/runtime": "^7.6.3",
+        "csstype": "^2.6.7"
+      }
+    },
     "dom-serializer": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
@@ -3692,6 +3839,14 @@
         "minimalistic-crypto-utils": "^1.0.1"
       }
     },
+    "hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw==",
+      "requires": {
+        "react-is": "^16.7.0"
+      }
+    },
     "homedir-polyfill": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
@@ -3803,6 +3958,11 @@
         "debug": "^3.1.0"
       }
     },
+    "hyphenate-style-name": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz",
+      "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ=="
+    },
     "iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -4025,6 +4185,11 @@
         "is-extglob": "^1.0.0"
       }
     },
+    "is-in-browser": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
+      "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU="
+    },
     "is-number": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
@@ -4123,8 +4288,7 @@
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
     },
     "js-yaml": {
       "version": "3.13.1",
@@ -4198,6 +4362,83 @@
       "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
       "dev": true
     },
+    "jss": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.3.tgz",
+      "integrity": "sha512-AcDvFdOk16If9qvC9KN3oFXsrkHWM9+TaPMpVB9orm3z+nq1Xw3ofHyflRe/mkSucRZnaQtlhZs1hdP3DR9uRw==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "csstype": "^2.6.5",
+        "is-in-browser": "^1.1.3",
+        "tiny-warning": "^1.0.2"
+      }
+    },
+    "jss-plugin-camel-case": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.3.tgz",
+      "integrity": "sha512-rild/oFKFkmRP7AoiX9D6bdDAUfmJv8c7sEBvFoi+JP31dn2W8nw4txMKGnV1LJKlFkYprdZt1X99Uvztl1hug==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "hyphenate-style-name": "^1.0.3",
+        "jss": "^10.0.3"
+      }
+    },
+    "jss-plugin-default-unit": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.3.tgz",
+      "integrity": "sha512-n+XfVLPF9Qh7IOTdQ8M4oRpjpg6egjr/r0NNytubbCafMgCILJYIVrMTGgOTydH+uvak8onQY3f/F9hasPUx6g==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "jss": "^10.0.3"
+      }
+    },
+    "jss-plugin-global": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.3.tgz",
+      "integrity": "sha512-kNotkAciJIXpIGYnmueaIifBne9rdq31O8Xq1nF7KMfKlskNRANTcEX5rVnsGKl2yubTMYfjKBFCeDgcQn6+gA==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "jss": "^10.0.3"
+      }
+    },
+    "jss-plugin-nested": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.3.tgz",
+      "integrity": "sha512-OMucRs9YLvWlZ3Ew+VhdgNVMwSS2zZy/2vy+s/etvopnPUzDHgCnJwdY2Wx/SlhLGERJeKKufyih2seH+ui0iw==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "jss": "^10.0.3",
+        "tiny-warning": "^1.0.2"
+      }
+    },
+    "jss-plugin-props-sort": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.3.tgz",
+      "integrity": "sha512-ufhvdCMnRcDa0tNHoZ12OcVNQQyE10yLMohxo/UIMarLV245rM6n9D19A12epjldRgyiS13SoSyLFCJEobprYg==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "jss": "^10.0.3"
+      }
+    },
+    "jss-plugin-rule-value-function": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.3.tgz",
+      "integrity": "sha512-RWwIT2UBAIwf3f6DQtt5gyjxHMRJoeO9TQku+ueR8dBMakqSSe8vFwQNfjXEoe0W+Tez5HZCTkZKNMulv3Z+9A==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "jss": "^10.0.3"
+      }
+    },
+    "jss-plugin-vendor-prefixer": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.3.tgz",
+      "integrity": "sha512-zVs6e5z4tFRK/fJ5kuTLzXlTFQbLeFTVwk7lTZiYNufmZwKT0kSmnOJDUukcSe7JLGSRztjWhnHB/6voP174gw==",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "css-vendor": "^2.0.7",
+        "jss": "^10.0.3"
+      }
+    },
     "keygrip": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.3.tgz",
@@ -4540,6 +4781,14 @@
       "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=",
       "dev": true
     },
+    "loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "requires": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      }
+    },
     "lru-cache": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -5205,6 +5454,11 @@
         "remove-trailing-separator": "^1.0.1"
       }
     },
+    "normalize-scroll-left": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/normalize-scroll-left/-/normalize-scroll-left-0.2.0.tgz",
+      "integrity": "sha512-t5oCENZJl8TGusJKoCJm7+asaSsPuNmK6+iEjrZ5TyBj2f02brCRsd4c83hwtu+e5d4LCSBZ0uoDlMjBo+A8yA=="
+    },
     "npm-run-all": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
@@ -5265,8 +5519,7 @@
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-      "dev": true
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
     },
     "object-copy": {
       "version": "0.1.0",
@@ -5599,6 +5852,11 @@
         "find-up": "^3.0.0"
       }
     },
+    "popper.js": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.0.tgz",
+      "integrity": "sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw=="
+    },
     "posix-character-classes": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -5708,6 +5966,16 @@
       "resolved": "https://registry.npmjs.org/promise-worker/-/promise-worker-2.0.1.tgz",
       "integrity": "sha512-jR7vHqMEwWJ15i9vA3qyCKwRHihyLJp1sAa3RyY5F35m3u5s2lQUfq0nzVjbA8Xc7+3mL3Y9+9MHBO9UFRpFxA=="
     },
+    "prop-types": {
+      "version": "15.7.2",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+      "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+      "requires": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.8.1"
+      }
+    },
     "prr": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
@@ -5875,6 +6143,43 @@
       "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=",
       "dev": true
     },
+    "react": {
+      "version": "16.12.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz",
+      "integrity": "sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA==",
+      "requires": {
+        "loose-envify": "^1.1.0",
+        "object-assign": "^4.1.1",
+        "prop-types": "^15.6.2"
+      }
+    },
+    "react-dom": {
+      "version": "16.12.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz",
+      "integrity": "sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw==",
+      "requires": {
+        "loose-envify": "^1.1.0",
+        "object-assign": "^4.1.1",
+        "prop-types": "^15.6.2",
+        "scheduler": "^0.18.0"
+      }
+    },
+    "react-is": {
+      "version": "16.12.0",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
+      "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q=="
+    },
+    "react-transition-group": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz",
+      "integrity": "sha512-1qRV1ZuVSdxPlPf4O8t7inxUGpdyO5zG9IoNfJxSO0ImU2A1YWkEQvFPuIPZmMLkg5hYs7vv5mMOyfgSkvAwvw==",
+      "requires": {
+        "@babel/runtime": "^7.5.5",
+        "dom-helpers": "^5.0.1",
+        "loose-envify": "^1.4.0",
+        "prop-types": "^15.6.2"
+      }
+    },
     "read-pkg": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -6128,6 +6433,15 @@
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "dev": true
     },
+    "scheduler": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.18.0.tgz",
+      "integrity": "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==",
+      "requires": {
+        "loose-envify": "^1.1.0",
+        "object-assign": "^4.1.1"
+      }
+    },
     "schema-utils": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
@@ -6879,6 +7193,11 @@
       "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
       "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
     },
+    "tiny-warning": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+      "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+    },
     "tmp": {
       "version": "0.0.30",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",

+ 4 - 1
esp/src/package.json

@@ -40,6 +40,7 @@
     "@hpcc-js/map": "2.14.3",
     "@hpcc-js/other": "2.13.8",
     "@hpcc-js/tree": "2.8.6",
+    "@material-ui/core": "4.8.3",
     "clipboard": "2.0.4",
     "codemirror": "5.50.2",
     "dijit": "1.16.0",
@@ -48,7 +49,9 @@
     "dojo-util": "1.16.0",
     "dojox": "1.16.0",
     "es6-promise": "4.2.8",
-    "font-awesome": "4.7.0"
+    "font-awesome": "4.7.0",
+    "react": "16.12.0",
+    "react-dom": "16.12.0"
   },
   "devDependencies": {
     "@types/dojo": "1.9.42",

+ 2 - 0
esp/src/src/react/index.ts

@@ -0,0 +1,2 @@
+export * from "./render";
+export * from "./wuStatus";

+ 14 - 0
esp/src/src/react/render.ts

@@ -0,0 +1,14 @@
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+
+export function render<P>(C: React.FunctionComponent<P>, props: Readonly<P>, parent: Element | Document | ShadowRoot | DocumentFragment, replaceNode?: Element | Text) {
+    ReactDOM.render(React.createElement(C, props), parent, replaceNode);
+}
+
+export function svgRender<P>(C: React.FunctionComponent<P>, props: Readonly<P>, parent: Element | Document | ShadowRoot | DocumentFragment, replaceNode?: Element | Text) {
+    ReactDOM.render(React.createElement("svg", null, React.createElement(C, props)), parent, replaceNode);
+}
+
+export function unrender(parent: Element | Document | ShadowRoot | DocumentFragment) {
+    ReactDOM.unmountComponentAtNode(parent);
+}

+ 102 - 0
esp/src/src/react/wuStatus.tsx

@@ -0,0 +1,102 @@
+import { Workunit, WUStateID } from "@hpcc-js/comms";
+import Step from "@material-ui/core/Step";
+import StepLabel from "@material-ui/core/StepLabel";
+import Stepper from "@material-ui/core/Stepper";
+import * as React from "react";
+
+import "dojo/i18n";
+// @ts-ignore
+import * as nlsHPCC from "dojo/i18n!hpcc/nls/hpcc";
+
+const Steps = [
+    {
+        text: nlsHPCC.Created,
+        activeText: nlsHPCC.Creating
+    },
+    {
+        text: nlsHPCC.Compiled,
+        activeText: nlsHPCC.Compiling
+    },
+    {
+        text: nlsHPCC.Executed,
+        activeText: nlsHPCC.Executing
+    },
+    {
+        text: nlsHPCC.Completed,
+        activeText: nlsHPCC.Completing
+    }
+];
+
+const wuSteps = (compile: boolean) => {
+    return compile ? [Steps[0], Steps[1], Steps[3]] : [...Steps];
+}
+
+const wuStep = (wu?: Workunit): number => {
+    switch (wu ? wu.StateID : WUStateID.Unknown) {
+        case WUStateID.Blocked:
+        case WUStateID.Wait:
+        case WUStateID.Scheduled:
+        case WUStateID.UploadingFiled:
+            return 0;
+        case WUStateID.Compiling:
+            return 1;
+        case WUStateID.Submitted:
+            return 0;
+        case WUStateID.Compiled:
+            return wu.ActionEx === "compile" ? 4 : 1;
+        case WUStateID.Aborting:
+        case WUStateID.Running:
+            return 2;
+        case WUStateID.Aborted:
+            return 4;
+        case WUStateID.Archived:
+            return 4;
+        case WUStateID.Completed:
+            return 4;
+        case WUStateID.Failed:
+            return 4;
+        case WUStateID.DebugPaused:
+        case WUStateID.DebugRunning:
+        case WUStateID.Paused:
+        case WUStateID.Unknown:
+        default:
+            return 0;
+    }
+};
+
+interface WUStatus {
+    wuid: string;
+}
+
+export const WUStatus: React.FunctionComponent<WUStatus> = ({
+    wuid
+}) => {
+    const [activeStep, setActiveStep] = React.useState(-1);
+    const [failed, setFailed] = React.useState(false);
+    const [steps, setSteps] = React.useState([]);
+
+    React.useEffect(() => {
+        const wu = Workunit.attach({ baseUrl: "" }, wuid);
+        const wuWatchHandle = wu.watch(() => {
+            setActiveStep(wuStep(wu));
+            setFailed(wu.isFailed());
+            setSteps(wuSteps(wu.ActionEx === "compile"));
+        });
+        wu.refresh(true);
+        return () => {
+            wuWatchHandle.release();
+        };
+    }, []);
+
+    return <Stepper activeStep={activeStep} alternativeLabel>
+        {steps.map((step, i) => {
+            const labelProps = {
+                error: i <= activeStep ? failed : false
+            };
+            const label = activeStep === i ? step.activeText : step.text;
+            return <Step key={i}>
+                <StepLabel {...labelProps}>{label}</StepLabel>
+            </Step>;
+        })}
+    </Stepper>;
+};

+ 1 - 0
esp/src/tsconfig.json

@@ -14,6 +14,7 @@
         "allowJs": true,
         "skipLibCheck": true,
         "noImplicitUseStrict": true,
+        "jsx": "react",
         "lib": [
             "dom",
             "es5",