IGNITE-5388 Added support to configuration of Ignite 2.x and Ignite 1.x.

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

Branch: refs/heads/ignite-5075
Commit: e04df7d1fb6cf0ed1756cd7df9980cf4c509ab6f
Parents: 898781a
Author: Andrey Novikov <[email protected]>
Authored: Mon Jun 5 10:27:23 2017 +0700
Committer: Andrey Novikov <[email protected]>
Committed: Mon Jun 5 10:27:23 2017 +0700

----------------------------------------------------------------------
 modules/web-console/backend/app/mongo.js        |  79 ++-
 modules/web-console/backend/services/caches.js  |   2 +
 modules/web-console/backend/services/igfss.js   |   5 +
 modules/web-console/frontend/app/app.config.js  |   3 +-
 modules/web-console/frontend/app/app.js         |  12 +-
 .../cluster-select/cluster-select.pug           |   2 +-
 .../list-of-registered-users.column-defs.js     |   2 +-
 .../app/components/version-picker/component.js  |  52 ++
 .../app/components/version-picker/index.js      |  25 +
 .../app/components/version-picker/style.scss    |  41 ++
 .../app/components/version-picker/template.pug  |  33 ++
 .../frontend/app/data/event-groups.json         |  14 +
 .../ui-ace-docker/ui-ace-docker.controller.js   |   8 +-
 .../ui-ace-java/ui-ace-java.controller.js       |  29 +-
 .../ui-ace-java/ui-ace-java.directive.js        |  12 +-
 .../ui-ace-pom/ui-ace-pom.controller.js         |   8 +-
 .../ui-ace-spring/ui-ace-spring.controller.js   |  29 +-
 .../ui-ace-spring/ui-ace-spring.directive.js    |  12 +-
 .../frontend/app/helpers/jade/mixins.pug        |   4 +-
 .../app/modules/agent/AgentManager.service.js   |  15 +-
 .../frontend/app/modules/cluster/Cache.js       |   4 +
 .../app/modules/cluster/CacheMetrics.js         |   4 +
 .../modules/configuration/Version.service.js    | 180 +++---
 .../generator/AbstractTransformer.js            | 110 ++--
 .../generator/ConfigurationGenerator.js         | 570 +++++++++++++++----
 .../configuration/generator/Docker.service.js   |  12 +-
 .../generator/JavaTransformer.service.js        |  32 +-
 .../configuration/generator/Maven.service.js    |  38 +-
 .../generator/PlatformGenerator.js              |  19 +-
 .../generator/SpringTransformer.service.js      |  23 +-
 .../defaults/Cache.platform.service.js          |   9 +
 .../generator/defaults/Cache.service.js         |  23 +-
 .../generator/defaults/Cluster.service.js       |  46 +-
 .../generator/defaults/IGFS.service.js          |   9 +-
 .../frontend/app/modules/sql/sql.controller.js  |   6 +-
 .../app/modules/states/configuration.state.js   |  21 +-
 .../states/configuration/caches/affinity.pug    |  23 +-
 .../states/configuration/caches/concurrency.pug |  14 +
 .../states/configuration/caches/general.pug     |  71 ++-
 .../states/configuration/caches/memory.pug      |  99 +++-
 .../states/configuration/caches/node-filter.pug |  27 +-
 .../states/configuration/caches/query.pug       |  25 +-
 .../states/configuration/caches/store.pug       |   5 +
 .../configuration/clusters/deployment.pug       |   8 +-
 .../states/configuration/clusters/discovery.pug |  14 +-
 .../states/configuration/clusters/events.pug    |  26 +-
 .../states/configuration/clusters/failover.pug  |   9 +
 .../states/configuration/clusters/general.pug   |   2 +-
 .../states/configuration/clusters/hadoop.pug    | 119 ++++
 .../configuration/clusters/marshaller.pug       |  37 +-
 .../states/configuration/clusters/memory.pug    | 114 ++++
 .../states/configuration/clusters/metrics.pug   |   2 +-
 .../states/configuration/clusters/misc.pug      |  60 ++
 .../states/configuration/clusters/service.pug   |  88 +++
 .../states/configuration/clusters/swap.pug      |  72 +++
 .../states/configuration/clusters/thread.pug    |  54 +-
 .../states/configuration/clusters/time.pug      |  13 +-
 .../states/configuration/domains/query.pug      |   2 +-
 .../modules/states/configuration/igfs/dual.pug  |  42 ++
 .../modules/states/configuration/igfs/misc.pug  |  25 +-
 .../summary/summary-zipper.service.js           |   4 +-
 .../configuration/summary/summary.controller.js |   2 +-
 .../configuration/summary/summary.worker.js     |  13 +-
 .../frontend/app/primitives/btn-group/index.pug |  12 +-
 .../frontend/app/primitives/btn/index.scss      |   6 +
 .../frontend/app/primitives/dropdown/index.pug  |   3 +-
 .../frontend/app/primitives/dropdown/index.scss |  19 +-
 .../frontend/controllers/caches-controller.js   |  71 ++-
 .../frontend/controllers/clusters-controller.js | 190 ++++++-
 .../frontend/controllers/domains-controller.js  |   7 +-
 .../frontend/controllers/igfs-controller.js     |   9 +-
 .../frontend/public/stylesheets/style.scss      |  19 +-
 .../frontend/test/unit/Version.test.js          |  95 ++--
 .../frontend/views/configuration/caches.tpl.pug |   2 +-
 .../views/configuration/clusters.tpl.pug        |  13 +-
 .../views/configuration/domains.tpl.pug         |   2 +-
 .../frontend/views/configuration/igfs.tpl.pug   |   6 +-
 .../views/configuration/sidebar.tpl.pug         |   4 +-
 .../frontend/views/includes/header-left.pug     |   3 -
 .../frontend/views/includes/header-right.pug    |   1 -
 .../frontend/views/settings/admin.tpl.pug       |   2 +-
 .../frontend/views/settings/profile.tpl.pug     |   2 +-
 .../web-console/frontend/views/signin.tpl.pug   |   6 +-
 .../web-console/frontend/views/sql/sql.tpl.pug  |   8 +-
 .../frontend/webpack/webpack.common.js          |   8 +-
 .../frontend/webpack/webpack.dev.babel.js       |   5 +-
 .../console/agent/handlers/ClusterListener.java |  12 +-
 87 files changed, 2396 insertions(+), 572 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/backend/app/mongo.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/mongo.js 
b/modules/web-console/backend/app/mongo.js
index 077044c..d3bc4c0 100644
--- a/modules/web-console/backend/app/mongo.js
+++ b/modules/web-console/backend/app/mongo.js
@@ -101,7 +101,7 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
 
     // Define Domain model schema.
     const DomainModelSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
+        space: {type: ObjectId, ref: 'Space', index: true, required: true},
         caches: [{type: ObjectId, ref: 'Cache'}],
         queryMetadata: {type: String, enum: ['Annotations', 'Configuration']},
         kind: {type: String, enum: ['query', 'store', 'both']},
@@ -139,7 +139,7 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
 
     // Define Cache schema.
     const CacheSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
+        space: {type: ObjectId, ref: 'Space', index: true, required: true},
         name: {type: String},
         clusters: [{type: ObjectId, ref: 'Cluster'}],
         domains: [{type: ObjectId, ref: 'DomainModel'}],
@@ -180,6 +180,10 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
         },
 
         backups: Number,
+        memoryMode: {type: String, enum: ['ONHEAP_TIERED', 'OFFHEAP_TIERED', 
'OFFHEAP_VALUES']},
+        offHeapMaxMemory: Number,
+        startSize: Number,
+        swapEnabled: Boolean,
 
         onheapCacheEnabled: Boolean,
 
@@ -259,16 +263,19 @@ module.exports.factory = function(passportMongo, 
settings, pluginMongo, mongoose
         writeBehindFlushSize: Number,
         writeBehindFlushFrequency: Number,
         writeBehindFlushThreadCount: Number,
-        writeBehindCoalescing: Boolean,
+        writeBehindCoalescing: {type: Boolean, default: true},
 
         invalidate: Boolean,
         defaultLockTimeout: Number,
+        atomicWriteOrderMode: {type: String, enum: ['CLOCK', 'PRIMARY']},
         writeSynchronizationMode: {type: String, enum: ['FULL_SYNC', 
'FULL_ASYNC', 'PRIMARY_SYNC']},
 
         sqlEscapeAll: Boolean,
         sqlSchema: String,
+        sqlOnheapRowCacheSize: Number,
         longQueryWarningTimeout: Number,
         sqlFunctionClasses: [String],
+        snapshotableIndex: Boolean,
         queryDetailMetricsSize: Number,
         queryParallelism: Number,
         statisticsEnabled: Boolean,
@@ -332,15 +339,18 @@ module.exports.factory = function(passportMongo, 
settings, pluginMongo, mongoose
     result.Cache = mongoose.model('Cache', CacheSchema);
 
     const IgfsSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
+        space: {type: ObjectId, ref: 'Space', index: true, required: true},
         name: {type: String},
         clusters: [{type: ObjectId, ref: 'Cluster'}],
         affinnityGroupSize: Number,
         blockSize: Number,
-        bufferSize: Number,
+        streamBufferSize: Number,
         dataCacheName: String,
         metaCacheName: String,
         defaultMode: {type: String, enum: ['PRIMARY', 'PROXY', 'DUAL_SYNC', 
'DUAL_ASYNC']},
+        dualModeMaxPendingPutsSize: Number,
+        dualModePutExecutorService: String,
+        dualModePutExecutorServiceShutdown: Boolean,
         fragmentizerConcurrentFiles: Number,
         fragmentizerEnabled: Boolean,
         fragmentizerThrottlingBlockLength: Number,
@@ -354,6 +364,7 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
             threadCount: Number
         },
         ipcEndpointEnabled: Boolean,
+        maxSpaceSize: Number,
         maximumTaskRangeLength: Number,
         managementPort: Number,
         pathModes: [{path: String, mode: {type: String, enum: ['PRIMARY', 
'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']}}],
@@ -361,6 +372,7 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
         perNodeParallelBatchCount: Number,
         prefetchBlocks: Number,
         sequentialReadsBeforePrefetch: Number,
+        trashPurgeTimeout: Number,
         secondaryFileSystemEnabled: Boolean,
         secondaryFileSystem: {
             uri: String,
@@ -369,7 +381,7 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
         },
         colocateMetadata: Boolean,
         relaxedConsistency: Boolean,
-        updateFileLenOnFlush: Boolean
+        updateFileLengthOnFlush: Boolean
     });
 
     IgfsSchema.index({name: 1, space: 1}, {unique: true});
@@ -379,9 +391,9 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
 
     // Define Cluster schema.
     const ClusterSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
+        space: {type: ObjectId, ref: 'Space', index: true, required: true},
         name: {type: String},
-        activeOnStart: Boolean,
+        activeOnStart: {type: Boolean, default: true},
         localHost: String,
         discovery: {
             localAddress: String,
@@ -394,7 +406,9 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
             networkTimeout: Number,
             joinTimeout: Number,
             threadPriority: Number,
-            metricsUpdateFrequency: Number,
+            heartbeatFrequency: Number,
+            maxMissedHeartbeats: Number,
+            maxMissedClientHeartbeats: Number,
             topHistorySize: Number,
             listener: String,
             dataExchange: String,
@@ -553,6 +567,8 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
             compactFooter: Boolean
         },
         caches: [{type: ObjectId, ref: 'Cache'}],
+        clockSyncSamples: Number,
+        clockSyncFrequency: Number,
         deploymentMode: {type: String, enum: ['PRIVATE', 'ISOLATED', 'SHARED', 
'CONTINUOUS']},
         discoveryStartupDelay: Number,
         igfsThreadPoolSize: Number,
@@ -578,6 +594,8 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
             }
         },
         marshalLocalJobs: Boolean,
+        marshallerCacheKeepAliveTime: Number,
+        marshallerCacheThreadPoolSize: Number,
         metricsExpireTime: Number,
         metricsHistorySize: Number,
         metricsLogFrequency: Number,
@@ -635,6 +653,16 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
         peerClassLoadingMissedResourcesCacheSize: Number,
         peerClassLoadingThreadPoolSize: Number,
         publicThreadPoolSize: Number,
+        swapSpaceSpi: {
+            kind: {type: String, enum: ['FileSwapSpaceSpi']},
+            FileSwapSpaceSpi: {
+                baseDirectory: String,
+                readStripesNumber: Number,
+                maximumSparsity: Number,
+                maxWriteQueueSize: Number,
+                writeBufferSize: Number
+            }
+        },
         systemThreadPoolSize: Number,
         timeServerPortBase: Number,
         timeServerPortRange: Number,
@@ -858,10 +886,22 @@ module.exports.factory = function(passportMongo, 
settings, pluginMongo, mongoose
         },
         warmupClosure: String,
         hadoopConfiguration: {
+            mapReducePlanner: {
+                kind: {type: String, enum: ['Weighted', 'Custom']},
+                Weighted: {
+                    localMapperWeight: Number,
+                    remoteMapperWeight: Number,
+                    localReducerWeight: Number,
+                    remoteReducerWeight: Number,
+                    preferLocalReducerThresholdWeight: Number
+                },
+                Custom: {
+                    className: String
+                }
+            },
             finishedJobInfoTtl: Number,
-            mapReducePlanner: String,
             maxParallelTasks: Number,
-            naxTaskQueueSize: Number,
+            maxTaskQueueSize: Number,
             nativeLibraryNames: [String]
         },
         serviceConfigurations: [{
@@ -884,10 +924,11 @@ module.exports.factory = function(passportMongo, 
settings, pluginMongo, mongoose
             cache: {type: ObjectId, ref: 'Cache'},
             affinityKey: String
         }],
-        cacheSanityCheckEnabled: Boolean,
+        cacheSanityCheckEnabled: {type: Boolean, default: true},
         classLoader: String,
         consistentId: String,
         failureDetectionTimeout: Number,
+        clientFailureDetectionTimeout: Number,
         workDirectory: String,
         lateAffinityAssignment: Boolean,
         utilityCacheKeepAliveTime: Number,
@@ -899,18 +940,24 @@ module.exports.factory = function(passportMongo, 
settings, pluginMongo, mongoose
         utilityCacheThreadPoolSize: Number,
         executorConfiguration: [{
             name: String,
-            poolSize: Number
+            size: Number
         }],
         memoryConfiguration: {
+            systemCacheInitialSize: Number,
+            systemCacheMaxSize: Number,
             pageSize: Number,
-            systemCacheMemorySize: Number,
             concurrencyLevel: Number,
             defaultMemoryPolicyName: String,
+            defaultMemoryPolicySize: Number,
             memoryPolicies: [{
                 name: String,
+                initialSize: Number,
                 maxSize: Number,
                 swapFilePath: String,
-                pageEvictionMode: {type: String, enum: ['DISABLED', 
'RANDOM_LRU', 'RANDOM_2_LRU']}
+                pageEvictionMode: {type: String, enum: ['DISABLED', 
'RANDOM_LRU', 'RANDOM_2_LRU']},
+                evictionThreshold: Number,
+                emptyPagesPoolSize: Number,
+                metricsEnabled: Boolean
             }]
         }
     });
@@ -922,7 +969,7 @@ module.exports.factory = function(passportMongo, settings, 
pluginMongo, mongoose
 
     // Define Notebook schema.
     const NotebookSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
+        space: {type: ObjectId, ref: 'Space', index: true, required: true},
         name: String,
         expandedParagraphs: [Number],
         paragraphs: [{

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/backend/services/caches.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/caches.js 
b/modules/web-console/backend/services/caches.js
index 646fbea..19aed82 100644
--- a/modules/web-console/backend/services/caches.js
+++ b/modules/web-console/backend/services/caches.js
@@ -131,6 +131,8 @@ module.exports.factory = (_, mongo, spaceService, errors) 
=> {
 
             return mongo.Cluster.update({caches: {$in: [cacheId]}}, {$pull: 
{caches: cacheId}}, {multi: true}).exec()
                 .then(() => mongo.Cluster.update({}, {$pull: {checkpointSpi: 
{kind: 'Cache', Cache: {cache: cacheId}}}}, {multi: true}).exec())
+                // TODO WC-201 fix clenup of cache on deletion for cluster 
service configuration.
+                // .then(() => 
mongo.Cluster.update({'serviceConfigurations.cache': cacheId}, {$unset: 
{'serviceConfigurations.$.cache': ''}}, {multi: true}).exec())
                 .then(() => mongo.DomainModel.update({caches: {$in: 
[cacheId]}}, {$pull: {caches: cacheId}}, {multi: true}).exec())
                 .then(() => mongo.Cache.remove({_id: cacheId}).exec())
                 .then(convertRemoveStatus);

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/backend/services/igfss.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/igfss.js 
b/modules/web-console/backend/services/igfss.js
index 578c642..acb565b 100644
--- a/modules/web-console/backend/services/igfss.js
+++ b/modules/web-console/backend/services/igfss.js
@@ -122,6 +122,11 @@ module.exports.factory = (_, mongo, spacesService, errors) 
=> {
                 return Promise.reject(new 
errors.IllegalArgumentException('IGFS id can not be undefined or null'));
 
             return mongo.Cluster.update({igfss: {$in: [igfsId]}}, {$pull: 
{igfss: igfsId}}, {multi: true}).exec()
+                // TODO WC-201 fix clenup on node filter on deletion for 
cluster serviceConfigurations and caches.
+                // .then(() => mongo.Cluster.update({ 
'serviceConfigurations.$.nodeFilter.kind': { $ne: 'IGFS' }, 
'serviceConfigurations.nodeFilter.IGFS.igfs': igfsId},
+                //     {$unset: 
{'serviceConfigurations.$.nodeFilter.IGFS.igfs': ''}}, {multi: true}).exec())
+                // .then(() => mongo.Cluster.update({ 
'serviceConfigurations.nodeFilter.kind': 'IGFS', 
'serviceConfigurations.nodeFilter.IGFS.igfs': igfsId},
+                //     {$unset: {'serviceConfigurations.$.nodeFilter': ''}}, 
{multi: true}).exec())
                 .then(() => mongo.Igfs.remove({_id: igfsId}).exec())
                 .then(convertRemoveStatus);
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/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 1772453..f93ee7e 100644
--- a/modules/web-console/frontend/app/app.config.js
+++ b/modules/web-console/frontend/app/app.config.js
@@ -98,7 +98,8 @@ igniteConsoleCfg.config(['$alertProvider', ($alertProvider) 
=> {
 // AngularStrap dropdowns () configuration.
 igniteConsoleCfg.config(['$dropdownProvider', ($dropdownProvider) => {
     angular.extend($dropdownProvider.defaults, {
-        templateUrl: dropdownTemplateUrl
+        templateUrl: dropdownTemplateUrl,
+        animation: ''
     });
 }]);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.js 
b/modules/web-console/frontend/app/app.js
index df58f0e..ff089bb 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -103,11 +103,7 @@ import hasPojo from './filters/hasPojo.filter';
 import uiGridSubcategories from './filters/uiGridSubcategories.filter';
 
 // Controllers
-import caches from '../controllers/caches-controller';
-import clusters from '../controllers/clusters-controller';
-import domains from '../controllers/domains-controller';
-import igfs from '../controllers/igfs-controller';
-import profile from '../controllers/profile-controller';
+import profile from 'Controllers/profile-controller';
 import auth from './controllers/auth.controller';
 import resetPassword from './controllers/reset-password.controller';
 
@@ -119,6 +115,7 @@ import './components/input-dialog';
 import webConsoleHeader from './components/web-console-header';
 import webConsoleFooter from './components/web-console-footer';
 import igniteIcon from './components/ignite-icon';
+import versionPicker from './components/version-picker';
 
 // Inject external modules.
 import IgniteModules from 'IgniteModules/index';
@@ -179,6 +176,7 @@ angular
     webConsoleHeader.name,
     webConsoleFooter.name,
     igniteIcon.name,
+    versionPicker.name,
     // Ignite modules.
     IgniteModules.name
 ])
@@ -227,10 +225,6 @@ angular
 // Controllers.
 .controller(...auth)
 .controller(...resetPassword)
-.controller(...caches)
-.controller(...clusters)
-.controller(...domains)
-.controller(...igfs)
 .controller(...profile)
 // Filters.
 .filter('byName', byName)

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug 
b/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
index 444e567..a5fd08c 100644
--- 
a/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
+++ 
b/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
@@ -26,7 +26,7 @@ ul.nav(ng-switch='ctrl.clusters.length')
             label.padding-left-dflt {{ctrl.cluster.name}}
 
     li(ng-switch-default)
-        a.dropdown-toggle(bs-dropdown='' data-placement='bottom-left' 
data-trigger='hover focus' data-container='self' data-animation='' 
ng-click='$event.stopPropagation()' aria-haspopup='true' 
aria-expanded='expanded')
+        a.dropdown-toggle(bs-dropdown='' data-placement='bottom-left' 
data-trigger='hover focus' data-container='self' 
ng-click='$event.stopPropagation()' aria-haspopup='true' 
aria-expanded='expanded')
             i.icon-cluster
             label.padding-left-dflt {{ctrl.cluster.name}}
             span.caret

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/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 cb95735..d50c44a 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
@@ -51,7 +51,7 @@ const EMAIL_TEMPLATE = '<div class="ui-grid-cell-contents"><a 
ng-href="mailto:{{
 export default [
     {name: 'actions', displayName: 'Actions', categoryDisplayName: 'Actions', 
cellTemplate: ACTIONS_TEMPLATE, field: 'actions', minWidth: 70, width: 70, 
enableFiltering: false, enableSorting: false, visible: false},
     {name: 'user', displayName: 'User', categoryDisplayName: 'User', field: 
'userName', cellTemplate: USER_TEMPLATE, minWidth: 160, enableFiltering: true, 
pinnedLeft: true, filter: { placeholder: 'Filter by name...' }},
-    {name: 'email', displayName: 'Email', categoryDisplayName: 'Email', field: 
'email', cellTemplate: EMAIL_TEMPLATE, minWidth: 160, enableFiltering: false, 
filter: { placeholder: 'Filter by email...' }},
+    {name: 'email', displayName: 'Email', categoryDisplayName: 'Email', field: 
'email', cellTemplate: EMAIL_TEMPLATE, minWidth: 160, enableFiltering: true, 
filter: { placeholder: 'Filter by email...' }},
     {name: 'company', displayName: 'Company', categoryDisplayName: 'Company', 
field: 'company', minWidth: 180, enableFiltering: true, filter: { placeholder: 
'Filter by company...' }},
     {name: 'country', displayName: 'Country', categoryDisplayName: 'Country', 
field: 'countryCode', minWidth: 160, enableFiltering: true, filter: { 
placeholder: 'Filter by country...' }},
     {name: 'lastlogin', displayName: 'Last login', categoryDisplayName: 'Last 
login', field: 'lastLogin', cellFilter: 'date:"M/d/yy HH:mm"', minWidth: 120, 
width: 120, enableFiltering: false, visible: false},

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/components/version-picker/component.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/version-picker/component.js 
b/modules/web-console/frontend/app/components/version-picker/component.js
new file mode 100644
index 0000000..68382ee
--- /dev/null
+++ b/modules/web-console/frontend/app/components/version-picker/component.js
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+import template from './template.pug';
+import './style.scss';
+
+export default {
+    template,
+    controller: class {
+        static $inject = ['IgniteVersion', '$scope'];
+
+        constructor(Version, $scope) {
+            this.currentSbj = Version.currentSbj;
+            this.supportedVersions = Version.supportedVersions;
+
+            const dropdownToggle = (active) => {
+                this.isActive = active;
+
+                // bs-dropdown does not call apply on callbacks
+                $scope.$apply();
+            };
+
+            this.onDropdownShow = () => dropdownToggle(true);
+            this.onDropdownHide = () => dropdownToggle(false);
+        }
+
+        $onInit() {
+            this.dropdown = _.map(this.supportedVersions, (ver) => ({
+                text: ver.label,
+                click: () => this.currentSbj.next(ver)
+            }));
+
+            this.currentSbj.subscribe({
+                next: (ver) => this.currentVersion = ver.label
+            });
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/components/version-picker/index.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/version-picker/index.js 
b/modules/web-console/frontend/app/components/version-picker/index.js
new file mode 100644
index 0000000..f58753e
--- /dev/null
+++ b/modules/web-console/frontend/app/components/version-picker/index.js
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+import angular from 'angular';
+import component from './component';
+
+export default angular
+    .module('ignite-console.version-picker', [
+        'ignite-console.configuration'
+    ])
+    .component('versionPicker', component);

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/components/version-picker/style.scss
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/version-picker/style.scss 
b/modules/web-console/frontend/app/components/version-picker/style.scss
new file mode 100644
index 0000000..98a4e9d
--- /dev/null
+++ b/modules/web-console/frontend/app/components/version-picker/style.scss
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+version-picker {
+    display: inline-flex;
+    align-items: center;
+
+    .btn-ignite {
+        border-radius: 9px;
+        min-height: 0;
+        font-size: 12px;
+        font-weight: bold;
+        line-height: 17px;
+        padding-top: 0;
+        padding-bottom: 1px;
+    }
+
+    .icon-help {
+        margin-left: 5px;
+        font-size: 16px;
+    }
+
+    .dropdown-menu a {
+        // Fixes style leak from above
+        font-size: 14px !important;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/components/version-picker/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/version-picker/template.pug 
b/modules/web-console/frontend/app/components/version-picker/template.pug
new file mode 100644
index 0000000..1abe471
--- /dev/null
+++ b/modules/web-console/frontend/app/components/version-picker/template.pug
@@ -0,0 +1,33 @@
+//-
+    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.
+
+.btn-ignite.btn-ignite--primary(
+    bs-dropdown='$ctrl.dropdown'
+    data-trigger='hover focus'
+    bs-on-before-show='$ctrl.onDropdownShow'
+    bs-on-before-hide='$ctrl.onDropdownHide'
+    data-container='self'
+    ng-class='{"active": $ctrl.isActive }'
+)
+    | {{$ctrl.currentVersion}}
+    span.icon-right.fa.fa-caret-down
+    
+i.icon-help(
+    bs-tooltip=''
+    data-title='Web Console supports multiple Ignite versions.<br /> \
+                Select version you need to configure cluster.'
+    data-placement='right'
+)

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/data/event-groups.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/event-groups.json 
b/modules/web-console/frontend/app/data/event-groups.json
index 094fd28..8d0c878 100644
--- a/modules/web-console/frontend/app/data/event-groups.json
+++ b/modules/web-console/frontend/app/data/event-groups.json
@@ -97,6 +97,8 @@
       "EVT_CACHE_OBJECT_REMOVED",
       "EVT_CACHE_OBJECT_LOCKED",
       "EVT_CACHE_OBJECT_UNLOCKED",
+      "EVT_CACHE_OBJECT_SWAPPED",
+      "EVT_CACHE_OBJECT_UNSWAPPED",
       "EVT_CACHE_OBJECT_EXPIRED"
     ]
   },
@@ -134,6 +136,18 @@
     ]
   },
   {
+    "label": "EVTS_SWAPSPACE",
+    "value": "EVTS_SWAPSPACE",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_SWAP_SPACE_CLEARED",
+      "EVT_SWAP_SPACE_DATA_REMOVED",
+      "EVT_SWAP_SPACE_DATA_READ",
+      "EVT_SWAP_SPACE_DATA_STORED",
+      "EVT_SWAP_SPACE_DATA_EVICTED"
+    ]
+  },
+  {
     "label": "EVTS_IGFS",
     "value": "EVTS_IGFS",
     "class": "org.apache.ignite.events.EventType",

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
 
b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
index de335ae..8ebaae4 100644
--- 
a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
+++ 
b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-export default ['$scope', 'IgniteDockerGenerator', function($scope, docker) {
+export default ['$scope', 'IgniteVersion', 'IgniteDockerGenerator', 
function($scope, Version, docker) {
     const ctrl = this;
 
     // Watchers definition.
@@ -25,9 +25,13 @@ export default ['$scope', 'IgniteDockerGenerator', 
function($scope, docker) {
         if (!$scope.cluster)
             return;
 
-        ctrl.data = docker.generate($scope.cluster, 'latest');
+        ctrl.data = docker.generate($scope.cluster, 
Version.currentSbj.getValue());
     };
 
     // Setup watchers.
+    Version.currentSbj.subscribe({
+        next: clusterWatcher
+    });
+
     $scope.$watch('cluster', clusterWatcher);
 }];

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
 
b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
index 7e7a0e4..66a10af 100644
--- 
a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
+++ 
b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
@@ -15,19 +15,21 @@
  * limitations under the License.
  */
 
-export default ['$scope', 'JavaTransformer', function($scope, java) {
+export default ['IgniteVersion', 'JavaTransformer', function(Version, java) {
     const ctrl = this;
 
     delete ctrl.data;
 
     const client = ctrl.client === 'true';
 
+    const available = Version.available.bind(Version);
+
     // Setup generator.
     switch (ctrl.generator) {
         case 'igniteConfiguration':
             const clsName = client ? 'ClientConfigurationFactory' : 
'ServerConfigurationFactory';
 
-            ctrl.generate = (cluster) => java.cluster(cluster, 'config', 
clsName, client);
+            ctrl.generate = (cluster) => java.cluster(cluster, 
Version.current, 'config', clsName, client);
 
             break;
         case 'clusterCaches':
@@ -39,9 +41,9 @@ export default ['$scope', 'JavaTransformer', function($scope, 
java) {
                     return acc;
                 }, []);
 
-                const cfg = java.generator.clusterGeneral(cluster);
+                const cfg = java.generator.clusterGeneral(cluster, available);
 
-                java.generator.clusterCaches(cluster, clusterCaches, null, 
false, cfg);
+                java.generator.clusterCaches(cluster, clusterCaches, null, 
available, false, cfg);
 
                 return java.toSection(cfg);
             };
@@ -57,7 +59,7 @@ export default ['$scope', 'JavaTransformer', function($scope, 
java) {
                     return acc;
                 }, []);
 
-                return java[ctrl.generator](cache, cacheDomains);
+                return java[ctrl.generator](cache, cacheDomains, available);
             };
 
             break;
@@ -73,6 +75,19 @@ export default ['$scope', 'JavaTransformer', 
function($scope, java) {
             };
 
             break;
+        case 'clusterServiceConfiguration':
+            ctrl.generate = (cluster, caches) => {
+                const clusterCaches = _.reduce(caches, (acc, cache) => {
+                    if (_.includes(cluster.caches, cache.value))
+                        acc.push(cache.cache);
+
+                    return acc;
+                }, []);
+
+                return 
java.clusterServiceConfiguration(cluster.serviceConfigurations, clusterCaches);
+            };
+
+            break;
         case 'igfss':
             ctrl.generate = (cluster, igfss) => {
                 const clusterIgfss = _.reduce(igfss, (acc, igfs) => {
@@ -82,11 +97,11 @@ export default ['$scope', 'JavaTransformer', 
function($scope, java) {
                     return acc;
                 }, []);
 
-                return java.clusterIgfss(clusterIgfss);
+                return java.clusterIgfss(clusterIgfss, available);
             };
 
             break;
         default:
-            ctrl.generate = (master, detail) => java[ctrl.generator](master, 
detail);
+            ctrl.generate = (master) => java[ctrl.generator](master, 
available);
     }
 }];

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
 
b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
index 5f43b23..5d1df42 100644
--- 
a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
+++ 
b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
@@ -18,7 +18,7 @@
 import template from './ui-ace-java.pug';
 import controller from './ui-ace-java.controller';
 
-export default ['igniteUiAceJava', [() => {
+export default ['igniteUiAceJava', ['IgniteVersion', (Version) => {
     const link = (scope, $el, attrs, [ctrl, igniteUiAceTabs, formCtrl, 
ngModelCtrl]) => {
         if (formCtrl && ngModelCtrl)
             formCtrl.$removeControl(ngModelCtrl);
@@ -36,10 +36,14 @@ export default ['igniteUiAceJava', [() => {
 
         const noDeepWatch = !(typeof attrs.noDeepWatch !== 'undefined');
 
-        // Setup watchers.
-        scope.$watch('master', () => {
+        const next = () => {
             ctrl.data = _.isNil(scope.master) ? null : 
ctrl.generate(scope.master, scope.detail).asString();
-        }, noDeepWatch);
+        };
+
+        // Setup watchers.
+        scope.$watch('master', next, noDeepWatch);
+
+        Version.currentSbj.subscribe({next});
     };
 
     return {

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/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 0ae1269..0135eb3 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', function($scope, maven) {
+export default ['$scope', 'IgniteVersion', 'IgniteMavenGenerator', 
function($scope, Version, maven) {
     const ctrl = this;
 
     // Watchers definition.
@@ -25,9 +25,13 @@ export default ['$scope', 'IgniteMavenGenerator', 
function($scope, maven) {
         if (!value)
             return;
 
-        ctrl.data = maven.generate($scope.cluster);
+        ctrl.data = maven.generate($scope.cluster, 
Version.currentSbj.getValue());
     };
 
     // Setup watchers.
+    Version.currentSbj.subscribe({
+        next: clusterWatcher
+    });
+
     $scope.$watch('cluster', clusterWatcher);
 }];

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.controller.js
 
b/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.controller.js
index 50b71cb..92b0ae8 100644
--- 
a/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.controller.js
+++ 
b/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.controller.js
@@ -15,15 +15,17 @@
  * limitations under the License.
  */
 
-export default ['$scope', 'SpringTransformer', function($scope, spring) {
+export default ['IgniteVersion', 'SpringTransformer', function(Version, 
spring) {
     const ctrl = this;
 
     delete ctrl.data;
 
+    const targetSince = Version.available.bind(Version);
+
     // Setup generator.
     switch (ctrl.generator) {
         case 'igniteConfiguration':
-            ctrl.generate = (cluster) => spring.cluster(cluster, ctrl.client 
=== 'true');
+            ctrl.generate = (cluster) => spring.cluster(cluster, 
Version.current, ctrl.client === 'true');
 
             break;
         case 'clusterCaches':
@@ -35,9 +37,9 @@ export default ['$scope', 'SpringTransformer', 
function($scope, spring) {
                     return acc;
                 }, []);
 
-                const cfg = spring.generator.clusterGeneral(cluster);
+                const cfg = spring.generator.clusterGeneral(cluster, 
targetSince);
 
-                spring.generator.clusterCaches(cluster, clusterCaches, null, 
false, cfg);
+                spring.generator.clusterCaches(cluster, clusterCaches, null, 
targetSince, false, cfg);
 
                 return spring.toSection(cfg);
             };
@@ -53,7 +55,7 @@ export default ['$scope', 'SpringTransformer', 
function($scope, spring) {
                     return acc;
                 }, []);
 
-                return spring[ctrl.generator](cache, cacheDomains);
+                return spring[ctrl.generator](cache, cacheDomains, 
targetSince);
             };
 
             break;
@@ -69,6 +71,19 @@ export default ['$scope', 'SpringTransformer', 
function($scope, spring) {
             };
 
             break;
+        case 'clusterServiceConfiguration':
+            ctrl.generate = (cluster, caches) => {
+                const clusterCaches = _.reduce(caches, (acc, cache) => {
+                    if (_.includes(cluster.caches, cache.value))
+                        acc.push(cache.cache);
+
+                    return acc;
+                }, []);
+
+                return 
spring.clusterServiceConfiguration(cluster.serviceConfigurations, 
clusterCaches);
+            };
+
+            break;
         case 'igfss':
             ctrl.generate = (cluster, igfss) => {
                 const clusterIgfss = _.reduce(igfss, (acc, igfs) => {
@@ -78,11 +93,11 @@ export default ['$scope', 'SpringTransformer', 
function($scope, spring) {
                     return acc;
                 }, []);
 
-                return spring.clusterIgfss(clusterIgfss);
+                return spring.clusterIgfss(clusterIgfss, targetSince);
             };
 
             break;
         default:
-            ctrl.generate = (master, detail) => spring[ctrl.generator](master, 
detail);
+            ctrl.generate = (master) => spring[ctrl.generator](master, 
targetSince);
     }
 }];

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.directive.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.directive.js
 
b/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.directive.js
index de3f434..953d6cd 100644
--- 
a/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.directive.js
+++ 
b/modules/web-console/frontend/app/directives/ui-ace-spring/ui-ace-spring.directive.js
@@ -20,7 +20,7 @@ import _ from 'lodash';
 import template from './ui-ace-spring.pug';
 import controller from './ui-ace-spring.controller';
 
-export default ['igniteUiAceSpring', [() => {
+export default ['igniteUiAceSpring', ['IgniteVersion', (Version) => {
     const link = (scope, $el, attrs, [ctrl, igniteUiAceTabs, formCtrl, 
ngModelCtrl]) => {
         if (formCtrl && ngModelCtrl)
             formCtrl.$removeControl(ngModelCtrl);
@@ -39,10 +39,14 @@ export default ['igniteUiAceSpring', [() => {
 
         const noDeepWatch = !(typeof attrs.noDeepWatch !== 'undefined');
 
-        // Setup watchers.
-        scope.$watch('master', () => {
+        const next = () => {
             ctrl.data = _.isNil(scope.master) ? null : 
ctrl.generate(scope.master, scope.detail).asString();
-        }, noDeepWatch);
+        };
+
+        // Setup watchers.
+        scope.$watch('master', next, noDeepWatch);
+
+        Version.currentSbj.subscribe({next});
     };
 
     return {

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/helpers/jade/mixins.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/mixins.pug 
b/modules/web-console/frontend/app/helpers/jade/mixins.pug
index 3176cb8..a357966 100644
--- a/modules/web-console/frontend/app/helpers/jade/mixins.pug
+++ b/modules/web-console/frontend/app/helpers/jade/mixins.pug
@@ -66,9 +66,9 @@ mixin save-remove-clone-undo-buttons(objectName)
         .panel-tip-container(ng-show='backupItem._id')
             a.btn.btn-primary(id='clone-item' ng-click='cloneItem()' 
bs-tooltip=cloneTip data-placement='bottom' data-trigger='hover') Clone
 
-        -var actions = [{ text: "Remove", click: "removeItem()" }, { text: 
"Remove All", click: "removeAllItems()" }]
+        -var options = [{ text: "Remove", click: "removeItem()" }, { text: 
"Remove All", click: "removeAllItems()" }]
 
-        +btn-group(actions, removeTip)(ng-show='backupItem._id')
+        +btn-group(false, options, removeTip)(ng-show='backupItem._id')
 
         .panel-tip-container(ng-show='backupItem')
             i.btn.btn-primary.fa.fa-undo(id='undo-item' 
ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && resetAll()' 
bs-tooltip=undoTip data-placement='bottom' data-trigger='hover')

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/modules/agent/AgentManager.service.js 
b/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
index 3344ef2..58e071b 100644
--- a/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
+++ b/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
@@ -45,12 +45,14 @@ export default class IgniteAgentManager {
 
         this.ignite2x = false;
 
-        $root.$watch(() => _.get(this, 'cluster.clusterVersion'), (ver) => {
-            if (_.isEmpty(ver))
-                return;
+        if (!$root.IgniteDemoMode) {
+            $root.$watch(() => _.get(this, 'cluster.clusterVersion'), (ver) => 
{
+                if (_.isEmpty(ver))
+                    return;
 
-            this.ignite2x = ver.startsWith('2.');
-        }, true);
+                this.ignite2x = ver.startsWith('2.');
+            }, true);
+        }
 
         /**
          * Connection to backend.
@@ -509,6 +511,9 @@ export default class IgniteAgentManager {
      * @returns {Promise}
      */
     queryNextPage(nid, queryId, pageSize) {
+        if (this.ignite2x)
+            return this.visorTask('queryFetchX2', nid, queryId, pageSize);
+
         return this.visorTask('queryFetch', nid, queryId, pageSize);
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/modules/cluster/Cache.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/cluster/Cache.js 
b/modules/web-console/frontend/app/modules/cluster/Cache.js
index f954ad2..4918a7c 100644
--- a/modules/web-console/frontend/app/modules/cluster/Cache.js
+++ b/modules/web-console/frontend/app/modules/cluster/Cache.js
@@ -40,6 +40,10 @@ export default class Cache {
         this.offHeapPrimarySize = cache.offHeapPrimaryEntriesCount || 0;
         this.offHeapBackupSize = cache.offHeapBackupEntriesCount || 0;
 
+        // Swap.
+        this.swapSize = cache.swapSize;
+        this.swapKeys = cache.swapKeys;
+
         const m = cache.metrics;
 
         // Read/write metrics.

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/modules/cluster/CacheMetrics.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/cluster/CacheMetrics.js 
b/modules/web-console/frontend/app/modules/cluster/CacheMetrics.js
index 160b7d1..90d3a9b 100644
--- a/modules/web-console/frontend/app/modules/cluster/CacheMetrics.js
+++ b/modules/web-console/frontend/app/modules/cluster/CacheMetrics.js
@@ -40,6 +40,10 @@ export default class CacheMetrics {
         this.offHeapPrimarySize = cache.offHeapPrimaryEntriesCount || 0;
         this.offHeapBackupSize = cache.offHeapBackupEntriesCount || 0;
 
+        // Swap.
+        this.swapSize = cache.swapSize;
+        this.swapKeys = cache.swapKeys;
+
         const m = cache.metrics;
 
         // Read/write metrics.

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/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 1cbe635..cf2bfc5 100644
--- a/modules/web-console/frontend/app/modules/configuration/Version.service.js
+++ b/modules/web-console/frontend/app/modules/configuration/Version.service.js
@@ -15,96 +15,148 @@
  * limitations under the License.
  */
 
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+
 /**
  * Utility service for version parsing and comparing
  */
 const VERSION_MATCHER = 
/(\d+)\.(\d+)\.(\d+)([-.]([^0123456789][^-]+)(-SNAPSHOT)?)?(-(\d+))?(-([\da-f]+))?/i;
 
-const numberComparator = (a, b) => a > b ? 1 : a < b ? -1 : 0;
+/**
+ * Tries to parse product version from it's string representation.
+ *
+ * @param {String} ver - String representation of version.
+ * @returns {{major: Number, minor: Number, maintenance: Number, stage: 
String, revTs: Number, revHash: String}} - Object that contains product version 
fields.
+ */
+const parse = (ver) => {
+    // Development or built from source ZIP.
+    ver = ver.replace(/(-DEV|-n\/a)$/i, '');
+
+    const [, major, minor, maintenance, stage, ...chunks] = 
ver.match(VERSION_MATCHER);
+
+    return {
+        major: parseInt(major, 10),
+        minor: parseInt(minor, 10),
+        maintenance: parseInt(maintenance, 10),
+        stage: (stage || '').substring(1),
+        revTs: chunks[2] ? parseInt(chunks[3], 10) : 0,
+        revHash: chunks[4] ? chunks[5] : null
+    };
+};
 
-export default class IgniteVersion {
-    /** Current product version. */
-    static ignite = '2.0.0';
+const numberComparator = (a, b) => a > b ? 1 : a < b ? -1 : 0;
 
-    /**
-     * Tries to parse product version from it's string representation.
-     *
-     * @param {String} ver - String representation of version.
-     * @returns {{major: Number, minor: Number, maintenance: Number, stage: 
String, revTs: Number, revHash: String}} - Object that contains product version 
fields.
-     */
-    parse(ver) {
-        // Development or built from source ZIP.
-        ver = ver.replace(/(-DEV|-n\/a)$/i, '');
-
-        const [, major, minor, maintenance, stage, ...chunks] = 
ver.match(VERSION_MATCHER);
-
-        return {
-            major: parseInt(major, 10),
-            minor: parseInt(minor, 10),
-            maintenance: parseInt(maintenance, 10),
-            stage: (stage || '').substring(1),
-            revTs: chunks[2] ? parseInt(chunks[3], 10) : 0,
-            revHash: chunks[4] ? chunks[5] : null
-        };
-    }
+/**
+ * Compare to version.
+ * @param a {Object} first compared version.
+ * @param b {Object} second compared version.
+ * @returns {Number} 1 if a > b, 0 if versions equals, -1 if a < b
+ */
+const compare = (a, b) => {
+    let res = numberComparator(a.major, b.major);
 
-    /**
-     * Compare to version.
-     * @param a {String} first compared version.
-     * @param b {String} second compared version.
-     * @returns {Number} 1 if a > b, 0 if versions equals, -1 if a < b
-     */
-    compare(a, b) {
-        const pa = this.parse(a);
-        const pb = this.parse(b);
+    if (res !== 0)
+        return res;
 
-        let res = numberComparator(pa.major, pb.major);
+    res = numberComparator(a.minor, b.minor);
 
-        if (res !== 0)
-            return res;
+    if (res !== 0)
+        return res;
 
-        res = numberComparator(pa.minor, pb.minor);
+    res = numberComparator(a.maintenance, b.maintenance);
 
-        if (res !== 0)
-            return res;
+    if (res !== 0)
+        return res;
 
-        res = numberComparator(pa.maintenance, pb.maintenance);
+    return numberComparator(a.revTs, b.revTs);
+};
 
-        if (res !== 0)
-            return res;
+export default class IgniteVersion {
+    constructor() {
+        this.supportedVersions = [
+            {
+                label: 'Ignite 2.0',
+                ignite: '2.0.0'
+            },
+            {
+                label: 'Ignite 1.x',
+                ignite: '1.9.0'
+            }
+        ];
+
+        /** Current product version. */
+        let current = _.head(this.supportedVersions);
+
+        try {
+            const ignite = localStorage.configurationVersion;
+
+            const restored = _.find(this.supportedVersions, {ignite});
+
+            if (restored)
+                current = restored;
+        }
+        catch (ignored) {
+            // No-op.
+        }
+
+        this.currentSbj = new BehaviorSubject(current);
+
+        this.currentSbj.subscribe({
+            next: (ver) => {
+                try {
+                    localStorage.setItem('configurationVersion', ver.ignite);
+                }
+                catch (ignored) {
+                    // No-op.
+                }
+            }
+        });
+    }
 
-        return numberComparator(pa.revTs, pb.revTs);
+    /**
+     * @return {String} Target Ignite version.
+     */
+    get current() {
+        return this.currentSbj.getValue().ignite;
     }
 
     /**
-     * Check if node version in range
-     * @param {String} nodeVer Node version.
-     * @param {Array.<String>} ranges Version ranges to compare with.
-     * @returns {Boolean} `True` if node version is equal or greater than 
specified range.
+     * Check if version in range
+     * @param {String} target Target version.
+     * @param {String | Array.<String>} ranges Version ranges to compare with.
+     * @returns {Boolean} `True` if version is equal or greater than specified 
range.
      */
-    includes(nodeVer, ...ranges) {
-        return !!_.find(ranges, ([after, before]) =>
-            this.compare(nodeVer, after) >= 0 && (_.isNil(before) || 
this.compare(nodeVer, before) < 0)
-        );
+    since(target, ...ranges) {
+        const targetVer = parse(target);
+
+        return !!_.find(ranges, (range) => {
+            if (_.isArray(range)) {
+                const [after, before] = range;
+
+                return compare(targetVer, parse(after)) >= 0 &&
+                    (_.isNil(before) || compare(targetVer, parse(before)) < 0);
+            }
+
+            return compare(targetVer, parse(range)) >= 0;
+        });
     }
 
     /**
-     * Check if node version is newer or same
-     * @param {String} nodeVer Node version.
-     * @param {String} sinceVer Version to compare with.
-     * @returns {Boolean} `True` if node version is equal or greater than 
specified version.
+     * Check whether version before than specified version.
+     * @param {String} target Target version.
+     * @param {String} ranges Version ranges to compare with.
+     * @return {Boolean} `True` if version before than specified version.
      */
-    since(nodeVer, sinceVer) {
-        return this.includes(nodeVer, [sinceVer]);
+    before(target, ...ranges) {
+        return !this.since(target, ...ranges);
     }
 
     /**
-     * Check whether node version before than specified version.
-     * @param {String} nodeVer Node version.
-     * @param {String} sinceVer Version to compare with.
-     * @return {Boolean} `True` if node version before than specified version.
+     * Check if configuration version in range
+     * @param {String|Array.<String>} ranges Version ranges to compare with.
+     * @returns {Boolean} `True` if configuration version is equal or greater 
than specified range.
      */
-    before(nodeVer, sinceVer) {
-        return !this.since(nodeVer, sinceVer);
+    available(...ranges) {
+        return this.since(this.current, ...ranges);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e04df7d1/modules/web-console/frontend/app/modules/configuration/generator/AbstractTransformer.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/modules/configuration/generator/AbstractTransformer.js
 
b/modules/web-console/frontend/app/modules/configuration/generator/AbstractTransformer.js
index e008fc6..20393c5 100644
--- 
a/modules/web-console/frontend/app/modules/configuration/generator/AbstractTransformer.js
+++ 
b/modules/web-console/frontend/app/modules/configuration/generator/AbstractTransformer.js
@@ -18,7 +18,6 @@
 import StringBuilder from './StringBuilder';
 
 import IgniteConfigurationGenerator from './ConfigurationGenerator';
-import IgniteEventGroups from './defaults/Event-groups.service';
 
 import IgniteClusterDefaults from './defaults/Cluster.service';
 import IgniteCacheDefaults from './defaults/Cache.service';
@@ -33,7 +32,6 @@ const igfsDflts = new IgniteIGFSDefaults();
 export default class AbstractTransformer {
     static generator = IgniteConfigurationGenerator;
     static javaTypes = new JavaTypes(clusterDflts, cacheDflts, igfsDflts);
-    static eventGroups = new IgniteEventGroups();
 
     // Append comment with time stamp.
     static mainComment(sb, ...lines) {
@@ -61,8 +59,8 @@ export default class AbstractTransformer {
     }
 
     // Generate general section.
-    static clusterGeneral(cluster) {
-        return this.toSection(this.generator.clusterGeneral(cluster));
+    static clusterGeneral(cluster, available) {
+        return this.toSection(this.generator.clusterGeneral(cluster, 
available));
     }
 
     // Generate atomics group.
@@ -96,28 +94,33 @@ export default class AbstractTransformer {
     }
 
     // Generate deployment group.
-    static clusterDeployment(cluster) {
-        return this.toSection(this.generator.clusterDeployment(cluster));
+    static clusterDeployment(cluster, available) {
+        return this.toSection(this.generator.clusterDeployment(cluster, 
available));
     }
 
     // Generate discovery group.
-    static clusterDiscovery(disco) {
-        return this.toSection(this.generator.clusterDiscovery(disco));
+    static clusterDiscovery(disco, available) {
+        return this.toSection(this.generator.clusterDiscovery(disco, 
available));
     }
 
     // Generate events group.
-    static clusterEvents(cluster) {
-        return this.toSection(this.generator.clusterEvents(cluster));
+    static clusterEvents(cluster, available) {
+        return this.toSection(this.generator.clusterEvents(cluster, 
available));
     }
 
     // Generate failover group.
-    static clusterFailover(cluster) {
-        return this.toSection(this.generator.clusterFailover(cluster));
+    static clusterFailover(cluster, available) {
+        return this.toSection(this.generator.clusterFailover(cluster, 
available));
+    }
+
+    // Generate hadoop group.
+    static clusterHadoop(hadoop) {
+        return this.toSection(this.generator.clusterHadoop(hadoop));
     }
 
     // Generate cluster IGFSs group.
-    static clusterIgfss(igfss) {
-        return this.toSection(this.generator.clusterIgfss(igfss));
+    static clusterIgfss(igfss, available) {
+        return this.toSection(this.generator.clusterIgfss(igfss, available));
     }
 
     // Generate load balancing SPI group.
@@ -130,14 +133,24 @@ export default class AbstractTransformer {
         return this.toSection(this.generator.clusterLogger(cluster));
     }
 
+    // Generate memory configuration group.
+    static clusterMemory(memoryConfiguration) {
+        return 
this.toSection(this.generator.clusterMemory(memoryConfiguration));
+    }
+
+    // Generate marshaller group.
+    static clusterMisc(cluster, available) {
+        return this.toSection(this.generator.clusterMisc(cluster, available));
+    }
+
     // Generate marshaller group.
-    static clusterMarshaller(cluster) {
-        return this.toSection(this.generator.clusterMarshaller(cluster));
+    static clusterMarshaller(cluster, available) {
+        return this.toSection(this.generator.clusterMarshaller(cluster, 
available));
     }
 
     // Generate metrics group.
-    static clusterMetrics(cluster) {
-        return this.toSection(this.generator.clusterMetrics(cluster));
+    static clusterMetrics(cluster, available) {
+        return this.toSection(this.generator.clusterMetrics(cluster, 
available));
     }
 
     // Generate ODBC group.
@@ -145,19 +158,29 @@ export default class AbstractTransformer {
         return this.toSection(this.generator.clusterODBC(odbc));
     }
 
+    // Generate cache node filter group.
+    static clusterServiceConfiguration(srvs, caches) {
+        return this.toSection(this.generator.clusterServiceConfiguration(srvs, 
caches));
+    }
+
     // Generate ssl group.
     static clusterSsl(cluster) {
         return this.toSection(this.generator.clusterSsl(cluster));
     }
 
+    // Generate swap group.
+    static clusterSwap(cluster) {
+        return this.toSection(this.generator.clusterSwap(cluster));
+    }
+
     // Generate time group.
-    static clusterTime(cluster) {
-        return this.toSection(this.generator.clusterTime(cluster));
+    static clusterTime(cluster, available) {
+        return this.toSection(this.generator.clusterTime(cluster, available));
     }
 
     // Generate thread pools group.
-    static clusterPools(cluster) {
-        return this.toSection(this.generator.clusterPools(cluster));
+    static clusterPools(cluster, available) {
+        return this.toSection(this.generator.clusterPools(cluster, available));
     }
 
     // Generate transactions group.
@@ -171,8 +194,8 @@ export default class AbstractTransformer {
     }
 
     // Generate IGFS general group.
-    static igfsGeneral(igfs) {
-        return this.toSection(this.generator.igfsGeneral(igfs));
+    static igfsGeneral(igfs, available) {
+        return this.toSection(this.generator.igfsGeneral(igfs, available));
     }
 
     // Generate IGFS secondary file system group.
@@ -190,39 +213,44 @@ export default class AbstractTransformer {
         return this.toSection(this.generator.igfsFragmentizer(igfs));
     }
 
+    // Generate IGFS Dual mode group.
+    static igfsDualMode(igfs) {
+        return this.toSection(this.generator.igfsDualMode(igfs));
+    }
+
     // Generate IGFS miscellaneous group.
-    static igfsMisc(igfs) {
-        return this.toSection(this.generator.igfsMisc(igfs));
+    static igfsMisc(igfs, available) {
+        return this.toSection(this.generator.igfsMisc(igfs, available));
     }
 
     // Generate cache general group.
-    static cacheGeneral(cache) {
-        return this.toSection(this.generator.cacheGeneral(cache));
+    static cacheGeneral(cache, available) {
+        return this.toSection(this.generator.cacheGeneral(cache, available));
     }
 
     // Generate cache memory group.
-    static cacheAffinity(cache) {
-        return this.toSection(this.generator.cacheAffinity(cache));
+    static cacheAffinity(cache, available) {
+        return this.toSection(this.generator.cacheAffinity(cache, available));
     }
 
     // Generate cache memory group.
-    static cacheMemory(cache) {
-        return this.toSection(this.generator.cacheMemory(cache));
+    static cacheMemory(cache, available) {
+        return this.toSection(this.generator.cacheMemory(cache, available));
     }
 
     // Generate cache queries & Indexing group.
-    static cacheQuery(cache, domains) {
-        return this.toSection(this.generator.cacheQuery(cache, domains));
+    static cacheQuery(cache, domains, available) {
+        return this.toSection(this.generator.cacheQuery(cache, domains, 
available));
     }
 
     // Generate cache store group.
-    static cacheStore(cache, domains) {
-        return this.toSection(this.generator.cacheStore(cache, domains));
+    static cacheStore(cache, domains, available) {
+        return this.toSection(this.generator.cacheStore(cache, domains, 
available));
     }
 
     // Generate cache concurrency control group.
-    static cacheConcurrency(cache) {
-        return this.toSection(this.generator.cacheConcurrency(cache));
+    static cacheConcurrency(cache, available) {
+        return this.toSection(this.generator.cacheConcurrency(cache, 
available));
     }
 
     // Generate cache node filter group.
@@ -251,12 +279,12 @@ export default class AbstractTransformer {
     }
 
     // Generate caches configs.
-    static clusterCaches(cluster, caches, igfss, client) {
-        return this.toSection(this.generator.clusterCaches(cluster, caches, 
igfss, client));
+    static clusterCaches(cluster, available, caches, igfss, client) {
+        return this.toSection(this.generator.clusterCaches(cluster, caches, 
igfss, available, client));
     }
 
     // Generate caches configs.
-    static clusterCheckpoint(cluster, caches) {
+    static clusterCheckpoint(cluster, available, caches) {
         return this.toSection(this.generator.clusterCheckpoint(cluster, 
caches));
     }
 

Reply via email to