From 2fbf8926c461b9d94a77aba0c3fcb4fce3f7fecf Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Thu, 22 Mar 2018 17:23:49 +0200 Subject: [PATCH] gridstack: optimizations and bugfixes --- client/app/assets/less/inc/gridster.less | 29 -- client/app/assets/less/main.less | 2 - .../dashboards/gridstack/gridstack.js | 3 - .../components/dashboards/gridstack/index.js | 58 ++- client/app/config/dashboard-grid-options.js | 26 +- client/app/config/index.js | 2 - client/app/config/styles.js | 1 - client/app/pages/dashboards/dashboard.html | 3 +- client/app/pages/dashboards/dashboard.js | 3 +- .../dashboards/public-dashboard-page.html | 12 +- package-lock.json | 339 +++++++++++++++++- package.json | 8 +- webpack.config.js | 5 + 13 files changed, 407 insertions(+), 84 deletions(-) delete mode 100755 client/app/assets/less/inc/gridster.less diff --git a/client/app/assets/less/inc/gridster.less b/client/app/assets/less/inc/gridster.less deleted file mode 100755 index fbfc20b2387..00000000000 --- a/client/app/assets/less/inc/gridster.less +++ /dev/null @@ -1,29 +0,0 @@ -.gridster .preview-holder { - border: none !important; - border-radius: 0 !important; - background: rgba(0, 0, 0, 0.5) !important; -} - -.gridster li .heading { - border: #ddd; - background-color: #f5f5f5; - padding: 5px; -} - -li.widget { - /*background-color:grey;*/ - border-width: 1px; - border-style: solid; - border-color: grey; - opacity: 0.7; - cursor: move; - &:hover { - opacity: 1.0 !important; - - -webkit-transition: opacity .6s; - -moz-transition: opacity .6s; - -o-transition: opacity .6s; - -ms-transition: opacity .6s; - transition: opacity .6s; - } -} diff --git a/client/app/assets/less/main.less b/client/app/assets/less/main.less index c0dbe77a871..de139f3f86a 100644 --- a/client/app/assets/less/main.less +++ b/client/app/assets/less/main.less @@ -9,7 +9,6 @@ @import '~ui-select/dist/select.css'; @import '~angular-toastr/src/toastr'; @import '~angular-resizable/src/angular-resizable.css'; -@import '~angular-gridster/src/angular-gridster'; @import '~pace-progress/themes/blue/pace-theme-minimal.css'; @import '~material-design-iconic-font/dist/css/material-design-iconic-font.css'; @@ -51,7 +50,6 @@ @import 'inc/navbar'; @import 'inc/edit-in-place'; @import 'inc/growl'; -@import 'inc/gridster'; @import 'inc/flex'; @import 'inc/ace-editor'; @import 'inc/overlay'; diff --git a/client/app/components/dashboards/gridstack/gridstack.js b/client/app/components/dashboards/gridstack/gridstack.js index 8d3d9309413..3d2a879ed8a 100644 --- a/client/app/components/dashboards/gridstack/gridstack.js +++ b/client/app/components/dashboards/gridstack/gridstack.js @@ -5,9 +5,6 @@ import 'jquery-ui/ui/widgets/droppable'; import 'jquery-ui/ui/widgets/resizable'; import 'gridstack/dist/gridstack.css'; -window.$ = window.jQuery = $; -window._ = _; - // eslint-disable-next-line import/first import gridstack from 'gridstack'; diff --git a/client/app/components/dashboards/gridstack/index.js b/client/app/components/dashboards/gridstack/index.js index 2ece843ae5e..2f364153ecd 100644 --- a/client/app/components/dashboards/gridstack/index.js +++ b/client/app/components/dashboards/gridstack/index.js @@ -59,13 +59,14 @@ function computeAutoHeight($element, grid, node, minHeight, maxHeight) { return Math.min(Math.max(minHeight, resultHeight), maxHeight); } -function gridstack() { +function gridstack($parse, dashboardGridOptions) { return { restrict: 'A', replace: false, scope: { editing: '=', batchUpdate: '=', // set by directive - for using in wrapper components + isOneColumnMode: '=', }, controller() { this.$el = null; @@ -205,16 +206,22 @@ function gridstack() { }; }, link: ($scope, $element, $attr, controller) => { + const batchUpdateAssignable = _.isFunction($parse($attr.batchUpdate).assign); + const isOneColumnModeAssignable = _.isFunction($parse($attr.batchUpdate).assign); + + let enablePolling = true; + $element.addClass('grid-stack'); $element.gridstack({ auto: false, - verticalMargin: 15, - cellHeight: 35, // real row height will be `cellHeight` + `verticalMargin` - width: 6, // columns + verticalMargin: dashboardGridOptions.margins, + // real row height will be `cellHeight` + `verticalMargin` + cellHeight: dashboardGridOptions.rowHeight - dashboardGridOptions.margins, + width: dashboardGridOptions.columns, // columns height: 0, // max rows (0 for unlimited) animate: true, float: false, - minWidth: 800, + minWidth: dashboardGridOptions.mobileBreakPoint, resizable: { handles: 'e, se, s, sw, w', start: (event, ui) => { @@ -253,25 +260,56 @@ function gridstack() { }); controller.$el = $element; - $element.on('change', (event, nodes) => { - nodes = _.isArray(nodes) ? nodes : []; - console.log('+', nodes.length); - _.each(nodes, (node) => { + // `change` events sometimes fire too frequently (for example, + // on initial rendering when all widgets add themselves to grid, grid + // will fire `change` event will _all_ items available at that moment). + // Collect changed items, and then delegate event with some delay + let changedNodes = {}; + const triggerChange = _.debounce(() => { + _.each(changedNodes, (node) => { if (node.el) { $(node.el).trigger('gridstack.changed', node); } }); + changedNodes = {}; + }); + + $element.on('change', (event, nodes) => { + nodes = _.isArray(nodes) ? nodes : []; + _.each(nodes, (node) => { + changedNodes[node.id] = node; + }); + triggerChange(); }); $scope.$watch('editing', (value) => { controller.setEditing(!!value); }); - $scope.batchUpdate = controller.batchUpdateWidgets; + if (batchUpdateAssignable) { + $scope.batchUpdate = controller.batchUpdateWidgets; + } $scope.$on('$destroy', () => { + enablePolling = false; controller.$el = null; }); + + function updateOneColumnMode() { + const grid = controller.grid(); + if (grid) { + $scope.isOneColumnMode = $element.hasClass(grid.opts.oneColumnModeClass); + $scope.$applyAsync(); + } + + if (enablePolling) { + setTimeout(updateOneColumnMode, 150); + } + } + + if (isOneColumnModeAssignable) { + updateOneColumnMode(); + } }, }; } diff --git a/client/app/config/dashboard-grid-options.js b/client/app/config/dashboard-grid-options.js index fffbdabb898..f30c918dc18 100644 --- a/client/app/config/dashboard-grid-options.js +++ b/client/app/config/dashboard-grid-options.js @@ -1,33 +1,15 @@ const dashboardGridOptions = { - columns: 6, - pushing: true, - floating: true, - swapping: false, - width: 'auto', - colWidth: 'auto', - rowHeight: 50, - margins: [15, 15], - outerMargin: false, - sparse: false, - isMobile: false, + columns: 6, // grid columns count + rowHeight: 50, // grid row height (incl. bottom padding) + margins: 15, // widget margins mobileBreakPoint: 800, - mobileModeEnabled: true, - minColumns: 6, - minRows: 1, - maxRows: 1000, + // defaults for widgets defaultSizeX: 3, defaultSizeY: 3, minSizeX: 1, maxSizeX: 6, minSizeY: 1, maxSizeY: 1000, - resizable: { - enabled: false, - handles: ['n', 'e', 's', 'w', 'ne', 'se', 'sw', 'nw'], - }, - draggable: { - enabled: false, - }, }; export default function init(ngModule) { diff --git a/client/app/config/index.js b/client/app/config/index.js index 4f154b72af6..239e80b5105 100644 --- a/client/app/config/index.js +++ b/client/app/config/index.js @@ -17,7 +17,6 @@ import 'angular-moment'; import 'brace'; import 'angular-ui-ace'; import 'angular-resizable'; -import ngGridster from 'angular-gridster'; import { each, isFunction } from 'underscore'; import '@/lib/sortable'; @@ -52,7 +51,6 @@ const requirements = [ 'angularResizable', vsRepeat, 'ui.sortable', - ngGridster.name, ]; const ngModule = angular.module('app', requirements); diff --git a/client/app/config/styles.js b/client/app/config/styles.js index 468747588be..40dbd271312 100644 --- a/client/app/config/styles.js +++ b/client/app/config/styles.js @@ -3,7 +3,6 @@ import 'font-awesome/css/font-awesome.css'; import 'ui-select/dist/select.css'; import 'angular-toastr/dist/angular-toastr.css'; import 'angular-resizable/src/angular-resizable.css'; -import 'angular-gridster/dist/angular-gridster.css'; import 'pace-progress/themes/blue/pace-theme-minimal.css'; import '@/assets/css/superflat_redash.css'; diff --git a/client/app/pages/dashboards/dashboard.html b/client/app/pages/dashboards/dashboard.html index 68cc3eaa6f5..74e04a8e81e 100644 --- a/client/app/pages/dashboards/dashboard.html +++ b/client/app/pages/dashboards/dashboard.html @@ -85,7 +85,8 @@

-
{ this.extractGlobalParameters(); if (!this.layoutEditing) { - // We need to wait a bit for `angular-gridster` before it updates widgets, - // and only then save new layout + // We need to wait a bit while `angular` updates widgets, and only then save new layout $timeout(() => { const changedWidgets = getWidgetsWithChangedPositions(this.dashboard.widgets); saveDashboardLayout(changedWidgets); diff --git a/client/app/pages/dashboards/public-dashboard-page.html b/client/app/pages/dashboards/public-dashboard-page.html index 3eeb542748a..b35f0efa06b 100644 --- a/client/app/pages/dashboards/public-dashboard-page.html +++ b/client/app/pages/dashboards/public-dashboard-page.html @@ -6,10 +6,14 @@
-
-
-
- +
+
+
+
+ +
diff --git a/package-lock.json b/package-lock.json index 86816adc53b..c19d3c076f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -192,11 +192,6 @@ "resolved": "https://registry.npmjs.org/angular-base64-upload/-/angular-base64-upload-0.1.23.tgz", "integrity": "sha512-vRSY+7/pag2hEdTSB90LTvT5rU5XPxBNMA1WGz60pNSpChRUzf+h5FR9lObRcGg1WUOvlYinnvoPTD6Nktcx1g==" }, - "angular-gridster": { - "version": "0.13.14", - "resolved": "https://registry.npmjs.org/angular-gridster/-/angular-gridster-0.13.14.tgz", - "integrity": "sha1-er6/Y9fJ++xFOLnMpFfg2oBdQgQ=" - }, "angular-messages": { "version": "1.5.11", "resolved": "https://registry.npmjs.org/angular-messages/-/angular-messages-1.5.11.tgz", @@ -447,6 +442,12 @@ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1374,6 +1375,25 @@ "tweetnacl": "0.14.5" } }, + "bfj-node4": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/bfj-node4/-/bfj-node4-5.3.1.tgz", + "integrity": "sha512-SOmOsowQWfXc7ybFARsK3C4MCOWzERaOMV/Fl3Tgjs+5dJWyzo3oa127jL44eMbQiAN17J7SvAs2TRxEScTUmg==", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "check-types": "7.3.0", + "tryer": "1.0.0" + }, + "dependencies": { + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true + } + } + }, "big-rat": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/big-rat/-/big-rat-1.0.4.tgz", @@ -1929,6 +1949,12 @@ "strip-ansi": "0.1.1" } }, + "check-types": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.3.0.tgz", + "integrity": "sha1-Ro9XGkQ1wkJI9f0MsOjYfDw0Hn0=", + "dev": true + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -3148,6 +3174,12 @@ "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz", "integrity": "sha1-UfxaxoX4GWRp3wuQXpNLIK9bQCk=" }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, "duplexer2": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", @@ -3237,6 +3269,12 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "ejs": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", + "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=", + "dev": true + }, "electron-to-chromium": { "version": "1.3.24", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.24.tgz", @@ -4170,6 +4208,12 @@ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "dev": true }, + "filesize": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.0.tgz", + "integrity": "sha512-g5OWtoZWcPI56js1DFhIEqyG9tnu/7sG3foHwgS9KGYFMfsYguI3E+PRVCmtmE96VajQIEMRU2OhN+ME589Gdw==", + "dev": true + }, "fill-range": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", @@ -6833,6 +6877,24 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, + "gzip-size": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-4.1.0.tgz", + "integrity": "sha1-iuCWJX6r59acRb4rZ8RIEk/7UXw=", + "dev": true, + "requires": { + "duplexer": "0.1.1", + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "handle-thing": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", @@ -9581,6 +9643,12 @@ "mimic-fn": "1.1.0" } }, + "opener": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", + "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "dev": true + }, "opn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", @@ -12702,6 +12770,12 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "tryer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.0.tgz", + "integrity": "sha1-Antp+oIyJeVRys4+8DsR9qs3wdc=", + "dev": true + }, "tryit": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", @@ -13352,6 +13426,251 @@ } } }, + "webpack-bundle-analyzer": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.11.1.tgz", + "integrity": "sha512-VKUVkVMc6TWVXmF1OxsBXoiRjYiDRA4XT0KqtbLMDK+891VX7FCuklYwzldND8J2upUcHHnuXYNTP+4mSFi4Kg==", + "dev": true, + "requires": { + "acorn": "5.5.3", + "bfj-node4": "5.3.1", + "chalk": "2.3.2", + "commander": "2.15.1", + "ejs": "2.5.7", + "express": "4.16.3", + "filesize": "3.6.0", + "gzip-size": "4.1.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "opener": "1.4.3", + "ws": "4.1.0" + }, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", + "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "express": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "dev": true, + "requires": { + "accepts": "1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.3", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "1.4.0", + "type-is": "1.6.16", + "utils-merge": "1.0.1", + "vary": "1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.4.0", + "unpipe": "1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "ipaddr.js": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", + "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=", + "dev": true + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, + "proxy-addr": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", + "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", + "dev": true, + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.6.0" + } + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.4.0" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.2" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.18" + } + } + } + }, "webpack-dev-middleware": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz", @@ -13773,6 +14092,16 @@ "mkdirp": "0.5.1" } }, + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "dev": true, + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1" + } + }, "xml-char-classes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", diff --git a/package.json b/package.json index 328b37177a0..150003d627b 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,10 @@ "scripts": { "start": "webpack-dev-server", "dev": "REDASH_BACKEND=https://dev.redashapp.com npm start", - "build": "rm -rf ./client/dist/ && NODE_ENV=production node node_modules/.bin/webpack", - "watch": "webpack --watch --progress --colors -d" + "build": "rm -rf ./client/dist/ && NODE_ENV=production webpack", + "watch": "webpack --watch --progress --colors -d", + "analyze": "rm -rf ./client/dist/ && BUNDLE_ANALYZER=on webpack", + "analyze:build": "rm -rf ./client/dist/ && NODE_ENV=production BUNDLE_ANALYZER=on webpack" }, "repository": { "type": "git", @@ -26,7 +28,6 @@ "dependencies": { "angular": "~1.5.8", "angular-base64-upload": "^0.1.23", - "angular-gridster": "^0.13.14", "angular-messages": "~1.5.8", "angular-moment": "^1.1.0", "angular-resizable": "^1.2.0", @@ -89,6 +90,7 @@ "url-loader": "^0.5.9", "webpack": "^3.6.0", "webpack-build-notifier": "^0.1.16", + "webpack-bundle-analyzer": "^2.11.1", "webpack-dev-server": "^2.9.1", "webpack-manifest-plugin": "^1.3.2" } diff --git a/webpack.config.js b/webpack.config.js index ecf2b1dc641..6c21795162f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -8,6 +8,7 @@ const WebpackBuildNotifierPlugin = require('webpack-build-notifier'); const ManifestPlugin = require('webpack-manifest-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const LessPluginAutoPrefix = require('less-plugin-autoprefix'); +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const path = require('path'); const redashBackend = process.env.REDASH_BACKEND || 'http://localhost:5000'; @@ -204,4 +205,8 @@ if (process.env.NODE_ENV === 'production') { config.devtool = 'source-map'; } +if (process.env.BUNDLE_ANALYZER) { + config.plugins.push(new BundleAnalyzerPlugin()); +} + module.exports = config;