You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2017/03/02 11:30:49 UTC

[12/50] [abbrv] ignite git commit: IGNITE-4472 UI fix, minor fixes

IGNITE-4472 UI fix, minor fixes


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/79e1e536
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/79e1e536
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/79e1e536

Branch: refs/heads/ignite-4565-ddl
Commit: 79e1e536e5a6ee366da94f563355429635cbfdd2
Parents: 4923734
Author: Andrey Novikov <an...@gridgain.com>
Authored: Tue Feb 14 23:28:06 2017 +0700
Committer: Andrey Novikov <an...@gridgain.com>
Committed: Tue Feb 14 23:28:06 2017 +0700

----------------------------------------------------------------------
 .../web-console/backend/routes/activities.js    |   7 -
 .../web-console/backend/services/activities.js  |  27 +---
 .../backend/test/unit/ActivitiesService.test.js | 131 +++++++++++++++++++
 modules/web-console/frontend/app/app.config.js  |   4 +
 .../activities-user-dialog.controller.js        |  39 +-----
 .../activities-user-dialog.jade                 |   2 +-
 .../components/activities-user-dialog/index.js  |   5 +-
 .../form-field-datepicker.jade                  |   4 +-
 .../list-of-registered-users.column-defs.js     |  26 ++--
 .../list-of-registered-users.controller.js      |  32 +++--
 .../app/core/activities/Activities.data.js      |   5 -
 modules/web-console/frontend/app/data/i18n.js   |   1 +
 .../ui-ace-pom/ui-ace-pom.controller.js         |   4 +-
 .../frontend/app/modules/agent/agent.module.js  |  15 ---
 .../modules/configuration/Version.service.js    |  13 +-
 .../configuration/generator/Maven.service.js    |  10 +-
 .../configuration/summary/summary.worker.js     |   6 +-
 modules/web-console/frontend/package.json       |  14 +-
 .../frontend/public/stylesheets/style.scss      |   8 --
 .../frontend/public/stylesheets/variables.scss  |   1 -
 .../views/templates/agent-download.jade         |   6 +-
 21 files changed, 206 insertions(+), 154 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/backend/routes/activities.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/activities.js b/modules/web-console/backend/routes/activities.js
index 08c27cf..ad0e469 100644
--- a/modules/web-console/backend/routes/activities.js
+++ b/modules/web-console/backend/routes/activities.js
@@ -33,13 +33,6 @@ module.exports.factory = function(express, activitiesService) {
     return new Promise((factoryResolve) => {
         const router = new express.Router();
 
-        // Get user activities.
-        router.get('/user/:userId', (req, res) => {
-            activitiesService.listByUser(req.params.userId, req.query)
-                .then(res.api.ok)
-                .catch(res.api.error);
-        });
-
         // Post user activities to page.
         router.post('/page', (req, res) => {
             activitiesService.merge(req.user._id, req.body)

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/backend/services/activities.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/activities.js b/modules/web-console/backend/services/activities.js
index 7f3a777..124c775 100644
--- a/modules/web-console/backend/services/activities.js
+++ b/modules/web-console/backend/services/activities.js
@@ -35,10 +35,12 @@ module.exports.factory = (_, mongo) => {
          * Update page activities.
          *
          * @param {String} owner - User ID
-         * @param {Object} page - The page
+         * @param {String} action - Action string presentation.
+         * @param {String} group - Action group string presentation.
+         * @param {Date} [date] - Optional date to save in activity.
          * @returns {Promise.<mongo.ObjectId>} that resolve activity
          */
-        static merge(owner, {action, group}) {
+        static merge(owner, {action, group}, date = new Date()) {
             mongo.Account.findById(owner)
                 .then((user) => {
                     user.lastActivity = new Date();
@@ -46,8 +48,6 @@ module.exports.factory = (_, mongo) => {
                     return user.save();
                 });
 
-            const date = new Date();
-
             date.setDate(1);
             date.setHours(0, 0, 0, 0);
 
@@ -63,25 +63,6 @@ module.exports.factory = (_, mongo) => {
                 });
         }
 
-        /**
-         * Get user activities
-         * @param {String} owner - User ID
-         * @returns {Promise.<mongo.ObjectId>} that resolve activities
-         */
-        static listByUser(owner, {startDate, endDate}) {
-            const $match = {owner};
-
-            if (startDate)
-                $match.date = {$gte: new Date(startDate)};
-
-            if (endDate) {
-                $match.date = $match.date || {};
-                $match.date.$lt = new Date(endDate);
-            }
-
-            return mongo.Activities.find($match);
-        }
-
         static total({startDate, endDate}) {
             const $match = {};
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/backend/test/unit/ActivitiesService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/ActivitiesService.test.js b/modules/web-console/backend/test/unit/ActivitiesService.test.js
new file mode 100644
index 0000000..40088bf
--- /dev/null
+++ b/modules/web-console/backend/test/unit/ActivitiesService.test.js
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+const assert = require('chai').assert;
+const injector = require('../injector');
+const testAccounts = require('../data/accounts.json');
+
+let activitiesService;
+let mongo;
+let db;
+
+const owner = testAccounts[0]._id;
+const group = 'test';
+const action1 = '/test/activity1';
+const action2 = '/test/activity2';
+
+suite('ActivitiesServiceTestsSuite', () => {
+    suiteSetup(() => {
+        return Promise.all([
+            injector('services/activities'),
+            injector('mongo'),
+            injector('dbHelper')
+        ])
+            .then(([_activitiesService, _mongo, _db]) => {
+                mongo = _mongo;
+                activitiesService = _activitiesService;
+                db = _db;
+            });
+    });
+
+    setup(() => db.init());
+
+    test('Activities creation and update', (done) => {
+        activitiesService.merge(owner, { group, action: action1 })
+            .then((activity) => {
+                assert.isNotNull(activity);
+                assert.equal(activity.amount, 1);
+
+                return mongo.Activities.findById(activity._id);
+            })
+            .then((activityDoc) => {
+                assert.isNotNull(activityDoc);
+                assert.equal(activityDoc.amount, 1);
+            })
+            .then(() => activitiesService.merge(owner, { group, action: action1 }))
+            .then((activity) => {
+                assert.isNotNull(activity);
+                assert.equal(activity.amount, 2);
+
+                return mongo.Activities.findById(activity._id);
+            })
+            .then((activityDoc) => {
+                assert.isNotNull(activityDoc);
+                assert.equal(activityDoc.amount, 2);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Activities total and detail information', (done) => {
+        const startDate = new Date();
+
+        startDate.setDate(1);
+        startDate.setHours(0, 0, 0, 0);
+
+        const endDate = new Date(startDate);
+        endDate.setMonth(endDate.getMonth() + 1);
+
+        Promise.all([
+            activitiesService.merge(owner, {group, action: action1}),
+            activitiesService.merge(owner, {group, action: action2})
+        ])
+            .then(() => activitiesService.total(owner, {startDate, endDate}))
+            .then((activities) =>
+                assert.equal(activities[owner].test, 2)
+            )
+            .then(() => activitiesService.detail(owner, {startDate, endDate}))
+            .then((activities) =>
+                assert.deepEqual(activities[owner], {
+                    '/test/activity2': 1, '/test/activity1': 1
+                })
+            )
+            .then(done)
+            .catch(done);
+    });
+
+    test('Activities periods', (done) => {
+        const startDate = new Date();
+
+        startDate.setDate(1);
+        startDate.setHours(0, 0, 0, 0);
+
+        const nextMonth = (baseDate) => {
+            const date = new Date(baseDate);
+
+            date.setMonth(date.getMonth() + 1);
+
+            return date;
+        };
+
+        const borderDate = nextMonth(startDate);
+        const endDate = nextMonth(borderDate);
+
+        activitiesService.merge(owner, { group, action: action1 })
+            .then(() => activitiesService.merge(owner, { group, action: action1 }, borderDate))
+            .then(() => activitiesService.total({ startDate, endDate: borderDate }))
+            .then((activities) =>
+                assert.equal(activities[owner].test, 1)
+            )
+            .then(() => activitiesService.total({ startDate: borderDate, endDate }))
+            .then((activities) =>
+                assert.equal(activities[owner].test, 1)
+            )
+            .then(done)
+            .catch(done);
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/app.config.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.config.js b/modules/web-console/frontend/app/app.config.js
index 0e85711..39d761f 100644
--- a/modules/web-console/frontend/app/app.config.js
+++ b/modules/web-console/frontend/app/app.config.js
@@ -103,3 +103,7 @@ igniteConsoleCfg.config(['$datepickerProvider', ($datepickerProvider) => {
         iconRight: 'icon-datepicker-right'
     });
 }]);
+
+igniteConsoleCfg.config(['$translateProvider', ($translateProvider) => {
+    $translateProvider.useSanitizeValueStrategy('sanitize');
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.controller.js b/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.controller.js
index 46853b2..078f725 100644
--- a/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.controller.js
+++ b/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.controller.js
@@ -15,46 +15,13 @@
  * limitations under the License.
  */
 
-const COLUMNS_DEFS = [
-    {displayName: 'Action', field: 'action', minWidth: 65 },
-    {displayName: 'Description', field: 'title', minWidth: 65 },
-    {displayName: 'Visited', field: 'amount', minWidth: 65 }
-];
-
 export default class ActivitiesCtrl {
-    static $inject = ['$state', 'user', 'params', 'IgniteActivitiesData'];
+    static $inject = ['user'];
 
-    constructor($state, user, params, ActivitiesData) {
+    constructor(user) {
         const $ctrl = this;
-        const userId = user._id;
 
         $ctrl.user = user;
-
-        $ctrl.gridOptions = {
-            data: [],
-            columnVirtualizationThreshold: 30,
-            columnDefs: COLUMNS_DEFS,
-            categories: [
-                {name: 'Action', visible: true, selectable: true},
-                {name: 'Description', visible: true, selectable: true},
-                {name: 'Visited', visible: true, selectable: true}
-            ],
-            enableRowSelection: false,
-            enableRowHeaderSelection: false,
-            enableColumnMenus: false,
-            multiSelect: false,
-            modifierKeysToMultiSelect: true,
-            noUnselect: true,
-            flatEntityAccess: true,
-            fastWatch: true,
-            onRegisterApi: (api) => {
-                $ctrl.gridApi = api;
-            }
-        };
-
-        ActivitiesData.listByUser(userId, params)
-            .then((data) => {
-                $ctrl.data = data;
-            });
+        $ctrl.data = _.map(user.activitiesDetail, (amount, action) => ({ action, amount }));
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.jade b/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.jade
index 2c55ebd..074851c 100644
--- a/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.jade
+++ b/modules/web-console/frontend/app/components/activities-user-dialog/activities-user-dialog.jade
@@ -24,7 +24,7 @@
             .modal-body.modal-body-with-scroll(id='activities-user-dialog')
                 table.table.table-striped.table-bordered.table-hover(scrollable-container='#activities-user-dialog' st-table='displayedRows' st-safe-src='ctrl.data')
                     thead
-                        th.text-center(st-sort='title') Description
+                        th.text-center(st-sort='action | translate') Description
                         th.text-center(st-sort='action') Action
                         th.text-center(st-sort='amount') Visited
                     tbody

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/components/activities-user-dialog/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/activities-user-dialog/index.js b/modules/web-console/frontend/app/components/activities-user-dialog/index.js
index 03d3585..dca6ba9 100644
--- a/modules/web-console/frontend/app/components/activities-user-dialog/index.js
+++ b/modules/web-console/frontend/app/components/activities-user-dialog/index.js
@@ -18,13 +18,12 @@
  import controller from './activities-user-dialog.controller';
  import templateUrl from './activities-user-dialog.jade';
 
- export default ['$modal', ($modal) => ({ show = true, user, params }) => {
+ export default ['$modal', ($modal) => ({ show = true, user }) => {
      const ActivitiesUserDialog = $modal({
          templateUrl,
          show,
          resolve: {
-             user: () => user,
-             params: () => params
+             user: () => user
          },
          placement: 'center',
          controller,

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/components/form-field-datepicker/form-field-datepicker.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/form-field-datepicker/form-field-datepicker.jade b/modules/web-console/frontend/app/components/form-field-datepicker/form-field-datepicker.jade
index 6792977..2578cf4 100644
--- a/modules/web-console/frontend/app/components/form-field-datepicker/form-field-datepicker.jade
+++ b/modules/web-console/frontend/app/components/form-field-datepicker/form-field-datepicker.jade
@@ -28,8 +28,8 @@ mixin ignite-form-field-datepicker(label, model, name, disabled, required, place
             data-ng-disabled=disabled && '#{disabled}'
 
             bs-datepicker
-            data-date-format='MMM yyyy' 
-            data-start-view='1' 
+            data-date-format='MMM yyyy'
+            data-start-view='1'
             data-min-view='1' 
             data-max-date='today'
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
index 61e1bd8..4dc4655 100644
--- a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
+++ b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
@@ -49,7 +49,7 @@ const ACTIONS_TEMPLATE = `
 const EMAIL_TEMPLATE = '<div class="ui-grid-cell-contents"><a ng-href="mailto:{{ COL_FIELD }}">{{ COL_FIELD }}</a></div>';
 
 export default [
-    {displayName: 'Actions', categoryDisplayName: 'Actions', cellTemplate: ACTIONS_TEMPLATE, field: 'test', minWidth: 70, width: 70, enableFiltering: false, enableSorting: false, pinnedLeft: true},
+    {displayName: 'Actions', categoryDisplayName: 'Actions', cellTemplate: ACTIONS_TEMPLATE, field: 'actions', minWidth: 70, width: 70, enableFiltering: false, enableSorting: false, pinnedLeft: true},
     {displayName: 'User', categoryDisplayName: 'User', field: 'userName', cellTemplate: USER_TEMPLATE, minWidth: 160, enableFiltering: true, filter: { placeholder: 'Filter by name...' }, pinnedLeft: true},
     {displayName: 'Email', categoryDisplayName: 'Email', field: 'email', cellTemplate: EMAIL_TEMPLATE, minWidth: 160, enableFiltering: true, filter: { placeholder: 'Filter by email...' }},
     {displayName: 'Company', categoryDisplayName: 'Company', field: 'company', minWidth: 160, enableFiltering: true},
@@ -62,19 +62,19 @@ export default [
     {displayName: 'Caches count', categoryDisplayName: 'Configurations', headerCellTemplate: CACHE_HEADER_TEMPLATE, field: 'counters.caches', type: 'number', headerTooltip: 'Caches count', minWidth: 50, width: 50, enableFiltering: false, visible: false},
     {displayName: 'IGFS count', categoryDisplayName: 'Configurations', headerCellTemplate: IGFS_HEADER_TEMPLATE, field: 'counters.igfs', type: 'number', headerTooltip: 'IGFS count', minWidth: 50, width: 50, enableFiltering: false, visible: false},
     // Activities Total
-    {displayName: 'Cfg', categoryDisplayName: 'Total activities', field: 'activitiesTotal["configuration"] || 0', type: 'number', headerTooltip: 'Configuration', minWidth: 50, width: 50, enableFiltering: false},
-    {displayName: 'Qry', categoryDisplayName: 'Total activities', field: 'activitiesTotal["queries"] || 0', type: 'number', headerTooltip: 'Queries', minWidth: 50, width: 50, enableFiltering: false},
-    {displayName: 'Demo', categoryDisplayName: 'Total activities', field: 'activitiesTotal["demo"] || 0', type: 'number', headerTooltip: 'Demo', minWidth: 50, width: 50, enableFiltering: false},
-    {displayName: 'AD', categoryDisplayName: 'Total activities', field: 'activitiesDetail["/agent/download"] || 0', type: 'number', headerTooltip: 'Agent Download', minWidth: 50, width: 50, enableFiltering: false},
-    {displayName: 'AS', categoryDisplayName: 'Total activities', field: 'activitiesDetail["/agent/start"] || 0', type: 'number', headerTooltip: 'Agent Start', minWidth: 50, width: 50, enableFiltering: false},
+    {displayName: 'Cfg', categoryDisplayName: 'Total activities', field: 'activitiesTotal["configuration"] || 0', type: 'number', headerTooltip: 'Total count of configuration usages', minWidth: 50, width: 50, enableFiltering: false},
+    {displayName: 'Qry', categoryDisplayName: 'Total activities', field: 'activitiesTotal["queries"] || 0', type: 'number', headerTooltip: 'Total count of queries usages', minWidth: 50, width: 50, enableFiltering: false},
+    {displayName: 'Demo', categoryDisplayName: 'Total activities', field: 'activitiesTotal["demo"] || 0', type: 'number', headerTooltip: 'Total count of demo startup', minWidth: 50, width: 50, enableFiltering: false},
+    {displayName: 'Dnld', categoryDisplayName: 'Total activities', field: 'activitiesDetail["/agent/download"] || 0', type: 'number', headerTooltip: 'Total count of agent downloads', minWidth: 50, width: 50, enableFiltering: false},
+    {displayName: 'Str', categoryDisplayName: 'Total activities', field: 'activitiesDetail["/agent/start"] || 0', type: 'number', headerTooltip: 'Total count of agent startup', minWidth: 50, width: 50, enableFiltering: false},
     // Activities Configuration
-    {displayName: 'Clusters', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/clusters"] || 0', type: 'number', headerTooltip: 'Configuration Clusters', minWidth: 50, width: 80, enableFiltering: false, visible: false},
-    {displayName: 'Model', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/domains"] || 0', type: 'number', headerTooltip: 'Configuration Model', minWidth: 50, width: 80, enableFiltering: false, visible: false},
-    {displayName: 'Caches', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/caches"] || 0', type: 'number', headerTooltip: 'Configuration Caches', minWidth: 50, width: 80, enableFiltering: false, visible: false},
+    {displayName: 'Clusters', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/clusters"] || 0', type: 'number', headerTooltip: 'Configuration clusters', minWidth: 50, width: 80, enableFiltering: false, visible: false},
+    {displayName: 'Model', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/domains"] || 0', type: 'number', headerTooltip: 'Configuration model', minWidth: 50, width: 80, enableFiltering: false, visible: false},
+    {displayName: 'Caches', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/caches"] || 0', type: 'number', headerTooltip: 'Configuration caches', minWidth: 50, width: 80, enableFiltering: false, visible: false},
     {displayName: 'IGFS', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/igfs"] || 0', type: 'number', headerTooltip: 'Configuration IGFS', minWidth: 50, width: 80, enableFiltering: false, visible: false},
-    {displayName: 'Summary', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/summary"] || 0', type: 'number', headerTooltip: 'Configuration Summary', minWidth: 50, width: 80, enableFiltering: false, visible: false},
+    {displayName: 'Summary', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/summary"] || 0', type: 'number', headerTooltip: 'Configuration summary', minWidth: 50, width: 80, enableFiltering: false, visible: false},
     // Activities Queries
-    {displayName: 'Execute', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/execute"] || 0', type: 'number', headerTooltip: 'Query execute', minWidth: 50, width: 80, enableFiltering: false, visible: false},
-    {displayName: 'Explain', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/explain"] || 0', type: 'number', headerTooltip: 'Query explain', minWidth: 50, width: 80, enableFiltering: false, visible: false},
-    {displayName: 'Scan', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/scan"] || 0', type: 'number', headerTooltip: 'Scan', minWidth: 50, width: 80, enableFiltering: false, visible: false}
+    {displayName: 'Execute', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/execute"] || 0', type: 'number', headerTooltip: 'Query executions', minWidth: 50, width: 80, enableFiltering: false, visible: false},
+    {displayName: 'Explain', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/explain"] || 0', type: 'number', headerTooltip: 'Query explain executions', minWidth: 50, width: 80, enableFiltering: false, visible: false},
+    {displayName: 'Scan', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/scan"] || 0', type: 'number', headerTooltip: 'Scan query executions', minWidth: 50, width: 80, enableFiltering: false, visible: false}
 ];

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
index 19f7921..1f2a348 100644
--- a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
+++ b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.controller.js
@@ -20,15 +20,26 @@ import headerTemplate from 'app/components/ui-grid-header/ui-grid-header.jade';
 import columnDefs from './list-of-registered-users.column-defs';
 import categories from './list-of-registered-users.categories';
 
+const rowTemplate = `<div
+  ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.uid"
+  ng-mouseover="grid.api.selection.selectRow(row.entity);"
+  ui-grid-one-bind-id-grid="rowRenderIndex + '-' + col.uid + '-cell'"
+  class="ui-grid-cell"
+  ng-class="{ 'ui-grid-row-header-cell': col.isRowHeader }"
+  role="{{col.isRowHeader ? 'rowheader' : 'gridcell'}}"
+  ui-grid-cell/>`;
+
 export default class IgniteListOfRegisteredUsersCtrl {
-    static $inject = ['$scope', '$state', '$templateCache', 'User', 'uiGridConstants', 'IgniteAdminData', 'IgniteNotebookData', 'IgniteConfirm', 'IgniteActivitiesUserDialog'];
+    static $inject = ['$scope', '$state', '$filter', '$templateCache', 'User', 'uiGridConstants', 'IgniteAdminData', 'IgniteNotebookData', 'IgniteConfirm', 'IgniteActivitiesUserDialog'];
 
-    constructor($scope, $state, $templateCache, User, uiGridConstants, AdminData, NotebookData, Confirm, ActivitiesUserDialog) {
+    constructor($scope, $state, $filter, $templateCache, User, uiGridConstants, AdminData, NotebookData, Confirm, ActivitiesUserDialog) {
         const $ctrl = this;
 
         const companySelectOptions = [];
         const countrySelectOptions = [];
 
+        const dtFilter = $filter('date');
+
         $ctrl.params = {
             startDate: new Date()
         };
@@ -82,7 +93,7 @@ export default class IgniteListOfRegisteredUsersCtrl {
         };
 
         const showActivities = (user) => {
-            return new ActivitiesUserDialog({ user, params: $ctrl.params });
+            return new ActivitiesUserDialog({ user });
         };
 
         $ctrl.gridOptions = {
@@ -91,14 +102,17 @@ export default class IgniteListOfRegisteredUsersCtrl {
             columnDefs,
             categories,
             headerTemplate: $templateCache.get(headerTemplate),
+            rowTemplate,
             enableFiltering: true,
-            enableRowSelection: false,
+            enableRowSelection: true,
             enableRowHeaderSelection: false,
             enableColumnMenus: false,
             multiSelect: false,
             modifierKeysToMultiSelect: true,
             noUnselect: true,
             fastWatch: true,
+            exporterSuppressColumns: ['actions'],
+            exporterCsvColumnSeparator: ';',
             onRegisterApi: (api) => {
                 $ctrl.gridApi = api;
 
@@ -139,14 +153,14 @@ export default class IgniteListOfRegisteredUsersCtrl {
                 .then((data) => $ctrl.adjustHeight(data.length));
         };
 
-        $scope.$watch(() => $ctrl.params.startDate, () => {
-            const endDate = new Date($ctrl.params.startDate);
+        $scope.$watch(() => $ctrl.params.startDate, (dt) => {
+            $ctrl.gridOptions.exporterCsvFilename = `web_console_users_${dtFilter(dt, 'yyyy_MM')}.csv`;
 
-            endDate.setMonth(endDate.getMonth() + 1);
+            const endDate = new Date(dt);
 
-            $ctrl.params.endDate = endDate;
+            endDate.setMonth(endDate.getMonth() + 1);
 
-            reloadUsers($ctrl.params);
+            reloadUsers({startDate: dtFilter(dt, 'yyyy-MM-dd'), endDate: dtFilter(endDate, 'yyyy-MM-dd')});
         });
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/core/activities/Activities.data.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/core/activities/Activities.data.js b/modules/web-console/frontend/app/core/activities/Activities.data.js
index 8a67a97..8d9447c 100644
--- a/modules/web-console/frontend/app/core/activities/Activities.data.js
+++ b/modules/web-console/frontend/app/core/activities/Activities.data.js
@@ -31,9 +31,4 @@ export default class ActivitiesData {
 
         return this.$http.post('/api/v1/activities/page', { group, action });
     }
-
-    listByUser(userId, params) {
-        return this.$http.get(`/api/v1/activities/user/${userId}`, { params })
-            .then(({ data }) => data);
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/data/i18n.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/i18n.js b/modules/web-console/frontend/app/data/i18n.js
index bc8c700..3385f60 100644
--- a/modules/web-console/frontend/app/data/i18n.js
+++ b/modules/web-console/frontend/app/data/i18n.js
@@ -23,6 +23,7 @@ export default {
     '/configuration/domains': 'Configure domain model',
     '/configuration/igfs': 'Configure IGFS',
     '/configuration/summary': 'Configurations summary',
+    '/configuration/download': 'Download project',
     '/demo/resume': 'Demo resume',
     '/demo/reset': 'Demo reset',
     '/queries/execute': 'Query execute',

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
index 477cf20..0ae1269 100644
--- a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
+++ b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-export default ['$scope', 'IgniteMavenGenerator', 'IgniteVersion', function($scope, maven, Version) {
+export default ['$scope', 'IgniteMavenGenerator', function($scope, maven) {
     const ctrl = this;
 
     // Watchers definition.
@@ -25,7 +25,7 @@ export default ['$scope', 'IgniteMavenGenerator', 'IgniteVersion', function($sco
         if (!value)
             return;
 
-        ctrl.data = maven.generate($scope.cluster, Version.productVersion().ignite).asString();
+        ctrl.data = maven.generate($scope.cluster);
     };
 
     // Setup watchers.

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/modules/agent/agent.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/agent/agent.module.js b/modules/web-console/frontend/app/modules/agent/agent.module.js
index d6fc863..7ac39d1 100644
--- a/modules/web-console/frontend/app/modules/agent/agent.module.js
+++ b/modules/web-console/frontend/app/modules/agent/agent.module.js
@@ -62,21 +62,6 @@ class IgniteAgentMonitor {
                 this._scope.$$postDigest(() => $state.go(this._scope.backState));
         };
 
-        this._scope.downloadAgent = () => {
-            const lnk = document.createElement('a');
-
-            lnk.setAttribute('href', '/api/v1/agent/download/zip');
-            lnk.setAttribute('target', '_self');
-            lnk.setAttribute('download', null);
-            lnk.style.display = 'none';
-
-            document.body.appendChild(lnk);
-
-            lnk.click();
-
-            document.body.removeChild(lnk);
-        };
-
         this._scope.hasAgents = null;
         this._scope.showModal = false;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/modules/configuration/Version.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/Version.service.js b/modules/web-console/frontend/app/modules/configuration/Version.service.js
index f0e9c4c..746b1ed 100644
--- a/modules/web-console/frontend/app/modules/configuration/Version.service.js
+++ b/modules/web-console/frontend/app/modules/configuration/Version.service.js
@@ -23,6 +23,9 @@ const VERSION_MATCHER = /(\d+)\.(\d+)\.(\d+)([-.]([^0123456789][^-]+)(-SNAPSHOT)
 const numberComparator = (a, b) => a > b ? 1 : a < b ? -1 : 0;
 
 export default class IgniteVersion {
+    /** Current product version. */
+    static ignite = '1.8.0';
+
     /**
      * Tries to parse product version from it's string representation.
      *
@@ -74,16 +77,6 @@ export default class IgniteVersion {
     }
 
     /**
-     * Return current product version.
-     * @returns {{ignite: string}}
-     */
-    productVersion() {
-        return {
-            ignite: '1.8.0'
-        };
-    }
-
-    /**
      * Check if node version is newer or same
      * @param {String} nodeVer
      * @param {String} sinceVer

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/modules/configuration/generator/Maven.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/Maven.service.js b/modules/web-console/frontend/app/modules/configuration/generator/Maven.service.js
index 2e01761..23a9c4e 100644
--- a/modules/web-console/frontend/app/modules/configuration/generator/Maven.service.js
+++ b/modules/web-console/frontend/app/modules/configuration/generator/Maven.service.js
@@ -16,6 +16,7 @@
  */
 
 import StringBuilder from './StringBuilder';
+import IgniteVersion from 'app/modules/configuration/Version.service';
 
 // Java built-in class names.
 import POM_DEPENDENCIES from 'app/data/pom-dependencies.json';
@@ -142,11 +143,10 @@ export default class IgniteMavenGenerator {
      * Generate pom.xml.
      *
      * @param cluster Cluster  to take info about dependencies.
-     * @param version Ignite version for Ignite dependencies.
-     * @param sb Resulting output with generated pom.
+     * @param version Version for Ignite dependencies.
      * @returns {string} Generated content.
      */
-    generate(cluster, version, sb = new StringBuilder()) {
+    generate(cluster, version = IgniteVersion.ignite) {
         const caches = cluster.caches;
         const deps = [];
         const storeDeps = [];
@@ -162,6 +162,8 @@ export default class IgniteMavenGenerator {
                 this.addDependency(deps, 'org.apache.ignite', 'ignite-extdata-p2p', version);
         });
 
+        const sb = new StringBuilder();
+
         sb.append('<?xml version="1.0" encoding="UTF-8"?>');
 
         sb.emptyLine();
@@ -229,6 +231,6 @@ export default class IgniteMavenGenerator {
 
         this.build(sb, cluster, excludeGroupIds);
 
-        return sb;
+        return sb.asString();
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/app/modules/states/configuration/summary/summary.worker.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.worker.js b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.worker.js
index 6b24001..070b6ce 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.worker.js
+++ b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.worker.js
@@ -17,8 +17,6 @@
 
 import JSZip from 'jszip';
 
-import IgniteVersion from 'app/modules/configuration/Version.service';
-
 import MavenGenerator from 'app/modules/configuration/generator/Maven.service';
 import DockerGenerator from 'app/modules/configuration/generator/Docker.service';
 import ReadmeGenerator from 'app/modules/configuration/generator/Readme.service';
@@ -28,8 +26,6 @@ import ConfigurationGenerator from 'app/modules/configuration/generator/Configur
 import JavaTransformer from 'app/modules/configuration/generator/JavaTransformer.service';
 import SpringTransformer from 'app/modules/configuration/generator/SpringTransformer.service';
 
-const Version = new IgniteVersion();
-
 const maven = new MavenGenerator();
 const docker = new DockerGenerator();
 const readme = new ReadmeGenerator();
@@ -100,7 +96,7 @@ onmessage = function(e) {
     zip.file(`${startupPath}/ClientNodeCodeStartup.java`, java.nodeStartup(cluster, 'startup.ClientNodeCodeStartup',
         'ClientConfigurationFactory.createConfiguration()', 'config.ClientConfigurationFactory', clientNearCaches));
 
-    zip.file('pom.xml', maven.generate(cluster, Version.productVersion().ignite).asString());
+    zip.file('pom.xml', maven.generate(cluster));
 
     zip.file('README.txt', readme.generate());
     zip.file('jdbc-drivers/README.txt', readme.generateJDBC());

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/package.json b/modules/web-console/frontend/package.json
index 0fde6d4..2d12655 100644
--- a/modules/web-console/frontend/package.json
+++ b/modules/web-console/frontend/package.json
@@ -35,7 +35,7 @@
     "angular-aria": "1.5.11",
     "angular-cookies": "1.5.11",
     "angular-drag-and-drop-lists": "1.4.0",
-    "angular-gridster": "0.13.4",
+    "angular-gridster": "0.13.14",
     "angular-motion": "0.4.4",
     "angular-nvd3": "1.0.9",
     "angular-retina": "0.4.0",
@@ -66,16 +66,16 @@
   "devDependencies": {
     "assets-webpack-plugin": "3.5.1",
     "autoprefixer-core": "6.0.1",
-    "babel-core": "6.23.1",
-    "babel-eslint": "7.1.1",
+    "babel-core": "6.20.0",
+    "babel-eslint": "7.0.0",
     "babel-loader": "6.2.10",
     "babel-plugin-add-module-exports": "0.2.1",
     "babel-plugin-transform-builtin-extend": "1.1.2",
-    "babel-plugin-transform-runtime": "6.23.0",
-    "babel-polyfill": "6.23.0",
+    "babel-plugin-transform-runtime": "6.15.0",
+    "babel-polyfill": "6.20.0",
     "babel-preset-angular": "6.0.15",
-    "babel-preset-es2015": "6.22.0",
-    "babel-runtime": "6.22.0",
+    "babel-preset-es2015": "6.18.0",
+    "babel-runtime": "6.20.0",
     "chai": "3.5.0",
     "cross-env": "1.0.8",
     "css-loader": "0.26.1",

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/public/stylesheets/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/style.scss b/modules/web-console/frontend/public/stylesheets/style.scss
index 67cfed1..ab7e3dd 100644
--- a/modules/web-console/frontend/public/stylesheets/style.scss
+++ b/modules/web-console/frontend/public/stylesheets/style.scss
@@ -2331,14 +2331,6 @@ html,body,.splash-screen {
     .ui-grid-cell-contents > i {
         line-height: $line-height-base;
     }
-
-    .ui-grid-row:nth-child(odd):hover .ui-grid-cell {
-        background: $ignite-row-hover;
-    }
-    
-    .ui-grid-row:nth-child(even):hover .ui-grid-cell {
-        background: $ignite-row-hover;
-    }
 }
 
 .datepicker.dropdown-menu {

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/public/stylesheets/variables.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/variables.scss b/modules/web-console/frontend/public/stylesheets/variables.scss
index e30bbdd..8500eac 100644
--- a/modules/web-console/frontend/public/stylesheets/variables.scss
+++ b/modules/web-console/frontend/public/stylesheets/variables.scss
@@ -26,4 +26,3 @@ $ignite-border-bottom-color: $brand-primary;
 $ignite-background-color: #fff;
 $ignite-header-color: #555;
 $ignite-invalid-color: $brand-primary;
-$ignite-row-hover: #c9dde1;

http://git-wip-us.apache.org/repos/asf/ignite/blob/79e1e536/modules/web-console/frontend/views/templates/agent-download.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/agent-download.jade b/modules/web-console/frontend/views/templates/agent-download.jade
index f57bf1d..f5a6ba0 100644
--- a/modules/web-console/frontend/views/templates/agent-download.jade
+++ b/modules/web-console/frontend/views/templates/agent-download.jade
@@ -23,10 +23,10 @@
                     span(ng-if='!hasAgents') Connection to Ignite Web Agent is not established
                     span(ng-if='hasAgents') Connection to Ignite Node is not established
             .agent-download(ng-if='!hasAgents')
-                p Please download and run #[a(href='javascript:void(0)' ng-click='downloadAgent()') ignite-web-agent] in order to {{::agentGoal}}
+                p Please download and run #[a(href='/api/v1/agent/download/zip' target='_self') ignite-web-agent] in order to {{::agentGoal}}
                 p For run:
                 ul
-                    li Download and unzip #[a(href='javascript:void(0)' ng-click='downloadAgent()') ignite-web-agent] archive
+                    li Download and unzip #[a(href='/api/v1/agent/download/zip' target='_self') ignite-web-agent] archive
                     li Run shell file #[b ignite-web-agent.{sh|bat}]
                 p Refer to #[b README.txt] in agent folder for more information
                 .modal-advanced-options
@@ -47,4 +47,4 @@
                     li Refer to #[b README.txt] in agent folder for more information
             .modal-footer
                 button.btn.btn-default(ng-click='back()') {{::backText}}
-                button.btn.btn-primary(ng-if='!hasAgents' ng-click='downloadAgent()') Download agent
+                a.btn.btn-primary(ng-if='!hasAgents' href='/api/v1/agent/download/zip' target='_self') Download agent