浏览代码

HPCC-18512 Switch to WebPack for ECL Watch build

* Start using NPM for third party packages
* Call "npm install" as part of the build process
* Refactored code so WebPack can spot dynamic loading
* Refactored resources to simplify deploy
* Added missing dojox css directly into hpcc.css
* Add es6-promise polyfill for IE
* Fix lint issue.

Signed-off-by: Gordon Smith <gordonjsmith@gmail.com>
Gordon Smith 7 年之前
父节点
当前提交
9aba0126bc
共有 66 个文件被更改,包括 2159 次插入1008 次删除
  1. 0 15
      .gitmodules
  2. 5 3
      .travis.yml
  3. 6 40
      esp/build.sh
  4. 0 85
      esp/profiles/eclwatch.profile.js
  5. 1 0
      esp/src/.jshintrc
  6. 15 11
      esp/src/CMakeLists.txt
  7. 0 1
      esp/src/dijit
  8. 0 1
      esp/src/dojo
  9. 0 1
      esp/src/dojox
  10. 6 5
      esp/src/eclwatch/ActivityWidget.js
  11. 6 6
      esp/src/eclwatch/DFUQueryWidget.js
  12. 2 85
      esp/src/eclwatch/DFUSearchWidget.js
  13. 5 6
      esp/src/eclwatch/DelayLoadWidget.js
  14. 1 1
      esp/src/eclwatch/DynamicESDLMethodWidget.js
  15. 4 3
      esp/src/eclwatch/ECLPlaygroundWidget.js
  16. 15 14
      esp/src/eclwatch/ESPDFUWorkunit.js
  17. 6 5
      esp/src/eclwatch/ESPLogicalFile.js
  18. 5 4
      esp/src/eclwatch/ESPQueue.js
  19. 4 3
      esp/src/eclwatch/ESPResult.js
  20. 4 4
      esp/src/eclwatch/ESPWorkunit.js
  21. 4 3
      esp/src/eclwatch/FilterDropDownWidget.js
  22. 2 2
      esp/src/eclwatch/GetDFUWorkunitsWidget.js
  23. 6 5
      esp/src/eclwatch/GraphPageWidget.js
  24. 9 8
      esp/src/eclwatch/GraphTreeWidget.js
  25. 3 9
      esp/src/eclwatch/GraphWidget.js
  26. 5 4
      esp/src/eclwatch/GraphsWidget.js
  27. 9 0
      esp/src/eclwatch/HPCCPlatformWidget.js
  28. 417 430
      esp/src/eclwatch/JSGraphWidget.js
  29. 2 1
      esp/src/eclwatch/LFDetailsWidget.js
  30. 6 5
      esp/src/eclwatch/LZBrowseWidget.js
  31. 6 5
      esp/src/eclwatch/MonitoringWidget.js
  32. 7 6
      esp/src/eclwatch/QuerySetDetailsWidget.js
  33. 9 9
      esp/src/eclwatch/QuerySetQueryWidget.js
  34. 8 7
      esp/src/eclwatch/SFDetailsWidget.js
  35. 4 3
      esp/src/eclwatch/SearchResultsWidget.js
  36. 4 3
      esp/src/eclwatch/SourceFilesWidget.js
  37. 6 4
      esp/src/eclwatch/TargetSelectClass.js
  38. 5 4
      esp/src/eclwatch/TopologyWidget.js
  39. 363 1
      esp/src/eclwatch/Utility.js
  40. 9 16
      esp/src/eclwatch/VizWidget.js
  41. 1 0
      esp/src/eclwatch/WUDetailsWidget.js
  42. 2 2
      esp/src/eclwatch/WUQueryWidget.js
  43. 309 1
      esp/src/eclwatch/css/hpcc.css
  44. 72 102
      esp/src/eclwatch/dojoConfig.js
  45. 二进制
      esp/src/eclwatch/img/blank.gif
  46. 二进制
      esp/src/eclwatch/img/hue.png
  47. 二进制
      esp/src/eclwatch/img/hueHandle.png
  48. 二进制
      esp/src/eclwatch/img/hueHandleA11y.png
  49. 二进制
      esp/src/eclwatch/img/pickerPointer.png
  50. 二进制
      esp/src/eclwatch/img/underlay.png
  51. 26 13
      esp/src/eclwatch/stub.js
  52. 1 1
      esp/src/eclwatch/templates/HPCCPlatformWidget.html
  53. 0 1
      esp/src/eclwatch/templates/TimingTreeMapWidget.html
  54. 3 3
      esp/src/eclwatch/templates/WUDetailsWidget.html
  55. 3 3
      esp/src/eclwatch/viz/DojoD3.js
  56. 8 8
      esp/src/eclwatch/viz/DojoD32DChart.js
  57. 14 16
      esp/src/eclwatch/viz/DojoD3Choropleth.js
  58. 9 8
      esp/src/eclwatch/viz/DojoD3NDChart.js
  59. 528 0
      esp/src/loader/css.js
  60. 34 0
      esp/src/loader/less.min.js
  61. 48 10
      esp/src/package.json
  62. 12 20
      esp/src/stub.htm
  63. 0 1
      esp/src/themes
  64. 26 0
      esp/src/tsconfig.json
  65. 0 1
      esp/src/util
  66. 94 0
      esp/src/webpack.config.js

+ 0 - 15
.gitmodules

@@ -7,21 +7,6 @@
 [submodule "esp/src/dgrid"]
 	path = esp/src/dgrid
 	url = https://github.com/hpcc-systems/dgrid.git
-[submodule "esp/src/dojo"]
-	path = esp/src/dojo
-	url = https://github.com/hpcc-systems/dojo.git
-[submodule "esp/src/dijit"]
-	path = esp/src/dijit
-	url = https://github.com/hpcc-systems/dijit.git
-[submodule "esp/src/dojox"]
-	path = esp/src/dojox
-	url = https://github.com/hpcc-systems/dojox.git
-[submodule "esp/src/themes"]
-	path = esp/src/themes
-	url = https://github.com/hpcc-systems/themes.git
-[submodule "esp/src/util"]
-	path = esp/src/util
-	url = https://github.com/hpcc-systems/util.git
 [submodule "plugins/cassandra/libuv"]
 	path = plugins/cassandra/libuv
 	url = https://github.com/hpcc-systems/libuv.git

+ 5 - 3
.travis.yml

@@ -1,7 +1,9 @@
 sudo : false
 language: node_js
 node_js:
-  - "6.9.1"
-before_script:
+  - '6'
+before_install:
   - cd ./esp/src
-  - npm install
+after_script:
+  - npm run copy-res;
+  - npm run bundle;

+ 6 - 40
esp/build.sh

@@ -9,27 +9,16 @@ BASEDIR=$(cd $(dirname $0) && pwd)
 # Source directory for unbuilt code
 SRCDIR="$BASEDIR/src"
 
-# Directory containing dojo build utilities
-TOOLSDIR="$SRCDIR/util/buildscripts"
-
 # Destination directory for built code
 DISTDIR=$1
 
-# Main application package build configuration
-PROFILE="$BASEDIR/profiles/eclwatch.profile.js"
-
 # Configuration over. Main application start up!
 
-echo "Building application with $PROFILE to $DISTDIR."
+echo "EclWatch:  Building to $DISTDIR."
 
-echo -n "Cleaning old files..."
+echo -n "EclWatch:  Cleaning $DISTDIR"
 rm -rf "$DISTDIR"
-echo " Done"
-
-if [ ! -d "$TOOLSDIR" ]; then
-    echoerr "ERROR:  Can't find Dojo build tools -- did you initialise submodules? (git submodule update --init --recursive)"
-    exit 1
-fi
+echo "EclWatch:  Cleaning Done"
 
 mkdir -p "$DISTDIR"
 cp -r "$SRCDIR/CodeMirror2" "$DISTDIR/CodeMirror2"
@@ -43,31 +32,8 @@ perl -pe "
   s/<\!--.*?-->//g;                          # Strip comments
   s/\s+/ /g;                                 # Collapse white-space" > "$DISTDIR/stub.htm"
 
-echo "Building: $SRCDIR/Visualization"
-cd "$SRCDIR/Visualization/"
-mkdir -p "$DISTDIR/Visualization"
-cp -r "$SRCDIR/Visualization/dist-amd" "$DISTDIR/Visualization/dist-amd"
-
-cd "$TOOLSDIR"
-
-if which node >/dev/null; then
-    node ../../dojo/dojo.js baseUrl=../../dojo load=build --profile "$PROFILE" --releaseDir "$DISTDIR" ${*:2}
-else
-    echoerr "ERROR:  node.js is required to build - see https://nodejs.org/en/download/package-manager/"
-    exit 1
-fi
-
-echo "Build complete"
-
-cd "$BASEDIR"
+cd "$SRCDIR"
 
-for dojodir in dojo dojox dijit
-do
-  for f in  $(find ${DISTDIR}/${dojo_dir} -type f -perm /a+x ! -name "*.sh" \
-              ! -name "*.php" ! -name "*.cgi" -print)
-  do
-     chmod -x $f
-  done
-done
+cp -r "$SRCDIR/build/." "$DISTDIR"
 
-echo "Post process complete"
+echo "EclWatch:  Build complete"

+ 0 - 85
esp/profiles/eclwatch.profile.js

@@ -1,85 +0,0 @@
-var profile = {
-    basePath: "../src/",
-    action: "release",
-    layerOptimize: "closure",
-    optimize: "closure",
-    cssOptimize: "comments",
-    mini: true,
-    stripConsole: "all",
-    selectorEngine: "lite",
-    
-    defaultConfig: {
-        hasCache: {
-            "dojo-built": 1,
-            "dojo-loader": 1,
-            "dom": 1,
-            "host-browser": 1,
-            "config-selectorEngine": "lite"
-        },
-        async: 1
-    },
-
-    staticHasFeatures: {
-        "config-deferredInstrumentation": 0,
-        "config-dojo-loader-catches": 0,
-        "config-tlmSiblingOfDojo": 0,
-        "dojo-amd-factory-scan": 0,
-        "dojo-combo-api": 0,
-        "dojo-config-api": 1,
-        "dojo-config-require": 0,
-        "dojo-debug-messages": 0,
-        "dojo-dom-ready-api": 1,
-        "dojo-firebug": 0,
-        "dojo-guarantee-console": 1,
-        "dojo-has-api": 1,
-        "dojo-inject-api": 1,
-        "dojo-loader": 1,
-        "dojo-log-api": 0,
-        "dojo-modulePaths": 0,
-        "dojo-moduleUrl": 0,
-        "dojo-publish-privates": 0,
-        "dojo-requirejs-api": 0,
-        "dojo-sniff": 1,
-        "dojo-sync-loader": 0,
-        "dojo-test-sniff": 0,
-        "dojo-timeout-api": 0,
-        "dojo-trace-api": 0,
-        "dojo-undef-api": 0,
-        "dojo-v1x-i18n-Api": 1,
-        "dom": 1,
-        "host-browser": 1,
-        "extend-dojo": 1
-    },
-
-    packages: [
-        'dojo',
-        'dijit',
-        'dojox',
-        'themes',
-        'dgrid',
-        'put-selector',
-        'xstyle',
-        {
-            name: "hpcc",
-            location: "./eclwatch"
-        },
-        {
-            name: "templates",
-            location: "eclwatch/templates"
-        }
-    ],
-        
-    layers: {
-        "hpcc/hpcc": {
-            include: [ 
-                "hpcc/stub",
-                "hpcc/HPCCPlatformWidget",
-                "hpcc/ActivityWidget",
-                "hpcc/HPCCPlatformECLWidget",
-                "hpcc/WUQueryWidget"
-            ],
-            customBase: true,
-            boot: true
-        }
-    }
-};

+ 1 - 0
esp/src/.jshintrc

@@ -1,5 +1,6 @@
 {
     "predef": [
+        "module",
         "debugConfig",
         "define",
         "require",

+ 15 - 11
esp/src/CMakeLists.txt

@@ -33,18 +33,22 @@ else ()
             message ( \"---- Build Target: ${ECLWATCH_BUILD_DEST}\" )
             message ( \"---- Output log:   ${ECLWATCH_BUILD_OUT}\" )
             message ( \"---- Error log:    ${ECLWATCH_BUILD_ERR}\" )
-            if ( NOT EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/util/buildscripts\" )
-                message ( FATAL_ERROR \"Can't find Dojo build tools -- did you initialise submodules? (git submodule update --init --recursive)\" )
+            message ( \"---- Installing third party libraries\" )
+            execute_process ( WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\" COMMAND \"npm\" \"install\" OUTPUT_FILE \"${ECLWATCH_BUILD_OUT}\" )
+            message ( \"---- Clean previous build\" )
+            execute_process ( WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\" COMMAND \"npm\" \"run\" \"clean\" OUTPUT_FILE \"${ECLWATCH_BUILD_OUT}\")
+            message ( \"---- Copy resources\" ) 
+            execute_process ( WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\" COMMAND \"npm\" \"run\" \"copy-res\" OUTPUT_FILE \"${ECLWATCH_BUILD_OUT}\" )
+            message ( \"---- Build website\" )
+            execute_process ( WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\" COMMAND \"npm\" \"run\" \"bundle\" OUTPUT_FILE \"${ECLWATCH_BUILD_OUT}\" )
+            execute_process ( COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../build.sh\" \"${ECLWATCH_BUILD_DEST}\" OUTPUT_FILE \"${ECLWATCH_BUILD_OUT}\" ERROR_FILE \"${ECLWATCH_BUILD_ERR}\" )
+            execute_process ( COMMAND \"sed\" \"-n\" \"/ERROR/p\" \"${CMAKE_CURRENT_BINARY_DIR}/eclwatch_build_err.txt\" OUTPUT_VARIABLE BUILD_ERROR )
+            if ( \"\${BUILD_ERROR}\" STREQUAL \"\" )
+                execute_process ( COMMAND \"tail\" \"--lines=4\" \"${CMAKE_CURRENT_BINARY_DIR}/eclwatch_build_err.txt\" )
+                message ( \"\" )
             else ()
-                execute_process ( COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../build.sh\" \"${ECLWATCH_BUILD_DEST}\" OUTPUT_FILE \"${ECLWATCH_BUILD_OUT}\" ERROR_FILE \"${ECLWATCH_BUILD_ERR}\" )
-                execute_process ( COMMAND \"sed\" \"-n\" \"/ERROR/p\" \"${CMAKE_CURRENT_BINARY_DIR}/eclwatch_build_err.txt\" OUTPUT_VARIABLE BUILD_ERROR )
-                if ( \"\${BUILD_ERROR}\" STREQUAL \"\" )
-                    execute_process ( COMMAND \"tail\" \"--lines=4\" \"${ECLWATCH_BUILD_DEST}/build-report.txt\" )
-                    message ( \"\" )
-                else ()
-                    message ( \"Process finished with errors:\" )
-                    message ( FATAL_ERROR \"\${BUILD_ERROR}\" )
-                endif ()
+                message ( \"Process finished with errors:\" )
+                message ( FATAL_ERROR \"\${BUILD_ERROR}\" )
             endif ()
         else ()
             message( \"-- ECL Watch:  Reusing (old) Site\" )

+ 0 - 1
esp/src/dijit

@@ -1 +0,0 @@
-Subproject commit 0b9aeffbf3e156a470b2396e87a719a7f9e9bcf5

+ 0 - 1
esp/src/dojo

@@ -1 +0,0 @@
-Subproject commit f8fafaeec7d066e07814ec3057f424d5d745eb6c

+ 0 - 1
esp/src/dojox

@@ -1 +0,0 @@
-Subproject commit c9df88e70397d53e05c8f42dadccf448a05cc809

+ 6 - 5
esp/src/eclwatch/ActivityWidget.js

@@ -35,12 +35,13 @@ define([
     "hpcc/ESPRequest",
     "hpcc/ESPActivity",
     "hpcc/DelayLoadWidget",
-    "hpcc/ESPUtil"
+    "hpcc/ESPUtil",
+    "hpcc/Utility",
 
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, on,
                 registry, Button, ToggleButton, ToolbarSeparator, ContentPane, Tooltip,
                 selector, tree,
-                GridDetailsWidget, ESPRequest, ESPActivity, DelayLoadWidget, ESPUtil) {
+                GridDetailsWidget, ESPRequest, ESPActivity, DelayLoadWidget, ESPUtil, Utility) {
     return declare("ActivityWidget", [GridDetailsWidget], {
 
         i18n: nlsHPCC,
@@ -380,16 +381,16 @@ define([
                     }),
                     Priority: {
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("priority.png", context.i18n.Priority);
+                            node.innerHTML = Utility.getImageHTML("priority.png", context.i18n.Priority);
                         },
                         width: 25,
                         sortable: false,
                         formatter: function (Priority) {
                             switch (Priority) {
                                 case "high":
-                                    return dojoConfig.getImageHTML("priority_high.png");
+                                    return Utility.getImageHTML("priority_high.png");
                                 case "low":
-                                    return dojoConfig.getImageHTML("priority_low.png");
+                                    return Utility.getImageHTML("priority_low.png");
                             }
                             return "";
                         }

+ 6 - 6
esp/src/eclwatch/DFUQueryWidget.js

@@ -563,13 +563,13 @@ define([
                     }),
                     IsProtected: {
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("locked.png", context.i18n.Protected);
+                            node.innerHTML = Utility.getImageHTML("locked.png", context.i18n.Protected);
                         },
                         width: 25,
                         sortable: false,
                         formatter: function (_protected) {
                             if (_protected === true) {
-                                return dojoConfig.getImageHTML("locked.png");
+                                return Utility.getImageHTML("locked.png");
                             }
                             return "";
                         }
@@ -577,11 +577,11 @@ define([
                     IsCompressed: {
                         width: 25, sortable: false,
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("compressed.png", context.i18n.Compressed);
+                            node.innerHTML = Utility.getImageHTML("compressed.png", context.i18n.Compressed);
                         },
                         formatter: function (compressed) {
                             if (compressed === true) {
-                                return dojoConfig.getImageHTML("compressed.png");
+                                return Utility.getImageHTML("compressed.png");
                             }
                             return "";
                         }
@@ -589,11 +589,11 @@ define([
                     IsKeyFile: {
                         width: 25, sortable: false,
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("index.png", context.i18n.Index);
+                            node.innerHTML = Utility.getImageHTML("index.png", context.i18n.Index);
                         },
                         formatter: function (keyfile, row) {
                             if (row.ContentType === "key") {
-                                return dojoConfig.getImageHTML("index.png");
+                                return Utility.getImageHTML("index.png");
                             }
                             return "";
                         }

+ 2 - 85
esp/src/eclwatch/DFUSearchWidget.js

@@ -15,8 +15,6 @@
 ############################################################################## */
 define([
     "dojo/_base/declare",
-    "dojo/_base/xhr",
-    "dojo/dom",
 
     "dijit/layout/BorderContainer",
     "dijit/layout/TabContainer",
@@ -27,37 +25,21 @@ define([
     "dijit/registry",
 
     "hpcc/_Widget",
-    "hpcc/ECLSourceWidget",
     "hpcc/TargetSelectWidget",
-    "hpcc/GraphWidget",
     "hpcc/ResultsWidget",
     "hpcc/InfoGridWidget",
     "hpcc/ESPWorkunit",
 
     "dojo/text!../templates/DFUSearchWidget.html"
-], function (declare, xhr, dom,
+], function (declare,
                 BorderContainer, TabContainer, ContentPane, Toolbar, Textarea, TitlePane, registry,
-                _Widget, EclSourceWidget, TargetSelectWidget, GraphWidget, ResultsWidget, InfoGridWidget, Workunit,
+                _Widget, TargetSelectWidget, ResultsWidget, InfoGridWidget, Workunit,
                 template) {
     return declare("DFUSearchWidget", [_Widget], {
         templateString: template,
         baseClass: "DFUSearchWidget",
         borderContainer: null,
         tabContainer: null,
-        resultsWidget: null,
-        resultsWidgetLoaded: false,
-        filesWidget: null,
-        filesWidgetLoaded: false,
-        timersWidget: null,
-        timersWidgetLoaded: false,
-        graphsWidget: null,
-        graphsWidgetLoaded: false,
-        sourceWidget: null,
-        sourceWidgetLoaded: false,
-        playgroundWidget: null,
-        playgroundWidgetLoaded: false,
-        xmlWidget: null,
-        xmlWidgetLoaded: false,
 
         wu: null,
         loaded: false,
@@ -69,57 +51,6 @@ define([
         postCreate: function (args) {
             this.inherited(arguments);
             this.borderContainer = registry.byId(this.id + "BorderContainer");
-            //this.tabContainer = registry.byId(this.id + "TabContainer");
-            //this.resultsWidget = registry.byId(this.id + "Results");
-            //this.filesWidget = registry.byId(this.id + "Files");
-            //this.timersWidget = registry.byId(this.id + "Timers");
-           // this.graphsWidget = registry.byId(this.id + "Graphs");
-            //this.sourceWidget = registry.byId(this.id + "Source");
-            //this.playgroundWidget = registry.byId(this.id + "Playground");
-            //this.xmlWidget = registry.byId(this.id + "XML");
-            //this.infoGridWidget = registry.byId(this.id + "InfoContainer");
-            var context = this;
-           /* this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
-                if (nval.id == context.id + "Results" && !context.resultsWidgetLoaded) {
-                    context.resultsWidgetLoaded = true;
-                    context.resultsWidget.init({
-                        Wuid: context.wu.wuid
-                    });
-                } else if (nval.id == context.id + "Files" && !context.filesWidgetLoaded) {
-                    context.filesWidgetLoaded = true;
-                    context.filesWidget.init({
-                        Wuid: context.wu.wuid,
-                        SourceFiles: true
-                    });
-                } else if (nval.id == context.id + "Timers" && !context.timersWidgetLoaded) {
-                    context.timersWidgetLoaded = true;
-                    context.timersWidget.init({
-                        Wuid: context.wu.wuid
-                    });
-                } else if (nval.id == context.id + "Graphs" && !context.graphsWidgetLoaded) {
-                    context.graphsWidgetLoaded = true;
-                    context.graphsWidget.init({
-                        Wuid: context.wu.wuid
-                    });
-                } else if (nval.id == context.id + "Source" && !context.sourceWidgetLoaded) {
-                    context.sourceWidgetLoaded = true;
-                    context.sourceWidget.init({
-                        Wuid: context.wu.wuid
-                    });
-                } else if (nval.id == context.id + "Playground" && !context.playgroundWidgetLoaded) {
-                    context.playgroundWidgetLoaded = true;
-                    context.playgroundWidget.init({
-                        Wuid: context.wu.wuid
-                    });
-                } else if (nval.id == context.id + "XML" && !context.xmlWidgetLoaded) {
-                    context.xmlWidgetLoaded = true;
-                    context.xmlWidget.init({
-                        Wuid: context.wu.wuid
-                    });
-                }
-            });*/
-
-            
         },
 
         startup: function (args) {
@@ -158,9 +89,7 @@ define([
             if (this.inherited(arguments))
                 return;
 
-            //dom.byId("showWuid").innerHTML = params.Wuid;
             if (params.Wuid) {
-                //dom.byId(this.id + "Wuid").innerHTML = params.Wuid;
                 this.wu = new Workunit({
                     wuid: params.Wuid
                 });
@@ -196,16 +125,6 @@ define([
 
         monitorWorkunit: function (response) {
             if (!this.loaded) {
-                //dom.byId(this.id + "WUInfoResponse").innerHTML = this.objectToText(response);             
-                //dom.byId("showStateIdImage").src = this.wu.getStateImage();
-                //dom.byId("showStateIdImage").title = response.State;
-                //dom.byId("showStateReadOnly").innerHTML = response.State;
-                //dom.byId("showAction").innerHTML = response.ActionId;
-               // dom.byId("showOwner").innerHTML = response.Owner;
-                //dom.byId("showScope").value = response.Scope;
-                //dom.byId("showJobName").value = response.Jobname;
-                //dom.byId("showCluster").innerHTML = response.Cluster;
-                
                 this.loaded = true;
             }
 
@@ -229,8 +148,6 @@ define([
                     },
 
                     onAfterSend: function (response) {
-                        //dom.byId(context.id + "WUInfoResponse").innerHTML = context.objectToText(response);
-
                     }
                 });
             }

+ 5 - 6
esp/src/eclwatch/DelayLoadWidget.js

@@ -20,10 +20,12 @@ define([
     "dojo/dom",
     "dojo/dom-style",
 
-    "dijit/layout/ContentPane"
+    "dijit/layout/ContentPane",
 
+    "hpcc/Utility"
 ], function (declare, Deferred, lang, dom, domStyle,
-    ContentPane) {
+    ContentPane,
+    Utility) {
     return declare("DelayLoadWidget", [ContentPane], {
         __hpcc_initalized: false,
         refresh: null,
@@ -57,10 +59,7 @@ define([
             this.deferred = new Deferred();
             this.startLoading();
             var context = this;
-            require([(this.delayFolder ? "plugins/" + this.delayFolder + "/" : "hpcc/") + this.delayWidget], function (widget) {
-                if (widget.fixCircularDependency) {
-                    widget = widget.fixCircularDependency;
-                }
+                Utility.resolve(this.delayWidget, function (widget) {
                 var widgetInstance = new widget(lang.mixin({
                     id: context.childWidgetID,
                     style: {

+ 1 - 1
esp/src/eclwatch/DynamicESDLMethodWidget.js

@@ -120,7 +120,7 @@ define([
             var results = this.store.query();
 
             arrayUtil.forEach(results, function(row, idx){
-                if (row.__hpcc_parentName !== null && row.Value !="") {
+                if (row.__hpcc_parentName !== null && row.Value !== "") {
                     userXML += row.Value;
                 }
             });

+ 4 - 3
esp/src/eclwatch/ECLPlaygroundWidget.js

@@ -35,21 +35,22 @@ define([
     "hpcc/ECLPlaygroundResultsWidget",
     "hpcc/ESPWorkunit",
     "hpcc/ESPQuery",
-
+    "hpcc/Utility",
+    
     "dojo/text!../templates/ECLPlaygroundWidget.html",
 
     "hpcc/InfoGridWidget"
 
 ], function (declare, lang, i18n, nlsHPCC, xhr, dom, query,
                 BorderContainer, TabContainer, ContentPane, registry,
-                _Widget, EclSourceWidget, TargetSelectWidget, GraphWidget, JSGraphWidget, ResultsWidget, ESPWorkunit, ESPQuery,
+                _Widget, EclSourceWidget, TargetSelectWidget, GraphWidget, JSGraphWidget, ResultsWidget, ESPWorkunit, ESPQuery, Utility,
                 template) {
     return declare("ECLPlaygroundWidget", [_Widget], {
         templateString: template,
         baseClass: "ECLPlaygroundWidget",
         i18n: nlsHPCC,
 
-        graphType: dojoConfig.isPluginInstalled() ? "GraphWidget" : "JSGraphWidget",
+        graphType: Utility.isPluginInstalled() ? "GraphWidget" : "JSGraphWidget",
         wu: null,
         editorControl: null,
         graphControl: null,

+ 15 - 14
esp/src/eclwatch/ESPDFUWorkunit.js

@@ -26,9 +26,10 @@ define([
     "hpcc/FileSpray",
     "hpcc/ESPUtil",
     "hpcc/ESPRequest",
-    "hpcc/ESPResult"
+    "hpcc/ESPResult",
+    "hpcc/Utility",
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, Deferred, Observable, topic,
-    FileSpray, ESPUtil, ESPRequest, ESPResult) {
+    FileSpray, ESPUtil, ESPRequest, ESPResult, Utility) {
 
     var i18n = nlsHPCC;
 
@@ -255,9 +256,9 @@ define([
         },
         getProtectedImage: function () {
             if (this.isProtected) {
-                return dojoConfig.getImageURL("locked.png");
+                return Utility.getImageURL("locked.png");
             }
-            return dojoConfig.getImageURL("unlocked.png");
+            return Utility.getImageURL("unlocked.png");
         },
         getStateIconClass: function () {
             switch (this.State) {
@@ -285,25 +286,25 @@ define([
         getStateImage: function () {
             switch (this.State) {
                 case 1:
-                    return dojoConfig.getImageURL("workunit_warning.png");
+                    return Utility.getImageURL("workunit_warning.png");
                 case 2:
-                    return dojoConfig.getImageURL("workunit_submitted.png");
+                    return Utility.getImageURL("workunit_submitted.png");
                 case 3:
-                    return dojoConfig.getImageURL("workunit_running.png");
+                    return Utility.getImageURL("workunit_running.png");
                 case 4:
-                    return dojoConfig.getImageURL("workunit_failed.png");
+                    return Utility.getImageURL("workunit_failed.png");
                 case 5:
-                    return dojoConfig.getImageURL("workunit_failed.png");
+                    return Utility.getImageURL("workunit_failed.png");
                 case 6:
-                    return dojoConfig.getImageURL("workunit_completed.png");
+                    return Utility.getImageURL("workunit_completed.png");
                 case 7:
-                    return dojoConfig.getImageURL("workunit_running.png");
+                    return Utility.getImageURL("workunit_running.png");
                 case 8:
-                    return dojoConfig.getImageURL("workunit_aborting.png");
+                    return Utility.getImageURL("workunit_aborting.png");
                 case 999:
-                    return dojoConfig.getImageURL("workunit_deleted.png");
+                    return Utility.getImageURL("workunit_deleted.png");
             }
-            return dojoConfig.getImageURL("workunit.png");
+            return Utility.getImageURL("workunit.png");
         }
     });
 

+ 6 - 5
esp/src/eclwatch/ESPLogicalFile.js

@@ -26,9 +26,10 @@ define([
     "hpcc/FileSpray",
     "hpcc/ESPRequest",
     "hpcc/ESPUtil",
-    "hpcc/ESPResult"
+    "hpcc/ESPResult",
+    "hpcc/Utility"
 ], function (declare, arrayUtil, lang, Deferred, Observable, QueryResults, Stateful,
-        WsDfu, FileSpray, ESPRequest, ESPUtil, ESPResult) {
+        WsDfu, FileSpray, ESPRequest, ESPUtil, ESPResult, Utility) {
 
     var _logicalFiles = {};
 
@@ -402,13 +403,13 @@ define([
             }
         },
         getStateImageHTML: function () {
-            return dojoConfig.getImageHTML(this.getStateImageName());
+            return Utility.getImageHTML(this.getStateImageName());
         },
         getProtectedImage: function () {
             if (this.IsProtected) {
-                return dojoConfig.getImageURL("locked.png");
+                return Utility.getImageURL("locked.png");
             }
-            return dojoConfig.getImageURL("unlocked.png");
+            return Utility.getImageURL("unlocked.png");
         },
         getCompressedImage: function () {
             if (this.IsCompressed) {

+ 5 - 4
esp/src/eclwatch/ESPQueue.js

@@ -24,10 +24,11 @@ define([
     "hpcc/ESPUtil",
     "hpcc/ESPRequest",
     "hpcc/ESPWorkunit",
-    "hpcc/ESPDFUWorkunit"
+    "hpcc/ESPDFUWorkunit",
+    "hpcc/Utility"
 
 ], function (declare, arrayUtil, lang, Memory, Observable,
-    WsSMC, ESPUtil, ESPRequest, ESPWorkunit, ESPDFUWorkunit) {
+    WsSMC, ESPUtil, ESPRequest, ESPWorkunit, ESPDFUWorkunit, Utility) {
 
     var Store = declare([Memory], {
         idProperty: "__hpcc_id"
@@ -272,7 +273,7 @@ define([
         },
 
         getStateImage: function () {
-            return dojoConfig.getImageURL(this.getStateImageName());
+            return Utility.getImageURL(this.getStateImageName());
         }
     });
 
@@ -346,7 +347,7 @@ define([
         },
 
         getStateImage: function () {
-            return dojoConfig.getImageURL(this.getStateImageName());
+            return Utility.getImageURL(this.getStateImageName());
         }
 
     });

+ 4 - 3
esp/src/eclwatch/ESPResult.js

@@ -27,10 +27,11 @@ define([
 
     "hpcc/ESPBase",
     "hpcc/ESPRequest",
-    "hpcc/WsWorkunits"
+    "hpcc/WsWorkunits",
+    "hpcc/Utility"
 ], function (declare, arrayUtil, i18n, nlsHPCC, Deferred, lang, domConstruct,
             parser, entities,
-            ESPBase, ESPRequest, WsWorkunits) {
+    ESPBase, ESPRequest, WsWorkunits, Utility) {
 
     var safeEncode = function (item) {
         switch (Object.prototype.toString.call(item)) {
@@ -477,7 +478,7 @@ define([
                         column.sortable = false;
                         column.width += keyed ? 16 : 0;
                         column.renderHeaderCell = function (node) {
-                            node.innerHTML = this.label + (this.__hpcc_keyed ? dojoConfig.getImageHTML("index.png", context.i18n.Index) : "");
+                            node.innerHTML = this.label + (this.__hpcc_keyed ? Utility.getImageHTML("index.png", context.i18n.Index) : "");
                         };
                         if (children) {
                             column.children = children;

+ 4 - 4
esp/src/eclwatch/ESPWorkunit.js

@@ -708,10 +708,10 @@ define([
             return "workunit.png";
         },
         getStateImage: function () {
-            return dojoConfig.getImageURL(this.getStateImageName());
+            return Utility.getImageURL(this.getStateImageName());
         },
         getStateImageHTML: function () {
-            return dojoConfig.getImageHTML(this.getStateImageName());
+            return Utility.getImageHTML(this.getStateImageName());
         },
         getProtectedImageName: function () {
             if (this.Protected) {
@@ -720,10 +720,10 @@ define([
             return "unlocked.png";
         },
         getProtectedImage: function () {
-            return dojoConfig.getImageURL(this.getProtectedImageName());
+            return Utility.getImageURL(this.getProtectedImageName());
         },
         getProtectedHTML: function () {
-            return dojoConfig.getImageHTML(this.getProtectedImageName());
+            return Utility.getImageHTML(this.getProtectedImageName());
         },
         fetchText: function (onFetchText) {
             var context = this;

+ 4 - 3
esp/src/eclwatch/FilterDropDownWidget.js

@@ -29,6 +29,7 @@ define([
     "dijit/form/CheckBox",
 
     "hpcc/_Widget",
+    "hpcc/Utility",
 
     "dojo/text!../templates/FilterDropDownWidget.html",
 
@@ -41,7 +42,7 @@ define([
 
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, dom, domForm, on, domStyle,
                 registry, Select, CheckBox,
-                _Widget,
+                _Widget, Utility,
                 template) {
     return declare("FilterDropDownWidget", [_Widget], {
         templateString: template,
@@ -160,13 +161,13 @@ define([
 
         refreshState: function () {
             if (this.exists()) {
-                this.iconFilter.src = dojoConfig.getImageURL("filter1.png");
+                this.iconFilter.src = Utility.getImageURL("filter1.png");
                 dom.byId(this.id + "FilterDropDown_label").innerHTML = this.i18n.FilterSet;
                 domStyle.set(this.id + "FilterDropDown_label", {
                     "font-weight": "bold"
                 });
             } else {
-                this.iconFilter.src = dojoConfig.getImageURL("noFilter1.png");
+                this.iconFilter.src = Utility.getImageURL("noFilter1.png");
                 dom.byId(this.id + "FilterDropDown_label").innerHTML = this.i18n.Filter;
                 domStyle.set(this.id + "FilterDropDown_label", {
                     "font-weight": "normal"

+ 2 - 2
esp/src/eclwatch/GetDFUWorkunitsWidget.js

@@ -364,13 +364,13 @@ define([
                     }),
                     isProtected: {
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("locked.png", context.i18n.Protected);
+                            node.innerHTML = Utility.getImageHTML("locked.png", context.i18n.Protected);
                         },
                         width: 25,
                         sortable: false,
                         formatter: function (_protected) {
                             if (_protected === true) {
-                                return dojoConfig.getImageHTML("locked.png");
+                                return Utility.getImageHTML("locked.png");
                             }
                             return "";
                         }

+ 6 - 5
esp/src/eclwatch/GraphPageWidget.js

@@ -37,6 +37,7 @@ define([
     "hpcc/ESPWorkunit",
     "hpcc/TimingTreeMapWidget",
     "hpcc/WsWorkunits",
+    "hpcc/Utility",
 
     "dojo/text!../templates/GraphPageWidget.html",
 
@@ -55,14 +56,14 @@ define([
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, Deferred, dom, domConstruct, on, html,
             registry, Dialog,
             entities,
-            _Widget, GraphWidget, JSGraphWidget, ESPUtil, ESPWorkunit, TimingTreeMapWidget, WsWorkunits,
+            _Widget, GraphWidget, JSGraphWidget, ESPUtil, ESPWorkunit, TimingTreeMapWidget, WsWorkunits, Utility,
             template) {
     return declare("GraphPageWidget", [_Widget], {
         templateString: template,
         baseClass: "GraphPageWidget",
         i18n: nlsHPCC,
 
-        graphType: dojoConfig.isPluginInstalled() ? "GraphWidget" : "JSGraphWidget",
+        graphType: Utility.isPluginInstalled() ? "GraphWidget" : "JSGraphWidget",
         borderContainer: null,
         rightBorderContainer: null,
         graphName: "",
@@ -570,7 +571,7 @@ define([
                 {
                     label: this.i18n.ID, field: "id", width: 54,
                     formatter: function (_id, row) {
-                        var img = dojoConfig.getImageURL("folder.png");
+                        var img = Utility.getImageURL("folder.png");
                         return "<img src='" + img + "'/>&nbsp;" + _id;
                     }
                 }
@@ -587,7 +588,7 @@ define([
                 {
                     label: this.i18n.ID, field: "id", width: 54,
                     formatter: function (_id, row) {
-                        var img = dojoConfig.getImageURL("file.png");
+                        var img = Utility.getImageURL("file.png");
                         return "<img src='" + img + "'/>&nbsp;" + _id;
                     }
                 },
@@ -620,7 +621,7 @@ define([
             }
         },
 
-        _syncSelectionFrom: dojoConfig.debounce(function (sourceControl) {
+        _syncSelectionFrom: Utility.debounce(function (sourceControl) {
             this.inSyncSelectionFrom = true;
             var selectedGlobalIDs = [];
 

+ 9 - 8
esp/src/eclwatch/GraphTreeWidget.js

@@ -45,6 +45,7 @@ define([
     "hpcc/ESPWorkunit",
     "hpcc/TimingTreeMapWidget",
     "hpcc/WsWorkunits",
+    "hpcc/Utility",
 
     "dojo/text!../templates/GraphTreeWidget.html",
 
@@ -63,7 +64,7 @@ define([
             registry, Dialog, Menu, MenuItem, MenuSeparator, CheckedMenuItem,
             entities,
             tree,
-            _Widget, GraphWidget, JSGraphWidget, ESPUtil, ESPWorkunit, TimingTreeMapWidget, WsWorkunits,
+            _Widget, GraphWidget, JSGraphWidget, ESPUtil, ESPWorkunit, TimingTreeMapWidget, WsWorkunits, Utility,
             template) {
 
     return declare("GraphTreeWidget", [_Widget], {
@@ -71,7 +72,7 @@ define([
         baseClass: "GraphTreeWidget",
         i18n: nlsHPCC,
 
-        graphType: dojoConfig.isPluginInstalled() ? "GraphWidget" : "JSGraphWidget",
+        graphType: Utility.isPluginInstalled() ? "GraphWidget" : "JSGraphWidget",
         graphName: "",
         wu: null,
         global: null,
@@ -597,15 +598,15 @@ define([
                         return false;
                     },
                     formatter: function (_id, row) {
-                        var img = dojoConfig.getImageURL("file.png");
+                        var img = Utility.getImageURL("file.png");
                         var label = _id + " - ";
                         switch (row._globalType) {
                             case "Graph":
-                                img = dojoConfig.getImageURL("server.png");
+                                img = Utility.getImageURL("server.png");
                                 label = context.params.GraphName + " (" + row._children.length + ")";
                                 break;
                             case "Cluster":
-                                img = dojoConfig.getImageURL("folder.png");
+                                img = Utility.getImageURL("folder.png");
                                 label += context.i18n.Subgraph + " (" + row._children.length + ")";
                                 break;
                             case "Vertex":
@@ -636,7 +637,7 @@ define([
                 {
                     label: this.i18n.ID, field: "id", width: 54,
                     formatter: function (_id, row) {
-                        var img = dojoConfig.getImageURL("folder.png");
+                        var img = Utility.getImageURL("folder.png");
                         return "<img src='" + img + "'/>&nbsp;" + _id;
                     }
                 }
@@ -653,7 +654,7 @@ define([
                 {
                     label: this.i18n.ID, field: "id", width: 54,
                     formatter: function (_id, row) {
-                        var img = dojoConfig.getImageURL("file.png");
+                        var img = Utility.getImageURL("file.png");
                         return "<img src='" + img + "'/>&nbsp;" + _id;
                     }
                 },
@@ -703,7 +704,7 @@ define([
             }
         },
 
-        _syncSelectionFrom: dojoConfig.debounce(function (sourceControlOrGlobalIDs) {
+        _syncSelectionFrom: Utility.debounce(function (sourceControlOrGlobalIDs) {
             this.inSyncSelectionFrom = true;
             var sourceControl = sourceControlOrGlobalIDs instanceof Array ? null : sourceControlOrGlobalIDs;
             var selectedGlobalIDs = sourceControlOrGlobalIDs instanceof Array ? sourceControlOrGlobalIDs : [];

+ 3 - 9
esp/src/eclwatch/GraphWidget.js

@@ -560,7 +560,7 @@ define([
 
             startup: function (args) {
                 this.inherited(arguments);
-                this._isPluginInstalled = dojoConfig.isPluginInstalled();
+                this._isPluginInstalled = Utility.isPluginInstalled();
                 this.createPlugin();
                 this.watchStyleChange();
                 this.watchSelect(this.zoomDropCombo);
@@ -747,14 +747,8 @@ define([
                 return this.depth.get("value");
             },
 
-            localLayout: function(callback) {
-                var context = this;
-                require(
-                  ["hpcc/viz"],
-                  function (viz) {
-                      callback(viz(context.dot, "svg"));
-                  }
-                );
+            localLayout: function (callback) {
+                callback("Deprecated...");
             },
 
             displayProperties: function (wu, globalID, place) {

+ 5 - 4
esp/src/eclwatch/GraphsWidget.js

@@ -32,12 +32,13 @@ define([
     "hpcc/ESPLogicalFile",
     "hpcc/DelayLoadWidget",
     "hpcc/TimingTreeMapWidget",
-    "hpcc/ESPUtil"
+    "hpcc/ESPUtil",
+    "hpcc/Utility",
 
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, on, has,
                 Button,
                 selector,
-                GridDetailsWidget, ESPWorkunit, ESPQuery, ESPLogicalFile, DelayLoadWidget, TimingTreeMapWidget, ESPUtil) {
+                GridDetailsWidget, ESPWorkunit, ESPQuery, ESPLogicalFile, DelayLoadWidget, TimingTreeMapWidget, ESPUtil, Utility) {
     return declare("GraphsWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 
@@ -113,7 +114,7 @@ define([
         },
 
         getStateImageHTML: function (row) {
-            return dojoConfig.getImageHTML(this.getStateImageName(row));
+            return Utility.getImageHTML(this.getStateImageName(row));
         },
 
         createGrid: function (domID) {
@@ -126,7 +127,7 @@ define([
                     });
                 }
             }).placeAt(this.widget.Open.domNode, "after");
-            if (dojoConfig.isPluginInstalled() && !this.isIE8) {
+            if (Utility.isPluginInstalled() && !this.isIE8) {
                 this.openNativeMode = new Button({
                     label: this.i18n.OpenNativeMode,
                     onClick: function (event) {

+ 9 - 0
esp/src/eclwatch/HPCCPlatformWidget.js

@@ -70,6 +70,15 @@ define([
                 UpgradeBar, ColorPicker,
                 _TabContainerWidget, ESPRequest, ESPActivity, WsAccount, WsAccess, WsSMC, WsTopology, GraphWidget, DelayLoadWidget, WsMachine,
                 template) {
+
+    declare("HPCCColorPicker", [ColorPicker], {
+        _underlay: "/esp/files/eclwatch/img/underlay.png",
+        _hueUnderlay: "/esp/files/eclwatch/img/hue.png",
+        _pickerPointer: "/esp/files/eclwatch/img/pickerPointer.png",
+        _huePickerPointer: "/esp/files/eclwatch/img/hueHandle.png",
+        _huePickerPointerAlly: "/esp/files/eclwatch/img/hueHandleA11y.png"
+    });
+
     return declare("HPCCPlatformWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformWidget",

+ 417 - 430
esp/src/eclwatch/JSGraphWidget.js

@@ -21,10 +21,15 @@ define([
     "dojo/_base/array",
     "dojo/Evented",
 
+    "@hpcc-js/common",
+    "@hpcc-js/graph",
+    "@hpcc-js/layout",
+    
     "hpcc/WsWorkunits",
     "hpcc/GraphWidget",
     "hpcc/ESPGraph"
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, Evented,
+            hpccCommon, hpccGraph, hpccLayout,
             WsWorkunits, GraphWidget, ESPGraph) {
 
     var Persist = declare([], {
@@ -110,419 +115,403 @@ define([
         return "\uf063";
     };
 
-    var loadJSPlugin = function (callback) {
-        function requireWidgets() {
-            require(["src/common/Shape", "src/common/Icon", "src/common/TextBox", "src/common/Surface", "src/graph/Graph", "src/graph/Vertex", "src/graph/Edge", "src/layout/Layered"], function (Shape, Icon, TextBox, Surface, Graph, Vertex, Edge, Layered) {
-                callback(declare([Evented], {
-                    KeyState_None: 0,
-                    KeyState_Shift: 1,
-                    KeyState_Control: 2,
-                    KeyState_Menu: 4,
-
-                    constructor: function (domNode) {
-                        this.graphData = new ESPGraph();
-                        this.graphWidget = new Graph()
-                            .allowDragging(false)
-                        ;
-                        var context = this;
-                        this.graphWidget.vertex_click = function (item, event) {
-                            context.emit("SelectionChanged", [item]);
-                        }
-                        this.graphWidget.edge_click = function (item, event) {
-                            context.emit("SelectionChanged", [item]);
-                        }
-                        this.graphWidget.vertex_dblclick = function (item, event) {
-                            context.emit("MouseDoubleClick", item, (event.shiftKey ? context.KeyState_Shift : 0) + (event.ctrlKey ? context.KeyState_Control : 0) + (event.altKey ? context.KeyState_Menu : 0));
+    var JSPlugin = declare([Evented], {
+        KeyState_None: 0,
+        KeyState_Shift: 1,
+        KeyState_Control: 2,
+        KeyState_Menu: 4,
+
+        constructor: function (domNode) {
+            this.graphData = new ESPGraph();
+            this.graphWidget = new hpccGraph.Graph()
+                .allowDragging(false)
+            ;
+            var context = this;
+            this.graphWidget.vertex_click = function (item, event) {
+                context.emit("SelectionChanged", [item]);
+            }
+            this.graphWidget.edge_click = function (item, event) {
+                context.emit("SelectionChanged", [item]);
+            }
+            this.graphWidget.vertex_dblclick = function (item, event) {
+                context.emit("MouseDoubleClick", item, (event.shiftKey ? context.KeyState_Shift : 0) + (event.ctrlKey ? context.KeyState_Control : 0) + (event.altKey ? context.KeyState_Menu : 0));
+            }
+            this.messageWidget = new hpccCommon.TextBox()
+                .shape_colorFill("#006CCC")
+                .shape_colorStroke("#003666")
+                .text_colorFill("#FFFFFF")
+            ;
+            this.layout = new hpccLayout.Layered()
+                .target(domNode.id)
+                .widgets([this.messageWidget, this.graphWidget])
+                .render()
+            ;
+            this._options = {};
+        },
+
+        option: function (key, _) {
+            if (arguments.length < 1) throw Error("Invalid Call:  option");
+            if (arguments.length === 1) return this._options[key];
+            this._options[key] = _ instanceof Array ? _.length > 0 : _;
+            return this;
+        },
+
+        optionsReset: function (options) {
+            options = options || this._optionsDefault;
+            for (var key in options) {
+                this.option(key, options[key]);
+            }
+        },
+
+        setMessage: function (msg) {
+            if (msg !== this._prevMsg) {
+                this.messageWidget.text(msg).render();
+                if ((msg && this.graphWidget.visible()) || (!msg && !this.graphWidget.visible())) {
+                    this.graphWidget.visible(msg ? false : true).render();
+                }
+                this._prevMsg = msg;
+            }
+        },
+
+        setScale: function (scale) {
+            this.graphWidget.zoomTo(undefined, scale / 100);
+        },
+
+        centerOnItem: function (item, scaleToFit, widthOnly) {
+            if (item) {
+                if (scaleToFit) {
+                    var bbox = item.__widget.getBBox();
+                    this.graphWidget.zoomToBBox(bbox);
+                } else {
+                    var bounds = this.graphWidget.getBounds([item.__widget]);
+                    this.graphWidget.centerOn(bounds);
+                }    
+            } else {
+                if (scaleToFit) {
+                    this.graphWidget.zoomToFit();
+                } else {
+                    var bounds = this.graphWidget.getVertexBounds();
+                    this.graphWidget.centerOn(bounds);
+                }    
+            }
+        },
+
+        getSelectionAsGlobalID: function () {
+            var selection = this.graphWidget.selection();
+            return selection.map(function (item) {
+                return item.__hpcc_globalID;
+            });
+        },
+
+        setSelectedAsGlobalID: function (globalIDs) {
+            var selection = [];
+            globalIDs.forEach(function (globalID, idx) {
+                var item = this.getItem(globalID);
+                if (item && item.__widget) {
+                    selection.push(item.__widget);
+                }
+            }, this);
+            this.graphWidget.selection(selection);
+        },
+
+        getGlobalType: function (item) {
+            return this.graphData.getGlobalTypeString(item);
+        },
+
+        getGlobalID: function (item) {
+            return item.__hpcc_id;
+        },
+
+        getItem: function (globalID) {
+            return this.graphData.idx[globalID];
+        },
+
+        setSelected: function (items) {
+            this.graphWidget.selection(items);
+        },
+
+        getSelection: function () {
+            return this.graphWidget.selection();
+        },
+
+        getSVG: function () {
+            return "";  //TODO - Should be Serialized Layout to prevent re-calculation on prev/next  ---
+        },
+
+        getDOT: function () {
+            return "";
+        },
+
+        getVertices: function () {
+            return this.graphData.vertices;
+        },
+
+        find: function (findText) {
+            var findProp = "";
+            var findTerm = findText;
+            var findTextParts = findText.split(":");
+            if (findTextParts.length > 1) {
+                findProp = findTextParts[0];
+                findTextParts.splice(0, 1);
+                findTerm = findTextParts.join(":");
+            }
+            return arrayUtil.filter(this.graphData.vertices, function (item) {
+                if (findProp) {
+                    if (item.hasOwnProperty(findProp)) {
+                        return (item[findProp].toString().toLowerCase().indexOf(findTerm.toLowerCase()) >= 0);
+                    }
+                } else {
+                    for (var key in item) {
+                        if (item.hasOwnProperty(key) && item[key].toString().toLowerCase().indexOf(findTerm.toLowerCase()) >= 0) {
+                            return true;
                         }
-                        this.messageWidget = new TextBox()
-                            .shape_colorFill("#006CCC")
-                            .shape_colorStroke("#003666")
-                            .text_colorFill("#FFFFFF")
-                        ;
-                        this.layout = new Layered()
-                            .target(domNode.id)
-                            .widgets([this.messageWidget, this.graphWidget])
-                            .render()
+                    }
+                }
+                return false;
+            });
+        },
+
+        cleanObject: function (object) {
+            var retVal = {};
+            for (var key in object) {
+                if (object.hasOwnProperty(key) && typeof object[key] !== "function") {
+                    retVal[key] = object[key];
+                }
+            }
+            return retVal;
+        },
+
+        cleanObjects: function (objects) {
+            return objects.map(function (object) {
+                return this.cleanObject(object);
+            }, this);
+        },
+
+        gatherTreeWithProperties: function (subgraph) {
+            subgraph = subgraph || this.graphData.subgraphs[0];
+            var retVal = subgraph.getProperties();
+            retVal._children = [];
+            arrayUtil.forEach(subgraph.__hpcc_subgraphs, function (subgraph, idx) {
+                retVal._children.push(this.gatherTreeWithProperties(subgraph));
+            }, this);
+            arrayUtil.forEach(subgraph.__hpcc_vertices, function (vertex, idx) {
+                retVal._children.push(vertex.getProperties());
+            }, this);
+            return retVal;
+        },
+
+        getProperties: function (item) {
+            return item.getProperties();
+        },
+
+        getTreeWithProperties: function () {
+            return [this.gatherTreeWithProperties()];
+        },
+
+        getSubgraphsWithProperties: function () {
+            return this.cleanObjects(this.graphData.subgraphs);
+        },
+
+        getVerticesWithProperties: function () {
+            return this.cleanObjects(this.graphData.vertices);
+        },
+
+        getEdgesWithProperties: function () {
+            return this.cleanObjects(this.graphData.edges);
+        },
+
+        getLocalisedXGMML2: function (selectedItems, depth, distance, noSpills) {
+            return this.graphData.getLocalisedXGMML(selectedItems, depth, distance, noSpills);
+        },
+
+        startLayout: function (layout) {
+            var context = this;
+            setTimeout(function (layout) {
+                context.graphWidget
+                    .layout("Hierarchy")
+                    .render()
+                ;
+                context.emit("LayoutFinished", {});
+            }, 100);
+        },
+
+        clear: function () {
+            this.graphData.clear();
+            this.graphWidget.clear();
+        },
+
+        mergeXGMML: function (xgmml) {
+            this._loadXGMML(xgmml, true);
+        },
+
+        loadXGMML: function (xgmml) {
+            this._loadXGMML(xgmml, false);
+        },
+
+        _loadXGMML: function (xgmml, merge) {
+            if (merge) {
+                this.graphData.merge(xgmml, {});
+            } else {
+                this.graphData.load(xgmml, {});
+            }
+            if (!this._skipRender) {
+                this.rebuild(merge);
+            }
+        },
+
+        format: function (labelTpl, obj) {
+            var retVal = "";
+            var lpos = labelTpl.indexOf("%");
+            var rpos = -1;
+            while (lpos >= 0) {
+                retVal += labelTpl.substring(rpos + 1, lpos);
+                rpos = labelTpl.indexOf("%", lpos + 1);
+                if (rpos < 0) {
+                    console.log("Invalid Label Template");
+                    break;
+                }
+                var key = labelTpl.substring(lpos + 1, rpos);
+                retVal += !key ? "%" : (obj[labelTpl.substring(lpos + 1, rpos)] || "");
+                lpos = labelTpl.indexOf("%", rpos + 1);
+            }
+            retVal += labelTpl.substring(rpos + 1, labelTpl.length);
+            return retVal.split("\\n").join("\n");
+        },
+
+        rebuild: function (merge) {
+            merge = merge || false;
+            var vertices = [];
+            var edges = [];
+            var hierarchy = [];
+
+            if (this.option("subgraph")) {
+                arrayUtil.forEach(this.graphData.subgraphs, function (subgraph, idx) {
+                    if (!merge || !subgraph.__widget) {
+                        subgraph.__widget = new hpccCommon.Surface()
+                            .classed({ subgraph: true })
+                            .showIcon(false)
+                            .width(0)
+                            .height(0)
+                            .title(subgraph.__hpcc_id)
                         ;
-                        this._options = {};
-                    },
-
-                    option: function (key, _) {
-                        if (arguments.length < 1) throw Error("Invalid Call:  option");
-                        if (arguments.length === 1) return this._options[key];
-                        this._options[key] = _ instanceof Array ? _.length > 0 : _;
-                        return this;
-                    },
-
-                    optionsReset: function (options) {
-                        options = options || this._optionsDefault;
-                        for (var key in options) {
-                            this.option(key, options[key]);
-                        }
-                    },
-
-                    setMessage: function (msg) {
-                        if (msg !== this._prevMsg) {
-                            this.messageWidget.text(msg).render();
-                            if ((msg && this.graphWidget.visible()) || (!msg && !this.graphWidget.visible())) {
-                                this.graphWidget.visible(msg ? false : true).render();
-                            }
-                            this._prevMsg = msg;
-                        }
-                    },
-
-                    setScale: function (scale) {
-                        this.graphWidget.zoom.scale(scale / 100);
-                        this.graphWidget.applyZoom(this.graphWidget._transitionDuration);
-                    },
-
-                    centerOnItem: function (item, scaleToFit, widthOnly) {
-                        var bounds = item === 0 ? this.graphWidget.getVertexBounds() : this.graphWidget.getBounds([item.__widget]);
-                        if (scaleToFit) {
-                            if (widthOnly) {
-                                bounds[0][1] = 0;
-                                bounds[1][1] = 0;
-                            }
-                            this.graphWidget.shrinkToFit(bounds);
-                        } else {
-                            this.graphWidget.centerOn(bounds);
-                        }
-                    },
-
-                    getSelectionAsGlobalID: function () {
-                        var selection = this.graphWidget.selection();
-                        return selection.map(function (item) {
-                            return item.__hpcc_globalID;
-                        });
-                    },
-
-                    setSelectedAsGlobalID: function (globalIDs) {
-                        var selection = [];
-                        globalIDs.forEach(function (globalID, idx) {
-                            var item = this.getItem(globalID);
-                            if (item && item.__widget) {
-                                selection.push(item.__widget);
-                            }
-                        }, this);
-                        this.graphWidget.selection(selection);
-                    },
-
-                    getGlobalType: function (item) {
-                        return this.graphData.getGlobalTypeString(item);
-                    },
-
-                    getGlobalID: function (item) {
-                        return item.__hpcc_id;
-                    },
-
-                    getItem: function (globalID) {
-                        return this.graphData.idx[globalID];
-                    },
-
-                    setSelected: function (items) {
-                        this.graphWidget.selection(items);
-                    },
-
-                    getSelection: function () {
-                        return this.graphWidget.selection();
-                    },
-
-                    getSVG: function () {
-                        return "";  //TODO - Should be Serialized Layout to prevent re-calculation on prev/next  ---
-                    },
-
-                    getDOT: function () {
-                        return "";
-                    },
-
-                    getVertices: function () {
-                        return this.graphData.vertices;
-                    },
-
-                    find: function (findText) {
-                        var findProp = "";
-                        var findTerm = findText;
-                        var findTextParts = findText.split(":");
-                        if (findTextParts.length > 1) {
-                            findProp = findTextParts[0];
-                            findTextParts.splice(0, 1);
-                            findTerm = findTextParts.join(":");
-                        }
-                        return arrayUtil.filter(this.graphData.vertices, function (item) {
-                            if (findProp) {
-                                if (item.hasOwnProperty(findProp)) {
-                                    return (item[findProp].toString().toLowerCase().indexOf(findTerm.toLowerCase()) >= 0);
-                                }
-                            } else {
-                                for (var key in item) {
-                                    if (item.hasOwnProperty(key) && item[key].toString().toLowerCase().indexOf(findTerm.toLowerCase()) >= 0) {
-                                        return true;
-                                    }
-                                }
-                            }
-                            return false;
-                        });
-                    },
-
-                    cleanObject: function (object) {
-                        var retVal = {};
-                        for (var key in object) {
-                            if (object.hasOwnProperty(key) && typeof object[key] !== "function") {
-                                retVal[key] = object[key];
-                            }
-                        }
-                        return retVal;
-                    },
-
-                    cleanObjects: function (objects) {
-                        return objects.map(function (object) {
-                            return this.cleanObject(object);
-                        }, this);
-                    },
-
-                    gatherTreeWithProperties: function (subgraph) {
-                        subgraph = subgraph || this.graphData.subgraphs[0];
-                        var retVal = subgraph.getProperties();
-                        retVal._children = [];
-                        arrayUtil.forEach(subgraph.__hpcc_subgraphs, function (subgraph, idx) {
-                            retVal._children.push(this.gatherTreeWithProperties(subgraph));
-                        }, this);
-                        arrayUtil.forEach(subgraph.__hpcc_vertices, function (vertex, idx) {
-                            retVal._children.push(vertex.getProperties());
-                        }, this);
-                        return retVal;
-                    },
-
-                    getProperties: function (item) {
-                        return item.getProperties();
-                    },
-
-                    getTreeWithProperties: function () {
-                        return [this.gatherTreeWithProperties()];
-                    },
-
-                    getSubgraphsWithProperties: function () {
-                        return this.cleanObjects(this.graphData.subgraphs);
-                    },
-
-                    getVerticesWithProperties: function () {
-                        return this.cleanObjects(this.graphData.vertices);
-                    },
-
-                    getEdgesWithProperties: function () {
-                        return this.cleanObjects(this.graphData.edges);
-                    },
-
-                    getLocalisedXGMML2: function (selectedItems, depth, distance, noSpills) {
-                        return this.graphData.getLocalisedXGMML(selectedItems, depth, distance, noSpills);
-                    },
-
-                    startLayout: function (layout) {
-                        var context = this;
-                        setTimeout(function (layout) {
-                            context.graphWidget
-                                .layout("Hierarchy")
-                                .render()
-                            ;
-                            context.emit("LayoutFinished", {});
-                        }, 100);
-                    },
-
-                    clear: function () {
-                        this.graphData.clear();
-                        this.graphWidget.clear();
-                    },
-
-                    mergeXGMML: function (xgmml) {
-                        this._loadXGMML(xgmml, true);
-                    },
-
-                    loadXGMML: function (xgmml) {
-                        this._loadXGMML(xgmml, false);
-                    },
-
-                    _loadXGMML: function (xgmml, merge) {
-                        if (merge) {
-                            this.graphData.merge(xgmml, {});
-                        } else {
-                            this.graphData.load(xgmml, {});
-                        }
-                        if (!this._skipRender) {
-                            this.rebuild(merge);
-                        }
-                    },
-
-                    format: function (labelTpl, obj) {
-                        var retVal = "";
-                        var lpos = labelTpl.indexOf("%");
-                        var rpos = -1;
-                        while (lpos >= 0) {
-                            retVal += labelTpl.substring(rpos + 1, lpos);
-                            rpos = labelTpl.indexOf("%", lpos + 1);
-                            if (rpos < 0) {
-                                console.log("Invalid Label Template");
+                        subgraph.__widget.__hpcc_globalID = subgraph.__hpcc_id;
+                    }
+                    vertices.push(subgraph.__widget);
+                }, this);
+            }
+            var labelTpl = this.option("vlabel");
+            var tooltipTpl = this.option("vtooltip");
+            arrayUtil.forEach(this.graphData.vertices, function (item, idx) {
+                if (!this.option("vhidespills") || !item.isSpill()) {
+                    if (!merge || !item.__widget) {
+                        switch (item._kind) {
+                            case "point":
+                                item.__widget = new hpccCommon.Shape()
+                                    .radius(7)
+                                ;
                                 break;
-                            }
-                            var key = labelTpl.substring(lpos + 1, rpos);
-                            retVal += !key ? "%" : (obj[labelTpl.substring(lpos + 1, rpos)] || "");
-                            lpos = labelTpl.indexOf("%", rpos + 1);
-                        }
-                        retVal += labelTpl.substring(rpos + 1, labelTpl.length);
-                        return retVal.split("\\n").join("\n");
-                    },
-
-                    rebuild: function (merge) {
-                        merge = merge || false;
-                        var vertices = [];
-                        var edges = [];
-                        var hierarchy = [];
-
-                        if (this.option("subgraph")) {
-                            arrayUtil.forEach(this.graphData.subgraphs, function (subgraph, idx) {
-                                if (!merge || !subgraph.__widget) {
-                                    subgraph.__widget = new Surface()
-                                        .classed({ subgraph: true })
-                                        .showIcon(false)
-                                        .width(0)
-                                        .height(0)
-                                        .title(subgraph.__hpcc_id)
+                            default:
+                                if (this.option("vicon") && this.option("vlabel")) {
+                                    item.__widget = new hpccGraph.Vertex()
+                                        .faChar(faCharFactory(item._kind))
                                     ;
-                                    subgraph.__widget.__hpcc_globalID = subgraph.__hpcc_id;
-                                }
-                                vertices.push(subgraph.__widget);
-                            }, this);
-                        }
-                        var labelTpl = this.option("vlabel");
-                        var tooltipTpl = this.option("vtooltip");
-                        arrayUtil.forEach(this.graphData.vertices, function (item, idx) {
-                            if (!this.option("vhidespills") || !item.isSpill()) {
-                                if (!merge || !item.__widget) {
-                                    switch (item._kind) {
-                                        case "point":
-                                            item.__widget = new Shape()
-                                                .radius(7)
-                                            ;
-                                            break;
-                                        default:
-                                            if (this.option("vicon") && this.option("vlabel")) {
-                                                item.__widget = new Vertex()
-                                                    .faChar(faCharFactory(item._kind))
-                                                ;
-                                            } else if (this.option("vicon")) {
-                                                item.__widget = new Icon()
-                                                    .faChar(faCharFactory(item._kind))
-                                                ;
-                                            } else if (this.option("vlabel")) {
-                                                item.__widget = new TextBox()
-                                                ;
-                                            } else {
-                                                item.__widget = new Shape()
-                                                    .radius(7)
-                                                ;
-                                            }
-                                            break;
-                                    }
-                                    item.__widget.__hpcc_globalID = item.__hpcc_id;
-                                }
-                                if (item.__widget.text) {
-                                    var label = this.format(labelTpl, item);
-                                    item.__widget.text(label);
-                                }
-                                if (item.__widget.tooltip) {
-                                    var tooltip = this.format(tooltipTpl, item);
-                                    item.__widget.tooltip(tooltip);
-                                }
-                                vertices.push(item.__widget);
-                            }
-                        }, this);
-                        labelTpl = this.option("elabel");
-                        tooltipTpl = this.option("etooltip");
-                        arrayUtil.forEach(this.graphData.edges, function (item, idx) {
-                            var source = item.getSource();
-                            var target = item.getTarget();
-                            if (!this.option("vhidespills") || !target.isSpill()) {
-                                var label = this.format(labelTpl, item);
-                                var tooltip = this.format(tooltipTpl, item);
-                                var slavesTotal = parseInt(item.NumSlaves);
-                                var started = parseInt(item.NumStarted) > 0;
-                                var finished = parseInt(item.NumStopped) === parseInt(item.NumSlaves);
-                                var active = started && !finished;
-
-                                var strokeDasharray = null;
-                                var weight = 100;
-                                if (item._dependsOn) {
-                                    weight = 10;
-                                    strokeDasharray = "1,5";
-                                } else if (item._childGraph) {
-                                    strokeDasharray = "5,5";
-                                } else if (item._isSpill) {
-                                    weight = 25;
-                                    strokeDasharray = "5,5,10,5";
-                                }
-                                if (this.option("vhidespills") && source.isSpill()) {
-                                    label += "\n(" + nlsHPCC.Spill + ")";
-                                    weight = 25;
-                                    strokeDasharray = "5,5,10,5";
-                                    while (source.isSpill()) {
-                                        var inputs = source.getInVertices();
-                                        source = inputs[0];
-                                    }
-                                }
-                                if (!merge || !item.__widget) {
-                                    item.__widget = new Edge()
-                                        .sourceVertex(source.__widget)
-                                        .targetVertex(target.__widget)
-                                        .targetMarker("arrowHead")
-                                        .weight(weight)
-                                        .strokeDasharray(strokeDasharray)
+                                } else if (this.option("vicon")) {
+                                    item.__widget = new hpccCommon.Icon()
+                                        .faChar(faCharFactory(item._kind))
+                                    ;
+                                } else if (this.option("vlabel")) {
+                                    item.__widget = new hpccCommon.TextBox()
+                                    ;
+                                } else {
+                                    item.__widget = new hpccCommon.Shape()
+                                        .radius(7)
                                     ;
-                                    item.__widget.__hpcc_globalID = item.__hpcc_id;
                                 }
-                                item.__widget.text(label);
-                                item.__widget.tooltip(tooltip);
-                                item.__widget.classed({
-                                    started: started && !finished && !active,
-                                    finished: finished && !active,
-                                    active: active
-                                });
-                                edges.push(item.__widget);
-                            }
-                        }, this);
-                        if (this.option("subgraph")) {
-                            arrayUtil.forEach(this.graphData.subgraphs, function (subgraph, idx) {
-                                arrayUtil.forEach(subgraph.__hpcc_subgraphs, function (item, idx) {
-                                    if (subgraph.__widget && item.__widget) {
-                                        hierarchy.push({ parent: subgraph.__widget, child: item.__widget });
-                                    }
-                                }, this);
-                                arrayUtil.forEach(subgraph.__hpcc_vertices, function (item, idx) {
-                                    if (subgraph.__widget && item.__widget) {
-                                        hierarchy.push({ parent: subgraph.__widget, child: item.__widget });
-                                    }
-                                }, this);
-                            }, this);
+                                break;
                         }
-                        this.graphWidget.data({ vertices: vertices, edges: edges, hierarchy: hierarchy, merge: merge });
+                        item.__widget.__hpcc_globalID = item.__hpcc_id;
                     }
-                }));
-            });
-        }
-        if (dojoConfig.vizDebug) {
-            requireWidgets();
-        } else {
-            require(["dist-amd/hpcc-viz"], function() {
-                require(["dist-amd/hpcc-viz-common"], function () {
-                    require(["dist-amd/hpcc-viz-api"], function () {
-                        require(["dist-amd/hpcc-viz-graph"], function () {
-                            require(["dist-amd/hpcc-viz-layout"], function () {
-                                requireWidgets();
-                            });
-                        });
+                    if (item.__widget.text) {
+                        var label = this.format(labelTpl, item);
+                        item.__widget.text(label);
+                    }
+                    if (item.__widget.tooltip) {
+                        var tooltip = this.format(tooltipTpl, item);
+                        item.__widget.tooltip(tooltip);
+                    }
+                    vertices.push(item.__widget);
+                }
+            }, this);
+            labelTpl = this.option("elabel");
+            tooltipTpl = this.option("etooltip");
+            arrayUtil.forEach(this.graphData.edges, function (item, idx) {
+                var source = item.getSource();
+                var target = item.getTarget();
+                if (!this.option("vhidespills") || !target.isSpill()) {
+                    var label = this.format(labelTpl, item);
+                    var tooltip = this.format(tooltipTpl, item);
+                    var slavesTotal = parseInt(item.NumSlaves);
+                    var started = parseInt(item.NumStarted) > 0;
+                    var finished = parseInt(item.NumStopped) === parseInt(item.NumSlaves);
+                    var active = started && !finished;
+
+                    var strokeDasharray = null;
+                    var weight = 100;
+                    if (item._dependsOn) {
+                        weight = 10;
+                        strokeDasharray = "1,5";
+                    } else if (item._childGraph) {
+                        strokeDasharray = "5,5";
+                    } else if (item._isSpill) {
+                        weight = 25;
+                        strokeDasharray = "5,5,10,5";
+                    }
+                    if (this.option("vhidespills") && source.isSpill()) {
+                        label += "\n(" + nlsHPCC.Spill + ")";
+                        weight = 25;
+                        strokeDasharray = "5,5,10,5";
+                        while (source.isSpill()) {
+                            var inputs = source.getInVertices();
+                            source = inputs[0];
+                        }
+                    }
+                    if (!merge || !item.__widget) {
+                        item.__widget = new hpccGraph.Edge()
+                            .sourceVertex(source.__widget)
+                            .targetVertex(target.__widget)
+                            .targetMarker("arrowHead")
+                            .weight(weight)
+                            .strokeDasharray(strokeDasharray)
+                        ;
+                        item.__widget.__hpcc_globalID = item.__hpcc_id;
+                    }
+                    item.__widget.text(label);
+                    item.__widget.tooltip(tooltip);
+                    item.__widget.classed({
+                        started: started && !finished && !active,
+                        finished: finished && !active,
+                        active: active
                     });
-                });
-            });
+                    edges.push(item.__widget);
+                }
+            }, this);
+            if (this.option("subgraph")) {
+                arrayUtil.forEach(this.graphData.subgraphs, function (subgraph, idx) {
+                    arrayUtil.forEach(subgraph.__hpcc_subgraphs, function (item, idx) {
+                        if (subgraph.__widget && item.__widget) {
+                            hierarchy.push({ parent: subgraph.__widget, child: item.__widget });
+                        }
+                    }, this);
+                    arrayUtil.forEach(subgraph.__hpcc_vertices, function (item, idx) {
+                        if (subgraph.__widget && item.__widget) {
+                            hierarchy.push({ parent: subgraph.__widget, child: item.__widget });
+                        }
+                    }, this);
+                }, this);
+            }
+            this.graphWidget.data({ vertices: vertices, edges: edges, hierarchy: hierarchy, merge: merge });
         }
-    };
+    });
 
     return declare("JSGraphWidget", [GraphWidget], {
         baseClass: "JSGraphWidget",
@@ -567,33 +556,31 @@ define([
             if (!this.hasPlugin()) {
                 this.persist = new Persist(this._persistID || "");
                 var context = this;
-                loadJSPlugin(function (JSPlugin) {
-                    context._plugin = new JSPlugin(context.graphContentPane.domNode);
-                    context._plugin._optionsDefault = context.optionsForm.getValues();
-                    switch (context._persistID) {
-                        case "overview":
-                            context._plugin._optionsDefault.subgraph = ["on"];
-                            context._plugin._optionsDefault.vlabel = "";
-                            break;
-                        case "local":
-                            context._plugin._optionsDefault.subgraph = ["on"];
-                            context._plugin._optionsDefault.vhidespills = ["off"];
-                            break;
-                        default:
-                            context._plugin._optionsDefault.vhidespills = ["on"];
-                            break;
-                    }
-                    var optionsValues = lang.mixin({}, context._plugin._optionsDefault, context.persist.getObj("options"));
-                    context._plugin.optionsReset(optionsValues);
-                    context.optionsForm.setValues(optionsValues);
-                    context.version = {
-                        major: 6,
-                        minor: 0
-                    };
-                    context.registerEvents();
-                    context.refreshRootState();
-                    context.emit("ready");
-                });
+                context._plugin = new JSPlugin(context.graphContentPane.domNode);
+                context._plugin._optionsDefault = context.optionsForm.getValues();
+                switch (context._persistID) {
+                    case "overview":
+                        context._plugin._optionsDefault.subgraph = ["on"];
+                        context._plugin._optionsDefault.vlabel = "";
+                        break;
+                    case "local":
+                        context._plugin._optionsDefault.subgraph = ["on"];
+                        context._plugin._optionsDefault.vhidespills = ["off"];
+                        break;
+                    default:
+                        context._plugin._optionsDefault.vhidespills = ["on"];
+                        break;
+                }
+                var optionsValues = lang.mixin({}, context._plugin._optionsDefault, context.persist.getObj("options"));
+                context._plugin.optionsReset(optionsValues);
+                context.optionsForm.setValues(optionsValues);
+                context.version = {
+                    major: 6,
+                    minor: 0
+                };
+                context.registerEvents();
+                context.refreshRootState();
+                context.emit("ready");
             }
         },
 

+ 2 - 1
esp/src/eclwatch/LFDetailsWidget.js

@@ -55,6 +55,7 @@ define([
     "dijit/TooltipDialog",
     "dijit/form/ValidationTextBox",
     "dijit/form/CheckBox",
+    "dijit/form/NumberTextBox",
     "dijit/Fieldset",
 
     "hpcc/TableContainer"
@@ -302,7 +303,7 @@ define([
                         NodeGroup: this.logicalFile.NodeGroup,
                         Name: this.logicalFile.Name
                     });
-                 } else if (currSel.id == this.fileHistoryWidget.id) {
+                 } else if (currSel.id === this.fileHistoryWidget.id) {
                     this.fileHistoryWidget.init({
                         Name: this.logicalFile.Name
                     });

+ 6 - 5
esp/src/eclwatch/LZBrowseWidget.js

@@ -47,6 +47,7 @@ define([
     "hpcc/TargetComboBoxWidget",
     "hpcc/SelectionGridWidget",
     "hpcc/FilterDropDownWidget",
+    "hpcc/Utility",
 
     "dojo/text!../templates/LZBrowseWidget.html",
 
@@ -73,7 +74,7 @@ define([
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, dom, domForm, domClass, iframe, on, topic,
                 registry, Dialog, Menu, MenuItem, MenuSeparator, PopupMenuItem,
                 tree, editor, selector,
-                _TabContainerWidget, FileSpray, ESPUtil, ESPRequest, ESPDFUWorkunit, DelayLoadWidget, TargetSelectWidget, TargetComboBoxWidget, SelectionGridWidget, FilterDropDownWidget,
+                _TabContainerWidget, FileSpray, ESPUtil, ESPRequest, ESPDFUWorkunit, DelayLoadWidget, TargetSelectWidget, TargetComboBoxWidget, SelectionGridWidget, FilterDropDownWidget, Utility,
                 template) {
     return declare("LZBrowseWidget", [_TabContainerWidget, ESPUtil.FormHelper], {
         templateString: template,
@@ -671,14 +672,14 @@ define([
                             var img = "";
                             var name = _name;
                             if (row.isDir === undefined) {
-                                img = dojoConfig.getImageHTML("server.png");
+                                img = Utility.getImageHTML("server.png");
                                 name += " [" + row.Path + "]";
                             } else if (row.isMachine) {
-                                 img = dojoConfig.getImageHTML("machine.png");
+                                img = Utility.getImageHTML("machine.png");
                             } else if (row.isDir) {
-                                img = dojoConfig.getImageHTML("folder.png");
+                                img = Utility.getImageHTML("folder.png");
                             } else {
-                                img = dojoConfig.getImageHTML("file.png");
+                                img = Utility.getImageHTML("file.png");
                             }
                             return img + "&nbsp;" + name;
                         }

+ 6 - 5
esp/src/eclwatch/MonitoringWidget.js

@@ -34,12 +34,13 @@ define([
     "hpcc/ws_machine",
     "hpcc/ESPWorkunit",
     "hpcc/DelayLoadWidget",
-    "hpcc/ESPUtil"
+    "hpcc/ESPUtil",
+    "hpcc/Utility"
 
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, on, domClass, topic,
                 registry, ToggleButton, ToolbarSeparator,
                 tree, ColumnHider,
-                GridDetailsWidget, WsMachine, ESPWorkunit, DelayLoadWidget, ESPUtil) {
+                GridDetailsWidget, WsMachine, ESPWorkunit, DelayLoadWidget, ESPUtil, Utility) {
     return declare("MonitoringWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 
@@ -82,11 +83,11 @@ define([
                         formatter: function (Name, row) {
                             switch (row.Status) {
                                 case "Normal":
-                                    return dojoConfig.getImageHTML("normal.png") + Name;
+                                    return Utility.getImageHTML("normal.png") + Name;
                                 case "Warning":
-                                    return dojoConfig.getImageHTML("warning.png") + Name;
+                                    return Utility.getImageHTML("warning.png") + Name;
                                 case "Error":
-                                    return dojoConfig.getImageHTML("error.png") + Name;
+                                    return Utility.getImageHTML("error.png") + Name;
                             }
                             return "";
                         }

+ 7 - 6
esp/src/eclwatch/QuerySetDetailsWidget.js

@@ -35,6 +35,7 @@ define([
     "hpcc/ESPQuery",
     "hpcc/_TabContainerWidget",
     "hpcc/DelayLoadWidget",
+    "hpcc/Utility",
 
     "dojo/text!../templates/QuerySetDetailsWidget.html",
 
@@ -52,7 +53,7 @@ define([
 ], function (declare, lang, i18n, nlsHPCC, dom, domAttr, all, arrayUtil,
                 registry,
                 OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
-                ESPQuery, _TabContainerWidget, DelayLoadWidget,
+                ESPQuery, _TabContainerWidget, DelayLoadWidget, Utility,
                 template) {
     return declare("QuerySetDetailsWidget", [_TabContainerWidget], {
         templateString: template,
@@ -214,11 +215,11 @@ define([
             if (name === "Wuid") {
                 this.workunitsTab.set("title", newValue);
             } else if (name === "Suspended") {
-                dom.byId(this.id + "SuspendImg").src = newValue ? dojoConfig.getImageURL("suspended.png") : "";
+                dom.byId(this.id + "SuspendImg").src = newValue ? Utility.getImageURL("suspended.png") : "";
             } else if (name === "Activated") {
-                dom.byId(this.id + "ActiveImg").src = newValue ? dojoConfig.getImageURL("active.png") : "";
+                dom.byId(this.id + "ActiveImg").src = newValue ? Utility.getImageURL("active.png") : "";
             } else if (name === "SuspendedReason" && newValue === "cluster"){
-                dom.byId(this.id + "SuspendCluster").src = dojoConfig.getImageURL("error-icon.png");
+                dom.byId(this.id + "SuspendCluster").src = Utility.getImageURL("error-icon.png");
             } else if (name === "CountGraphs" && newValue) {
                 this.graphsTab.set("title", this.i18n.Graphs + " (" + newValue + ")");
             } else if (name === "graphs") {
@@ -275,10 +276,10 @@ define([
                 if (lang.exists("ClusterQueryState.length", newValue)) {
                     var checkIfSuspended = false;
                     if (newValue.ClusterQueryState[0].MixedNodeStates === true) {
-                        dom.byId(this.id + "SuspendCluster").src = dojoConfig.getImageURL("mixwarn.png");
+                        dom.byId(this.id + "SuspendCluster").src = Utility.getImageURL("mixwarn.png");
                         checkIfSuspended = true;
                     } else if (newValue.ClusterQueryState[0].State === "Suspended") {
-                        dom.byId(this.id + "SuspendCluster").src = dojoConfig.getImageURL("errwarn.png");
+                        dom.byId(this.id + "SuspendCluster").src = Utility.getImageURL("errwarn.png");
                         checkIfSuspended = true;
                     }
                     this.suspended.set("checked", checkIfSuspended);

+ 9 - 9
esp/src/eclwatch/QuerySetQueryWidget.js

@@ -321,53 +321,53 @@ define([
                     Suspended: {
                         label: this.i18n.Suspended,
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("suspended.png", context.i18n.Suspended);
+                            node.innerHTML = Utility.getImageHTML("suspended.png", context.i18n.Suspended);
                         },
                         width: 25,
                         sortable: false,
                         formatter: function (suspended) {
                             if (suspended === true) {
-                                return dojoConfig.getImageHTML("suspended.png");
+                                return Utility.getImageHTML("suspended.png");
                             }
                             return "";
                         }
                     },
                     ErrorCount: {
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("errwarn.png", context.i18n.ErrorWarnings);
+                            node.innerHTML = Utility.getImageHTML("errwarn.png", context.i18n.ErrorWarnings);
                         },
                         width: 25,
                         sortable: false,
                         formatter: function (error) {
                             if (error > 0) {
-                                return dojoConfig.getImageHTML("errwarn.png");
+                                return Utility.getImageHTML("errwarn.png");
                             }
                             return "";
                         }
                     },
                     MixedNodeStates: {
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("mixwarn.png", context.i18n.MixedNodeStates);
+                            node.innerHTML = Utility.getImageHTML("mixwarn.png", context.i18n.MixedNodeStates);
                         },
                         width: 25,
                         sortable: false,
                         formatter: function (mixed) {
                             if (mixed === true) {
-                                return dojoConfig.getImageHTML("mixwarn.png");
+                                return Utility.getImageHTML("mixwarn.png");
                             }
                             return "";
                         }
                     },
                     Activated: {
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("active.png", context.i18n.Active);
+                            node.innerHTML = Utility.getImageHTML("active.png", context.i18n.Active);
                         },
                         width: 25,
                         formatter: function (activated) {
                             if (activated === true) {
-                                return dojoConfig.getImageHTML("active.png");
+                                return Utility.getImageHTML("active.png");
                             }
-                            return dojoConfig.getImageHTML("inactive.png");
+                            return Utility.getImageHTML("inactive.png");
                         }
                     },
                     Id: {

+ 8 - 7
esp/src/eclwatch/SFDetailsWidget.js

@@ -49,6 +49,7 @@ define([
     "hpcc/ESPUtil",
     "hpcc/ESPLogicalFile",
     "hpcc/DelayLoadWidget",
+    "hpcc/Utility",
 
     "dojo/text!../templates/SFDetailsWidget.html",
 
@@ -57,7 +58,7 @@ define([
                 BorderContainer, TabContainer, ContentPane, Toolbar, ToolbarSeparator, TooltipDialog, Form, SimpleTextarea, TextBox, Button, DropDownButton, TitlePane, registry,
                 selector,
                 _TabContainerWidget,
-                ESPUtil, ESPLogicalFile, DelayLoadWidget,
+                ESPUtil, ESPLogicalFile, DelayLoadWidget, Utility,
                 template) {
     exports.fixCircularDependency = declare("SFDetailsWidget", [_TabContainerWidget], {
         templateString: template,
@@ -187,11 +188,11 @@ define([
                     IsCompressed: {
                         width: 25, sortable: false,
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("compressed.png", context.i18n.Compressed);
+                            node.innerHTML = Utility.getImageHTML("compressed.png", context.i18n.Compressed);
                         },
                         formatter: function (compressed) {
                             if (compressed === true) {
-                                return dojoConfig.getImageHTML("compressed.png");
+                                return Utility.getImageHTML("compressed.png");
                             }
                             return "";
                         }
@@ -199,11 +200,11 @@ define([
                     IsKeyFile: {
                         width: 25, sortable: false,
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("index.png", context.i18n.Index);
+                            node.innerHTML = Utility.getImageHTML("index.png", context.i18n.Index);
                         },
                         formatter: function (keyfile, row) {
                             if (row.ContentType === "key") {
-                                return dojoConfig.getImageHTML("index.png");
+                                return Utility.getImageHTML("index.png");
                             }
                             return "";
                         }
@@ -211,11 +212,11 @@ define([
                     isSuperfile: {
                         width: 25, sortable: false,
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("superfile.png", context.i18n.Superfile);
+                            node.innerHTML = Utility.getImageHTML("superfile.png", context.i18n.Superfile);
                         },
                         formatter: function (superfile) {
                             if (superfile === true) {
-                                return dojoConfig.getImageHTML("superfile.png");
+                                return Utility.getImageHTML("superfile.png");
                             }
                             return "";
                         }

+ 4 - 3
esp/src/eclwatch/SearchResultsWidget.js

@@ -40,13 +40,14 @@ define([
     "hpcc/FileSpray",
     "hpcc/WsDfu",
     "hpcc/DelayLoadWidget",
-    "hpcc/ESPUtil"
+    "hpcc/ESPUtil",
+    "hpcc/Utility"
 
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, Memory, Observable, on, all,
                 Button,
                 Standby, validate,
                 selector,
-                GridDetailsWidget, WsWorkunits, ESPWorkunit, ESPDFUWorkunit, ESPLogicalFile, ESPQuery, FileSpray, WsDfu, DelayLoadWidget, ESPUtil) {
+                GridDetailsWidget, WsWorkunits, ESPWorkunit, ESPDFUWorkunit, ESPLogicalFile, ESPQuery, FileSpray, WsDfu, DelayLoadWidget, ESPUtil, Utility) {
     return declare("SearchResultsWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 
@@ -154,7 +155,7 @@ define([
 
             this.standby = new Standby({
                 target: this.domNode,
-                image: dojoConfig.getImageURL("loadingBar.gif"),
+                image: Utility.getImageURL("loadingBar.gif"),
                 color: null
             });
             document.body.appendChild(this.standby.domNode);

+ 4 - 3
esp/src/eclwatch/SourceFilesWidget.js

@@ -27,11 +27,12 @@ define([
     "hpcc/GridDetailsWidget",
     "hpcc/ESPWorkunit",
     "hpcc/DelayLoadWidget",
-    "hpcc/ESPUtil"
+    "hpcc/ESPUtil",
+    "hpcc/Utility",
 
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, on,
                 tree, selector,
-                GridDetailsWidget, ESPWorkunit, DelayLoadWidget, ESPUtil) {
+                GridDetailsWidget, ESPWorkunit, DelayLoadWidget, ESPUtil, Utility) {
     return declare("SourceFilesWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 
@@ -75,7 +76,7 @@ define([
                     Name: tree({
                         label: "Name", sortable: true,
                         formatter: function (Name, row) {
-                            return dojoConfig.getImageHTML(row.IsSuperFile ? "folder_table.png" : "file.png") + "&nbsp;<a href='#' class='dgrid-row-url'>" + Name + "</a>";
+                            return Utility.getImageHTML(row.IsSuperFile ? "folder_table.png" : "file.png") + "&nbsp;<a href='#' class='dgrid-row-url'>" + Name + "</a>";
                         }
                     }),
                     FileCluster: { label: this.i18n.FileCluster, width: 300, sortable: false },

+ 6 - 4
esp/src/eclwatch/TargetSelectClass.js

@@ -33,10 +33,12 @@ define([
     "hpcc/FileSpray",
     "hpcc/ws_access",
     "hpcc/WsESDLConfig",
-    "hpcc/WsPackageMaps"
+    "hpcc/WsPackageMaps",
+    "hpcc/Utility"
+
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, xhr, Deferred, ItemFileReadStore, all, Memory, on,
     registry,
-    WsTopology, WsWorkunits, FileSpray, WsAccess, WsESDLConfig, WsPackageMaps) {
+    WsTopology, WsWorkunits, FileSpray, WsAccess, WsESDLConfig, WsPackageMaps, Utility) {
 
     return {
         i18n: nlsHPCC,
@@ -509,14 +511,14 @@ define([
 
         loadECLSamples: function () {
             var sampleStore = new ItemFileReadStore({
-                url: dojoConfig.getURL("ecl/ECLPlaygroundSamples.json")
+                url: Utility.getURL("ecl/ECLPlaygroundSamples.json")
             });
             this.setStore(sampleStore);
             var context = this;
             this.on("change", function (evt) {
                 var filename = this.get("value");
                 xhr.get({
-                    url: dojoConfig.getURL("ecl/" + filename),
+                    url: Utility.getURL("ecl/" + filename),
                     handleAs: "text",
                     load: function (eclText) {
                         context.onNewSelection(eclText);

+ 5 - 4
esp/src/eclwatch/TopologyWidget.js

@@ -43,12 +43,13 @@ define([
     "hpcc/DelayLoadWidget",
     "hpcc/ESPUtil",
     "hpcc/FilterDropDownWidget",
-    "hpcc/ws_machine"
+    "hpcc/ws_machine",
+    "hpcc/Utility"
 
 ], function (declare, i18n, nlsHPCC, on, dom, domConstruct, lang,
                 CheckBox, TextBox, ValidationTextBox, registry, ToggleButton, Select, ToolbarSeparator, ContentPane,
                 tree, selector,
-                GridDetailsWidget, PreflightDetailsWidget, RequestInformationWidget, ESPRequest, ESPTopology, TopologyDetailsWidget, DelayLoadWidget, ESPUtil, FilterDropDownWidget, WsMachine) {
+                GridDetailsWidget, PreflightDetailsWidget, RequestInformationWidget, ESPRequest, ESPTopology, TopologyDetailsWidget, DelayLoadWidget, ESPUtil, FilterDropDownWidget, WsMachine, Utility) {
     return declare("TopologyWidget", [GridDetailsWidget], {
 
         i18n: nlsHPCC,
@@ -164,7 +165,7 @@ define([
         resetFilter: function () {
             this.filter.filterForm.reset();
             this.filter.filterDropDown.set("label", this.i18n.MachineInformation);
-            this.filter.iconFilter.src = dojoConfig.getImageURL("noFilter1.png");
+            this.filter.iconFilter.src = Utility.getImageURL("noFilter1.png");
             this.filter.disable(true);
         },
 
@@ -296,7 +297,7 @@ define([
                             return false;
                         },
                         formatter: function (_id, row) {
-                            return "<img src='" + dojoConfig.getImageURL(row.getIcon()) + "'/>&nbsp;" + row.getLabel();
+                            return "<img src='" + Utility.getImageURL(row.getIcon()) + "'/>&nbsp;" + row.getLabel();
                         }
                     })
                 ]

+ 363 - 1
esp/src/eclwatch/Utility.js

@@ -339,6 +339,362 @@
         }
     }
 
+    function resolve(hpccWidget, callback) {
+        function doLoad(widget) {
+            if (widget.fixCircularDependency) {
+                widget = widget.fixCircularDependency;
+            }
+            callback(widget);
+        }
+
+        switch (hpccWidget) {
+            case "ActivityWidget":
+                require(["hpcc/ActivityWidget"], doLoad);
+                break;
+            case "CurrentUserDetailsWidget":
+                require(["hpcc/CurrentUserDetailsWidget"], doLoad);
+                break;
+            case "DelayLoadWidget":
+                require(["hpcc/DelayLoadWidget"], doLoad);
+                break;
+            case "DFUQueryWidget":
+                require(["hpcc/DFUQueryWidget"], doLoad);
+                break;
+            case "DFUSearchWidget":
+                require(["hpcc/DFUSearchWidget"], doLoad);
+                break;
+            case "DFUWUDetailsWidget":
+                require(["hpcc/DFUWUDetailsWidget"], doLoad);
+                break;
+            case "DiskUsageWidget":
+                require(["hpcc/DiskUsageWidget"], doLoad);
+                break;
+            case "DynamicESDLDefinitionDetailsWidget":
+                require(["hpcc/DynamicESDLDefinitionDetailsWidget"], doLoad);
+                break;
+            case "DynamicESDLDefinitionQueryWidget":
+                require(["hpcc/DynamicESDLDefinitionQueryWidget"], doLoad);
+                break;
+            case "DynamicESDLDetailsWidget":
+                require(["hpcc/DynamicESDLDetailsWidget"], doLoad);
+                break;
+            case "DynamicESDLMethodWidget":
+                require(["hpcc/DynamicESDLMethodWidget"], doLoad);
+                break;
+            case "DynamicESDLQueryWidget":
+                require(["hpcc/DynamicESDLQueryWidget"], doLoad);
+                break;
+            case "ECLPlaygroundResultsWidget":
+                require(["hpcc/ECLPlaygroundResultsWidget"], doLoad);
+                break;
+            case "ECLPlaygroundWidget":
+                require(["hpcc/ECLPlaygroundWidget"], doLoad);
+                break;
+            case "ECLSourceWidget":
+                require(["hpcc/ECLSourceWidget"], doLoad);
+                break;
+            case "EventScheduleWorkunitWidget":
+                require(["hpcc/EventScheduleWorkunitWidget"], doLoad);
+                break;
+            case "FileBelongsToWidget":
+                require(["hpcc/FileBelongsToWidget"], doLoad);
+                break;
+            case "FileHistoryWidget":
+                require(["hpcc/FileHistoryWidget"], doLoad);
+                break;
+            case "FilePartsWidget":
+                require(["hpcc/FilePartsWidget"], doLoad);
+                break;
+            case "FilterDropDownWidget":
+                require(["hpcc/FilterDropDownWidget"], doLoad);
+                break;
+            case "FullResultWidget":
+                require(["hpcc/FullResultWidget"], doLoad);
+                break;
+            case "GetDFUWorkunitsWidget":
+                require(["hpcc/GetDFUWorkunitsWidget"], doLoad);
+                break;
+            case "GetNumberOfFilesToCopyWidget":
+                require(["hpcc/GetNumberOfFilesToCopyWidget"], doLoad);
+                break;
+            case "GraphPageWidget":
+                require(["hpcc/GraphPageWidget"], doLoad);
+                break;
+            case "GraphsWidget":
+                require(["hpcc/GraphsWidget"], doLoad);
+                break;
+            case "GraphTreeWidget":
+                require(["hpcc/GraphTreeWidget"], doLoad);
+                break;
+            case "GraphWidget":
+                require(["hpcc/GraphWidget"], doLoad);
+                break;
+            case "GridDetailsWidget":
+                require(["hpcc/GridDetailsWidget"], doLoad);
+                break;
+            case "GroupDetailsWidget":
+                require(["hpcc/GroupDetailsWidget"], doLoad);
+                break;
+            case "HelpersWidget":
+                require(["hpcc/HelpersWidget"], doLoad);
+                break;
+            case "HexViewWidget":
+                require(["hpcc/HexViewWidget"], doLoad);
+                break;
+            case "HPCCPlatformECLWidget":
+                require(["hpcc/HPCCPlatformECLWidget"], doLoad);
+                break;
+            case "HPCCPlatformFilesWidget":
+                require(["hpcc/HPCCPlatformFilesWidget"], doLoad);
+                break;
+            case "HPCCPlatformMainWidget":
+                require(["hpcc/HPCCPlatformMainWidget"], doLoad);
+                break;
+            case "HPCCPlatformOpsWidget":
+                require(["hpcc/HPCCPlatformOpsWidget"], doLoad);
+                break;
+            case "HPCCPlatformRoxieWidget":
+                require(["hpcc/HPCCPlatformRoxieWidget"], doLoad);
+                break;
+            case "HPCCPlatformServicesPluginWidget":
+                require(["hpcc/HPCCPlatformServicesPluginWidget"], doLoad);
+                break;
+            case "HPCCPlatformWidget":
+                require(["hpcc/HPCCPlatformWidget"], doLoad);
+                break;
+            case "IFrameWidget":
+                require(["hpcc/IFrameWidget"], doLoad);
+                break;
+            case "InfoGridWidget":
+                require(["hpcc/InfoGridWidget"], doLoad);
+                break;
+            case "JSGraphWidget":
+                require(["hpcc/JSGraphWidget"], doLoad);
+                break;
+            case "LFDetailsWidget":
+                require(["hpcc/LFDetailsWidget"], doLoad);
+                break;
+            case "LibrariesUsedWidget":
+                require(["hpcc/LibrariesUsedWidget"], doLoad);
+                break;
+            case "LogWidget":
+                require(["hpcc/LogWidget"], doLoad);
+                break;
+            case "LZBrowseWidget":
+                require(["hpcc/LZBrowseWidget"], doLoad);
+                break;
+            case "MemberOfWidget":
+                require(["hpcc/MemberOfWidget"], doLoad);
+                break;
+            case "MembersWidget":
+                require(["hpcc/MembersWidget"], doLoad);
+                break;
+            case "MonitoringWidget":
+                require(["hpcc/MonitoringWidget"], doLoad);
+                break;
+            case "PackageMapDetailsWidget":
+                require(["hpcc/PackageMapDetailsWidget"], doLoad);
+                break;
+            case "PackageMapPartsWidget":
+                require(["hpcc/PackageMapPartsWidget"], doLoad);
+                break;
+            case "PackageMapQueryWidget":
+                require(["hpcc/PackageMapQueryWidget"], doLoad);
+                break;
+            case "PackageMapValidateContentWidget":
+                require(["hpcc/PackageMapValidateContentWidget"], doLoad);
+                break;
+            case "PackageMapValidateWidget":
+                require(["hpcc/PackageMapValidateWidget"], doLoad);
+                break;
+            case "PackageSourceWidget":
+                require(["hpcc/PackageSourceWidget"], doLoad);
+                break;
+            case "PermissionsWidget":
+                require(["hpcc/PermissionsWidget"], doLoad);
+                break;
+            case "PreflightDetailsWidget":
+                require(["hpcc/PreflightDetailsWidget"], doLoad);
+                break;
+            case "QuerySetDetailsWidget":
+                require(["hpcc/QuerySetDetailsWidget"], doLoad);
+                break;
+            case "QuerySetErrorsWidget":
+                require(["hpcc/QuerySetErrorsWidget"], doLoad);
+                break;
+            case "QuerySetLogicalFilesWidget":
+                require(["hpcc/QuerySetLogicalFilesWidget"], doLoad);
+                break;
+            case "QuerySetQueryWidget":
+                require(["hpcc/QuerySetQueryWidget"], doLoad);
+                break;
+            case "QuerySetSuperFilesWidget":
+                require(["hpcc/QuerySetSuperFilesWidget"], doLoad);
+                break;
+            case "QueryTestWidget":
+                require(["hpcc/QueryTestWidget"], doLoad);
+                break;
+            case "RequestInformationWidget":
+                require(["hpcc/RequestInformationWidget"], doLoad);
+                break;
+            case "ResourcesWidget":
+                require(["hpcc/ResourcesWidget"], doLoad);
+                break;
+            case "ResultsWidget":
+                require(["hpcc/ResultsWidget"], doLoad);
+                break;
+            case "ResultWidget":
+                require(["hpcc/ResultWidget"], doLoad);
+                break;
+            case "SearchResultsWidget":
+                require(["hpcc/SearchResultsWidget"], doLoad);
+                break;
+            case "SelectionGridWidget":
+                require(["hpcc/SelectionGridWidget"], doLoad);
+                break;
+            case "SFDetailsWidget":
+                require(["hpcc/SFDetailsWidget"], doLoad);
+                break;
+            case "ShowAccountPermissionsWidget":
+                require(["hpcc/ShowAccountPermissionsWidget"], doLoad);
+                break;
+            case "ShowIndividualPermissionsWidget":
+                require(["hpcc/ShowIndividualPermissionsWidget"], doLoad);
+                break;
+            case "ShowInheritedPermissionsWidget":
+                require(["hpcc/ShowInheritedPermissionsWidget"], doLoad);
+                break;
+            case "ShowPermissionsWidget":
+                require(["hpcc/ShowPermissionsWidget"], doLoad);
+                break;
+            case "SourceFilesWidget":
+                require(["hpcc/SourceFilesWidget"], doLoad);
+                break;
+            case "TargetComboBoxWidget":
+                require(["hpcc/TargetComboBoxWidget"], doLoad);
+                break;
+            case "TargetSelectWidget":
+                require(["hpcc/TargetSelectWidget"], doLoad);
+                break;
+            case "TimingGridWidget":
+                require(["hpcc/TimingGridWidget"], doLoad);
+                break;
+            case "TimingPageWidget":
+                require(["hpcc/TimingPageWidget"], doLoad);
+                break;
+            case "TimingTreeMapWidget":
+                require(["hpcc/TimingTreeMapWidget"], doLoad);
+                break;
+            case "TopologyDetailsWidget":
+                require(["hpcc/TopologyDetailsWidget"], doLoad);
+                break;
+            case "TopologyWidget":
+                require(["hpcc/TopologyWidget"], doLoad);
+                break;
+            case "TpClusterInfoWidget":
+                require(["hpcc/TpClusterInfoWidget"], doLoad);
+                break;
+            case "TpThorStatusWidget":
+                require(["hpcc/TpThorStatusWidget"], doLoad);
+                break;
+            case "UserDetailsWidget":
+                require(["hpcc/UserDetailsWidget"], doLoad);
+                break;
+            case "UserQueryWidget":
+                require(["hpcc/UserQueryWidget"], doLoad);
+                break;
+            case "VariablesWidget":
+                require(["hpcc/VariablesWidget"], doLoad);
+                break;
+            case "VizWidget":
+                require(["hpcc/VizWidget"], doLoad);
+                break;
+            case "WorkflowsWidget":
+                require(["hpcc/WorkflowsWidget"], doLoad);
+                break;
+            case "WUDetailsWidget":
+                require(["hpcc/WUDetailsWidget"], doLoad);
+                break;
+            case "WUQueryWidget":
+                require(["hpcc/WUQueryWidget"], doLoad);
+                break;
+//            case "WUStatsWidget":
+//                require(["hpcc/WUStatsWidget"], doLoad);
+//                break;
+            case "XrefDetailsWidget":
+                require(["hpcc/XrefDetailsWidget"], doLoad);
+                break;
+            case "XrefDirectoriesWidget":
+                require(["hpcc/XrefDirectoriesWidget"], doLoad);
+                break;
+            case "XrefErrorsWarningsWidget":
+                require(["hpcc/XrefErrorsWarningsWidget"], doLoad);
+                break;
+            case "XrefFoundFilesWidget":
+                require(["hpcc/XrefFoundFilesWidget"], doLoad);
+                break;
+            case "XrefLostFilesWidget":
+                require(["hpcc/XrefLostFilesWidget"], doLoad);
+                break;
+            case "XrefOrphanFilesWidget":
+                require(["hpcc/XrefOrphanFilesWidget"], doLoad);
+                break;
+            case "XrefQueryWidget":
+                require(["hpcc/XrefQueryWidget"], doLoad);
+                break;
+            default:
+                console.log("case \"" + hpccWidget + "\":\n" +
+                    "    require([\"hpcc/" + hpccWidget + "\"], doLoad);\n" +
+                    "    break;\n");
+        }
+    }
+
+    function getURL(name) {
+        return dojoConfig.urlInfo.resourcePath + "/" + name;
+    }
+
+    function getImageURL(name) {
+        return this.getURL("img/" + name);
+    }
+
+    function getImageHTML(name, tooltip) {
+        return "<img src='" + this.getImageURL(name) + "'" + (tooltip ? " title='" + tooltip + "'" : "") + " class='iconAlign'/>";
+    }
+
+    function isPluginInstalled() {
+        try {
+            var o = new ActiveXObject("HPCCSystems.HPCCSystemsGraphViewControl.1");
+            o = null;
+            return true;
+        } catch (e) {
+        }
+        if (navigator.plugins) {
+            for (var i = 0, p = navigator.plugins, l = p.length; i < l; i++) {
+                if (p[i].name.indexOf("HPCCSystemsGraphViewControl") > -1) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    function debounce(func, threshold, execAsap) {
+        var timeout;
+        return function debounced() {
+            var obj = this, args = arguments;
+            function delayed() {
+                if (!execAsap)
+                    func.apply(obj, args);
+                timeout = null;
+            }
+            if (timeout)
+                clearTimeout(timeout);
+            else if (execAsap)
+                func.apply(obj, args);
+            timeout = setTimeout(delayed, threshold || 100);
+        }
+    }
+
     return {
         espTime2Seconds: espTime2Seconds,
         espSize2Bytes: espSize2Bytes,
@@ -347,6 +703,12 @@
         xmlEncode2: xmlEncode2,
         alphanumSort: alphanumSort,
         downloadToCSV: downloadToCSV,
-        parseXML: parseXML
+        parseXML: parseXML,
+        resolve: resolve,
+        getURL: getURL,
+        getImageURL: getImageURL,
+        getImageHTML: getImageHTML,
+        isPluginInstalled:isPluginInstalled,
+        debounce: debounce
     }
 });

+ 9 - 16
esp/src/eclwatch/VizWidget.js

@@ -37,7 +37,8 @@ define([
     "hpcc/ESPWorkunit",
     "hpcc/WsWorkunits",
     "hpcc/SelectionGridWidget",
-
+    "hpcc/Utility",
+    
     "dojo/text!../templates/VizWidget.html",
 
     "dijit/layout/BorderContainer",
@@ -54,7 +55,7 @@ define([
 ], function (declare, lang, i18n, nlsHPCC, arrayUtil, Deferred, domConstruct, domForm, ioQuery, all,
                 registry, ContentPane, Select, CheckBox,
                 editor,
-                TableContainer, _Widget, ESPWorkunit, WsWorkunits, SelectionGridWidget,
+                TableContainer, _Widget, ESPWorkunit, WsWorkunits, SelectionGridWidget, Utility,
                 template) {
     return declare("VizWidget", [_Widget], {
         templateString: template,
@@ -369,7 +370,7 @@ define([
             var context = this;
 
             function requireWidget() {
-                require(["src/layout/Grid", "hpcc/viz/" + context.vizType], function (Grid, D3Viz) {
+                Utility.resolve("viz/" + context.vizType, function (D3Viz) {
                     context.d3Viz = new D3Viz();
                     context.d3Viz._chartType = chartType;
                     domConstruct.empty(context.id + "VizCP");
@@ -383,19 +384,7 @@ define([
             if (this.vizType !== value || this.chartType !== chartType) {
                 this.vizType = value;
                 this.chartType = chartType;
-                if (dojoConfig.vizDebug) {
-                    requireWidget();
-                } else {
-                    require(["dist-amd/hpcc-viz"], function () {
-                        require(["dist-amd/hpcc-viz-common"], function () {
-                            require(["dist-amd/hpcc-viz-api"], function () {
-                                require(["dist-amd/hpcc-viz-chart", "dist-amd/hpcc-viz-layout", "dist-amd/hpcc-viz-other", "dist-amd/hpcc-viz-map"], function () {
-                                    requireWidget();
-                                });
-                            });
-                        });
-                    });
-                }
+                requireWidget();
             }
 
             return deferred.promise;
@@ -434,6 +423,7 @@ define([
                 }
             }, this);
             var context = this;
+            /*
             var data = d3.nest()
                 .key(function (d) { return d[request.label] })
                 .rollup(function (leaves) {
@@ -461,6 +451,9 @@ define([
                     return retVal;
                 })
             ;
+            */
+            //  TODO - reimplement with d3v4  ---
+            var data = [];
 
             this.d3Viz.setData(data, null, request);
 

+ 1 - 0
esp/src/eclwatch/WUDetailsWidget.js

@@ -267,6 +267,7 @@ define([
                 });
                 this.wu.refresh();
             }
+            
             this.infoGridWidget.init(params);
             this.checkIfClustersAllowed();
             this.checkThorLogStatus();

+ 2 - 2
esp/src/eclwatch/WUQueryWidget.js

@@ -425,13 +425,13 @@ define([
                     }),
                     Protected: {
                         renderHeaderCell: function (node) {
-                            node.innerHTML = dojoConfig.getImageHTML("locked.png", context.i18n.Protected);
+                            node.innerHTML = Utility.getImageHTML("locked.png", context.i18n.Protected);
                         },
                         width: 25,
                         sortable: false,
                         formatter: function (_protected) {
                             if (_protected === true) {
-                                return dojoConfig.getImageHTML("locked.png");
+                                return Utility.getImageHTML("locked.png");
                             }
                             return "";
                         }

+ 309 - 1
esp/src/eclwatch/css/hpcc.css

@@ -1232,4 +1232,312 @@ margin-left:-20px;
     background-color:#eee;
     padding:3px;
     text-align: left;
-}
+}
+
+.dojoxColorPicker {
+    padding:8px;
+    -moz-border-radius:4pt;
+    -webkit-border-radius:5pt;
+    -webkit-drop-shadow:3pt;
+}
+
+.dojoxColorPickerRightPad {
+    padding-right: 8px;
+}
+
+.tundra .dojoxColorPicker {
+    background:#ededed;
+    border:1px solid #ccc;
+}
+
+.dojoxColorPickerBox {
+    position:relative;
+    width:150px;    
+    height:150px;    
+    margin:0; 
+    padding:0;
+}
+
+.dojoxColorPickerUnderlay {
+    position:relative; 
+    top:0; left:0;
+    width:150px; 
+    height:150px;
+    z-index:1;
+}
+
+.tundra .dojoxColorPickerUnderlay {
+    border:1px solid #a0a0a0;
+}
+
+.claro .dojoxColorPicker {
+    background:#ededed;
+    border:1px solid #cdcdcd;
+}
+
+.claro .dojoxColorPickerUnderlay {
+    border:1px solid #cccccc;
+}
+
+.dojoxHuePickerUnderlay {
+    position:relative;
+    top:0; left:0;
+    height:150px;
+    width:20px;
+    z-index:1;
+    text-align: center;
+}
+
+.dojoxHuePicker { position:relative; top: 0px; left: 0px; padding: 0px;}
+
+.dojoxHuePickerPoint {
+    position:absolute;
+    top:0; left:0;
+    width:20px;
+    height:8px;
+    z-index:3; 
+    cursor:move;
+}
+
+.dojoxColorPickerPoint {
+    position:absolute;
+    width:10px; 
+    height:10px;
+    border:0;
+    z-index:3; 
+    cursor:move; 
+}
+
+.dojoxColorPickerPreview {
+    display:block;    
+    width:45px;    
+    height:45px;
+    border:1px solid #333;
+    background-color:#fff; 
+    position:relative;
+    top: 0px;
+    left: 0px; 
+}
+.dojoxColorPickerWebSafePreview {
+    display:block;
+    width:25px; 
+    height:25px; 
+    position:relative;
+    top: 0px;
+    left: 0px; 
+    border:1px solid #333; 
+}
+
+.dojoxColorPickerOptional {
+    position:relative;
+    top: 0px;
+    left: 0px;
+    height: 100%;
+}
+
+.dojoxColorPickerOptional table {
+    border-spacing: 4px;
+}
+
+.dojoxColorPickerPreviewContainer table {
+    border-spacing: 6px 0px;
+}
+
+.dojoxColorPickerOptional input {
+    border:1px solid #a7a7a7;
+    width:25px;
+    padding:1px 3px 1px 3px;
+    line-height:1.1em;
+}
+
+.dojoxColorPickerHex input {
+    width:55px;    
+}
+
+.dojoxUpgradeBar {
+    position:absolute;
+    left:0;
+    top:0;
+    width:100%;
+    height:32px;
+    overflow:hidden;
+    z-index:100;
+    background:#f3f2af;
+    box-shadow:0 2px 6px #444;
+    -webkit-box-shadow:0 1px 6px #444;
+    -moz-box-shadow:0 1px 6px #444;
+    font-size:.8em;
+}
+
+.dj_ie .dojoxUpgradeBar {
+    border-bottom:#665F48 2px solid;
+}
+.dojoxUpgradeBarMessage {
+    position:absolute;
+    padding-left:10px;
+    top:50%;
+    margin-top:-.75em;
+    left:5px;
+    width:100%;
+}
+.dojoxUpgradeBarMessage a{
+    margin-left:10px;
+}
+.dojoxUpgradeBarReminderButton {
+    position:absolute;
+    top:25%;
+    margin-right:50px;
+    font-size:11px;
+    text-decoration:underline;
+    text-align:right;
+    cursor:pointer;
+    right:-20px;
+}
+.dj_ie6 .dojoxUpgradeBarReminderButton {
+    margin-top:2px;
+}
+
+.dojoxUpgradeBarCloseIcon {
+    background: url("../../node_modules/dijit/themes/tundra/images/tabClose.png") no-repeat right top;
+    position: absolute;
+    vertical-align: middle;
+    right: 5px;
+    top: 30%;
+    height: 15px;
+    width: 15px;
+    cursor: pointer;
+}
+.dj_ie6 .dojoxUpgradeBarCloseIcon {
+    background : url("../../node_modules/dijit/themes/tundra/images/tabClose.gif") no-repeat right top;
+}
+.dojoxUpgradeBarCloseIcon-hover {
+    background: url("../../node_modules/dijit/themes/tundra/images/tabCloseHover.png") no-repeat right top;
+}
+.dj_ie6 .dojoxUpgradeBarCloseIcon-hover {
+    background : url("../../node_modules/dijit/themes/tundra/images/tabCloseHover.gif") no-repeat right top;
+}
+
+.dojoxTreeMap {
+    background-color: #EBEADB;
+    font-family: Geneva, Arial, Helvetica, sans-serif;
+}
+
+.dojoxTreeMapLeaf {
+    border: 1px solid black;
+    padding: 3px;
+}
+
+.dojoxTreeMapGroup {
+}
+
+.dojoxTreeMapGroupContent {
+}
+
+.dojoxTreeMapHeader {
+    background-color: white;
+    border: 1px solid black;
+}
+
+/* on desktop recent browsers you may prefer to use :hover pseudo-class instead
+   of dojoxTreeMapHovered */
+
+.dojoxTreeMapLeaf.dojoxTreeMapHovered {
+    border-color: white;
+}
+
+.dojoxTreeMapGroup.dojoxTreeMapHovered {
+}
+
+.dojoxTreeMapSelected {
+    border-color: red;
+}
+
+.dojoxTreeMapSelected:before {
+    content: '';
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    right: 0px;
+    bottom: 0px;
+    border: 3px dashed red;
+    pointer-events: none;
+    z-index: 20;
+}
+
+.dojoxTreeMapGroup.dojoxTreeMapSelected:before {
+    content: '';
+    position: absolute;
+    left: 1px;
+    top: 1px;
+    right: 1px;
+    bottom: 1px;
+    border: 1px solid red;
+    pointer-events: none;
+    z-index: 20;
+}
+
+.dojoxTreeMapSelected:before {
+    content: '';
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    right: 0px;
+    bottom: 0px;
+    border: 2px dashed white;
+    pointer-events: none;
+    z-index: 20;
+}
+
+.dojoxTreeMapGroup.dojoxTreeMapSelected{
+    border:2px dashed red;
+}
+
+.dj_iequircks .dojoxTreeMapIEHack.dojoxTreeMapSelected,
+.dj_ie7 .dojoxTreeMapIEHack.dojoxTreeMapSelected + div,
+.dj_ie8 .dojoxTreeMapIEHack.dojoxTreeMapSelected + div {
+    border:  1px solid red;
+    z-index: 20;
+}
+
+/* main classes for dojox.widget.Toaster */
+
+.dijitToasterContent {
+	padding:1em;
+	padding-top:0.25em;
+	background:#73c74a;
+}
+
+.dijitToasterMessage{ 
+	color:#fff;
+}
+
+.dijitToasterWarning,
+.dijitToasterError,
+.dijitToasterFatal{
+	font-weight:bold;
+	color:#fff;
+}
+
+.dijitToasterWarning .dijitToasterContent{
+	background:#d4d943;
+} 
+
+.dijitToasterError .dijitToasterContent{
+	background:#c46600;
+}
+
+/* imported from dijit.css */
+ 
+.dijitToasterClip {
+	position: absolute;
+	z-index: 5000;
+	overflow: hidden;
+}
+
+.dijitToasterContainer {
+	display: block;
+	position: absolute;
+	width: 17.5em;
+	margin: 0px;
+	font:0.75em;
+}

+ 72 - 102
esp/src/eclwatch/dojoConfig.js

@@ -1,112 +1,82 @@
-var dojoConfig = (function () {
-    var initUrl = function () {
-        var baseHost = (typeof debugConfig !== "undefined" ) ? "http://" + debugConfig.IP + ":" + debugConfig.Port : "";
-        var hashNodes = location.hash.split("#");
-        var searchNodes = location.search.split("?");
-        var pathnodes = location.pathname.split("/");
-        pathnodes.pop();
+var dojoConfig;
 
-        return {
-            hostname: location.hostname,
-            port: location.port,
-            pathname: location.pathname,
-            hash: hashNodes.length >= 2 ? hashNodes[1] : "",
-            params: searchNodes.length >= 2 ? searchNodes[1] : "",
-            baseHost: baseHost,
-            basePath: baseHost + "/esp/files",
-            pluginsPath: baseHost + "/esp/files",
-            resourcePath: baseHost + "/esp/files/eclwatch",
-            scriptsPath: baseHost + "/esp/files/eclwatch",
-            thisPath: pathnodes.join("/")
-        };
-    }
-
-    var urlInfo = initUrl();
-    var vizDebug = false;
-    var paths = vizDebug ? {
-        "crossfilter": urlInfo.basePath + "/crossfilter/crossfilter.min",
-        "font-awesome.css": urlInfo.basePath + "/Visualization/dist-amd/font-awesome/css/font-awesome.min.css",
-        "src": urlInfo.basePath + "/Visualization/src",
-        "css": urlInfo.basePath + "/Visualization/node_modules/require-css/css",
-        "d3": urlInfo.basePath + "/Visualization/bower_components/d3/d3",
-        "c3": urlInfo.basePath + "/Visualization/bower_components/c3/c3",
-        "dagre": urlInfo.basePath + "/Visualization/bower_components/dagre/index",
-        "topojson": urlInfo.basePath + "/Visualization/bower_components/topojson/topojson",
-        "colorbrewer": urlInfo.basePath + "/Visualization/bower_components/colorbrewer/colorbrewer",
-        "d3-cloud": urlInfo.basePath + "/Visualization/bower_components/d3-cloud/build/d3.layout.cloud",
-        "font-awesome": urlInfo.basePath + "/Visualization/bower_components/font-awesome/css/font-awesome",
-        "es6-promise": urlInfo.basePath + "/Visualization/bower_components/es6-promise/promise"
-    } : {
-        "crossfilter": urlInfo.basePath + "/crossfilter/crossfilter.min",
-        "font-awesome.css": urlInfo.basePath + "/Visualization/dist-amd/font-awesome/css/font-awesome.min.css",
-        "dist-amd": urlInfo.basePath + "/Visualization/dist-amd",
-        "src": urlInfo.basePath + "/Visualization/dist-amd"
-    };
+function getConfig(env) {
+    // dojoRoot is defined if we're running in node (i.e. building)
+    var dojoRoot = env.dojoRoot;
+    var baseUrl = dojoRoot ? "." : "/esp/files";
 
     return {
+        baseUrl: baseUrl,
+        deps: ["hpcc/stub"],
         async: true,
+
         parseOnLoad: false,
-        urlInfo: urlInfo,
         isDebug: (typeof debugConfig !== "undefined"),
-        vizDebug: vizDebug,
+        vizDebug: false,
         selectorEngine: "lite",
-        getURL: function (name) {
-            return this.urlInfo.resourcePath + "/" + name;
-        },
-        getImageURL: function (name) {
-            return this.getURL("img/" + name);
-        },
-        getImageHTML: function (name, tooltip) {
-            return "<img src='" + this.getImageURL(name) + "'" + (tooltip ? " title='" + tooltip + "'" : "") + " class='iconAlign'/>";
+        blankGif: "/esp/files/eclwatch/img/blank.gif",
+        paths: {
+            "hpcc": baseUrl + "/eclwatch",
+            "src": baseUrl + "/lib",
+            "templates": baseUrl + "/eclwatch/templates",
+            "ecl": baseUrl + "/eclwatch/ecl",
+            "css": baseUrl + "/loader/css",
+            "d3-selection": baseUrl + "/node_modules/d3-selection/build/d3-selection",
+            "@hpcc-js/api": baseUrl + "/node_modules/@hpcc-js/api/dist/api",
+            "@hpcc-js/chart": baseUrl + "/node_modules/@hpcc-js/chart/dist/chart",
+            "@hpcc-js/common": baseUrl + "/node_modules/@hpcc-js/common/dist/common",
+            "@hpcc-js/composite": baseUrl + "/node_modules/@hpcc-js/composite/dist/composite",
+            "@hpcc-js/form": baseUrl + "/node_modules/@hpcc-js/form/dist/form",
+            "@hpcc-js/graph": baseUrl + "/node_modules/@hpcc-js/graph/dist/graph",
+            "@hpcc-js/layout": baseUrl + "/node_modules/@hpcc-js/layout/dist/layout",
+            "@hpcc-js/map": baseUrl + "/node_modules/@hpcc-js/map/dist/map",
+            "@hpcc-js/other": baseUrl + "/node_modules/@hpcc-js/other/dist/other",
+            "crossfilter": baseUrl + "/crossfilter/crossfilter.min"
         },
-        isPluginInstalled: function () {
-            try {
-                var o = new ActiveXObject("HPCCSystems.HPCCSystemsGraphViewControl.1");
-                o = null;
-                return true;
-            } catch (e) { 
+        packages: [
+            {
+                name: 'dojo',
+                location: baseUrl + '/node_modules/dojo',
+                lib: '.'
+            },
+            {
+                name: 'dijit',
+                location: baseUrl + '/node_modules/dijit',
+                lib: '.'
+            },
+            {
+                name: 'dojox',
+                location: baseUrl + '/node_modules/dojox',
+                lib: '.'
+            },
+            {
+                name: 'dojo-themes',
+                location: baseUrl + '/node_modules/dojo-themes',
+                lib: '.'
+            },
+            {
+                name: 'dgrid',
+                location: baseUrl + '/dgrid',
+                lib: '.'
+            },
+            {
+                name: 'xstyle',
+                location: baseUrl + '/xstyle',
+                lib: '.'
+            },
+            {
+                name: 'put-selector',
+                location: baseUrl + '/put-selector',
+                lib: '.'
             }
-            if (navigator.plugins) {
-                for (var i = 0, p = navigator.plugins, l = p.length; i < l; i++) {
-                    if (p[i].name.indexOf("HPCCSystemsGraphViewControl") > -1) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        },
-        paths: paths,
-        packages: [{
-            name: "hpcc",
-            location: urlInfo.scriptsPath
-        }, {
-            name: "templates",
-            location: urlInfo.resourcePath + "/templates"
-        }, {
-            name: "ecl",
-            location: urlInfo.resourcePath + "/ecl"
-        }, {
-            name: "plugins",
-            location: urlInfo.pluginsPath
-        }, {
-            name: "this",
-            location: urlInfo.thisPath
-        }],
-        debounce: function (func, threshold, execAsap) {
-            var timeout;
-            return function debounced() {
-                var obj = this, args = arguments;
-                function delayed() {
-                    if (!execAsap)
-                        func.apply(obj, args);
-                    timeout = null;
-                }
-                if (timeout)
-                    clearTimeout(timeout);
-                else if (execAsap)
-                    func.apply(obj, args);
-                timeout = setTimeout(delayed, threshold || 100);
-            }
-        }
+        ]
     };
-})();
+}
+
+// For Webpack, export the config.  This is needed both at build time and on the client at runtime
+// for the packed application.
+if (typeof module !== 'undefined' && module) {
+    module.exports = getConfig;
+} else {
+    dojoConfig = getConfig({});
+}

二进制
esp/src/eclwatch/img/blank.gif


二进制
esp/src/eclwatch/img/hue.png


二进制
esp/src/eclwatch/img/hueHandle.png


二进制
esp/src/eclwatch/img/hueHandleA11y.png


二进制
esp/src/eclwatch/img/pickerPointer.png


二进制
esp/src/eclwatch/img/underlay.png


+ 26 - 13
esp/src/eclwatch/stub.js

@@ -32,7 +32,11 @@ define([
     "hpcc/Utility",
 
     "dojox/html/entities",
-    "dojox/widget/Toaster"
+    "dojox/widget/Toaster",
+
+    "css!hpcc/css/ecl.css",
+    "css!dojo-themes/flat/flat.css",
+    "css!hpcc/css/hpcc.css",
 ], function (fx, dom, domStyle, ioQuery, ready, lang, arrayUtil, topic, xhr, cookie,
             Dialog, Button,
             ESPUtil, Utility,
@@ -122,13 +126,11 @@ define([
         }).play();
     }
 
-    function initUi() {
+    function initUI() {
         var params = ioQuery.queryToObject(dojo.doc.location.search.substr((dojo.doc.location.search.substr(0, 1) === "?" ? 1 : 0)));
         var hpccWidget = params.Widget ? params.Widget : "HPCCPlatformWidget";
 
-        require([
-                "hpcc/" + hpccWidget
-        ], function (WidgetClass) {
+            Utility.resolve(hpccWidget, function (WidgetClass) {
                 var webParams = {
                     id: "stub",
                     "class": "hpccApp"
@@ -143,7 +145,7 @@ define([
                         readOnly: params.ReadOnly
                     });
                 }
-                var widget = WidgetClass.fixCircularDependency ? new WidgetClass.fixCircularDependency(webParams) : new WidgetClass(webParams);
+                var widget = new WidgetClass(webParams);
 
                 var myToaster = new Toaster({
                     id: 'hpcc_toaster',
@@ -202,11 +204,22 @@ define([
         );
     }
 
-    return {
-        init: function () {
-            ready(function () {
-                initUi();
-            });
-        }
-    };
+    function parseUrl() {
+        var baseHost = (typeof debugConfig !== "undefined") ? "http://" + debugConfig.IP + ":" + debugConfig.Port : "";
+        var hashNodes = location.hash.split("#");
+        var searchNodes = location.search.split("?");
+
+        dojoConfig.urlInfo = {
+            baseHost: baseHost,
+            pathname: location.pathname,
+            hash: hashNodes.length >= 2 ? hashNodes[1] : "",
+            resourcePath: baseHost + "/esp/files/eclwatch",
+            basePath: baseHost + "/esp/files"
+        };
+    }
+        
+    ready(function () {
+        parseUrl();
+        initUI();
+    });
 });

+ 1 - 1
esp/src/eclwatch/templates/HPCCPlatformWidget.html

@@ -87,7 +87,7 @@
                 <div data-dojo-type="hpcc.TableContainer">
                     <input id="${id}ShowBanner" title="${i18n.Enable}:" name="BannerAction" data-dojo-type="dijit.form.CheckBox" />
                     <input id="${id}BannerContent" title="${i18n.BannerMessage}:" name="BannerContent" style="width:100%;" data-dojo-props="trim: true" data-dojo-type="dijit.form.Textarea" />
-                    <input id="${id}BannerColor" title="${i18n.BannerColor}:" name="BannerColor" style="width:100%;" value="red" data-dojo-props="trim: true" data-dojo-type="dojox.widget.ColorPicker" />
+                    <input id="${id}BannerColor" title="${i18n.BannerColor}:" name="BannerColor" style="width:100%;" value="red" data-dojo-props="trim: true" data-dojo-type="HPCCColorPicker" />
                     <input id="${id}BannerSize" title="${i18n.BannerSize}:" name="BannerSize" style="width:100%;" value="4" data-dojo-props="trim: true" data-dojo-type="dijit.form.Textarea" />
                     <input id="${id}BannerScroll" title="${i18n.BannerScroll}:" name="BannerScroll" style="width:100%;" value="2" data-dojo-props="trim: true" data-dojo-type="dijit.form.Textarea" />
                 </div>

+ 0 - 1
esp/src/eclwatch/templates/TimingTreeMapWidget.html

@@ -1,5 +1,4 @@
 <div class="${baseClass}">
-    <link rel="stylesheet" href="${dojoConfig.urlInfo.basePath}/dojox/treemap/themes/TreeMap.css">
     <p id="${id}Help">${i18n.help}</p>
     <div id="${id}TreeMap" style="width: 100%; height: 100%;" data-dojo-props="selectionMode: 'multiple'" data-dojo-type="dojox.treemap.TreeMap">
     </div>

+ 3 - 3
esp/src/eclwatch/templates/WUDetailsWidget.html

@@ -128,9 +128,9 @@
                             </li>
                         </ul>
                     </form>
-                </div>
-                <div id="${id}InfoContainer" class="wrap" style="height: 33%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120, showToolbar: true" data-dojo-type="InfoGridWidget">
-                </div>
+            </div>
+            <div id="${id}InfoContainer" class="wrap" style="height: 33%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120, showToolbar: true" data-dojo-type="InfoGridWidget">
+            </div>
             </div>
             <div id="${id}_Variables" title="${i18n.Variables}" data-dojo-props="delayWidget: 'VariablesWidget', disabled: true" data-dojo-type="DelayLoadWidget">
             </div>

+ 3 - 3
esp/src/eclwatch/viz/DojoD3.js

@@ -6,10 +6,10 @@
   "dojo/dom-geometry",
   "dojo/Evented",
 
-  "d3"
+  "d3-selection"
 
 ], function (declare, lang, dom, domConstruct, domGeom, Evented,
-    d3) {
+    d3Selection) {
     return declare([Evented], {
         constructor: function () {
         },
@@ -40,7 +40,7 @@
             this._target = _target;
             this.calcGeom();
             this.injectStyleSheet();
-            this.Svg = d3.select(this.target.domDivID).append("svg")
+            this.Svg = d3Selection.select(this.target.domDivID).append("svg")
                 .attr("width", this.target.width)
                 .attr("height", this.target.height)
             ;

+ 8 - 8
esp/src/eclwatch/viz/DojoD32DChart.js

@@ -4,9 +4,12 @@ define([
   "dojo/_base/array",
   "dojo/_base/Deferred",
 
+  "@hpcc-js/composite",
+
   "./DojoD3",
   "./Mapping"
 ], function (declare, lang, arrayUtil, Deferred,
+    hpccComposite,
     DojoD3, Mapping) {
     return declare([Mapping, DojoD3], {
         mapping: {
@@ -29,14 +32,11 @@ define([
 
         renderTo: function (_target) {
             var deferred = new Deferred();
-            var context = this;
-            require(["src/chart/MultiChart"], function (MultiChart) {
-                context.chart = new MultiChart()
-                    .chartType(context._chartType)
-                    .target(_target.domNodeID)
-                ;
-                deferred.resolve(context.chart);
-            });
+            this.chart = new hpccComposite.MultiChart()
+                .chartType(this._chartType)
+                .target(_target.domNodeID)
+            ;
+            deferred.resolve(this.chart);
             return deferred.promise;
         },
 

+ 14 - 16
esp/src/eclwatch/viz/DojoD3Choropleth.js

@@ -4,9 +4,13 @@ define([
   "dojo/_base/array",
   "dojo/_base/Deferred",
 
+  "@hpcc-js/map",
+
   "./DojoD3",
   "./Mapping"
+
 ], function (declare, lang, arrayUtil, Deferred,
+    hpccMap,
     DojoD3, Mapping) {
     return declare([Mapping, DojoD3], {
         mapping: {
@@ -32,28 +36,22 @@ define([
             var context = this;
             switch (this._chartType) {
                 case "COUNTRY":
-                    require(["src/map/ChoroplethCountries"], function (ChoroplethCountries) {
-                        context.chart = new ChoroplethCountries()
-                            .target(_target.domNodeID)
-                        ;
-                        deferred.resolve(context.chart);
-                    });
+                    this.chart = new hpccMap.ChoroplethCountries()
+                        .target(_target.domNodeID)
+                    ;
+                    deferred.resolve(this.chart);
                     break;
                 case "STATE":
-                    require(["src/map/ChoroplethStates"], function (ChoroplethStates) {
-                        context.chart = new ChoroplethStates()
-                            .target(_target.domNodeID)
-                        ;
-                        deferred.resolve(context.chart);
-                    });
+                    this.chart = new hpccMap.ChoroplethStates()
+                        .target(_target.domNodeID)
+                    ;
+                    deferred.resolve(this.chart);
                     break;
                 case "COUNTY":
-                    require(["src/map/ChoroplethCounties"], function (ChoroplethCounties) {
-                        context.chart = new ChoroplethCounties()
+                        this.chart = new hpccMap.ChoroplethCounties()
                             .target(_target.domNodeID)
                         ;
-                        deferred.resolve(context.chart);
-                    });
+                        deferred.resolve(this.chart);
                     break;
                 default:
                     console.log("Invalid visualization:  " + this._chartType)

+ 9 - 8
esp/src/eclwatch/viz/DojoD3NDChart.js

@@ -4,10 +4,14 @@ define([
   "dojo/_base/array",
   "dojo/_base/Deferred",
 
+  "@hpcc-js/composite",
+
   "./DojoD3",
   "./Mapping"
 ], function (declare, lang, arrayUtil, Deferred,
+    hpccComposite,
     DojoD3, Mapping) {
+
     return declare([Mapping, DojoD3], {
         mapping: {
             NDChart: {
@@ -33,14 +37,11 @@ define([
 
         renderTo: function (_target) {
             var deferred = new Deferred();
-            var context = this;
-            require(["src/chart/MultiChart"], function (MultiChart) {
-                context.chart = new MultiChart()
-                    .chartType(context._chartType)
-                    .target(_target.domNodeID)
-                ;
-                deferred.resolve(context.chart);
-            });
+            this.chart = new hpccComposite.MultiChart()
+            .chartType(this._chartType)
+                .target(_target.domNodeID)
+            ;
+            deferred.resolve(this.chart);
             return deferred.promise;
         },
 

+ 528 - 0
esp/src/loader/css.js

@@ -0,0 +1,528 @@
+/*
+ * (C) Copyright IBM Corp. 2012, 2016 All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+define([
+    'require',
+    'dojo/_base/window',
+    'dojo/_base/html',
+    'dojo/dom-construct',
+    'dojo/has',
+    'dojo/query',
+    'dojo/_base/array',
+    'dojo/_base/lang',
+    'dojo/io-query',
+    'dojo/_base/Deferred',
+    'dojo/has!dojo-combo-api?:postcss?dojo/promise/all',
+    'dojo/has!dojo-combo-api?:postcss?postcss',
+    'dojo/has!css-inject-api?dojo/aspect',
+    'dojo/text'
+], function (require, dwindow, dhtml, domConstruct, has, query, arrays, lang, ioQuery, Deferred, all, postcss, aspect) {
+	/*
+	 * module:
+	 *    css
+	 * summary:
+	 *    This plugin handles AMD module requests for CSS/LESS files.  Required files are
+	 *    loaded by delegating to the dojo/text plugin and then inserting the CSS into
+	 *    a style sheet element that is appended to the HEAD element in the DOM, and
+	 *    the style element is returned as the value of the module.
+	 *
+	 *    For LESS files, the LESS pre-processor specified by the 'lesspp' module identifier
+	 *    is used to convert the LESS markup into CSS.  The app is responsible for defining
+	 *    the path to the LESS pre-processor in the Dojo loader config.  This plugin has been 
+	 *    tested with //cdnjs.cloudflare.com/ajax/libs/less.js/1.7.3/less.min.js, which 
+	 *    would be specifed in the loader config as:
+	 *
+	 *    <code>
+	 *      paths: {
+	 *        lesspp: "//cdnjs.cloudflare.com/ajax/libs/less.js/1.7.3/less.min"
+	 *      }
+	 *    </code>
+	 *
+	 *    You do not need to define the path to 'lesspp' if your app does not use LESS
+	 *
+	 *    URLs for url(...) and @import statements in the CSS are fixed up to make them
+	 *    relative to the requested module's path.
+	 *
+	 *    This plugin guarantees that style elements will be inserted into the DOM in
+	 *    the same order that the associated CSS modules are required, except when a
+	 *    previously requested module is requested again.  In other words, if
+	 *    stylesA.css is required before stylesB.css, then the styles for stylesA.css
+	 *    will be inserted into the DOM ahead of the styles for stylesB.css.  This
+	 *    behavior helps to ensure proper cascading of styles based on order of request.
+	 *
+	 *    This plugin supports two modes of operation.  In the default mode, style
+	 *    elements are injected into the DOM when the plugin's load method is called
+	 *    for the resource.  This ensures that styles will be inserted into the DOM
+	 *    in the order that they appear in the dependency list, but the order of
+	 *    insertion for styles loaded by different modules is undefined.
+	 *
+	 *    The second mode of operation is enabled by the 'css-inject-api' feature.
+	 *    In this mode, CSS is not injected into the DOM directly by the plugin.  Instead,
+	 *    the application calls the inject() method to inject the CSS in the dependency
+	 *    list from within the require() or define() callback.  For example:
+	 *
+	 *    <code>
+	 *    	define(['app/foo', 'css!app/styles/foo.css'], function(foo) {
+	 *        require('css').inject.apply(this, arguments);
+	 *    </code>
+	 *
+	 *    The inject() function iterates over the arguments passed and injects into
+	 *    the DOM any style elements that have not previously been injected.  This mode
+	 *    provides for more predictable order of injection of styles since the order
+	 *    for styles injected from different modules corresponds to the define order
+	 *    of the JavaScript modules doing the injecting.
+	 *
+	 *    The task of calling inject() at the beginning of every require() or define()
+	 *    callback can be automated by calling installAutoInjectHooks().  This method
+	 *    installs intercepts for the global require() and define() functions.  The
+	 *    intercepts hook the callback functions passed to require() and define()
+	 *    for the purpose of automatically invoking the inject() method before the
+	 *    callback function is executed.  These hooks also watch for context require()
+	 *    instances and install intercepts for the context require() callbacks as well.
+	 *
+	 *    The only caveat is that installAutoInjectHooks() must be called before any
+	 *    require() or define() functions that use this plugin to load css, or that
+	 *    reference a context require which uses this plugin to load css, are called,
+	 *    otherwise the inject api will not automatically be invoked for those cases.
+	 */
+    var
+        head = dwindow.doc.getElementsByTagName('head')[0],
+
+        urlPattern = /(^[^:\/]+:\/\/[^\/\?]*)([^\?]*)(\??.*)/,
+
+        isLessUrl = function (url) {
+            return /\.less(?:$|\?)/i.test(url);
+        },
+
+        isRelative = function (url) {
+            return !/^[^:\/]+:\/\/|^\//.test(url);
+        },
+
+        dequote = function (url) {
+            // remove surrounding quotes and normalize slashes
+            return url.replace(/^\s\s*|\s*\s$|[\'\"]|\\/g, function (s) {
+                return s === '\\' ? '/' : '';
+            });
+        },
+
+        joinParts = function (parts) {
+            // joins URL parts into a single string, handling insertion of '/' were needed
+            var result = '';
+            arrays.forEach(parts, function (part) {
+                result = result +
+                    (result && result.charAt(result.length - 1) !== '/' && part && part.charAt(0) !== '/' ? '/' : '') +
+                    part;
+            });
+            return result;
+        },
+
+
+        normalize = function (url) {
+            // Collapse .. and . in url paths
+            var match = urlPattern.exec(url) || [url, '', url, ''],
+                host = match[1], path = match[2], queryArgs = match[3];
+
+            if (!path || path === '/') return url;
+
+            var parts = [];
+            arrays.forEach(path.split('/'), function (part, i, ary) {
+                if (part === '.') {
+                    if (i === ary.length - 1) {
+                        parts.push('');
+                    }
+                    return;
+                } else if (part == '..') {
+                    if ((parts.length > 1 || parts.length == 1 && parts[0] !== '') && parts[parts.length - 1] !== '..') {
+                        parts.pop();
+                    } else {
+                        parts.push(part);
+                    }
+                } else {
+                    parts.push(part);
+                }
+            });
+            var result = parts.join('/');
+
+            return joinParts([host, result]) + queryArgs;
+        },
+
+        resolve = function (base, relative) {
+            // Based on behavior of the Java URI.resolve() method.
+            if (!base || !isRelative(relative)) {
+                return normalize(relative);
+            }
+            if (!relative) {
+                return normalize(base);
+            }
+            var match = urlPattern.exec(base) || [base, '', base, ''],
+                host = match[1], path = match[2], queryArgs = match[3];
+
+            // remove last path component from base before appending relative
+            if (path.indexOf('/') !== -1 && path.charAt(path.length) !== '/') {
+                // remove last path component
+                path = path.split('/').slice(0, -1).join('/') + '/';
+            }
+
+            return normalize(joinParts([host, path, relative]));
+        },
+
+        addArgs = function (url, queryArgs) {
+            // Mix in the query args specified by queryArgs to the URL
+            if (queryArgs) {
+                var queryObj = ioQuery.queryToObject(queryArgs),
+                    mixedObj = lang.mixin(queryObj, ioQuery.queryToObject(url.split('?')[1] || ''));
+                url = url.split('?').shift() + '?' + ioQuery.objectToQuery(mixedObj);
+            }
+            return url;
+        },
+
+        fixUrlsInCssFile = function (/*String*/filePath, /*String*/content, /*boolean*/lessImportsOnly) {
+            var queryArgs = filePath.split('?')[1] || '';
+
+            var rewriteUrl = function (url) {
+                if (lessImportsOnly && url.charAt(0) === '@') {
+                    return url;
+                }
+                // only fix relative URLs.
+                if (isRelative(url)) {
+                    // Support webpack style module name indicator
+                    if (/^~[^/]/.test(url)) {
+                        // leading tilde means url is a module name, not a relative url
+                        url = require.toUrl(url.substring(1));
+                    } else {
+                        url = resolve(filePath, url);
+                    }
+                    if (lessImportsOnly && isLessUrl(url)) {
+                        // LESS compiler fails to locate imports using relative urls when
+                        // the document base has been modified (e.g. via a <base> tag),
+                        // so make the url absolute.
+                        var baseURI = dwindow.doc.baseURI;
+                        if (!baseURI) {
+                            // IE doesn't support document.baseURI.  See if there's a base tag
+                            var baseTags = dwindow.doc.getElementsByTagName("base");
+                            baseURI = baseTags.length && baseTags[0].href || dwindow.location && dwindow.location.href;
+                        }
+                        url = resolve(baseURI, url);
+                    }
+                }
+                return addArgs(url, queryArgs);		// add cachebust arg from including file
+            };
+
+            if (lessImportsOnly) {
+                // Only modify urls for less imports.  We need to do it this way because the LESS compiler
+                // needs to be able to find the imports, but we don't want to do non-less imports because
+                // that would result in those URLs being rewritten a second time when we process the compiled CSS.
+                content = content.replace(/@import\s+(url\()?([^\s;]+)(\))?/gi, function (match, prefix, url) {
+                    url = dequote(url);
+                    return isLessUrl(url) ? '@import \'' + rewriteUrl(url) + '\'' : match;
+                });
+            } else {
+                content = content.replace(/url\s*\(([^#\n\);]+)\)/gi, function (match, url) {
+                    return 'url(\'' + rewriteUrl(dequote(url)) + '\')';
+                });
+                // handle @imports that don't use url(...)
+                content = content.replace(/@import\s+(url\()?([^\s;]+)(\))?/gi, function (match, prefix, url) {
+                    return (prefix == 'url(' ? match : ('@import \'' + rewriteUrl(dequote(url)) + '\''));
+                });
+            }
+            return content;
+        },
+
+        postcssProcessor,
+
+        postcssPromise,
+
+		/*
+		 * Initialize PostCSS and configured plugins.  Plugins are configured with the postcssPlugins
+		 * property in dojoConfig or the global require object.
+		 *
+		 * Plugins are configured using an array of two element arrays as in the following example:
+		 * <code><pre>
+		 * postcss: {
+		 *    plugins: [
+		 *       [
+		 *          'autoprefixer',  // Name of the plugin resource
+		 *                           // Can be an AMD module id or an absolute URI to a server resource
+		 *          function(autoprefixer) {
+		 *             return autoprefixer({browsers: '> 1%'}).postcss; // the init function
+		 *          }
+		 *       ]
+		 *    ]
+		 * },
+		 * </pre></code>
+		 */
+        postcssInitialize = function () {
+            var deferred;
+            if (!has('dojo-combo-api') && has('postcss') && postcss) {
+                var postcssConfig = window.require.postcss || window.dojoConfig && window.dojoConfig.postcss;
+                if (postcssConfig) {
+                    var pluginsConfig = postcssConfig.plugins;
+                    if (pluginsConfig) {
+                        // Load each module using async require.  Each loaded module will get a Promise
+                        // that will be resolved when that module loads and the plugin object has been
+                        // initialized.
+                        var promises = [], plugins = [];
+                        arrays.forEach(pluginsConfig, function (pluginConfig) {
+                            var deferred = new Deferred();
+                            promises.push(deferred.promise);
+                            require([pluginConfig[0]], function (p) {
+                                try {
+                                    plugins.push(pluginConfig[1](p));
+                                    deferred.resolve();
+                                } catch (e) {
+                                    console.error(e);
+                                    deferred.reject(e);
+                                }
+                            });
+                        });
+                        if (promises.length > 0) {
+                            // Use dojo/promise/all so we know when all of the plugins have been
+                            // loaded and initialized.
+                            deferred = new Deferred();
+                            postcssPromise = deferred.promise;
+                            all(promises).then(function () {
+                                try {
+                                    postcssProcessor = postcss(plugins);
+                                    deferred.resolve();
+                                } catch (e) {
+                                    console.error(e);
+                                    deferred.reject(e);
+                                }
+                            }).otherwise(function (e) {
+                                // one or more plugins failed to initialize
+                                console.error(e);
+                                deferred.reject(e);
+                            });
+                        }
+                    }
+                }
+            }
+
+            if (!postcssPromise) {
+                // Not using PostCSS or there were no plugins configured.  Just create a
+                // resolved promise.
+                deferred = new Deferred();
+                postcssPromise = deferred.promise;
+                deferred.resolve();
+            }
+        };
+
+    postcssInitialize();
+
+
+    var test = require.toUrl("test");
+    var idx = test.indexOf("?");
+    var urlArgs = (idx === -1 ? "" : test.substring(idx));
+
+    return {
+        load: function (/*String*/id, /*Function*/parentRequire, /*Function*/load) {
+            if (has('no-css')) {
+                return load();
+            }
+            var url = parentRequire.toUrl(id).replace(/^\s+/g, ''); // Trim possible leading white-space
+
+            // see if a stylesheet element has already been added for this module
+            var styles = query("head>style[url='" + url.split('?').shift() + "']"), style;
+            if (styles.length === 0) {
+                // create a new style element for this module.  Add it to the DOM if the 'css-inject-api'
+                // feature is not true.
+                style = domConstruct.create('style', {}, has('css-inject-api') ? null : head);
+                style.type = 'text/css';
+                dhtml.setAttr(style, 'url', url.split('?').shift());
+                dhtml.setAttr(style, 'loading', '');
+            } else {
+                style = styles[0];
+                if (!dhtml.hasAttr(style, 'loading')) {
+                    load(style);
+                    return;
+                }
+            }
+
+            parentRequire(['dojo/text!' + id], function (text) {
+                // Check if we need to compile LESS client-side
+                if (isLessUrl(id) && !has('dojo-combo-api')) {
+                    processLess(text);
+                } else {
+                    processCss(text);
+                }
+            });
+
+			/**
+			 * Compiles LESS to CSS and passes off the result to the standard `processCss` method.
+			 * @param  {String} lessText The LESS text to compile.
+			 */
+            function processLess(lessText) {
+                var additionalData;
+                var lessGlobals = window.require.lessGlobals || window.dojoConfig && window.dojoConfig.lessGlobals;
+                if (lessGlobals) {
+                    additionalData = { globalVars: lessGlobals };
+                }
+                var pathParts = url.split('?').shift().split('/');
+                require(['lesspp'], function (lesspp) {
+                    var parser = new lesspp.Parser({
+                        filename: pathParts.pop(),
+                        paths: [pathParts.join('/')]  // the compiler seems to ignore this
+                    });
+                    // Override the parser's fileLoader method so we can add urlArgs to less modules loaded by the parser
+                    if (!lesspp.__originalFileLoader) {
+                        lesspp.__originalFileLoader = lesspp.Parser.fileLoader;
+                        lesspp.Parser.fileLoader = function () {
+                            // add query args if needed
+                            if (!/\?/.test(arguments[0])) {
+                                arguments[0] += urlArgs;
+                            }
+                            return lesspp.__originalFileLoader.apply(this, arguments);
+                        }
+                    }
+                    parser.parse(fixUrlsInCssFile(url, lessText, true), function (err, tree) {
+                        if (err) {
+                            console.error('LESS Parser Error!');
+                            console.error(err);
+                            return load.error(err);
+                        }
+                        processCss(tree.toCSS());
+                    }, additionalData);
+                });
+            }
+
+			/**
+			 * Injects CSS text into the stylesheet element, fixing relative URLs.
+			 * @param  {String} cssText The CSS to inject.
+			 */
+            function processCss(cssText) {
+                postcssPromise.always(function () {
+                    if (cssText && dojo.isString(cssText) && cssText.length) {
+                        cssText = fixUrlsInCssFile(url, cssText);
+                        if (postcssProcessor) {
+                            cssText = postcssProcessor.process(cssText, { safe: true });
+                        }
+                        if (style.styleSheet) {
+                            style.styleSheet.cssText = cssText;
+                        } else {
+                            while (style.firstChild) {
+                                style.removeChild(style.firstChild);
+                            }
+                            style.appendChild(dwindow.doc.createTextNode(cssText));
+                        }
+                    }
+                    dhtml.removeAttr(style, "loading");
+                    load(style);
+                });
+            }
+        },
+
+		/*
+		 * Iterates through the function arguments and for any style node arguments that
+		 * are not already in the DOM, appends them to the HEAD element of the DOM.  Used
+		 * when the 'css-injet-api' feature is true.
+		 */
+        inject: function () {
+            if (has('css-inject-api')) {
+                dojo.forEach(arguments, function (arg) {
+                    if (arg && arg.nodeType === Node.ELEMENT_NODE && arg.tagName === 'STYLE' && !arg.parentNode) {
+                        // Unparented style node.  Add it to the DOM
+                        domConstruct.place(arg, head);
+                    }
+                });
+            }
+        },
+
+		/*
+		 * Installs the global require() and define() function intercepts.
+		 *
+		 * @return An object with a remove() function that can be called to cancel the intercepts
+		 *         (useful for unit testing).
+		 */
+        installAutoInjectHooks: function () {
+            if (has('css-inject-api')) {
+                var self = this,
+
+                    // The return value from this function replaces the callback passed
+                    // to require() or define().  The callback replacement scans the arguments
+                    // for context require instances that need to be intercepted, and invokes
+                    // our inject() api before calling the original callback.
+                    callbackIntercept = function (moduleIdList, callbackFn) {
+                        return function () {
+                            var i, args = arguments, newArgValues = [];
+                            dojo.forEach(moduleIdList, function (mid, i) {
+                                newArgValues.push(mid === "require" ? contextRequireIntercept(args[i]) : args[i]);
+                            });
+                            self.inject.apply(this, newArgValues);
+                            return callbackFn.apply(this, newArgValues);
+                        };
+                    },
+
+                    // The return value from this function replaces the context require passed
+                    // in a require() or define() callback with a function that invokes our
+                    // intercept.
+                    contextRequireIntercept = function (contextRequire) {
+                        return lang.mixin(function () {
+                            return contextRequire.apply(this, reqDefIntercept.apply(this, arguments));
+                        }, contextRequire);
+                    },
+
+                    // The require()/define() intercept.  This function scans the require()/define()
+                    // arguments and replaces the callback function with our calback intercept
+                    // function.
+                    reqDefIntercept = function () {
+                        // copy arguments to a new array that will contain our callback intercept
+                        var callback, moduleList, newArgs = [];
+                        dojo.forEach(arguments, function (arg) {
+                            if (!callback && !moduleList && lang.isArray(arg)) {
+                                moduleList = arg;
+                            }
+                            if (!callback && lang.isFunction(arg) && moduleList) {
+                                callback = arg;
+                                arg = callbackIntercept(moduleList, callback);
+                            }
+                            newArgs.push(arg);
+                        });
+                        return newArgs;
+                    },
+
+                    result;
+
+                // install our intercepts for the global require() and define() functions
+                (function () {
+                    // Make sure we're looking at the global require/define
+                    var signals = [], req = this.require, def = this.define;
+                    signals.push(aspect.before(this, "define", reqDefIntercept));
+                    signals.push(aspect.before(this, "require", reqDefIntercept));
+                    if (!this.define.amd) {
+                        // mixin properties defined in original functions
+                        lang.mixin(this.define, def);
+                        lang.mixin(this.require, req);
+                    }
+                    result = {
+                        remove: function () {
+                            dojo.forEach(signals, function (signal) {
+                                signal.remove();
+                            });
+                        }
+                    };
+                })();
+                return result;
+            }
+        },
+
+        // export utility functions for unit tests
+        __isLessUrl: isLessUrl,
+        __isRelative: isRelative,
+        __dequote: dequote,
+        __normalize: normalize,
+        __resolve: resolve,
+        __fixUrlsInCssFile: fixUrlsInCssFile
+    };
+});

文件差异内容过多而无法显示
+ 34 - 0
esp/src/loader/less.min.js


+ 48 - 10
esp/src/package.json

@@ -1,18 +1,56 @@
 {
-  "name": "hpcc-platform-eclwatch",
+  "name": "eclwatch",
   "version": "1.0.0",
   "description": "'ECL Watch' Web interface for HPCC Platform.",
-  "devDependencies": {
-    "gulp": "~3.9.1",
-    "gulp-filter": "~3.0.1",
-    "gulp-jshint": "~2.0.0",
-    "jshint": "^2.9.4",
-    "jshint-stylish": "~2.1.0"
+  "scripts": {
+    "clean": "rimraf ./build && rimraf ./lib",
+    "lint":"jshint ./eclwatch",
+    "copy-res-es6-promise": "cpx \"./node_modules/es6-promise/dist/es6-promise.auto.min.js\" ./build/node_modules/es6-promise/dist/",
+    "copy-res-eclwatch-img": "cpx \"./eclwatch/img/**/*.{png,jpg,gif}\" ./build/eclwatch/img/",
+    "copy-res-eclwatch-ecl": "cpx \"./eclwatch/ecl/**/*.*\" ./build/eclwatch/ecl/",
+    "copy-res-dojo": "cpx \"./node_modules/dojo/resources/**/*.{png,jpg,gif}\" ./build/node_modules/dojo/resources/",
+    "copy-res-dojox": "cpx \"./node_modules/dojox/widget/ColorPicker/images/**/*.{png,jpg,gif}\" ./build/eclwatch/img/",
+    "copy-res": "npm run copy-res-es6-promise && npm run copy-res-eclwatch-img && npm run copy-res-eclwatch-ecl && npm run copy-res-dojo && npm run copy-res-dojox",
+    "compile": "tsc",
+    "bundle": "node node_modules/webpack/bin/webpack.js --config webpack.config.js",
+    "build": "npm run copy-res && npm run compile && npm run bundle",
+    "test": "npm run lint"    
   },
   "main": "src/stub.js",
-  "scripts": {
-    "test": "gulp lint"
+  "dependencies": {},
+  "devDependencies": {
+    "@hpcc-js/common": "0.0.40",
+    "@hpcc-js/composite": "0.0.43",
+    "@hpcc-js/form": "0.0.42",
+    "@hpcc-js/graph": "0.0.41",
+    "@hpcc-js/layout": "0.0.40",
+    "@hpcc-js/map": "0.0.44",
+    "@hpcc-js/other": "0.0.40",
+    "cpx":  "1.5.0",
+    "css-loader": "0.28.7",
+    "dijit": "1.13.0",
+    "dojo": "1.13.0",
+    "dojo-themes": "1.13.0",
+    "dojo-util": "1.13.0",
+    "dojo-webpack-plugin": "2.1.4",
+    "dojox": "1.13.0",
+    "es6-promise": "4.1.1",
+    "font-awesome": "4.7.0",
+    "jshint": "2.9.4",
+    "less": "2.7.2",
+    "less-loader": "2.2.3",
+    "rimraf": "2.6.2",
+    "style-loader": "0.19.0",
+    "tslib": "1.8.0",
+    "typescript": "2.5.3",
+    "url-loader": "0.6.2",
+    "webpack": "3.6.0",
+    "webpack-bundle-analyzer": "2.9.0"
   },
   "author": "HPCC Systems",
-  "license": "Apache-2.0"
+  "license": "Apache-2.0",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/hpcc-systems/HPCC-Platform"
+  }  
 }

+ 12 - 20
esp/src/stub.htm

@@ -17,9 +17,11 @@
 ##############################################################################
 -->
 <html>
+
 <head>
     <meta charset="utf-8">
     <title>ECL Watch</title>
+    <script src="/esp/files/node_modules/es6-promise/dist/es6-promise.auto.min.js"></script>
     <link rel="icon" type="image/png" href="/esp/files/img/favlogo.png">
     <link rel="stylesheet" href="/esp/files/CodeMirror2/lib/codemirror.css">
     <link rel="stylesheet" href="/esp/files/CodeMirror2/addon/dialog/dialog.css">
@@ -28,33 +30,23 @@
     <script src="/esp/files/CodeMirror2/codemirror-compressed.js"></script>
     <script src="/esp/files/CodeMirror2/addon/scroll/annotatescrollbar.js"></script>
     <script src="/esp/files/CodeMirror2/addon/search/matchesonscrollbar.js"></script>
-    <link href="/esp/files/eclwatch/css/ecl.css" rel="stylesheet">
-    <link href="/esp/files/themes/flat/flat.css" media="screen" rel="stylesheet">
-    <link href="/esp/files/dojox/grid/resources/Grid.css" rel="stylesheet">
-    <link href="/esp/files/dojox/grid/enhanced/resources/claro/EnhancedGrid.css" rel="stylesheet">
-    <link href="/esp/files/dojox/grid/resources/claroGrid.css" rel="stylesheet">
-    <link href="/esp/files/dojox/widget/Toaster/Toaster.css" rel="stylesheet">
-    <link href="/esp/files/dojox/widget/UpgradeBar/UpgradeBar.css" rel="stylesheet">
-    <link href="/esp/files/dojox/form/resources/FileUploader.css" rel="stylesheet">
-    <link href="/esp/files/dojox/form/resources/UploaderFileList.css" rel="stylesheet">
-    <link href="/esp/files/dojox/widget/ColorPicker/ColorPicker.css" rel="stylesheet">
-    <link href="/esp/files/dgrid/css/dgrid.css" rel="stylesheet">
-    <link href="/esp/files/dgrid/css/skins/claro.css" rel="stylesheet">
-    <link href="/esp/files/eclwatch/css/hpcc.css" rel="stylesheet">
     <!-- load dojo and provide config via dojoConfig global -->
-    <script src="/esp/files/eclwatch/dojoConfig.js"></script>
-    <script src="/esp/files/dojo/dojo.js"></script>
-    <script src="/esp/files/eclwatch/hpcc.js"></script>
-    <script>
-        require(["hpcc/stub"], function (stub) {
-            stub.init();
-        });
+    <script type="text/javascript">
+        if (/[?&]nopack=(1|true)/i.test(location.search)) {
+            document.write("<script type=\"text/javascript\" src=\"/esp/files/eclwatch/dojoConfig.js\" charset=\"utf-8\"><" + "/script>");
+            document.write("<script type=\"text/javascript\" src=\"/esp/files/node_modules/dojo/dojo.js\" charset=\"utf-8\"><" + "/script>");
+        } else {
+            document.write("<script type=\"text/javascript\" src=\"/esp/files/dist/node_modules.js\" charset=\"utf-8\"><" + "/script>");
+            document.write("<script type=\"text/javascript\" src=\"/esp/files/dist/stub.eclwatch.js\" charset=\"utf-8\"><" + "/script>");
+        }
     </script>
 </head>
+
 <body class="flat">
     <!-- overlay -->
     <div id="loadingOverlay" class="loadingOverlay pageOverlay">
     </div>
     <!-- application -->
 </body>
+
 </html>

+ 0 - 1
esp/src/themes

@@ -1 +0,0 @@
-Subproject commit a70ce68a7ec7148f47b3cc3bd49b6659832b873f

+ 26 - 0
esp/src/tsconfig.json

@@ -0,0 +1,26 @@
+{
+    "compilerOptions": {
+        "outDir": "./lib",
+        "target": "es5",
+        "module": "amd",
+        "moduleResolution": "node",
+        "sourceMap": true,
+        "noImplicitAny": false,
+        "noEmitOnError": false,
+        "noUnusedLocals": true,
+        "strictNullChecks": false,
+        "importHelpers": true,
+        "experimentalDecorators": true,
+        "allowJs": true,
+        "lib": [
+            "dom",
+            "es5",
+            "es2015.promise"
+        ],
+        "typeRoots": [],
+        "types": []
+    },
+    "include": [
+        "src/**/*"
+    ]
+}

+ 0 - 1
esp/src/util

@@ -1 +0,0 @@
-Subproject commit 8dfe525f49b2e649129394f3c04152e3108125d0

+ 94 - 0
esp/src/webpack.config.js

@@ -0,0 +1,94 @@
+
+var DojoWebpackPlugin = require("dojo-webpack-plugin");
+
+var path = require("path");
+var webpack = require("webpack");
+var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
+
+module.exports = {
+    context: __dirname,
+    entry: {
+        stub: "eclwatch/stub",
+        vendor: ["@hpcc-js/graph"] //  Trick CommonsChunkPlugin to move some extra modules into node_modules for a more balanced initial load.
+    },
+    output: {
+        filename: "[name].eclwatch.js",
+        path: path.join(__dirname, "build/dist"),
+        publicPath: "/esp/files/dist/",
+        pathinfo: false
+    },
+    module: {
+        loaders: [
+            {
+                test: /\.(png|jpg|gif)$/,
+                use: [
+                    {
+                        loader: 'url-loader',
+                        options: {
+                            limit: 8192
+                        }
+                    }
+                ]
+            }, {
+                test: /\.css$/,
+                use: ['style-loader', 'css-loader']
+            }, {
+                test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
+                use: [{
+                    loader: 'file-loader',
+                    options: {
+                        name: '[name].[ext]'
+                    }
+                }]
+            }]
+    },
+    plugins: [
+        new DojoWebpackPlugin({
+            loaderConfig: require.resolve("./eclwatch/dojoConfig"),
+            environment: { dojoRoot: "node_modules" },
+            locales: ["en", "bs", "es", "hr", "hu", "pt-br", "sr", "zh"]
+        }),
+        // For plugins registered after the DojoAMDPlugin, data.request has been normalized and
+        // resolved to an absMid and loader-config maps and aliases have been applied
+        new webpack.NormalModuleReplacementPlugin(/^dojox\/gfx\/renderer!/, "dojox/gfx/canvas"),
+        new webpack.NormalModuleReplacementPlugin(
+            /^css!/, function (data) {
+                data.request = data.request.replace(/^css!/, "!style-loader!css-loader!less-loader!")
+            }
+        ),
+        new webpack.NormalModuleReplacementPlugin(
+            /^xstyle\/css!/, function (data) {
+                data.request = data.request.replace(/^xstyle\/css!/, "!style-loader!css-loader!less-loader!")
+            }
+        ),
+        new webpack.optimize.CommonsChunkPlugin({
+            name: 'node_modules',
+            filename: 'node_modules.js',
+            minChunks(module, count) {
+                var context = module.context;
+                return context && context.indexOf('node_modules') >= 0;
+            },
+        }),
+        new webpack.optimize.CommonsChunkPlugin({
+            children: true,
+            minChunks: 4
+        }),
+        new webpack.optimize.UglifyJsPlugin({
+            output: { comments: false },
+            compress: { warnings: false },
+            sourceMap: false
+        })/*,
+        new BundleAnalyzerPlugin()
+        */
+    ],
+    resolveLoader: {
+        modules: [
+            path.join(__dirname, "node_modules")
+        ]
+    },
+    // devtool: "source-map",
+    node: {
+        process: false,
+        global: false
+    }
+};