Browse Source

HPCC-26799 Convert WU Detail grids to Fluent UI

Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
Gordon Smith 3 years ago
parent
commit
d77e9d2dbf

+ 111 - 116
esp/src/package-lock.json

@@ -747,37 +747,37 @@
       }
     },
     "@hpcc-js/api": {
-      "version": "2.8.53",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/api/-/api-2.8.53.tgz",
-      "integrity": "sha512-VGNoZ1kERMSjospnOMKaHynAcAI8EyQgCKpiQjkb7ecaPlBKLxCg+JyfqZp7lopPn5VyJfmRAIW+AtWYQb0zxg==",
+      "version": "2.8.54",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/api/-/api-2.8.54.tgz",
+      "integrity": "sha512-lIc5kQl1eq4kZ++oaTavH2lBWKOL128BxC/pfsME5laS2/GLaTQJbXsblwrcdBnZL/+/hLcE13QK8uOtUROmbw==",
       "requires": {
-        "@hpcc-js/common": "^2.58.0"
+        "@hpcc-js/common": "^2.59.0"
       }
     },
     "@hpcc-js/chart": {
-      "version": "2.68.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/chart/-/chart-2.68.0.tgz",
-      "integrity": "sha512-PlwqvDOURyRy5+S7WZ0MOHuEkaTDn/qr+eOfVRAG1jdCiVIZCRDe5EtNslVi3ZyyvGoFK9TDWhQtR2t8IB8wMg==",
+      "version": "2.69.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/chart/-/chart-2.69.0.tgz",
+      "integrity": "sha512-tcLzV9ykWuxRUbOEj6/C+p/lG6XlISMfe2BM3JuOfy2pLTVgp/+Zt41FxxB7JUscwWlx6UD6AMn0O/DV5Il2Iw==",
       "requires": {
-        "@hpcc-js/api": "^2.8.53",
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/util": "^2.39.0"
+        "@hpcc-js/api": "^2.8.54",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/util": "^2.40.0"
       }
     },
     "@hpcc-js/codemirror": {
-      "version": "2.51.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/codemirror/-/codemirror-2.51.0.tgz",
-      "integrity": "sha512-/GpSKK63obY3OHnq1SH6BuPouFaMwSQ++ftyE8ApESltRNsZXXlVGB9mMuN6iffUWROZ9gDwuWo+TJKPCMjp+Q==",
+      "version": "2.52.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/codemirror/-/codemirror-2.52.0.tgz",
+      "integrity": "sha512-X+t8ZX5ibMYVf7iJmSLPjgUnUHnyzjw6DMiYiK1XI4jOvKKGPp1RLP6J7lGk7ZqbIVJ9VznABlK2EXANBLAsKg==",
       "requires": {
-        "@hpcc-js/common": "^2.58.0"
+        "@hpcc-js/common": "^2.59.0"
       }
     },
     "@hpcc-js/common": {
-      "version": "2.58.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-2.58.0.tgz",
-      "integrity": "sha512-Y9yZqzDIFdF8SlBEGSmQ+po67WrA+QE9+a/nB5nflMP0PaMfJIGtM/pIbnJ8dMGwDRboi8o/TIezrYMJoaj57Q==",
+      "version": "2.59.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-2.59.0.tgz",
+      "integrity": "sha512-VPyyCNJxozSiNe/OjqgyvsGb9sOLN7NcvvGb1G2rxHaoUKjrm6glkXU0mNZhBOcM6Mz8LIEoJwJYYQaflDABog==",
       "requires": {
-        "@hpcc-js/util": "^2.39.0",
+        "@hpcc-js/util": "^2.40.0",
         "@types/d3-array": "1.2.6",
         "@types/d3-brush": "1.0.10",
         "@types/d3-collection": "1.0.8",
@@ -796,12 +796,12 @@
       }
     },
     "@hpcc-js/comms": {
-      "version": "2.60.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/comms/-/comms-2.60.0.tgz",
-      "integrity": "sha512-7CU06gsUGcmj8CAiEG/43UWptmn+DYpl0NIVJ+1WCfsDXwkSZddyTLG45zP/+O/x0nAwch6F3CbLyNneaswo8g==",
+      "version": "2.63.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/comms/-/comms-2.63.0.tgz",
+      "integrity": "sha512-UQC1FAKPTMochuCcgdNmdoo0iP/M0k/1UJySBuCQZdESiOQBQGBKWU8xIvWnBmOeBJrCL8ARiQ5UoIkxye6UXQ==",
       "requires": {
         "@hpcc-js/ddl-shim": "^2.17.19",
-        "@hpcc-js/util": "^2.39.0",
+        "@hpcc-js/util": "^2.40.0",
         "@xmldom/xmldom": "0.7.2",
         "abort-controller": "3.0.0",
         "node-fetch": "2.6.5",
@@ -823,113 +823,112 @@
       }
     },
     "@hpcc-js/dgrid": {
-      "version": "2.19.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid/-/dgrid-2.19.0.tgz",
-      "integrity": "sha512-d+27L3MOffJcelgbJXClg5Zcqh3VXnsD9COZvr6sOPeOwCLLQe3dEL5vhYUJ02xbZDdtJX/V/oRKL5YpwsZfQg==",
+      "version": "2.22.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid/-/dgrid-2.22.0.tgz",
+      "integrity": "sha512-1lKzlJ+9c0j1Ec2KLk379394cuikXgZGYEu/nheX3Txef5JKNe3crTzCHOkO9+HwfXoRRUPhYYzMSEMARfYalQ==",
       "requires": {
-        "@hpcc-js/common": "^2.58.0",
+        "@hpcc-js/common": "^2.59.0",
         "@hpcc-js/ddl-shim": "^2.17.19",
-        "@hpcc-js/dgrid-shim": "^2.15.0",
-        "@hpcc-js/util": "^2.39.0"
+        "@hpcc-js/dgrid-shim": "^2.17.0",
+        "@hpcc-js/util": "^2.40.0"
       }
     },
     "@hpcc-js/dgrid-shim": {
-      "version": "2.15.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid-shim/-/dgrid-shim-2.15.0.tgz",
-      "integrity": "sha512-cxK/wsQ4dX69IcHFbO3whxdTj2Kof0rOYdGxRqU0k2HTmx6mc8eIbyud7Sd/exbr3FQgwqgrV3WRMbG1kq073g=="
+      "version": "2.17.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid-shim/-/dgrid-shim-2.17.0.tgz",
+      "integrity": "sha512-SizPr8SH8YZ98TSYC8kV2CN+0h3/lvUMprCSY4TiOb34dtVMjDA8lHrTIFmQSGAmYZw2ufcPx1FdMRq+R39M8Q=="
     },
     "@hpcc-js/eclwatch": {
-      "version": "2.60.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/eclwatch/-/eclwatch-2.60.0.tgz",
-      "integrity": "sha512-/WSVNpz4M8i/qzTPnawGdkqogH8t0oKAZpqcJggBZ0IFxO6r6Y9uLFaH/h6hsjEmPSP1KzWBmieXd1A86PQZEw==",
-      "requires": {
-        "@hpcc-js/codemirror": "^2.51.0",
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/comms": "^2.60.0",
-        "@hpcc-js/dgrid": "^2.19.0",
-        "@hpcc-js/graph": "^2.70.0",
-        "@hpcc-js/layout": "^2.36.0",
-        "@hpcc-js/phosphor": "^2.14.50",
-        "@hpcc-js/timeline": "^2.39.0",
-        "@hpcc-js/tree": "^2.31.0",
-        "@hpcc-js/util": "^2.39.0"
+      "version": "2.63.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/eclwatch/-/eclwatch-2.63.0.tgz",
+      "integrity": "sha512-VOzgxZMO0A9wNbntNjKJcwVG7tHPbwnOPRW14EWA7pyn6KS0z9EBdR+NHueztArIP0D7YyTfTWEIWwZBCVo+PQ==",
+      "requires": {
+        "@hpcc-js/codemirror": "^2.52.0",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/comms": "^2.63.0",
+        "@hpcc-js/dgrid": "^2.22.0",
+        "@hpcc-js/graph": "^2.71.0",
+        "@hpcc-js/layout": "^2.39.0",
+        "@hpcc-js/phosphor": "^2.14.53",
+        "@hpcc-js/timeline": "^2.42.0",
+        "@hpcc-js/tree": "^2.32.0",
+        "@hpcc-js/util": "^2.40.0"
       }
     },
     "@hpcc-js/graph": {
-      "version": "2.70.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/graph/-/graph-2.70.0.tgz",
-      "integrity": "sha512-zyaX07ccZc+R5ZmgA4NgTiSI7s49Aut8x4EN9BVrT6DPqV2T/mz2RrPmXrIScZKWaTtPmwp2AbnuIiEy73coiw==",
+      "version": "2.71.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/graph/-/graph-2.71.0.tgz",
+      "integrity": "sha512-mXKSYvYxa2A1sH2wYt26s0p//en5Fo60BeGma3eGUZzBtGLWxowC+7nrg44i9Xb5qwQiWs878HKtlEFlHyeSAg==",
       "requires": {
-        "@hpcc-js/api": "^2.8.53",
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/html": "^2.33.0",
-        "@hpcc-js/react": "^2.41.0",
-        "@hpcc-js/util": "^2.39.0"
+        "@hpcc-js/api": "^2.8.54",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/html": "^2.34.0",
+        "@hpcc-js/react": "^2.42.0",
+        "@hpcc-js/util": "^2.40.0"
       }
     },
     "@hpcc-js/html": {
-      "version": "2.33.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/html/-/html-2.33.0.tgz",
-      "integrity": "sha512-6pi5iWfSHyJXx21Ici1mmvB7v6w0kByiT95TiKGqPSG0sb3d1BxFBlJ7SzYhcl9R85Co4A0iLCoTNQAG3ygHcw==",
+      "version": "2.34.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/html/-/html-2.34.0.tgz",
+      "integrity": "sha512-wQ0iIfDcOaz8PGakGy/hY4bofZD7Py/e31erU0jbqupQ3qU3VUzcdcXKkO8YYqIGnCuP/nOSekXc1gckqLUlJA==",
       "requires": {
-        "@hpcc-js/common": "^2.58.0",
+        "@hpcc-js/common": "^2.59.0",
         "@hpcc-js/preact-shim": "^2.13.17",
-        "@hpcc-js/util": "^2.39.0"
+        "@hpcc-js/util": "^2.40.0"
       }
     },
     "@hpcc-js/layout": {
-      "version": "2.36.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/layout/-/layout-2.36.0.tgz",
-      "integrity": "sha512-JjZbRNa2gOxrBpT7sCdSoXZpsEOjdRQ4MX/jb3BL1pj97abofz/3DK/16sn4B2ugxQ3VvDOggcBqQB9S3uGGYQ==",
+      "version": "2.39.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/layout/-/layout-2.39.0.tgz",
+      "integrity": "sha512-O/ZOHInOtmM+gvoSk69lJfSC24CxYpWYatii2+cx17J2Ge/yyEin4OiFxyi1/k1tZ98jf4L7jL+/y3HXPYmXmw==",
       "requires": {
-        "@hpcc-js/api": "^2.8.53",
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/dgrid": "^2.19.0"
+        "@hpcc-js/api": "^2.8.54",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/dgrid": "^2.22.0"
       }
     },
     "@hpcc-js/leaflet-shim": {
-      "version": "2.1.16",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/leaflet-shim/-/leaflet-shim-2.1.16.tgz",
-      "integrity": "sha512-UnvTLBcYSm5+5BApofIZogYZ5/U0HhphImH1vKX/qj7u3yxn9YqgvKg8/NojjJAo6WS7SCmb6NjuHHwlRFCKTg==",
+      "version": "2.1.18",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/leaflet-shim/-/leaflet-shim-2.1.18.tgz",
+      "integrity": "sha512-RWDHN5xl2jjG9hm5c+FqKtngaXqK1BPnPLoT742Xo395zXOsN5cdURuNjovYvU3JPMjNHXRodm1Fkb8qJC7kVg==",
       "requires": {
         "@types/leaflet": "1.5.1",
-        "leaflet": "1.5.1",
-        "leaflet.gridlayer.googlemutant": "git+https://github.com/GordonSmith/Leaflet.GridLayer.GoogleMutant.git#master"
+        "leaflet": "1.5.1"
       }
     },
     "@hpcc-js/map": {
-      "version": "2.63.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/map/-/map-2.63.0.tgz",
-      "integrity": "sha512-qqSt+ijIcYCCvSHjhkeqeb/oP4Z1rutNUytp7TRK99iYrL1roQAGvxV6fd3jFlzWxhKP4+Oa4WH+ajvN4Xjjwg==",
+      "version": "2.66.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/map/-/map-2.66.0.tgz",
+      "integrity": "sha512-O0giPk0ODT897vjHS9ATNYRKe8ZPGNuFOF2WUT7bweec38IGDrIAslbCB1LVkaSIaIgpUDBLBXlK7r6IHHFX9A==",
       "requires": {
-        "@hpcc-js/api": "^2.8.53",
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/graph": "^2.70.0",
-        "@hpcc-js/layout": "^2.36.0",
-        "@hpcc-js/leaflet-shim": "^2.1.16",
-        "@hpcc-js/other": "^2.13.69",
-        "@hpcc-js/util": "^2.39.0"
+        "@hpcc-js/api": "^2.8.54",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/graph": "^2.71.0",
+        "@hpcc-js/layout": "^2.39.0",
+        "@hpcc-js/leaflet-shim": "^2.1.18",
+        "@hpcc-js/other": "^2.13.72",
+        "@hpcc-js/util": "^2.40.0"
       }
     },
     "@hpcc-js/other": {
-      "version": "2.13.69",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/other/-/other-2.13.69.tgz",
-      "integrity": "sha512-NPKjFhPs6K+6gaEDhTM//f/Wj2Sc0vl8/+dfGEJCgAaVoI9PAZUwBSEzKilc+CQUQKcAlGUscE3lsNvX3l+ADA==",
+      "version": "2.13.72",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/other/-/other-2.13.72.tgz",
+      "integrity": "sha512-cdTsdVTEAe/NrXjL3yYKoEUws1Bz6B08bXxZVM9yWDSCHMT/h1+Io3u6m3obx+3isNWEsRXLBBrHypIA8G6XVw==",
       "requires": {
-        "@hpcc-js/api": "^2.8.53",
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/layout": "^2.36.0"
+        "@hpcc-js/api": "^2.8.54",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/layout": "^2.39.0"
       }
     },
     "@hpcc-js/phosphor": {
-      "version": "2.14.50",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/phosphor/-/phosphor-2.14.50.tgz",
-      "integrity": "sha512-dtkMGgiT1db5Y1O8J7xkKnemLv7t4UZaucPHjePDHMWJ01Gx8r2OKR+/LAlJ7HDBTDhhziV5CqjKJ4VetfPbJA==",
+      "version": "2.14.53",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/phosphor/-/phosphor-2.14.53.tgz",
+      "integrity": "sha512-vLgW0g5C04xHfYvz52Sf71sJ/jyGuR72bBjMBuWWyIfxYK0yw3W18RYfhBIb+Ud0WLI76F5f+kIp411qaKrPbA==",
       "requires": {
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/other": "^2.13.69",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/other": "^2.13.72",
         "@hpcc-js/phosphor-shim": "^2.11.21",
-        "@hpcc-js/util": "^2.39.0"
+        "@hpcc-js/util": "^2.40.0"
       }
     },
     "@hpcc-js/phosphor-shim": {
@@ -952,40 +951,40 @@
       }
     },
     "@hpcc-js/react": {
-      "version": "2.41.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/react/-/react-2.41.0.tgz",
-      "integrity": "sha512-MvQ2BpWHtZy6RROaG2H44XH33zTRQnqkTRNTqBBVXThUzotuRPwwpS0qjMgsuoGEkH52/hGsFsWP+p+fRVNFQw==",
+      "version": "2.42.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/react/-/react-2.42.0.tgz",
+      "integrity": "sha512-CLaTyL9EyWy/tTa/gj69I2fBTiHXI7a+M8WYAXXYDVWe/9no2VA27Ya90EDGCNSwT5mzXvjrZNfux9y34phCsw==",
       "requires": {
-        "@hpcc-js/common": "^2.58.0",
+        "@hpcc-js/common": "^2.59.0",
         "@hpcc-js/preact-shim": "^2.13.17"
       }
     },
     "@hpcc-js/timeline": {
-      "version": "2.39.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/timeline/-/timeline-2.39.0.tgz",
-      "integrity": "sha512-i9uB52DHSZscsSFq95XcPJSyPv3+HLGHg9k1Ie6Yq/tbqRlSe3hhoOAatWHPqQFqCNTuzIdVBlt4VHyoTNeUUg==",
+      "version": "2.42.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/timeline/-/timeline-2.42.0.tgz",
+      "integrity": "sha512-zGmDdZPHhBc+qmvuGN4pv3K1AsfdOsqbLlYrUMhMXM9jOH/ufBbejaS2y13maDCCipon48rHHBSI1RdvUmwRLw==",
       "requires": {
-        "@hpcc-js/api": "^2.8.53",
-        "@hpcc-js/chart": "^2.68.0",
-        "@hpcc-js/common": "^2.58.0",
-        "@hpcc-js/html": "^2.33.0",
-        "@hpcc-js/layout": "^2.36.0",
-        "@hpcc-js/react": "^2.41.0"
+        "@hpcc-js/api": "^2.8.54",
+        "@hpcc-js/chart": "^2.69.0",
+        "@hpcc-js/common": "^2.59.0",
+        "@hpcc-js/html": "^2.34.0",
+        "@hpcc-js/layout": "^2.39.0",
+        "@hpcc-js/react": "^2.42.0"
       }
     },
     "@hpcc-js/tree": {
-      "version": "2.31.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/tree/-/tree-2.31.0.tgz",
-      "integrity": "sha512-Eh0gtDWcHwmkpvkJETizlYIlrYkM2AM2Vt+MctoeZ9Q2WlF9V1bMoMlfDhy9QHQEaXg/KwCG4EkmCzFLXo/8pg==",
+      "version": "2.32.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/tree/-/tree-2.32.0.tgz",
+      "integrity": "sha512-0FhSAD9YCmGbT4qbsolT/Ui8ZQI/7vn8j7yxdwrl+G2Q47L1eECvK36Ox9kKB0L3euFOtJrJ6FzIeYY9fT8XTw==",
       "requires": {
-        "@hpcc-js/api": "^2.8.53",
-        "@hpcc-js/common": "^2.58.0"
+        "@hpcc-js/api": "^2.8.54",
+        "@hpcc-js/common": "^2.59.0"
       }
     },
     "@hpcc-js/util": {
-      "version": "2.39.0",
-      "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-2.39.0.tgz",
-      "integrity": "sha512-EKhOjbN+FZC17j5WDKgVfT1KX/Y6WXLaHDHEKQXZexbZOXkTBHjYgCiMU114fZnq703CLQwdiZdufBMkM2B2lA==",
+      "version": "2.40.0",
+      "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-2.40.0.tgz",
+      "integrity": "sha512-YoQGYuzxmBUFILxazEEz7Hpdm8z6ebp/aw5GCKJ0GnA2VCiODlFaZ6+cjA8LN6tI0ZucPuNbUz2iA0TfCd8GcQ==",
       "requires": {
         "tslib": "2.3.0"
       },
@@ -6320,10 +6319,6 @@
       "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.5.1.tgz",
       "integrity": "sha512-ekM9KAeG99tYisNBg0IzEywAlp0hYI5XRipsqRXyRTeuU8jcuntilpp+eFf5gaE0xubc9RuSNIVtByEKwqFV0w=="
     },
-    "leaflet.gridlayer.googlemutant": {
-      "version": "git+https://github.com/GordonSmith/Leaflet.GridLayer.GoogleMutant.git#76640a02252b784e3463c076a1ce1924682c270f",
-      "from": "git+https://github.com/GordonSmith/Leaflet.GridLayer.GoogleMutant.git#master"
-    },
     "levn": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",

+ 14 - 14
esp/src/package.json

@@ -37,21 +37,21 @@
     "@fluentui/react-cards": "1.0.0-beta.0",
     "@fluentui/react-hooks": "8.3.2",
     "@fluentui/react-icons-mdl2": "1.2.2",
-    "@hpcc-js/chart": "2.68.0",
-    "@hpcc-js/codemirror": "2.51.0",
-    "@hpcc-js/common": "2.58.0",
-    "@hpcc-js/comms": "2.60.0",
+    "@hpcc-js/chart": "2.69.0",
+    "@hpcc-js/codemirror": "2.52.0",
+    "@hpcc-js/common": "2.59.0",
+    "@hpcc-js/comms": "2.63.0",
     "@hpcc-js/dataflow": "3.0.1",
-    "@hpcc-js/eclwatch": "2.60.0",
-    "@hpcc-js/graph": "2.70.0",
-    "@hpcc-js/html": "2.33.0",
-    "@hpcc-js/layout": "2.36.0",
-    "@hpcc-js/map": "2.63.0",
-    "@hpcc-js/other": "2.13.69",
-    "@hpcc-js/phosphor": "2.14.50",
-    "@hpcc-js/react": "2.41.0",
-    "@hpcc-js/tree": "2.31.0",
-    "@hpcc-js/util": "2.39.0",
+    "@hpcc-js/eclwatch": "2.63.0",
+    "@hpcc-js/graph": "2.71.0",
+    "@hpcc-js/html": "2.34.0",
+    "@hpcc-js/layout": "2.39.0",
+    "@hpcc-js/map": "2.66.0",
+    "@hpcc-js/other": "2.13.72",
+    "@hpcc-js/phosphor": "2.14.53",
+    "@hpcc-js/react": "2.42.0",
+    "@hpcc-js/tree": "2.32.0",
+    "@hpcc-js/util": "2.40.0",
     "@material-ui/core": "4.12.3",
     "@material-ui/icons": "4.11.2",
     "@material-ui/lab": "4.0.0-alpha.60",

+ 3 - 3
esp/src/src-react/components/Common.tsx

@@ -5,18 +5,18 @@ import nlsHPCC from "src/nlsHPCC";
 
 export const ShortVerticalDivider = () => <VerticalDivider styles={{ divider: { paddingTop: "20%", height: "60%" } }} />;
 
-export function createCopyDownloadSelection(grid, selection: any, filename: string) {
+export function createCopyDownloadSelection(columns, selection: any, filename: string) {
     return [{
         key: "copy", text: nlsHPCC.CopySelectionToClipboard, disabled: !selection.length || !navigator?.clipboard?.writeText, iconOnly: true, iconProps: { iconName: "Copy" },
         onClick: () => {
-            const tsv = Utility.formatAsDelim(grid, selection, "\t");
+            const tsv = Utility.formatAsDelim(columns, selection, "\t");
             navigator?.clipboard?.writeText(tsv);
         }
     },
     {
         key: "download", text: nlsHPCC.DownloadSelectionAsCSV, disabled: !selection.length, iconOnly: true, iconProps: { iconName: "Download" },
         onClick: () => {
-            const csv = Utility.formatAsDelim(grid, selection, ",");
+            const csv = Utility.formatAsDelim(columns, selection, ",");
             Utility.downloadText(csv, filename);
         }
     }];

+ 6 - 8
esp/src/src-react/components/Helpers.tsx

@@ -1,13 +1,12 @@
 import * as React from "react";
-import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
+import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Link } from "@fluentui/react";
 import { useConst } from "@fluentui/react-hooks";
 import * as domClass from "dojo/dom-class";
-import * as Observable from "dojo/store/Observable";
 import * as ESPRequest from "src/ESPRequest";
 import { Memory } from "src/Memory";
 import * as Utility from "src/Utility";
 import nlsHPCC from "src/nlsHPCC";
-import { useGrid } from "../hooks/grid";
+import { useFluentGrid } from "../hooks/grid";
 import { HelperRow, useWorkunitHelpers } from "../hooks/workunit";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { ShortVerticalDivider } from "./Common";
@@ -105,8 +104,8 @@ export const Helpers: React.FunctionComponent<HelpersProps> = ({
     const [helpers, refreshData] = useWorkunitHelpers(wuid);
 
     //  Grid ---
-    const store = useConst(new Observable(new Memory("id")));
-    const [Grid, selection, refreshTable, copyButtons] = useGrid({
+    const store = useConst(new Memory("id"));
+    const [Grid, selection, copyButtons] = useFluentGrid({
         store,
         filename: "helpers",
         columns: {
@@ -120,7 +119,7 @@ export const Helpers: React.FunctionComponent<HelpersProps> = ({
                 formatter: function (Type, row) {
                     const target = getTarget(row.id, row);
                     if (target) {
-                        return `<a href='#/text?mode=${target.sourceMode}&src=${encodeURIComponent(target.url)}'>${Type + (row?.Orig?.Description ? " (" + row.Orig.Description + ")" : "")}</a>`;
+                        return <Link href={`#/text?mode=${target.sourceMode}&src=${encodeURIComponent(target.url)}`}>{Type + (row?.Orig?.Description ? " (" + row.Orig.Description + ")" : "")}</Link>;
                     }
                     return Type;
                 }
@@ -207,8 +206,7 @@ export const Helpers: React.FunctionComponent<HelpersProps> = ({
 
     React.useEffect(() => {
         store.setData(helpers);
-        refreshTable();
-    }, [store, helpers, refreshTable]);
+    }, [store, helpers]);
 
     return <HolyGrail
         header={<CommandBar items={buttons} farItems={copyButtons} />}

+ 6 - 8
esp/src/src-react/components/Resources.tsx

@@ -1,10 +1,9 @@
 import * as React from "react";
-import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
+import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Link } from "@fluentui/react";
 import { useConst } from "@fluentui/react-hooks";
 import { AlphaNumSortMemory } from "src/Memory";
-import * as Observable from "dojo/store/Observable";
 import nlsHPCC from "src/nlsHPCC";
-import { useGrid } from "../hooks/grid";
+import { useFluentGrid } from "../hooks/grid";
 import { useWorkunitResources } from "../hooks/workunit";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { ShortVerticalDivider } from "./Common";
@@ -26,8 +25,8 @@ export const Resources: React.FunctionComponent<ResourcesProps> = ({
     const [resources, , , refreshData] = useWorkunitResources(wuid);
 
     //  Grid ---
-    const store = useConst(new Observable(new AlphaNumSortMemory("DisplayPath", { Name: true, Value: true })));
-    const [Grid, selection, refreshTable, copyButtons] = useGrid({
+    const store = useConst(new AlphaNumSortMemory("DisplayPath", { Name: true, Value: true }));
+    const [Grid, selection, copyButtons] = useFluentGrid({
         store,
         sort: [{ attribute: "Wuid", "descending": true }],
         filename: "resources",
@@ -39,7 +38,7 @@ export const Resources: React.FunctionComponent<ResourcesProps> = ({
             DisplayPath: {
                 label: nlsHPCC.Name, sortable: true,
                 formatter: function (url, row) {
-                    return `<a href='#/iframe?src=${encodeURIComponent(`WsWorkunits/${row.URL}`)}' class='dgrid-row-url'>${url}</a>`;
+                    return <Link href={`#/iframe?src=${encodeURIComponent(`WsWorkunits/${row.URL}`)}`}>{url}</Link>;
                 }
             }
         }
@@ -96,8 +95,7 @@ export const Resources: React.FunctionComponent<ResourcesProps> = ({
                 DisplayPath: row.substring(`res/${wuid}/`.length)
             };
         }));
-        refreshTable();
-    }, [store, refreshTable, resources, wuid]);
+    }, [store, resources, wuid]);
 
     return <HolyGrail
         header={<CommandBar items={buttons} farItems={copyButtons} />}

+ 10 - 14
esp/src/src-react/components/Results.tsx

@@ -1,10 +1,9 @@
 import * as React from "react";
-import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
+import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Link } from "@fluentui/react";
 import { useConst } from "@fluentui/react-hooks";
 import { AlphaNumSortMemory } from "src/Memory";
-import * as Observable from "dojo/store/Observable";
 import nlsHPCC from "src/nlsHPCC";
-import { useGrid } from "../hooks/grid";
+import { useFluentGrid } from "../hooks/grid";
 import { useWorkunitResults } from "../hooks/workunit";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { ShortVerticalDivider } from "./Common";
@@ -26,8 +25,8 @@ export const Results: React.FunctionComponent<ResultsProps> = ({
     const [results, , , refreshData] = useWorkunitResults(wuid);
 
     //  Grid ---
-    const store = useConst(new Observable(new AlphaNumSortMemory("__hpcc_id", { Name: true, Value: true })));
-    const [Grid, selection, refreshTable, copyButtons] = useGrid({
+    const store = useConst(new AlphaNumSortMemory("__hpcc_id", { Name: true, Value: true }));
+    const [Grid, selection, copyButtons] = useFluentGrid({
         store,
         sort: [{ attribute: "Wuid", "descending": true }],
         filename: "results",
@@ -39,13 +38,13 @@ export const Results: React.FunctionComponent<ResultsProps> = ({
             Name: {
                 label: nlsHPCC.Name, width: 180, sortable: true,
                 formatter: function (Name, row) {
-                    return `<a href='#/workunits/${row.Wuid}/outputs/${Name}' class='dgrid-row-url'>${Name}</a>`;
+                    return <Link href={`#/workunits/${row.Wuid}/outputs/${Name}`}>{Name}</Link>;
                 }
             },
             FileName: {
                 label: nlsHPCC.FileName, sortable: true,
                 formatter: function (FileName, row) {
-                    return `<a href='#/files/${FileName}' class='dgrid-row-url2'>${FileName}</a>`;
+                    return <Link href={`#/files/${FileName}`}>{FileName}</Link>;
                 }
             },
             Value: {
@@ -56,11 +55,9 @@ export const Results: React.FunctionComponent<ResultsProps> = ({
             ResultViews: {
                 label: nlsHPCC.Views, sortable: true,
                 formatter: function (ResultViews, idx) {
-                    let retVal = "";
-                    ResultViews?.forEach((item, idx) => {
-                        retVal += "<a href='#' onClick='return false;' viewName=" + encodeURIComponent(item) + " class='dgrid-row-url3'>" + item + "</a>&nbsp;";
-                    });
-                    return retVal;
+                    return <>
+                        {ResultViews?.map((item, idx) => <Link href='#' viewName={encodeURIComponent(item)}>{item}</Link>)}
+                    </>;
                 }
             }
         }
@@ -123,8 +120,7 @@ export const Results: React.FunctionComponent<ResultsProps> = ({
                 Sequence: row.Sequence
             };
         }));
-        refreshTable();
-    }, [store, refreshTable, results]);
+    }, [store, results]);
 
     return <HolyGrail
         header={<CommandBar items={buttons} farItems={copyButtons} />}

+ 10 - 8
esp/src/src-react/components/SourceFiles.tsx

@@ -1,12 +1,11 @@
 import * as React from "react";
-import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
+import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, Image, Link } from "@fluentui/react";
 import { useConst } from "@fluentui/react-hooks";
-import * as Observable from "dojo/store/Observable";
 import * as domClass from "dojo/dom-class";
 import { AlphaNumSortMemory } from "src/Memory";
 import * as Utility from "src/Utility";
 import nlsHPCC from "src/nlsHPCC";
-import { useGrid } from "../hooks/grid";
+import { useFluentGrid } from "../hooks/grid";
 import { useWorkunitSourceFiles } from "../hooks/workunit";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { ShortVerticalDivider } from "./Common";
@@ -39,8 +38,8 @@ export const SourceFiles: React.FunctionComponent<SourceFilesProps> = ({
     const [sourceFiles, , , refreshData] = useWorkunitSourceFiles(wuid);
 
     //  Grid ---
-    const store = useConst(new Observable(new TreeStore("Name", { Name: true, Value: true })));
-    const [Grid, selection, refreshTable, copyButtons] = useGrid({
+    const store = useConst(new TreeStore("Name", { Name: true, Value: true }));
+    const [Grid, selection, copyButtons] = useFluentGrid({
         store,
         sort: [{ attribute: "Name", "descending": false }],
         query: { __hpcc_parentName: "" },
@@ -53,7 +52,11 @@ export const SourceFiles: React.FunctionComponent<SourceFilesProps> = ({
             Name: tree({
                 label: "Name", sortable: true,
                 formatter: function (Name, row) {
-                    return `${Utility.getImageHTML(row.IsSuperFile ? "folder_table.png" : "file.png")}&nbsp;<a href='#/files/${row.FileCluster}/${Name}' class='dgrid-row-url2'>${Name}</a>`;
+                    return <>
+                        <Image src={Utility.getImageURL(row.IsSuperFile ? "folder_table.png" : "file.png")} className='iconAlign' />
+                        &nbsp;
+                        <Link href={`#/files/${row.FileCluster}/${Name}`}>{Name}</Link>
+                    </>;
                 }
             }),
             FileCluster: { label: nlsHPCC.FileCluster, width: 300, sortable: false },
@@ -101,8 +104,7 @@ export const SourceFiles: React.FunctionComponent<SourceFilesProps> = ({
 
     React.useEffect(() => {
         store.setData(sourceFiles);
-        refreshTable();
-    }, [store, refreshTable, sourceFiles]);
+    }, [store, sourceFiles]);
 
     return <HolyGrail
         header={<CommandBar items={buttons} farItems={copyButtons} />}

+ 4 - 6
esp/src/src-react/components/Variables.tsx

@@ -1,10 +1,9 @@
 import * as React from "react";
 import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
 import { useConst } from "@fluentui/react-hooks";
-import * as Observable from "dojo/store/Observable";
 import { AlphaNumSortMemory } from "src/Memory";
 import nlsHPCC from "src/nlsHPCC";
-import { useGrid } from "../hooks/grid";
+import { useFluentGrid } from "../hooks/grid";
 import { useWorkunitVariables } from "../hooks/workunit";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { ShortVerticalDivider } from "./Common";
@@ -20,8 +19,8 @@ export const Variables: React.FunctionComponent<VariablesProps> = ({
     const [variables, , , refreshData] = useWorkunitVariables(wuid);
 
     //  Grid ---
-    const store = useConst(new Observable(new AlphaNumSortMemory("__hpcc_id", { Name: true, Value: true })));
-    const [Grid, _selection, refreshTable, copyButtons] = useGrid({
+    const store = useConst(new AlphaNumSortMemory("__hpcc_id", { Name: true, Value: true }));
+    const [Grid, _selection, copyButtons] = useFluentGrid({
         store,
         sort: [{ attribute: "Wuid", "descending": true }],
         filename: "variables",
@@ -39,8 +38,7 @@ export const Variables: React.FunctionComponent<VariablesProps> = ({
                 ...row
             };
         }));
-        refreshTable();
-    }, [store, refreshTable, variables]);
+    }, [store, variables]);
 
     //  Command Bar  ---
     const buttons = React.useMemo((): ICommandBarItemProps[] => [

+ 4 - 6
esp/src/src-react/components/Workflows.tsx

@@ -2,9 +2,8 @@ import * as React from "react";
 import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
 import { useConst } from "@fluentui/react-hooks";
 import { AlphaNumSortMemory } from "src/Memory";
-import * as Observable from "dojo/store/Observable";
 import nlsHPCC from "src/nlsHPCC";
-import { useGrid } from "../hooks/grid";
+import { useFluentGrid } from "../hooks/grid";
 import { useWorkunitWorkflows } from "../hooks/workunit";
 import { HolyGrail } from "../layouts/HolyGrail";
 import { ShortVerticalDivider } from "./Common";
@@ -20,8 +19,8 @@ export const Workflows: React.FunctionComponent<WorkflowsProps> = ({
     const [workflows, , refreshWorkflow] = useWorkunitWorkflows(wuid);
 
     //  Grid ---
-    const store = useConst(new Observable(new AlphaNumSortMemory("__hpcc_id", { Name: true, Value: true })));
-    const [Grid, _selection, refreshTable, copyButtons] = useGrid({
+    const store = useConst(new AlphaNumSortMemory("__hpcc_id", { Name: true, Value: true }));
+    const [Grid, _selection, copyButtons] = useFluentGrid({
         store,
         sort: [{ attribute: "Wuid", "descending": true }],
         filename: "workflows",
@@ -56,8 +55,7 @@ export const Workflows: React.FunctionComponent<WorkflowsProps> = ({
                 __hpcc_id: row.WFID
             };
         }));
-        refreshTable();
-    }, [store, refreshTable, workflows]);
+    }, [store, workflows]);
 
     //  Command Bar  ---
     const buttons = React.useMemo((): ICommandBarItemProps[] => [

+ 99 - 7
esp/src/src-react/hooks/grid.tsx

@@ -1,5 +1,5 @@
 import * as React from "react";
-import { ICommandBarItemProps } from "@fluentui/react";
+import { DetailsList, DetailsListLayoutMode, IColumn, ICommandBarItemProps, Selection } from "@fluentui/react";
 import { useConst } from "@fluentui/react-hooks";
 import { createCopyDownloadSelection } from "../components/Common";
 import { DojoGrid } from "../components/DojoGrid";
@@ -13,6 +13,7 @@ interface useGridProps {
     getSelected?: () => any[],
     filename: string
 }
+
 export function useGrid({ store, query = {}, sort = [], columns, getSelected, filename }: useGridProps): [React.FunctionComponent, any[], (clearSelection?: boolean) => void, ICommandBarItemProps[]] {
 
     const constStore = useConst(store);
@@ -46,13 +47,104 @@ export function useGrid({ store, query = {}, sort = [], columns, getSelected, fi
     }, [], [query]);
 
     const copyButtons = React.useMemo((): ICommandBarItemProps[] => [
-        ...createCopyDownloadSelection(grid, selection, `${filename}.csv`)
-    ], [filename, grid, selection]);
+        ...createCopyDownloadSelection(constColumns, selection, `${filename}.csv`)
+    ], [constColumns, filename, selection]);
 
     return [Grid, selection, refreshTable, copyButtons];
 }
 
-// export function useMemoryGrid({ query = {}, sort = [], columns, getSelected, filename }: useGridProps): [React.FunctionComponent, any[], (clearSelection?: boolean) => void, ICommandBarItemProps[]] {
-//     const [Grid, selection, refreshTable, copyButtons] = useGrid(params);
-//     return [Grid, selection, refreshTable, copyButtons];
-// };
+interface Sorted {
+    column: string;
+    descending: boolean;
+}
+
+function columnsAdapter(columns, sorted: Sorted): IColumn[] {
+    const retVal: IColumn[] = [];
+    for (const key in columns) {
+        const column = columns[key];
+        if (column?.selectorType === undefined) {
+            retVal.push({
+                key,
+                name: column.label ?? key,
+                fieldName: column.field ?? key,
+                minWidth: column.width,
+                maxWidth: column.width,
+                isResizable: true,
+                isSorted: key == sorted.column,
+                isSortedDescending: key == sorted.column && sorted.descending,
+            } as IColumn);
+        }
+    }
+    return retVal;
+}
+
+export function useFluentGrid({ store, query = {}, sort = [], columns, getSelected, filename }: useGridProps): [React.FunctionComponent, any[], ICommandBarItemProps[]] {
+
+    const constQuery = useConst({ ...query });
+    const constColumns = useConst({ ...columns });
+    const [sorted, setSorted] = React.useState<Sorted>({ column: "", descending: false });
+    const [selection, setSelection] = React.useState([]);
+
+    const fluentColumns: IColumn[] = React.useMemo(() => {
+        return columnsAdapter(constColumns, sorted);
+    }, [constColumns, sorted]);
+
+    const onColumnClick = React.useCallback((event: React.MouseEvent<HTMLElement>, column: IColumn) => {
+        let sorted = column.isSorted;
+        let isSortedDescending: boolean = column.isSortedDescending;
+        if (!sorted) {
+            sorted = true;
+            isSortedDescending = false;
+        } else if (!isSortedDescending) {
+            isSortedDescending = true;
+        } else {
+            sorted = false;
+            isSortedDescending = false;
+        }
+        setSorted({
+            column: sorted ? column.key : "",
+            descending: sorted ? isSortedDescending : false
+        });
+    }, []);
+
+    const [items, setItems] = React.useState<any[]>([]);
+
+    React.useEffect(() => {
+        const sort = sorted.column ? [{ attribute: sorted.column, descending: sorted.descending }] : undefined;
+        store.query(constQuery, { sort }).then(items => {
+            setItems(items);
+        });
+    }, [constQuery, sorted.column, sorted.descending, store, store.dataVersion]);
+
+    const selectionHandler = useConst(new Selection({
+        onSelectionChanged: () => {
+            setSelection(selectionHandler.getSelection());
+        }
+    }));
+
+    const renderItemColumn = React.useCallback((item: any, index: number, column: IColumn) => {
+        if (constColumns[column.key].formatter) {
+            return <span style={{ display: "flex" }}>{constColumns[column.key].formatter(item[column.key], item)}</span>;
+        }
+        return <span>{item[column.key]}</span>;
+    }, [constColumns]);
+
+    const Grid = React.useMemo(() => () => <DetailsList
+        compact={true}
+        items={items}
+        columns={fluentColumns}
+        setKey="set"
+        layoutMode={DetailsListLayoutMode.justified}
+        onRenderItemColumn={renderItemColumn}
+        selection={selectionHandler}
+        selectionPreservedOnEmptyClick={true}
+        onItemInvoked={this._onItemInvoked}
+        onColumnHeaderClick={onColumnClick}
+    />, [fluentColumns, items, onColumnClick, renderItemColumn, selectionHandler]);
+
+    const copyButtons = React.useMemo((): ICommandBarItemProps[] => [
+        ...createCopyDownloadSelection(constColumns, selection, `${filename}.csv`)
+    ], [constColumns, filename, selection]);
+
+    return [Grid, selection, copyButtons];
+}

+ 14 - 6
esp/src/src/Memory.ts

@@ -2,7 +2,7 @@ import * as Deferred from "dojo/Deferred";
 import * as Observable from "dojo/store/Observable";
 import * as QueryResults from "dojo/store/util/QueryResults";
 import * as SimpleQueryEngine from "dojo/store/util/SimpleQueryEngine";
-import { alphanumSort } from "./Utility";
+import { alphanum } from "./Utility";
 
 export {
     Observable
@@ -36,13 +36,13 @@ export class BaseStore {
         return Promise.resolve([]);
     }
 
-    query(query, options) {
+    query(query, options: { start: number, count: number, sort: { attribute: string, descending: boolean } }): QueryResults<any> {
         const retVal = new Deferred();
         this.fetchData().then(response => {
             const data = this.queryEngine(query, options)(response);
             retVal.resolve(data);
         });
-        return QueryResults(retVal.then(response => response), {
+        return QueryResults(retVal, {
             totalLength: retVal.then(response => response.length)
         });
     }
@@ -92,7 +92,9 @@ export class Memory extends BaseStore {
         }
     }
 
+    dataVersion = 0;
     setData(data) {
+        this.dataVersion++;
         if (data.items) {
             this.idProperty = data.identifier || this.idProperty;
             data = this.data = data.items;
@@ -117,11 +119,17 @@ export class AlphaNumSortMemory extends Memory {
     }
 
     query(query, options) {
-        const retVal = super.query(query, options);
         if (options?.sort && options?.sort.length && this.alphanumSort[options.sort[0].attribute]) {
-            alphanumSort(retVal, options.sort[0].attribute, options.sort[0].descending);
+            const col = options.sort[0].attribute;
+            const reverse = options.sort[0].descending;
+            return super.query(query, {
+                ...options,
+                sort: function (l, r) {
+                    return alphanum(l[col], r[col]) * (reverse ? -1 : 1);
+                }
+            });
         }
-        return retVal;
+        return super.query(query, options);
     }
 }
 

+ 10 - 11
esp/src/src/Utility.ts

@@ -228,18 +228,17 @@ export function espSkew2NumberTests() {
     }, this);
 }
 
-export function formatAsDelim(grid, rows: any, delim = ",") {
-    const headers = grid.columns;
+export function formatAsDelim(columns, rows: any, delim = ",") {
     const container: string[] = [];
     const headerNames: string[] = [];
 
-    for (const key in headers) {
-        if (key !== headers[key].id && headers[key].selectorType !== "checkbox") {
-            if (!headers[key].label) {
-                const str = csvEncode(headers[key].field);
+    for (const key in columns) {
+        if (key !== columns[key].id && columns[key].selectorType !== "checkbox") {
+            if (!columns[key].label) {
+                const str = csvEncode(columns[key].field);
                 headerNames.push(str);
             } else {
-                const str = csvEncode(headers[key].label);
+                const str = csvEncode(columns[key].label);
                 headerNames.push(str);
             }
         }
@@ -248,10 +247,10 @@ export function formatAsDelim(grid, rows: any, delim = ",") {
 
     rows.forEach(row => {
         const cells: any[] = [];
-        for (const key in headers) {
-            if (key !== headers[key].id && headers[key].selectorType !== "checkbox") {
-                const cell = row[headers[key].field];
-                cells.push(csvEncode(cell));
+        for (const key in columns) {
+            if (key !== columns[key].id && columns[key].selectorType !== "checkbox") {
+                const cell = row[columns[key].field ?? key];
+                cells.push(csvEncode(cell ?? ""));
             }
         }
         container.push(cells.join(delim));