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:50 UTC
[37/41] incubator-ignite git commit: # ignite-843 Rename
# ignite-843 Rename
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/96522874
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/96522874
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/96522874
Branch: refs/heads/ignite-1121
Commit: 96522874ebc7809a8f4256ce2e4aa681c2b9241c
Parents: cb2ecb5
Author: Andrey <an...@gridgain.com>
Authored: Wed Jul 29 10:39:34 2015 +0700
Committer: Andrey <an...@gridgain.com>
Committed: Wed Jul 29 10:39:34 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 | 156 +++
modules/control-center-web/src/main/js/bin/www | 85 ++
.../src/main/js/config/default.json | 8 +
.../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 | 84 ++
.../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 | 49 +
.../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 | 85 ++
.../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 | 156 ---
modules/web-control-center/src/main/js/bin/www | 85 --
.../src/main/js/config/default.json | 8 -
.../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 | 84 --
.../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 | 49 -
.../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 | 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 | 85 --
.../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, 10786 insertions(+), 10786 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/licenses/apache-2.0.txt
----------------------------------------------------------------------
diff --git a/modules/control-center-web/licenses/apache-2.0.txt b/modules/control-center-web/licenses/apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/control-center-web/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/.gitignore
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/.gitignore b/modules/control-center-web/src/main/js/.gitignore
new file mode 100644
index 0000000..65f2596
--- /dev/null
+++ b/modules/control-center-web/src/main/js/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+*.idea
+*.log
+*.css
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/DEVNOTES.txt
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/DEVNOTES.txt b/modules/control-center-web/src/main/js/DEVNOTES.txt
new file mode 100644
index 0000000..e8c558c
--- /dev/null
+++ b/modules/control-center-web/src/main/js/DEVNOTES.txt
@@ -0,0 +1,21 @@
+Ignite Web Control Center Instructions
+======================================
+
+How to deploy:
+
+1. Install locally NodeJS using installer from site https://nodejs.org for your OS.
+2. Install locally MongoDB folow instructions from site http://docs.mongodb.org/manual/installation
+3. Checkout ignite-843 branch.
+4. Change directory '$IGNITE_HOME/modules/web-control-center/src/main/js'.
+5. Run "npm install" in terminal for download all dependencies.
+
+Steps 1 - 5 should be executed once.
+
+How to run:
+
+1. Run MongoDB.
+ 1.1 In terminal change dir to $MONGO_ISNTALL_DIR/server/3.0/bin.
+ 1.2 Run "mongod".
+2. In new terminal change directory '$IGNITE_HOME/modules/web-control-center/src/main/js'.
+3. Start application by executing "npm start".
+4. In browser open: http://localhost:3000
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/app.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app.js b/modules/control-center-web/src/main/js/app.js
new file mode 100644
index 0000000..a67afc8
--- /dev/null
+++ b/modules/control-center-web/src/main/js/app.js
@@ -0,0 +1,156 @@
+/*
+ * 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 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);
+
+// 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/96522874/modules/control-center-web/src/main/js/bin/www
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/bin/www b/modules/control-center-web/src/main/js/bin/www
new file mode 100644
index 0000000..4cf0583
--- /dev/null
+++ b/modules/control-center-web/src/main/js/bin/www
@@ -0,0 +1,85 @@
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+var app = require('../app');
+var config = require('../helpers/configuration-loader.js');
+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);
+
+/**
+ * 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/96522874/modules/control-center-web/src/main/js/config/default.json
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/config/default.json b/modules/control-center-web/src/main/js/config/default.json
new file mode 100644
index 0000000..72dbd4e
--- /dev/null
+++ b/modules/control-center-web/src/main/js/config/default.json
@@ -0,0 +1,8 @@
+{
+ "express": {
+ "port": 3000
+ },
+ "mongoDB": {
+ "url": "mongodb://localhost/web-control-center"
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/controllers/admin-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/admin-controller.js b/modules/control-center-web/src/main/js/controllers/admin-controller.js
new file mode 100644
index 0000000..09490fe
--- /dev/null
+++ b/modules/control-center-web/src/main/js/controllers/admin-controller.js
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('adminController', ['$scope', '$http', '$common', '$confirm', function ($scope, $http, $common, $confirm) {
+ $scope.users = null;
+
+ function reload() {
+ $http.post('admin/list')
+ .success(function (data) {
+ $scope.users = data;
+ })
+ .error(function (errMsg) {
+ $common.showError($common.errorMessage(errMsg));
+ });
+ }
+
+ reload();
+
+ $scope.removeUser = function (user) {
+ $confirm.show('Are you sure you want to remove user: "' + user.username + '"?').then(function () {
+ $http.post('admin/remove', {userId: user._id}).success(
+ function () {
+ var i = _.findIndex($scope.users, function (u) {
+ return u._id == user._id;
+ });
+
+ if (i >= 0)
+ $scope.users.splice(i, 1);
+
+ $common.showInfo('User has been removed: "' + user.username + '"');
+ }).error(function (errMsg) {
+ $common.showError('Failed to remove user: "' + $common.errorMessage(errMsg) + '"');
+ });
+ });
+ };
+
+ $scope.toggleAdmin = function (user) {
+ if (user.adminChanging)
+ return;
+
+ user.adminChanging = true;
+
+ $http.post('admin/save', {userId: user._id, adminFlag: user.admin}).success(
+ function () {
+ $common.showInfo('Admin right was successfully toggled for user: "' + user.username + '"');
+
+ user.adminChanging = false;
+ }).error(function (errMsg) {
+ $common.showError('Failed to toggle admin right for user: "' + $common.errorMessage(errMsg) + '"');
+
+ user.adminChanging = false;
+ });
+ }
+}]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/controllers/cache-viewer-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/cache-viewer-controller.js b/modules/control-center-web/src/main/js/controllers/cache-viewer-controller.js
new file mode 100644
index 0000000..6e0c130
--- /dev/null
+++ b/modules/control-center-web/src/main/js/controllers/cache-viewer-controller.js
@@ -0,0 +1,77 @@
+/*
+ * 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,
+ s: 'com.foo.User@3213',
+ fields: {
+ id: 256,
+ firstName: 'Ivan',
+ lastName: 'Ivanov',
+ old: 23
+ }
+ },
+
+ {
+ id: 384,
+ s: 'com.foo.User@23214',
+ fields: {
+ id: 384,
+ firstName: 'Sergey',
+ lastName: 'Petrov',
+ old: 28
+ }
+ },
+
+ {
+ id: 923,
+ s: 'com.foo.User@93494',
+ fields: {
+ id: 923,
+ firstName: 'Andrey',
+ lastName: 'Sidorov',
+ old: 28
+ }
+ }
+];
+
+var demoCaches = ['Users', 'Organizations', 'Cities'];
+
+controlCenterModule.controller('cacheViewerController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
+ $scope.results = demoResults;
+
+ $scope.caches = demoCaches;
+
+ $scope.defCache = $scope.caches.length > 0 ? $scope.caches[0] : null;
+
+ var sqlEditor = ace.edit('querySql');
+
+ sqlEditor.setOptions({
+ highlightActiveLine: false,
+ showPrintMargin: false,
+ showGutter: true,
+ theme: "ace/theme/chrome",
+ mode: "ace/mode/sql",
+ fontSize: 14
+ });
+
+ sqlEditor.setValue("select u.id from User u where u.name like 'aaaa';");
+
+ sqlEditor.selection.clearSelection()
+
+}]);
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/caches-controller.js b/modules/control-center-web/src/main/js/controllers/caches-controller.js
new file mode 100644
index 0000000..e995233
--- /dev/null
+++ b/modules/control-center-web/src/main/js/controllers/caches-controller.js
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('cachesController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
+ $scope.joinTip = $common.joinTip;
+ $scope.getModel = $common.getModel;
+ $scope.javaBuildInTypes = $common.javaBuildInTypes;
+
+ $scope.tableReset = $table.tableReset;
+ $scope.tableNewItem = $table.tableNewItem;
+ $scope.tableNewItemActive = $table.tableNewItemActive;
+ $scope.tableEditing = $table.tableEditing;
+ $scope.tableStartEdit = $table.tableStartEdit;
+ $scope.tableRemove = $table.tableRemove;
+
+ $scope.tableSimpleSave = $table.tableSimpleSave;
+ $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
+ $scope.tableSimpleUp = $table.tableSimpleUp;
+ $scope.tableSimpleDown = $table.tableSimpleDown;
+ $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
+
+ $scope.tablePairSave = $table.tablePairSave;
+ $scope.tablePairSaveVisible = $table.tablePairSaveVisible;
+
+ $scope.atomicities = [
+ {value: 'ATOMIC', label: 'ATOMIC'},
+ {value: 'TRANSACTIONAL', label: 'TRANSACTIONAL'}
+ ];
+
+ $scope.modes = [
+ {value: 'PARTITIONED', label: 'PARTITIONED'},
+ {value: 'REPLICATED', label: 'REPLICATED'},
+ {value: 'LOCAL', label: 'LOCAL'}
+ ];
+
+ $scope.atomicWriteOrderModes = [
+ {value: 'CLOCK', label: 'CLOCK'},
+ {value: 'PRIMARY', label: 'PRIMARY'}
+ ];
+
+ $scope.memoryModes = [
+ {value: 'ONHEAP_TIERED', label: 'ONHEAP_TIERED'},
+ {value: 'OFFHEAP_TIERED', label: 'OFFHEAP_TIERED'},
+ {value: 'OFFHEAP_VALUES', label: 'OFFHEAP_VALUES'}
+ ];
+
+ $scope.evictionPolicies = [
+ {value: 'LRU', label: 'LRU'},
+ {value: 'RND', label: 'Random'},
+ {value: 'FIFO', label: 'FIFO'},
+ {value: 'SORTED', label: 'Sorted'},
+ {value: undefined, label: 'Not set'}
+ ];
+
+ $scope.rebalanceModes = [
+ {value: 'SYNC', label: 'SYNC'},
+ {value: 'ASYNC', label: 'ASYNC'},
+ {value: 'NONE', label: 'NONE'}
+ ];
+
+ $scope.cacheStoreFactories = [
+ {value: 'CacheJdbcPojoStoreFactory', label: 'JDBC POJO store factory'},
+ {value: 'CacheJdbcBlobStoreFactory', label: 'JDBC BLOB store factory'},
+ {value: 'CacheHibernateBlobStoreFactory', label: 'Hibernate BLOB store factory'},
+ {value: undefined, label: 'Not set'}
+ ];
+
+ $scope.cacheStoreJdbcDialects = [
+ {value: 'Oracle', label: 'Oracle'},
+ {value: 'DB2', label: 'IBM DB2'},
+ {value: 'SQLServer', label: 'Microsoft SQL Server'},
+ {value: 'MySQL', label: 'My SQL'},
+ {value: 'PostgreSQL', label: 'Postgre SQL'},
+ {value: 'H2', label: 'H2 database'}
+ ];
+
+ $scope.general = [];
+ $scope.advanced = [];
+
+ $http.get('/models/caches.json')
+ .success(function (data) {
+ $scope.screenTip = data.screenTip;
+ $scope.general = data.general;
+ $scope.advanced = data.advanced;
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+
+ $scope.caches = [];
+ $scope.queryMetadata = [];
+ $scope.storeMetadata = [];
+
+ $scope.required = function (field) {
+ var model = $common.isDefined(field.path) ? field.path + '.' + field.model : field.model;
+
+ var backupItem = $scope.backupItem;
+
+ var memoryMode = backupItem.memoryMode;
+
+ var onHeapTired = memoryMode == 'ONHEAP_TIERED';
+ var offHeapTired = memoryMode == 'OFFHEAP_TIERED';
+
+ var offHeapMaxMemory = backupItem.offHeapMaxMemory;
+
+ if (model == 'offHeapMaxMemory' && offHeapTired)
+ return true;
+
+ if (model == 'evictionPolicy.kind' && onHeapTired)
+ return backupItem.swapEnabled || ($common.isDefined(offHeapMaxMemory) && offHeapMaxMemory >= 0);
+
+ return false;
+ };
+
+ $scope.tableSimpleValid = function (item, field, fx, index) {
+ var model = item[field.model];
+
+ if ($common.isDefined(model)) {
+ var idx = _.indexOf(model, fx);
+
+ // Found itself.
+ if (index >= 0 && index == idx)
+ return true;
+
+ // Found duplicate.
+ if (idx >= 0) {
+ $common.showError('SQL function such class name already exists!');
+
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ $scope.tablePairValid = function (item, field, keyCls, valCls, index) {
+ var model = item[field.model];
+
+ if ($common.isDefined(model)) {
+ var idx = _.findIndex(model, function (pair) {
+ return pair.keyClass == keyCls
+ });
+
+ // Found itself.
+ if (index >= 0 && index == idx)
+ return true;
+
+ // Found duplicate.
+ if (idx >= 0) {
+ $common.showError('Indexed type with such key class already exists!');
+
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ // When landing on the page, get caches and show them.
+ $http.post('caches/list')
+ .success(function (data) {
+ $scope.spaces = data.spaces;
+ $scope.caches = data.caches;
+
+ _.forEach(data.metadatas, function (meta) {
+ var kind = meta.kind;
+
+ if (kind == 'query' || kind == 'both')
+ $scope.queryMetadata.push(meta);
+
+ if (kind == 'store' || kind == 'both')
+ $scope.storeMetadata.push(meta);
+ });
+
+ var restoredItem = angular.fromJson(sessionStorage.cacheBackupItem);
+
+ if (restoredItem) {
+ if (restoredItem._id) {
+ var idx = _.findIndex($scope.caches, function (cache) {
+ return cache._id == restoredItem._id;
+ });
+
+ if (idx >= 0) {
+ $scope.selectedItem = $scope.caches[idx];
+ $scope.backupItem = restoredItem;
+ }
+ else
+ sessionStorage.removeItem('cacheBackupItem');
+ }
+ else
+ $scope.backupItem = restoredItem;
+ }
+ else if ($scope.caches.length > 0)
+ $scope.selectItem($scope.caches[0]);
+
+ $scope.$watch('backupItem', function (val) {
+ if (val)
+ sessionStorage.cacheBackupItem = angular.toJson(val);
+ }, true);
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+
+ $scope.selectItem = function (item) {
+ $table.tableReset();
+
+ $scope.selectedItem = item;
+ $scope.backupItem = angular.copy(item);
+ };
+
+ // Add new cache.
+ $scope.createItem = function () {
+ $table.tableReset();
+
+ $scope.backupItem = {mode: 'PARTITIONED', atomicityMode: 'ATOMIC', readFromBackup: true, copyOnRead: true};
+ $scope.backupItem.queryMetadata = [];
+ $scope.backupItem.spaceMetadata = [];
+ $scope.backupItem.space = $scope.spaces[0]._id;
+ };
+
+ // Check cache logical consistency.
+ function validate(item) {
+ var cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
+
+ if (cacheStoreFactorySelected && !(item.readThrough || item.writeThrough)) {
+ $common.showError('Store is configured but read/write through are not enabled!');
+
+ return false;
+ }
+
+ if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected) {
+ $common.showError('Read / write through are enabled but store is not configured!');
+
+ return false;
+ }
+
+ if (item.writeBehindEnabled && !cacheStoreFactorySelected) {
+ $common.showError('Write behind enabled but store is not configured!');
+
+ return false;
+ }
+
+ return true;
+ }
+
+ // Save cache into database.
+ function save(item) {
+ $http.post('caches/save', item)
+ .success(function (_id) {
+ var idx = _.findIndex($scope.caches, function (cache) {
+ return cache._id == _id;
+ });
+
+ if (idx >= 0)
+ angular.extend($scope.caches[idx], item);
+ else {
+ item._id = _id;
+
+ $scope.caches.push(item);
+ }
+
+ $scope.selectItem(item);
+
+ $common.showInfo('Cache "' + item.name + '" saved.');
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+ }
+
+ // Save cache.
+ $scope.saveItem = function () {
+ $table.tableReset();
+
+ var item = $scope.backupItem;
+
+ if (validate(item))
+ save(item);
+ };
+
+ // Save cache with new name.
+ $scope.saveItemAs = function () {
+ $table.tableReset();
+
+ if (validate($scope.backupItem))
+ $copy.show($scope.backupItem.name).then(function (newName) {
+ var item = angular.copy($scope.backupItem);
+
+ item._id = undefined;
+ item.name = newName;
+
+ save(item);
+ });
+ };
+
+ // Remove cache from db.
+ $scope.removeItem = function () {
+ $table.tableReset();
+
+ var selectedItem = $scope.selectedItem;
+
+ $confirm.show('Are you sure you want to remove cache: "' + selectedItem.name + '"?').then(
+ function () {
+ var _id = selectedItem._id;
+
+ $http.post('caches/remove', {_id: _id})
+ .success(function () {
+ $common.showInfo('Cache has been removed: ' + selectedItem.name);
+
+ var caches = $scope.caches;
+
+ var idx = _.findIndex(caches, function (cache) {
+ return cache._id == _id;
+ });
+
+ if (idx >= 0) {
+ caches.splice(idx, 1);
+
+ if (caches.length > 0)
+ $scope.selectItem(caches[0]);
+ else {
+ $scope.selectedItem = undefined;
+ $scope.backupItem = undefined;
+ }
+ }
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+ }
+ );
+ };
+ }]
+);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/clusters-controller.js b/modules/control-center-web/src/main/js/controllers/clusters-controller.js
new file mode 100644
index 0000000..0b18868
--- /dev/null
+++ b/modules/control-center-web/src/main/js/controllers/clusters-controller.js
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('clustersController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
+ $scope.joinTip = $common.joinTip;
+ $scope.getModel = $common.getModel;
+
+ $scope.tableReset = $table.tableReset;
+ $scope.tableNewItem = $table.tableNewItem;
+ $scope.tableNewItemActive = $table.tableNewItemActive;
+ $scope.tableEditing = $table.tableEditing;
+ $scope.tableStartEdit = $table.tableStartEdit;
+ $scope.tableRemove = $table.tableRemove;
+
+ $scope.tableSimpleSave = $table.tableSimpleSave;
+ $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
+ $scope.tableSimpleUp = $table.tableSimpleUp;
+ $scope.tableSimpleDown = $table.tableSimpleDown;
+ $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
+
+ $scope.templates = [
+ {value: {discovery: {kind: 'Multicast', Vm: {addresses: ['127.0.0.1:47500..47510']}, Multicast: {}}},label: 'multicast'},
+ {value: {discovery: {kind: 'Vm', Vm: {addresses: ['127.0.0.1:47500..47510']}}}, label: 'local'}
+ ];
+
+ $scope.discoveries = [
+ {value: 'Vm', label: 'static IPs'},
+ {value: 'Multicast', label: 'multicast'},
+ {value: 'S3', label: 'AWS S3'},
+ {value: 'Cloud', label: 'apache jclouds'},
+ {value: 'GoogleStorage', label: 'google cloud storage'},
+ {value: 'Jdbc', label: 'JDBC'},
+ {value: 'SharedFs', label: 'shared filesystem'}
+ ];
+
+ $scope.swapSpaceSpis = [
+ {value: 'FileSwapSpaceSpi', label: 'File-based swap'},
+ {value: undefined, label: 'Not set'}
+ ];
+
+ $scope.events = [];
+
+ for (var eventGroupName in eventGroups) {
+ if (eventGroups.hasOwnProperty(eventGroupName)) {
+ $scope.events.push({value: eventGroupName, label: eventGroupName});
+ }
+ }
+
+ $scope.cacheModes = [
+ {value: 'LOCAL', label: 'LOCAL'},
+ {value: 'REPLICATED', label: 'REPLICATED'},
+ {value: 'PARTITIONED', label: 'PARTITIONED'}
+ ];
+
+ $scope.deploymentModes = [
+ {value: 'PRIVATE', label: 'PRIVATE'},
+ {value: 'ISOLATED', label: 'ISOLATED'},
+ {value: 'SHARED', label: 'SHARED'},
+ {value: 'CONTINUOUS', label: 'CONTINUOUS'}
+ ];
+
+ $scope.transactionConcurrency = [
+ {value: 'OPTIMISTIC', label: 'OPTIMISTIC'},
+ {value: 'PESSIMISTIC', label: 'PESSIMISTIC'}
+ ];
+
+ $scope.transactionIsolation = [
+ {value: 'READ_COMMITTED', label: 'READ_COMMITTED'},
+ {value: 'REPEATABLE_READ', label: 'REPEATABLE_READ'},
+ {value: 'SERIALIZABLE', label: 'SERIALIZABLE'}
+ ];
+
+ $scope.segmentationPolicy = [
+ {value: 'RESTART_JVM', label: 'RESTART_JVM'},
+ {value: 'STOP', label: 'STOP'},
+ {value: 'NOOP', label: 'NOOP'}
+ ];
+
+ $scope.marshallers = [
+ {value: 'OptimizedMarshaller', label: 'OptimizedMarshaller'},
+ {value: 'JdkMarshaller', label: 'JdkMarshaller'}
+ ];
+
+ $scope.tableSimpleValid = function (item, field, val, index) {
+ var model = $common.getModel(item, field)[field.model];
+
+ if ($common.isDefined(model)) {
+ var idx = _.indexOf(model, val);
+
+ // Found itself.
+ if (index >= 0 && index == idx)
+ return true;
+
+ // Found duplicate.
+ if (idx >= 0) {
+ var msg = 'Such IP address already exists!';
+
+ if (field.model == 'regions')
+ msg = 'Such region already exists!';
+ if (field.model == 'zones')
+ msg = 'Such zone already exists!';
+
+ $common.showError(msg);
+
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ $scope.clusters = [];
+
+ $http.get('/models/clusters.json')
+ .success(function (data) {
+ $scope.screenTip = data.screenTip;
+ $scope.templateTip = data.templateTip;
+
+ $scope.general = data.general;
+ $scope.advanced = data.advanced;
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+
+ // When landing on the page, get clusters and show them.
+ $http.post('clusters/list')
+ .success(function (data) {
+ $scope.caches = data.caches;
+ $scope.spaces = data.spaces;
+ $scope.clusters = data.clusters;
+
+ var restoredItem = angular.fromJson(sessionStorage.clusterBackupItem);
+
+ if (restoredItem) {
+ if (restoredItem._id) {
+ var idx = _.findIndex($scope.clusters, function (cluster) {
+ return cluster._id == restoredItem._id;
+ });
+
+ if (idx >= 0) {
+ $scope.selectedItem = $scope.clusters[idx];
+ $scope.backupItem = restoredItem;
+ }
+ else
+ sessionStorage.removeItem('clusterBackupItem');
+ }
+ else
+ $scope.backupItem = restoredItem;
+ }
+ else if ($scope.clusters.length > 0)
+ $scope.selectItem($scope.clusters[0]);
+
+ $scope.$watch('backupItem', function (val) {
+ if (val)
+ sessionStorage.clusterBackupItem = angular.toJson(val);
+ }, true);
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+
+ $scope.selectItem = function (item) {
+ $table.tableReset();
+
+ $scope.selectedItem = item;
+ $scope.backupItem = angular.copy(item);
+ };
+
+ // Add new cluster.
+ $scope.createItem = function () {
+ $table.tableReset();
+
+ $scope.backupItem = angular.copy($scope.create.template);
+ $scope.backupItem.caches = [];
+ $scope.backupItem.space = $scope.spaces[0]._id;
+ };
+
+ $scope.indexOfCache = function (cacheId) {
+ return _.findIndex($scope.caches, function (cache) {
+ return cache.value == cacheId;
+ });
+ };
+
+ // Check cluster logical consistency.
+ function validate(item) {
+ if (!item.swapSpaceSpi || !item.swapSpaceSpi.kind && item.caches) {
+ for (var i = 0; i < item.caches.length; i++) {
+ var idx = $scope.indexOfCache(item.caches[i]);
+
+ if (idx >= 0) {
+ var cache = $scope.caches[idx];
+
+ if (cache.swapEnabled) {
+ $common.showError('Swap space SPI is not configured, but cache "' + cache.label + '" configured to use swap!');
+
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // Save cluster in database.
+ function save(item) {
+ $http.post('clusters/save', item)
+ .success(function (_id) {
+ var idx = _.findIndex($scope.clusters, function (cluster) {
+ return cluster._id == _id;
+ });
+
+ if (idx >= 0)
+ angular.extend($scope.clusters[idx], item);
+ else {
+ item._id = _id;
+
+ $scope.clusters.push(item);
+ }
+
+ $scope.selectItem(item);
+
+ $common.showInfo('Cluster "' + item.name + '" saved.');
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+ }
+
+ // Save cluster.
+ $scope.saveItem = function () {
+ $table.tableReset();
+
+ var item = $scope.backupItem;
+
+ if (validate(item))
+ save(item);
+ };
+
+ // Save cluster with new name.
+ $scope.saveItemAs = function () {
+ $table.tableReset();
+
+ if (validate($scope.backupItem))
+ $copy.show($scope.backupItem.name).then(function (newName) {
+ var item = angular.copy($scope.backupItem);
+
+ item._id = undefined;
+ item.name = newName;
+
+ save(item);
+ });
+ };
+
+ // Remove cluster from db.
+ $scope.removeItem = function () {
+ $table.tableReset();
+
+ var selectedItem = $scope.selectedItem;
+
+ $confirm.show('Are you sure you want to remove cluster: "' + selectedItem.name + '"?').then(
+ function () {
+ var _id = selectedItem._id;
+
+ $http.post('clusters/remove', {_id: _id})
+ .success(function () {
+ $common.showInfo('Cluster has been removed: ' + selectedItem.name);
+
+ var clusters = $scope.clusters;
+
+ var idx = _.findIndex(clusters, function (cluster) {
+ return cluster._id == _id;
+ });
+
+ if (idx >= 0) {
+ clusters.splice(idx, 1);
+
+ if (clusters.length > 0)
+ $scope.selectItem(clusters[0]);
+ else {
+ $scope.selectedItem = undefined;
+ $scope.backupItem = undefined;
+ }
+ }
+ })
+ .error(function (errMsg) {
+ $common.showError(errMsg);
+ });
+ }
+ );
+ };
+ }]
+);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/controllers/common-module.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/common-module.js b/modules/control-center-web/src/main/js/controllers/common-module.js
new file mode 100644
index 0000000..df2ff19
--- /dev/null
+++ b/modules/control-center-web/src/main/js/controllers/common-module.js
@@ -0,0 +1,484 @@
+/*
+ * 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 controlCenterModule = angular.module('ignite-web-control-center', ['smart-table', 'mgcrea.ngStrap', 'ui.ace', 'ngSanitize']);
+
+// Modal popup configuration.
+controlCenterModule.config(function ($modalProvider) {
+ angular.extend($modalProvider.defaults, {
+ html: true
+ });
+});
+
+// Tooltips configuration.
+controlCenterModule.config(function ($tooltipProvider) {
+ angular.extend($tooltipProvider.defaults, {
+ container: 'body',
+ placement: 'right',
+ html: 'true',
+ trigger: 'click hover'
+ });
+});
+
+// Comboboxes configuration.
+controlCenterModule.config(function ($selectProvider) {
+ angular.extend($selectProvider.defaults, {
+ maxLength: '1',
+ allText: 'Select All',
+ noneText: 'Clear All',
+ templateUrl: '/select',
+ iconCheckmark: 'fa fa-check',
+ caretHtml: '<span class="caret"></span>'
+ });
+});
+
+// Alerts configuration.
+controlCenterModule.config(function ($alertProvider) {
+ angular.extend($alertProvider.defaults, {
+ container: 'body',
+ placement: 'top-right',
+ duration: '5',
+ type: 'danger'
+ });
+});
+
+// Common functions to be used in controllers.
+controlCenterModule.service('$common', ['$alert', function ($alert) {
+ var msgModal = undefined;
+
+ function errorMessage(errMsg) {
+ return errMsg ? errMsg : 'Internal server error.';
+ }
+
+ function isDefined(v) {
+ return !(v === undefined || v === null);
+ }
+
+ return {
+ getModel: function (obj, field) {
+ var path = field.path;
+
+ if (!isDefined(path))
+ return obj;
+
+ path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
+ path = path.replace(/^\./, ''); // strip a leading dot
+
+ var segs = path.split('.');
+ var root = obj;
+
+ while (segs.length > 0) {
+ var pathStep = segs.shift();
+
+ if (typeof root[pathStep] === 'undefined')
+ root[pathStep] = {};
+
+ root = root[pathStep];
+ }
+
+ return root;
+ },
+ joinTip: function (arr) {
+ if (!arr) {
+ return arr;
+ }
+
+ var lines = arr.map(function (line) {
+ var rtrimmed = line.replace(/\s+$/g, '');
+
+ if (rtrimmed.indexOf('>', this.length - 1) == -1) {
+ rtrimmed = rtrimmed + '<br/>';
+ }
+
+ return rtrimmed;
+ });
+
+ return lines.join("");
+ },
+ isDefined: isDefined,
+ isNonEmpty: function (s) {
+ return isDefined(s) && s.trim().length > 0;
+ },
+ errorMessage: errorMessage,
+ showError: function (msg) {
+ if (msgModal)
+ msgModal.hide();
+
+ msgModal = $alert({title: errorMessage(msg)});
+ },
+ showInfo: function (msg) {
+ if (msgModal)
+ msgModal.hide();
+
+ msgModal = $alert({
+ type: 'success',
+ title: msg,
+ duration: 2
+ });
+ },
+ javaBuildInTypes: [
+ 'Boolean', 'Byte', 'Date', 'Double', 'Float', 'Integer', 'Long', 'Short', 'String', 'Time', 'Timestamp', 'UUID'
+ ]
+ }
+}]);
+
+// Confirm popup service.
+controlCenterModule.service('$confirm', function ($modal, $rootScope, $q) {
+ var scope = $rootScope.$new();
+
+ var deferred;
+
+ scope.ok = function () {
+ deferred.resolve();
+
+ confirmModal.hide();
+ };
+
+ var confirmModal = $modal({templateUrl: '/confirm', scope: scope, placement: 'center', show: false});
+
+ var parentShow = confirmModal.show;
+
+ confirmModal.show = function (content) {
+ scope.content = content || 'Confirm deletion?';
+
+ deferred = $q.defer();
+
+ parentShow();
+
+ return deferred.promise;
+ };
+
+ return confirmModal;
+});
+
+// "Save as" popup service.
+controlCenterModule.service('$copy', function ($modal, $rootScope, $q) {
+ var scope = $rootScope.$new();
+
+ var deferred;
+
+ scope.ok = function (newName) {
+ deferred.resolve(newName);
+
+ copyModal.hide();
+ };
+
+ var copyModal = $modal({templateUrl: '/copy', scope: scope, placement: 'center', show: false});
+
+ var parentShow = copyModal.show;
+
+ copyModal.show = function (oldName) {
+ scope.newName = oldName + '(1)';
+
+ deferred = $q.defer();
+
+ parentShow();
+
+ return deferred.promise;
+ };
+
+ return copyModal;
+});
+
+// Tables support service.
+controlCenterModule.service('$table', ['$common', function ($common) {
+ function _swapSimpleItems(a, ix1, ix2) {
+ var tmp = a[ix1];
+
+ a[ix1] = a[ix2];
+ a[ix2] = tmp;
+ }
+
+ function _model(item, field) {
+ return $common.getModel(item, field);
+ }
+
+ var table = {name: 'none', editIndex: -1};
+
+ function _tableReset() {
+ table.name = 'none';
+ table.editIndex = -1;
+ }
+
+ function _tableState(name, editIndex) {
+ table.name = name;
+ table.editIndex = editIndex;
+ }
+
+ return {
+ tableState: function (name, editIndex) {
+ _tableState(name, editIndex);
+ },
+ tableReset: function () {
+ _tableReset();
+ },
+ tableNewItem: function (field) {
+ _tableState(field.model, -1);
+ },
+ tableNewItemActive: function (field) {
+ return table.name == field.model && table.editIndex < 0;
+ },
+ tableEditing: function (field, index) {
+ return table.name == field.model && table.editIndex == index;
+ },
+ tableStartEdit: function (item, field, index) {
+ _tableState(field.model, index);
+
+ return _model(item, field)[field.model][index];
+ },
+ tableRemove: function (item, field, index) {
+ _tableReset();
+
+ _model(item, field)[field.model].splice(index, 1);
+ },
+ tableSimpleSave: function (valueValid, item, field, newValue, index) {
+ if (valueValid(item, field, newValue, index)) {
+ _tableReset();
+
+ if (index < 0) {
+ if (_model(item, field)[field.model])
+ _model(item, field)[field.model].push(newValue);
+ else
+ _model(item, field)[field.model] = [newValue];
+ }
+ else
+ _model(item, field)[field.model][index] = newValue;
+ }
+ },
+ tableSimpleSaveVisible: function (newValue) {
+ return $common.isNonEmpty(newValue);
+ },
+ tableSimpleUp: function (item, field, index) {
+ _tableReset();
+
+ _swapSimpleItems(_model(item, field)[field.model], index, index - 1);
+ },
+ tableSimpleDown: function (item, field, index) {
+ _tableReset();
+
+ _swapSimpleItems(_model(item, field)[field.model], index, index + 1);
+ },
+ tableSimpleDownVisible: function (item, field, index) {
+ return index < _model(item, field)[field.model].length - 1;
+ },
+ tablePairSave: function (pairValid, item, field, newKey, newValue, index) {
+ if (pairValid(item, field, newKey, newValue, index)) {
+ _tableReset();
+
+ var pair = {};
+
+ if (index < 0) {
+ pair[field.keyName] = newKey;
+ pair[field.valueName] = newValue;
+
+ if (item[field.model])
+ item[field.model].push(pair);
+ else
+ item[field.model] = [pair];
+ }
+ else {
+ pair = item[field.model][index];
+
+ pair[field.keyName] = newKey;
+ pair[field.valueName] = newValue;
+ }
+ }
+ },
+ tablePairSaveVisible: function (newKey, newValue) {
+ return $common.isNonEmpty(newKey) && $common.isNonEmpty(newValue);
+ }
+ }
+}]);
+
+
+// Filter to decode name using map(value, label).
+controlCenterModule.filter('displayValue', function () {
+ return function (v, m, dflt) {
+ var i = _.findIndex(m, function (item) {
+ return item.value == v;
+ });
+
+ if (i >= 0) {
+ return m[i].label;
+ }
+
+ if (dflt) {
+ return dflt;
+ }
+
+ return 'Unknown value';
+ }
+});
+
+/**
+ * Filter for replacing all occurrences of {@code org.apache.ignite.} with {@code o.a.i.},
+ * {@code org.apache.ignite.internal.} with {@code o.a.i.i.},
+ * {@code org.apache.ignite.internal.visor.} with {@code o.a.i.i.v.} and
+ * {@code org.apache.ignite.scalar.} with {@code o.a.i.s.}.
+ *
+ * @param s String to replace in.
+ * @return Replaces string.
+ */
+controlCenterModule.filter('compact', function () {
+ return function (s) {
+ return s.replace("org.apache.ignite.internal.visor.", "o.a.i.i.v.").
+ replace("org.apache.ignite.internal.", "o.a.i.i.").
+ replace("org.apache.ignite.scalar.", "o.a.i.s.").
+ replace("org.apache.ignite.", "o.a.i.");
+ }
+});
+
+// Directive to enable validation for IP addresses.
+controlCenterModule.directive('ipaddress', function () {
+ const ip = '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])';
+ const port = '([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])';
+ const portRange = '(:' + port + '(..' + port + ')?)?';
+ const host = '(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])';
+
+ return {
+ require: 'ngModel',
+ link: function (scope, elem, attrs, ctrl) {
+ ctrl.$validators.ipaddress = function (modelValue, viewValue) {
+ if (ctrl.$isEmpty(modelValue) || !attrs['ipaddress'])
+ return true;
+
+ return viewValue.match(new RegExp('(^' + ip + portRange + '$)|(^' + host + portRange + '$)')) != null;
+ }
+ }
+ }
+});
+
+// Directive to enable validation to match specified value.
+controlCenterModule.directive('match', function ($parse) {
+ return {
+ require: 'ngModel',
+ link: function (scope, elem, attrs, ctrl) {
+ scope.$watch(function () {
+ return $parse(attrs.match)(scope) === ctrl.$modelValue;
+ }, function (currentValue) {
+ ctrl.$setValidity('mismatch', currentValue);
+ });
+ }
+ };
+});
+
+// Directive to bind ENTER key press with some user action.
+controlCenterModule.directive('ngEnter', function() {
+ return function(scope, element, attrs) {
+ element.bind('keydown keypress', function(event) {
+ if (event.which === 13) {
+ scope.$apply(function() {
+ scope.$eval(attrs.ngEnter);
+ });
+
+ event.preventDefault();
+ }
+ });
+ };
+});
+
+// Directive to bind ESC key press with some user action.
+controlCenterModule.directive('ngEscape', function() {
+ return function(scope, element, attrs) {
+ element.bind('keydown keyup', function(event) {
+ if (event.which === 27) {
+ scope.$apply(function() {
+ scope.$eval(attrs.ngEscape);
+ });
+
+ event.preventDefault();
+ }
+ });
+ };
+});
+
+// Factory function to focus element.
+controlCenterModule.factory('focus', function ($timeout, $window) {
+ return function (id) {
+ // Timeout makes sure that is invoked after any other event has been triggered.
+ // E.g. click events that need to run before the focus or inputs elements that are
+ // in a disabled state but are enabled when those events are triggered.
+ $timeout(function () {
+ var element = $window.document.getElementById(id);
+
+ if (element)
+ element.focus();
+ });
+ };
+});
+
+// Directive to mark elements to focus.
+controlCenterModule.directive('eventFocus', function (focus) {
+ return function (scope, elem, attr) {
+ elem.on(attr.eventFocus, function () {
+ focus(attr.eventFocusId);
+ });
+
+ // Removes bound events in the element itself when the scope is destroyed
+ scope.$on('$destroy', function () {
+ element.off(attr.eventFocus);
+ });
+ };
+});
+
+// Navigation bar controller.
+controlCenterModule.controller('activeLink', [
+ '$scope', function ($scope) {
+ $scope.isActive = function (path) {
+ return window.location.pathname.substr(0, path.length) == path;
+ };
+ }]);
+
+// Login popup controller.
+controlCenterModule.controller('auth', [
+ '$scope', '$modal', '$alert', '$http', '$window', '$common',
+ function ($scope, $modal, $alert, $http, $window, $common) {
+ $scope.errorMessage = $common.errorMessage;
+
+ $scope.action = 'login';
+
+ $scope.valid = false;
+
+ $scope.userDropdown = [{"text": "Profile", "href": "/profile"}];
+
+ if (!$scope.becomeUsed) {
+ if ($scope.user && $scope.user.admin)
+ $scope.userDropdown.push({"text": "Admin Panel", "href": "/admin"});
+
+ $scope.userDropdown.push({"text": "Log Out", "href": "/logout"});
+ }
+
+ // Pre-fetch an external template populated with a custom scope
+ var authModal = $modal({scope: $scope, templateUrl: '/login', show: false});
+
+ $scope.login = function () {
+ // Show when some event occurs (use $promise property to ensure the template has been loaded)
+ authModal.$promise.then(authModal.show);
+ };
+
+ $scope.auth = function (action, user_info) {
+ $http.post('/' + action, user_info)
+ .success(function () {
+ authModal.hide();
+
+ $window.location = '/configuration/clusters';
+ })
+ .error(function (data) {
+ $alert({placement: 'top', container: '#errors-container', title: $scope.errorMessage(data)});
+ });
+ };
+ }]);
\ No newline at end of file