You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by an...@apache.org on 2015/07/31 04:28:52 UTC

[39/41] incubator-ignite git commit: Merge branch 'ignite-843' of https://git-wip-us.apache.org/repos/asf/incubator-ignite into ignite-1121

Merge branch 'ignite-843' of https://git-wip-us.apache.org/repos/asf/incubator-ignite into ignite-1121


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

Branch: refs/heads/ignite-1121
Commit: 6b621759a2fb23f0b8ab121db2e69ff74868ea05
Parents: 89220b1 9652287
Author: Andrey <an...@gridgain.com>
Authored: Wed Jul 29 13:44:13 2015 +0700
Committer: Andrey <an...@gridgain.com>
Committed: Wed Jul 29 13:44:13 2015 +0700

----------------------------------------------------------------------
 .../control-center-web/licenses/apache-2.0.txt  |  202 +++
 .../control-center-web/src/main/js/.gitignore   |    4 +
 .../control-center-web/src/main/js/DEVNOTES.txt |   21 +
 modules/control-center-web/src/main/js/app.js   |  158 +++
 modules/control-center-web/src/main/js/bin/www  |  110 ++
 .../src/main/js/config/default.json             |   17 +
 .../src/main/js/controllers/admin-controller.js |   68 +
 .../js/controllers/cache-viewer-controller.js   |   77 ++
 .../main/js/controllers/caches-controller.js    |  349 +++++
 .../main/js/controllers/clusters-controller.js  |  308 +++++
 .../src/main/js/controllers/common-module.js    |  484 +++++++
 .../main/js/controllers/metadata-controller.js  |  709 ++++++++++
 .../src/main/js/controllers/models/caches.json  |  943 +++++++++++++
 .../main/js/controllers/models/clusters.json    |  909 +++++++++++++
 .../main/js/controllers/models/metadata.json    |  252 ++++
 .../src/main/js/controllers/models/sql.json     |    5 +
 .../src/main/js/controllers/models/summary.json |  163 +++
 .../main/js/controllers/profile-controller.js   |   51 +
 .../src/main/js/controllers/sql-controller.js   |  129 ++
 .../main/js/controllers/summary-controller.js   |  170 +++
 modules/control-center-web/src/main/js/db.js    |  370 +++++
 .../src/main/js/helpers/configuration-loader.js |   22 +
 .../src/main/js/helpers/data-structures.js      |   84 ++
 .../control-center-web/src/main/js/package.json |   50 +
 .../src/main/js/public/favicon.ico              |  Bin 0 -> 1150 bytes
 .../src/main/js/public/images/docker.png        |  Bin 0 -> 994 bytes
 .../src/main/js/public/images/java.png          |  Bin 0 -> 170 bytes
 .../src/main/js/public/images/logo.png          |  Bin 0 -> 8148 bytes
 .../src/main/js/public/images/xml.png           |  Bin 0 -> 232 bytes
 .../src/main/js/public/stylesheets/style.scss   | 1270 ++++++++++++++++++
 .../src/main/js/routes/admin.js                 |   79 ++
 .../src/main/js/routes/caches.js                |  105 ++
 .../src/main/js/routes/clusters.js              |  104 ++
 .../src/main/js/routes/generator/common.js      |  312 +++++
 .../src/main/js/routes/generator/docker.js      |   58 +
 .../src/main/js/routes/generator/java.js        |  788 +++++++++++
 .../src/main/js/routes/generator/xml.js         |  736 ++++++++++
 .../src/main/js/routes/metadata.js              |   95 ++
 .../src/main/js/routes/profile.js               |   97 ++
 .../src/main/js/routes/public.js                |  123 ++
 .../src/main/js/routes/sql.js                   |   24 +
 .../src/main/js/routes/summary.js               |  108 ++
 .../src/main/js/views/configuration/caches.jade |   74 +
 .../main/js/views/configuration/clusters.jade   |   77 ++
 .../main/js/views/configuration/metadata.jade   |  121 ++
 .../main/js/views/configuration/sidebar.jade    |   39 +
 .../main/js/views/configuration/summary.jade    |  113 ++
 .../src/main/js/views/error.jade                |   22 +
 .../src/main/js/views/includes/controls.jade    |  350 +++++
 .../src/main/js/views/includes/footer.jade      |   22 +
 .../src/main/js/views/includes/header.jade      |   39 +
 .../src/main/js/views/index.jade                |   30 +
 .../src/main/js/views/login.jade                |   55 +
 .../src/main/js/views/settings/admin.jade       |   58 +
 .../src/main/js/views/settings/profile.jade     |   58 +
 .../src/main/js/views/sql/sql.jade              |   84 ++
 .../src/main/js/views/templates/confirm.jade    |   27 +
 .../src/main/js/views/templates/copy.jade       |   31 +
 .../src/main/js/views/templates/layout.jade     |   61 +
 .../src/main/js/views/templates/select.jade     |   26 +
 .../src/main/js/views/templates/tab.jade        |   26 +
 .../web-control-center/licenses/apache-2.0.txt  |  202 ---
 .../web-control-center/src/main/js/.gitignore   |    4 -
 .../web-control-center/src/main/js/DEVNOTES.txt |   21 -
 modules/web-control-center/src/main/js/app.js   |  158 ---
 modules/web-control-center/src/main/js/bin/www  |  110 --
 .../src/main/js/config/default.json             |   17 -
 .../src/main/js/controllers/admin-controller.js |   68 -
 .../js/controllers/cache-viewer-controller.js   |   77 --
 .../main/js/controllers/caches-controller.js    |  349 -----
 .../main/js/controllers/clusters-controller.js  |  308 -----
 .../src/main/js/controllers/common-module.js    |  484 -------
 .../main/js/controllers/metadata-controller.js  |  709 ----------
 .../src/main/js/controllers/models/caches.json  |  943 -------------
 .../main/js/controllers/models/clusters.json    |  909 -------------
 .../main/js/controllers/models/metadata.json    |  252 ----
 .../src/main/js/controllers/models/sql.json     |    5 -
 .../src/main/js/controllers/models/summary.json |  163 ---
 .../main/js/controllers/profile-controller.js   |   51 -
 .../src/main/js/controllers/sql-controller.js   |  129 --
 .../main/js/controllers/summary-controller.js   |  170 ---
 modules/web-control-center/src/main/js/db.js    |  370 -----
 .../src/main/js/helpers/configuration-loader.js |   22 -
 .../src/main/js/helpers/data-structures.js      |   84 --
 .../web-control-center/src/main/js/package.json |   50 -
 .../src/main/js/public/favicon.ico              |  Bin 1150 -> 0 bytes
 .../src/main/js/public/images/docker.png        |  Bin 994 -> 0 bytes
 .../src/main/js/public/images/java.png          |  Bin 170 -> 0 bytes
 .../src/main/js/public/images/logo.png          |  Bin 8148 -> 0 bytes
 .../src/main/js/public/images/xml.png           |  Bin 232 -> 0 bytes
 .../src/main/js/public/stylesheets/style.scss   | 1270 ------------------
 .../src/main/js/routes/admin.js                 |   79 --
 .../src/main/js/routes/caches.js                |  105 --
 .../src/main/js/routes/clusters.js              |  104 --
 .../src/main/js/routes/generator/common.js      |  324 -----
 .../src/main/js/routes/generator/docker.js      |   58 -
 .../src/main/js/routes/generator/java.js        |  626 ---------
 .../src/main/js/routes/generator/xml.js         |  738 ----------
 .../src/main/js/routes/metadata.js              |   95 --
 .../src/main/js/routes/profile.js               |   97 --
 .../src/main/js/routes/public.js                |  123 --
 .../src/main/js/routes/sql.js                   |   24 -
 .../src/main/js/routes/summary.js               |  108 --
 .../src/main/js/views/configuration/caches.jade |   74 -
 .../main/js/views/configuration/clusters.jade   |   77 --
 .../main/js/views/configuration/metadata.jade   |  121 --
 .../main/js/views/configuration/sidebar.jade    |   39 -
 .../main/js/views/configuration/summary.jade    |  113 --
 .../src/main/js/views/error.jade                |   22 -
 .../src/main/js/views/includes/controls.jade    |  350 -----
 .../src/main/js/views/includes/footer.jade      |   22 -
 .../src/main/js/views/includes/header.jade      |   39 -
 .../src/main/js/views/index.jade                |   30 -
 .../src/main/js/views/login.jade                |   55 -
 .../src/main/js/views/settings/admin.jade       |   58 -
 .../src/main/js/views/settings/profile.jade     |   58 -
 .../src/main/js/views/sql/sql.jade              |   84 --
 .../src/main/js/views/templates/confirm.jade    |   27 -
 .../src/main/js/views/templates/copy.jade       |   31 -
 .../src/main/js/views/templates/layout.jade     |   61 -
 .../src/main/js/views/templates/select.jade     |   26 -
 .../src/main/js/views/templates/tab.jade        |   26 -
 122 files changed, 10867 insertions(+), 10719 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/6b621759/modules/control-center-web/src/main/js/app.js
----------------------------------------------------------------------
diff --cc modules/control-center-web/src/main/js/app.js
index 0000000,a67afc8..930c798
mode 000000,100644..100644
--- a/modules/control-center-web/src/main/js/app.js
+++ b/modules/control-center-web/src/main/js/app.js
@@@ -1,0 -1,156 +1,158 @@@
+ /*
+  * 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.
+  */
+ 
+ var flash = require('connect-flash');
+ var express = require('express');
+ var path = require('path');
+ var favicon = require('serve-favicon');
+ var logger = require('morgan');
+ var cookieParser = require('cookie-parser');
+ var bodyParser = require('body-parser');
+ var session = require('express-session');
+ var mongoStore = require('connect-mongo')(session);
+ 
+ var publicRoutes = require('./routes/public');
+ var clustersRouter = require('./routes/clusters');
+ var cachesRouter = require('./routes/caches');
+ var metadataRouter = require('./routes/metadata');
+ var summary = require('./routes/summary');
+ var adminRouter = require('./routes/admin');
+ var profileRouter = require('./routes/profile');
+ var sqlRouter = require('./routes/sql');
++var agentRouter = require('./routes/agent');
+ 
+ var passport = require('passport');
+ 
+ var db = require('./db');
+ 
+ var app = express();
+ 
+ // Views engine setup.
+ app.set('views', path.join(__dirname, 'views'));
+ app.set('view engine', 'jade');
+ 
+ // Site favicon.
+ app.use(favicon(__dirname + '/public/favicon.ico'));
+ 
+ app.use(logger('dev'));
+ 
+ app.use(bodyParser.json());
+ app.use(bodyParser.urlencoded({extended: false}));
+ 
+ app.use(require('node-sass-middleware')({
+     /* Options */
+     src: path.join(__dirname, 'public'),
+     dest: path.join(__dirname, 'public'),
+     debug: true,
+     outputStyle: 'nested'
+ }));
+ 
+ app.use(express.static(path.join(__dirname, 'public')));
+ app.use(express.static(path.join(__dirname, 'controllers')));
+ app.use(express.static(path.join(__dirname, 'helpers')));
+ 
+ app.use(cookieParser('keyboard cat'));
+ 
+ app.use(session({
+     secret: 'keyboard cat',
+     resave: false,
+     saveUninitialized: true,
+     store: new mongoStore({
+         mongooseConnection: db.mongoose.connection
+     })
+ }));
+ 
+ app.use(flash());
+ 
+ app.use(passport.initialize());
+ app.use(passport.session());
+ 
+ passport.serializeUser(db.Account.serializeUser());
+ passport.deserializeUser(db.Account.deserializeUser());
+ 
+ passport.use(db.Account.createStrategy());
+ 
+ var mustAuthenticated = function (req, res, next) {
+     req.isAuthenticated() ? next() : res.redirect('/');
+ };
+ 
+ var adminOnly = function(req, res, next) {
+     req.isAuthenticated() && req.user.admin ? next() : res.sendStatus(403);
+ };
+ 
+ app.all('/configuration/*', mustAuthenticated);
+ 
+ app.all('*', function(req, res, next) {
+     var becomeUsed = req.session.viewedUser && req.user.admin;
+ 
+     res.locals.user = becomeUsed ? req.session.viewedUser : req.user;
+     res.locals.becomeUsed = becomeUsed;
+ 
+     req.currentUserId = function() {
+         if (!req.user)
+             return null;
+ 
+         if (req.session.viewedUser && req.user.admin)
+             return req.session.viewedUser._id;
+ 
+         return req.user._id;
+     };
+ 
+     next();
+ });
+ 
+ app.use('/', publicRoutes);
+ app.use('/admin', mustAuthenticated, adminOnly, adminRouter);
+ app.use('/profile', mustAuthenticated, profileRouter);
+ 
+ app.use('/configuration/clusters', clustersRouter);
+ app.use('/configuration/caches', cachesRouter);
+ app.use('/configuration/metadata', metadataRouter);
+ app.use('/configuration/summary', summary);
+ app.use('/sql', sqlRouter);
++app.use('/agent', agentRouter);
+ 
+ // Catch 404 and forward to error handler.
+ app.use(function (req, res, next) {
+     var err = new Error('Not Found: ' + req.originalUrl);
+     err.status = 404;
+     next(err);
+ });
+ 
+ // Error handlers.
+ 
+ // Development error handler: will print stacktrace.
+ if (app.get('env') === 'development') {
+     app.use(function (err, req, res) {
+         res.status(err.status || 500);
+         res.render('error', {
+             message: err.message,
+             error: err
+         });
+     });
+ }
+ 
+ // Production error handler: no stacktraces leaked to user.
+ app.use(function (err, req, res) {
+     res.status(err.status || 500);
+     res.render('error', {
+         message: err.message,
+         error: {}
+     });
+ });
+ 
+ module.exports = app;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/6b621759/modules/control-center-web/src/main/js/bin/www
----------------------------------------------------------------------
diff --cc modules/control-center-web/src/main/js/bin/www
index 0000000,4cf0583..cbc637a
mode 000000,100644..100644
--- a/modules/control-center-web/src/main/js/bin/www
+++ b/modules/control-center-web/src/main/js/bin/www
@@@ -1,0 -1,85 +1,110 @@@
+ #!/usr/bin/env node
+ 
+ /**
+  * Module dependencies.
+  */
 -var app = require('../app');
++var http = require('http');
++var https = require('https');
+ var config = require('../helpers/configuration-loader.js');
++var app = require('../app');
++var agentManager = require('../agents/agent-manager');
++
++var fs = require('fs');
++
+ var debug = require('debug')('ignite-web-control-center:server');
 -var http = require('http');
+ 
+ /**
+  * Get port from environment and store in Express.
+  */
+ var port = normalizePort(process.env.PORT || config.get('express:port'));
+ app.set('port', port);
+ 
+ /**
+  * Create HTTP server.
+  */
+ var server = http.createServer(app);
+ 
+ /**
+  * Listen on provided port, on all network interfaces.
+  */
+ server.listen(port);
+ server.on('error', onError);
+ server.on('listening', onListening);
+ 
+ /**
++ * Start agent server.
++ */
++var agentServer;
++
++if (config.get('monitor:server:ssl')) {
++    agentServer = https.createServer({
++    key: fs.readFileSync(config.get('monitor:server:key')),
++    cert: fs.readFileSync(config.get('monitor:server:cert')),
++    passphrase: config.get('monitor:server:keyPassphrase')
++  });
++}
++else {
++  agentServer = http.createServer();
++}
++
++agentServer.listen(config.get('monitor:server:port'));
++
++agentManager.createManager(agentServer);
++
++/**
+  * Normalize a port into a number, string, or false.
+  */
+ function normalizePort(val) {
+   var port = parseInt(val, 10);
+ 
+   if (isNaN(port)) {
+     // named pipe
+     return val;
+   }
+ 
+   if (port >= 0) {
+     // port number
+     return port;
+   }
+ 
+   return false;
+ }
+ 
+ /**
+  * Event listener for HTTP server "error" event.
+  */
+ function onError(error) {
+   if (error.syscall !== 'listen') {
+     throw error;
+   }
+ 
+   var bind = typeof port === 'string'
+     ? 'Pipe ' + port
+     : 'Port ' + port;
+ 
+   // handle specific listen errors with friendly messages
+   switch (error.code) {
+     case 'EACCES':
+       console.error(bind + ' requires elevated privileges');
+       process.exit(1);
+       break;
+     case 'EADDRINUSE':
+       console.error(bind + ' is already in use');
+       process.exit(1);
+       break;
+     default:
+       throw error;
+   }
+ }
+ 
+ /**
+  * Event listener for HTTP server "listening" event.
+  */
+ function onListening() {
+   var addr = server.address();
+   var bind = typeof addr === 'string'
+     ? 'pipe ' + addr
+     : 'port ' + addr.port;
+ 
+   debug('Listening on ' + bind);
+ }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/6b621759/modules/control-center-web/src/main/js/config/default.json
----------------------------------------------------------------------
diff --cc modules/control-center-web/src/main/js/config/default.json
index 0000000,72dbd4e..f7f7a02
mode 000000,100644..100644
--- a/modules/control-center-web/src/main/js/config/default.json
+++ b/modules/control-center-web/src/main/js/config/default.json
@@@ -1,0 -1,8 +1,17 @@@
+ {
+     "express": {
+         "port": 3000
+     },
+     "mongoDB": {
+         "url": "mongodb://localhost/web-control-center"
++    },
++    "monitor": {
++        "server": {
++            "port": 3001,
++            "ssl": true,
++            "key": "keys/test.key",
++            "cert": "keys/test.crt",
++            "keyPassphrase": "password"
++        }
+     }
 -}
++}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/6b621759/modules/control-center-web/src/main/js/controllers/sql-controller.js
----------------------------------------------------------------------
diff --cc modules/control-center-web/src/main/js/controllers/sql-controller.js
index 0000000,12772c6..b4b4335
mode 000000,100644..100644
--- a/modules/control-center-web/src/main/js/controllers/sql-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/sql-controller.js
@@@ -1,0 -1,84 +1,129 @@@
+ /*
+  * 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.
+  */
+ 
 -var demoResults = [
 -    {
 -        id: 256,
 -        firstName: 'Ivan',
 -        lastName: 'Ivanov'
 -    },
 -    {
 -        id: 384,
 -        firstName: 'Sergey',
 -        lastName: 'Petrov'
 -    },
 -    {
 -        id: 923,
 -        firstName: 'Andrey',
 -        lastName: 'Sidorov'
 -    }
 -];
 -
 -var demoCaches = [{_id: '1', name: 'Users', mode: 'LOCAL'}, {_id: '2', name: 'Organizations', mode: 'REPLICATED'}, {_id: '3', name: 'Cities', mode: 'PARTITIONED'}];
 -
 -
 -
+ controlCenterModule.controller('sqlController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
+     $scope.joinTip = $common.joinTip;
+ 
+     $scope.pageSizes = [50, 100, 200, 400, 800, 1000];
+ 
 -    $scope.tabs = [
 -        {
 -            query: "SELECT u.id, u.firstName, u.lastName FROM User u WHERE u.name LIKE 'aaaa'",
 -            cols: Object.keys(demoResults[0]),
 -            page: 1,
 -            hasMore: true,
 -            total: 0,
 -            rows: demoResults
 -        },
 -        {query: "SELECT * FROM Organization"}
++    $scope.modes = [
++        {value: 'PARTITIONED', label: 'PARTITIONED'},
++        {value: 'REPLICATED', label: 'REPLICATED'},
++        {value: 'LOCAL', label: 'LOCAL'}
+     ];
+ 
++    $scope.tabs = [];
++
+     $scope.addTab = function() {
 -        console.log('addTab');
++        var tab = {query: "", pageSize: $scope.pageSizes[0]};
++
++        if ($scope.caches.length > 0)
++            tab.selectedItem = $scope.caches[0];
+ 
 -        $scope.tabs.push({query: "SELECT "});
++        $scope.tabs.push(tab);
+     };
+ 
+     $scope.removeTab = function(idx) {
 -        console.log('removeTab');
 -
+         $scope.tabs.splice(idx, 1);
+     };
+ 
 -    $scope.modes = [
 -        {value: 'PARTITIONED', label: 'PARTITIONED'},
 -        {value: 'REPLICATED', label: 'REPLICATED'},
 -        {value: 'LOCAL', label: 'LOCAL'}
 -    ];
 -
+     $http.get('/models/sql.json')
+         .success(function (data) {
+             $scope.screenTip = data.screenTip;
+         })
+         .error(function (errMsg) {
+             $common.showError(errMsg);
+         });
+ 
 -    $scope.caches = demoCaches;
++    $scope.caches = [];
++
++    $http.post('/agent/topology')
++        .success(function (clusters) {
++            var node = clusters[0];
++
++            $scope.caches = node.caches;
++
++            if ($scope.tabs.length == 0)
++                $scope.addTab();
++        })
++        .error(function (errMsg) {
++            $common.showError(errMsg);
++        });
++
++    $scope.execute = function(tab) {
++        $http.post('/agent/query', {query: tab.query, pageSize: tab.pageSize, cacheName: tab.selectedItem.name})
++            .success(function (res) {
++                tab.meta = [];
++
++                if (res.meta)
++                    tab.meta = res.meta;
++
++                tab.page = 1;
++
++                tab.total = 0;
++
++                tab.queryId = res.queryId;
++
++                tab.rows = res.rows;
++            })
++            .error(function (errMsg) {
++                $common.showError(errMsg);
++            });
++    };
++
++    $scope.explain = function(tab) {
++        $http.post('/agent/query', {query: 'EXPLAIN ' + tab.query, pageSize: tab.pageSize, cacheName: tab.selectedItem.name})
++            .success(function (res) {
++                tab.meta = [];
++
++                if (res.meta)
++                    tab.meta = res.meta;
++
++                tab.page = 1;
++
++                tab.total = 0;
++
++                tab.queryId = res.queryId;
++
++                tab.rows = res.rows;
++            })
++            .error(function (errMsg) {
++                $common.showError(errMsg);
++            });
++    };
++
++    $scope.nextPage = function(tab) {
++        $http.post('/agent/next_page', {queryId: tab.queryId, pageSize: tab.pageSize, cacheName: tab.selectedItem.name})
++            .success(function (res) {
++                tab.page++;
++
++                tab.total += tab.rows.length;
++
++                tab.rows = res.rows;
++
++                if (res.last)
++                    delete tab.queryId;
++            })
++            .error(function (errMsg) {
++                $common.showError(errMsg);
++            });
++    };
++
++    $scope.getter = function (value) {
++        return value;
++    }
+ }]);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/6b621759/modules/control-center-web/src/main/js/package.json
----------------------------------------------------------------------
diff --cc modules/control-center-web/src/main/js/package.json
index 0000000,fd82196..f7926cf
mode 000000,100644..100644
--- a/modules/control-center-web/src/main/js/package.json
+++ b/modules/control-center-web/src/main/js/package.json
@@@ -1,0 -1,49 +1,50 @@@
+ {
+   "name": "ignite-web-control-center",
+   "version": "1.0.0",
+   "description": "Web application for configuration, monitoring Ignite Cluster",
+   "private": true,
+   "scripts": {
+     "start": "node ./bin/www"
+   },
+   "author": "",
+   "contributors": [
+     {
+       "name": "",
+       "email": ""
+     }
+   ],
+   "license": "Apache-2.0",
+   "keywords": "grid",
+   "homepage": "https://ignite.incubator.apache.org/",
+   "engines": {
+     "node": ">=0.12.4"
+   },
+   "dependencies": {
+     "angular-ui-ace": "^0.2.3",
+     "archiver": "^0.14.4",
+     "body-parser": "~1.12.0",
+     "connect-flash": "^0.1.1",
+     "connect-mongo": "^0.8.1",
+     "cookie-parser": "~1.3.4",
+     "debug": "~2.1.1",
+     "express": "~4.12.2",
+     "express-session": "^1.11.1",
+     "jade": "~1.9.2",
+     "lodash": "3.10.0",
+     "mongoose": "^4.0.2",
+     "mongoose-deep-populate": "1.1.0",
+     "nconf": "^0.7.1",
+     "node-sass-middleware": "^0.9.0",
+     "passport": "^0.2.1",
+     "passport-local": "^1.0.0",
+     "passport-local-mongoose": "^1.0.0",
 -    "serve-favicon": "~2.2.0"
++    "serve-favicon": "~2.2.0",
++    "ws": "~0.7.2"
+   },
+   "devDependencies": {
+     "morgan": "~1.5.1",
+     "supertest": "^1.0.1",
+     "mocha": "~2.0.1",
+     "should": "~3.1.3"
+   }
+ }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/6b621759/modules/control-center-web/src/main/js/views/sql/sql.jade
----------------------------------------------------------------------
diff --cc modules/control-center-web/src/main/js/views/sql/sql.jade
index 0000000,97d34de..2ce6958
mode 000000,100644..100644
--- a/modules/control-center-web/src/main/js/views/sql/sql.jade
+++ b/modules/control-center-web/src/main/js/views/sql/sql.jade
@@@ -1,0 -1,85 +1,84 @@@
+ //-
+     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.
+ extends ../templates/layout
+ 
+ append scripts
+     script(src='/sql-controller.js')
+ 
+     script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/theme-chrome.js')
+     script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-sql.js')
+     script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ext-language_tools.js')
+ 
+ block container
+     .row
+         .col-sm-12
+             .docs-content
+                 .docs-header
+                     h1 Connect to Ignite and Execute SQL Queries
+                     hr
+                 .docs-body(ng-controller='sqlController')
+                     - var tab = 'tabs[tabs.activeIdx]'
+ 
+                     .block-callout-parent.block-callout-border.margin-bottom-dflt
+                         .block-callout
+                             p(ng-bind-html='joinTip(screenTip)')
+                     .tabs-below(bs-tabs bs-active-pane='tabs.activeIdx' data-template='/tab')
+                         div(ng-repeat='tab in tabs' title='Query' bs-pane)
+                     .row
+                         .col-sm-9(style='border-right: 1px solid #eee')
+                             div(style='height: 200px' ui-ace='{ theme: "chrome", mode: "sql",' +
+                                 'require: ["ace/ext/language_tools"],' +
+                                 'rendererOptions: {showPrintMargin: false, highlightGutterLine: false, fontSize: 14},' +
+                                 'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}' ng-model='#{tab}.query')
+                         .col-sm-3
+                             div(ng-hide='caches.length == 0' style='margin-top: 0.65em')
+                                 lable.labelHeader Caches:
+                                 table.links(st-table='caches')
+                                     tbody
 -                                        tr(ng-repeat='row in caches track by row._id')
 -                                            td.col-sm-6(ng-class='{active: row._id == #{tab}.selectedItem._id}')
 -                                                a(ng-click='#{tab}.selectedItem = row') {{$index + 1}}) {{row.name}}, {{row.mode | displayValue:modes:'Cache mode not set'}}
++                                        tr(ng-repeat='row in caches track by row.name')
++                                            td.col-sm-6(ng-class='{active: row.name == #{tab}.selectedItem.name}')
++                                                a(ng-click='#{tab}.selectedItem = row') {{$index + 1}}) {{::row.name}}, {{::row.mode}}
+                     hr(style='margin: 0')
+                     .settings-row
+                         label Page Size:&nbsp;
 -                        button.btn.btn-default.base-control(ng-init='pageSize = pageSizes[0]' ng-model='pageSize' bs-options='item for item in pageSizes' bs-select)
++                        button.btn.btn-default.base-control(ng-model='#{tab}.pageSize' bs-options='item for item in pageSizes' bs-select)
+                     .settings-row
 -                        button.btn.btn-primary(ng-click='') Explain
 -                        button.btn.btn-primary(ng-click='') Execute
 -                        button.btn.btn-primary(ng-click='' disabled) Scan
++                        button.btn.btn-primary(ng-click='explain(#{tab})') Explain
++                        button.btn.btn-primary(ng-click='execute(#{tab})') Execute
++                        button.btn.btn-primary(ng-click='scan(#{tab})' disabled) Scan
+ 
+                     div(ng-show='#{tab}.rows.length > 0' style='margin-top: 0.65em')
+                         hr
+                         div
 -                            table.table.table-striped.col-sm-12.sql-results(st-table='rows' st-safe-src='#{tab}.rows')
++                            table.table.table-striped.col-sm-12.sql-results(st-table='displayedCollection' st-safe-src='#{tab}.rows')
+                                 thead
+                                     tr(style='border-size: 0')
 -                                        td(colspan='{{#{tab}.cols.length}}')
++                                        td(colspan='{{#{tab}.meta.length}}')
+                                             .col-sm-8
+                                                 lable Page #:&nbsp;
+                                                 b {{#{tab}.page}}&nbsp;&nbsp;&nbsp;
+                                                 | Results:&nbsp;
+                                                 b {{#{tab}.rows.length + #{tab}.total}}
+                                             .col-sm-4
 -                                                button.btn.btn-primary.fieldButton(ng-click='') Next page
 -                                                .input-tip
 -                                                    input.form-control(type='text' st-search='' placeholder='Filter...')
 -
++                                                button.btn.btn-primary.fieldButton(ng-click='nextPage(#{tab})' ng-disabled='!#{tab}.queryId') Next page
++                                                //.input-tip
++                                                //    input.form-control(st-search placeholder='Filter...' type='search')
+                                     tr
 -                                        th(ng-repeat='column in #{tab}.cols' st-sort='{{column}}') {{column}}
++                                        th(ng-repeat='col in #{tab}.meta track by $index' st-sort='getter' data-ng-bind='::col.fieldName' bs-tooltip='col.schemaName + "." + col.typeName + "." + col.fieldName')
+                                 tbody
+                                     //tr
+                                     //    td(colspan='{{#{tab}.cols.length}}')
+                                     //        .loading-indicator
 -                                    tr(ng-repeat='row in rows')
 -                                        td(ng-repeat='column in #{tab}.cols') {{row[column]}}
++                                    tr(ng-repeat='row in displayedCollection track by $index')
++                                        td(ng-repeat='val in row track by $index') {{ val }}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/6b621759/modules/control-center-web/src/main/js/views/templates/layout.jade
----------------------------------------------------------------------
diff --cc modules/control-center-web/src/main/js/views/templates/layout.jade
index 0000000,71d8936..8e92edb
mode 000000,100644..100644
--- a/modules/control-center-web/src/main/js/views/templates/layout.jade
+++ b/modules/control-center-web/src/main/js/views/templates/layout.jade
@@@ -1,0 -1,61 +1,61 @@@
+ //-
+     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.
+ 
+ doctype html
+ html(ng-app='ignite-web-control-center' ng-init='user = #{JSON.stringify(user)}; becomeUsed = #{becomeUsed}')
+     head
+         title= title
+ 
+         block css
+             // Bootstrap
+             link(rel='stylesheet', href='//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.css')
+ 
+             // Font Awesome Icons
+             link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.css')
+ 
+             // Font
+             link(rel='stylesheet', href='//fonts.googleapis.com/css?family=Roboto+Slab:700:serif|Roboto+Slab:400:serif')
+ 
+             link(rel='stylesheet', href='/stylesheets/style.css')
+ 
+         block scripts
+             script(src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js')
+ 
+             script(src='//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js')
+ 
+             script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js')
+             script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular-sanitize.js')
+             script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.0/angular-strap.js')
+             script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.0/angular-strap.tpl.min.js')
+ 
 -            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.0.3/smart-table.js')
++            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.1.1/smart-table.js')
+ 
+             script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ace.js')
+             script(src='//angular-ui.github.io/ui-ace/dist/ui-ace.min.js')
+ 
+             script(src='/common-module.js')
+             script(src='/data-structures.js')
+ 
+     body.theme-line.body-overlap.greedy
+         .wrapper
+             include ../includes/header
+ 
+             block main-container
+                 .container.body-container
+                     .main-content
+                         block container
+ 
+             include ../includes/footer