You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/12/08 08:34:40 UTC
[09/30] ignite git commit: IGNITE-6390 Web Console: Added component
for cluster selection.
IGNITE-6390 Web Console: Added component for cluster selection.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/1367bc98
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/1367bc98
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/1367bc98
Branch: refs/heads/ignite-zk
Commit: 1367bc98eb08233f9e47ba45335f9dda1fbb7bbd
Parents: cbd69d6
Author: Dmitriy Shabalin <ds...@gridgain.com>
Authored: Wed Dec 6 10:36:42 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Wed Dec 6 10:36:42 2017 +0700
----------------------------------------------------------------------
.../internal/visor/util/VisorTaskUtils.java | 139 ++
.../commands/tasks/VisorTasksCommand.scala | 1 +
.../scala/org/apache/ignite/visor/visor.scala | 49 -
modules/web-console/backend/app/agentSocket.js | 2 +-
.../web-console/backend/app/agentsHandler.js | 51 +-
.../web-console/backend/app/browsersHandler.js | 7 +
modules/web-console/backend/app/mongo.js | 1 +
modules/web-console/backend/package.json | 3 +-
modules/web-console/frontend/app/app.js | 8 +-
.../app/components/bs-select-menu/style.scss | 4 +-
.../cluster-select/cluster-select.controller.js | 64 -
.../cluster-select/cluster-select.pug | 47 -
.../cluster-select/cluster-select.scss | 30 -
.../app/components/cluster-select/index.js | 29 -
.../components/cluster-selector/component.js | 25 +
.../components/cluster-selector/controller.js | 62 +
.../app/components/cluster-selector/index.js | 23 +
.../app/components/cluster-selector/style.scss | 66 +
.../components/cluster-selector/template.pug | 75 +
.../app/components/list-editable/controller.js | 2 +-
.../components/page-queries/Notebook.data.js | 168 ++
.../components/page-queries/Notebook.service.js | 74 +
.../app/components/page-queries/controller.js | 1938 ++++++++++++++++++
.../app/components/page-queries/index.js | 62 +
.../page-queries/notebook.controller.js | 62 +
.../app/components/page-queries/style.scss | 36 +
.../components/page-queries/template.tpl.pug | 385 ++++
.../app/modules/agent/AgentManager.service.js | 57 +-
.../frontend/app/modules/sql/Notebook.data.js | 168 --
.../app/modules/sql/Notebook.service.js | 74 -
.../app/modules/sql/notebook.controller.js | 62 -
.../frontend/app/modules/sql/sql.controller.js | 1887 -----------------
.../frontend/app/modules/sql/sql.module.js | 61 -
.../frontend/app/primitives/switcher/index.pug | 2 +-
.../frontend/app/primitives/switcher/index.scss | 69 +-
.../frontend/views/includes/header-right.pug | 2 -
.../web-console/frontend/views/sql/sql.tpl.pug | 381 ----
.../console/agent/handlers/ClusterListener.java | 178 +-
.../ignite/console/agent/rest/RestExecutor.java | 63 +-
39 files changed, 3477 insertions(+), 2940 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java
index ace451c..fda801c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java
@@ -23,8 +23,10 @@ import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.URL;
+import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.CharacterCodingException;
@@ -69,6 +71,7 @@ import org.apache.ignite.internal.visor.log.VisorLogFile;
import org.apache.ignite.lang.IgniteClosure;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.spi.eventstorage.NoopEventStorageSpi;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static java.lang.System.getProperty;
@@ -1113,4 +1116,140 @@ public class VisorTaskUtils {
public static boolean joinTimedOut(String msg) {
return msg != null && msg.startsWith("Join process timed out.");
}
+
+ /**
+ * Special wrapper over address that can be sorted in following order:
+ * IPv4, private IPv4, IPv4 local host, IPv6.
+ * Lower addresses first.
+ */
+ private static class SortableAddress implements Comparable<SortableAddress> {
+ /** */
+ private int type;
+
+ /** */
+ private BigDecimal bits;
+
+ /** */
+ private String addr;
+
+ /**
+ * Constructor.
+ *
+ * @param addr Address as string.
+ */
+ private SortableAddress(String addr) {
+ this.addr = addr;
+
+ if (addr.indexOf(':') > 0)
+ type = 4; // IPv6
+ else {
+ try {
+ InetAddress inetAddr = InetAddress.getByName(addr);
+
+ if (inetAddr.isLoopbackAddress())
+ type = 3; // localhost
+ else if (inetAddr.isSiteLocalAddress())
+ type = 2; // private IPv4
+ else
+ type = 1; // other IPv4
+ }
+ catch (UnknownHostException ignored) {
+ type = 5;
+ }
+ }
+
+ bits = BigDecimal.valueOf(0L);
+
+ try {
+ String[] octets = addr.contains(".") ? addr.split(".") : addr.split(":");
+
+ int len = octets.length;
+
+ for (int i = 0; i < len; i++) {
+ long oct = F.isEmpty(octets[i]) ? 0 : Long.valueOf( octets[i]);
+ long pow = Double.valueOf(Math.pow(256, octets.length - 1 - i)).longValue();
+
+ bits = bits.add(BigDecimal.valueOf(oct * pow));
+ }
+ }
+ catch (Exception ignore) {
+ // No-op.
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public int compareTo(@NotNull SortableAddress o) {
+ return (type == o.type ? bits.compareTo(o.bits) : Integer.compare(type, o.type));
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ SortableAddress other = (SortableAddress)o;
+
+ return addr != null ? addr.equals(other.addr) : other.addr == null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return addr != null ? addr.hashCode() : 0;
+ }
+
+ /**
+ * @return Address.
+ */
+ public String address() {
+ return addr;
+ }
+ }
+
+ /**
+ * Sort addresses: IPv4 & real addresses first.
+ *
+ * @param addrs Addresses to sort.
+ * @return Sorted list.
+ */
+ public static Collection<String> sortAddresses(Collection<String> addrs) {
+ if (F.isEmpty(addrs))
+ return Collections.emptyList();
+
+ int sz = addrs.size();
+
+ List<SortableAddress> sorted = new ArrayList<>(sz);
+
+ for (String addr : addrs)
+ sorted.add(new SortableAddress(addr));
+
+ Collections.sort(sorted);
+
+ Collection<String> res = new ArrayList<>(sz);
+
+ for (SortableAddress sa : sorted)
+ res.add(sa.address());
+
+ return res;
+ }
+
+ /**
+ * Split addresses.
+ *
+ * @param s String with comma separted addresses.
+ * @return Collection of addresses.
+ */
+ public static Collection<String> splitAddresses(String s) {
+ if (F.isEmpty(s))
+ return Collections.emptyList();
+
+ String[] addrs = s.split(",");
+
+ for (int i = 0; i < addrs.length; i++)
+ addrs[i] = addrs[i].trim();
+
+ return Arrays.asList(addrs);
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommand.scala
index 4d9b795..0d6753e 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommand.scala
@@ -32,6 +32,7 @@ import java.util.UUID
import org.apache.ignite.internal.visor.event.{VisorGridEvent, VisorGridJobEvent, VisorGridTaskEvent}
import org.apache.ignite.internal.visor.node.VisorNodeEventsCollectorTask
import org.apache.ignite.internal.visor.node.VisorNodeEventsCollectorTaskArg
+import org.apache.ignite.internal.visor.util.VisorTaskUtils._
import scala.collection.JavaConversions._
import scala.language.implicitConversions
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
index ffc7a00..1a46316 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
@@ -2694,53 +2694,4 @@ object visor extends VisorTag {
else
Long.MaxValue
}
-
- /**
- * Sort addresses to properly display in Visor.
- *
- * @param addrs Addresses to sort.
- * @return Sorted list.
- */
- def sortAddresses(addrs: Iterable[String]) = {
- def ipToLong(ip: String) = {
- try {
- val octets = if (ip.contains(".")) ip.split('.') else ip.split(':')
-
- var dec = BigDecimal.valueOf(0L)
-
- for (i <- octets.indices) dec += octets(i).toLong * math.pow(256, octets.length - 1 - i).toLong
-
- dec
- }
- catch {
- case _: Exception => BigDecimal.valueOf(0L)
- }
- }
-
- /**
- * Sort addresses to properly display in Visor.
- *
- * @param addr Address to detect type for.
- * @return IP class type for sorting in order: public addresses IPv4 + private IPv4 + localhost + IPv6.
- */
- def addrType(addr: String) = {
- if (addr.contains(':'))
- 4 // IPv6
- else {
- try {
- InetAddress.getByName(addr) match {
- case ip if ip.isLoopbackAddress => 3 // localhost
- case ip if ip.isSiteLocalAddress => 2 // private IPv4
- case _ => 1 // other IPv4
- }
- }
- catch {
- case ignore: UnknownHostException => 5
- }
- }
- }
-
- addrs.map(addr => (addrType(addr), ipToLong(addr), addr)).toSeq.
- sortWith((l, r) => if (l._1 == r._1) l._2.compare(r._2) < 0 else l._1 < r._1).map(_._3)
- }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/backend/app/agentSocket.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/agentSocket.js b/modules/web-console/backend/app/agentSocket.js
index 75dcd53..6e4518a 100644
--- a/modules/web-console/backend/app/agentSocket.js
+++ b/modules/web-console/backend/app/agentSocket.js
@@ -88,7 +88,7 @@ module.exports.factory = function(_) {
class AgentSocket {
/**
* @param {Socket} socket Socket for interaction.
- * @param {String} tokens Active tokens.
+ * @param {Array.<String>} tokens Agent tokens.
* @param {String} demoEnabled Demo enabled.
*/
constructor(socket, tokens, demoEnabled) {
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/backend/app/agentsHandler.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/agentsHandler.js b/modules/web-console/backend/app/agentsHandler.js
index 112793a..844ce1e 100644
--- a/modules/web-console/backend/app/agentsHandler.js
+++ b/modules/web-console/backend/app/agentsHandler.js
@@ -17,6 +17,8 @@
'use strict';
+const uuid = require('uuid/v4');
+
// Fire me up!
/**
@@ -82,19 +84,14 @@ module.exports.factory = function(_, fs, path, JSZip, socketio, settings, mongo,
class Cluster {
constructor(top) {
- let d = new Date().getTime();
-
- this.id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
- const r = (d + Math.random() * 16) % 16 | 0;
-
- d = Math.floor(d / 16);
-
- return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
- });
+ const clusterName = top.clusterName;
+ this.id = _.isEmpty(clusterName) ? `Cluster ${uuid().substring(0, 8).toUpperCase()}` : clusterName;
this.nids = top.nids;
-
+ this.addresses = top.addresses;
+ this.clients = top.clients;
this.clusterVersion = top.clusterVersion;
+ this.active = top.active;
}
isSameCluster(top) {
@@ -103,8 +100,18 @@ module.exports.factory = function(_, fs, path, JSZip, socketio, settings, mongo,
update(top) {
this.clusterVersion = top.clusterVersion;
-
this.nids = top.nids;
+ this.addresses = top.addresses;
+ this.clients = top.clients;
+ this.clusterVersion = top.clusterVersion;
+ this.active = top.active;
+ }
+
+ same(top) {
+ return _.difference(this.nids, top.nids).length === 0 &&
+ _.isEqual(this.addresses, top.addresses) &&
+ this.clusterVersion === top.clusterVersion &&
+ this.active === top.active;
}
}
@@ -192,10 +199,13 @@ module.exports.factory = function(_, fs, path, JSZip, socketio, settings, mongo,
}
getOrCreateCluster(top) {
- const cluster = _.find(this.clusters, (c) => c.isSameCluster(top));
+ let cluster = _.find(this.clusters, (c) => c.isSameCluster(top));
+
+ if (_.isNil(cluster)) {
+ cluster = new Cluster(top);
- if (_.isNil(cluster))
- this.clusters.push(new Cluster(top));
+ this.clusters.push(cluster);
+ }
return cluster;
}
@@ -230,8 +240,17 @@ module.exports.factory = function(_, fs, path, JSZip, socketio, settings, mongo,
this._browsersHnd.agentStats(token);
});
}
- else
- cluster.update(top);
+ else {
+ const changed = !cluster.same(top);
+
+ if (changed) {
+ cluster.update(top);
+
+ _.forEach(tokens, (token) => {
+ this._browsersHnd.clusterChanged(token, cluster);
+ });
+ }
+ }
});
sock.on('cluster:collector', (top) => {
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/backend/app/browsersHandler.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/browsersHandler.js b/modules/web-console/backend/app/browsersHandler.js
index 8b1385d..7ae247b 100644
--- a/modules/web-console/backend/app/browsersHandler.js
+++ b/modules/web-console/backend/app/browsersHandler.js
@@ -124,6 +124,12 @@ module.exports = {
.then((stat) => _.forEach(socks, (sock) => sock.emit('agents:stat', stat)));
}
+ clusterChanged(token, cluster) {
+ const socks = this._browserSockets.get(token);
+
+ _.forEach(socks, (sock) => sock.emit('cluster:changed', cluster));
+ }
+
emitNotification(sock) {
sock.emit('user:notifications', this.notification);
}
@@ -224,6 +230,7 @@ module.exports = {
this.registerVisorTask('queryClose', internalVisor('query.VisorQueryCleanupTask'), 'java.util.Map', 'java.util.UUID', 'java.util.Set');
this.registerVisorTask('queryCloseX2', internalVisor('query.VisorQueryCleanupTask'), internalVisor('query.VisorQueryCleanupTaskArg'));
+ this.registerVisorTask('toggleClusterState', internalVisor('misc.VisorChangeGridActiveStateTask'), internalVisor('misc.VisorChangeGridActiveStateTaskArg'));
// Return command result from grid to browser.
sock.on('node:visor', (clusterId, taskId, nids, ...args) => {
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/backend/app/mongo.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/mongo.js b/modules/web-console/backend/app/mongo.js
index 81076af..e0d0a0f 100644
--- a/modules/web-console/backend/app/mongo.js
+++ b/modules/web-console/backend/app/mongo.js
@@ -79,6 +79,7 @@ const defineSchema = (passportMongo, mongoose) => {
DUPLICATE_KEY_ERROR: 11000,
DUPLICATE_KEY_UPDATE_ERROR: 11001
};
+
// Define Account model.
result.Account = mongoose.model('Account', AccountSchema);
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/backend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/package.json b/modules/web-console/backend/package.json
index f0b2b5e..ba442f9 100644
--- a/modules/web-console/backend/package.json
+++ b/modules/web-console/backend/package.json
@@ -68,7 +68,8 @@
"passport-local": "1.0.0",
"passport-local-mongoose": "4.0.0",
"passport.socketio": "3.7.0",
- "socket.io": "1.7.3"
+ "socket.io": "1.7.3",
+ "uuid": "3.1.0"
},
"devDependencies": {
"chai": "4.1.0",
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.js b/modules/web-console/frontend/app/app.js
index ca678fc..f367d3e 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -22,7 +22,6 @@ import './app.config';
import './modules/form/form.module';
import './modules/agent/agent.module';
-import './modules/sql/sql.module';
import './modules/nodes/nodes.module';
import './modules/demo/Demo.module';
@@ -113,7 +112,6 @@ import resetPassword from './controllers/reset-password.controller';
// Components
import igniteListOfRegisteredUsers from './components/list-of-registered-users';
import IgniteActivitiesUserDialog from './components/activities-user-dialog';
-import clusterSelect from './components/cluster-select';
import './components/input-dialog';
import webConsoleHeader from './components/web-console-header';
import webConsoleFooter from './components/web-console-footer';
@@ -123,12 +121,14 @@ import userNotifications from './components/user-notifications';
import pageConfigure from './components/page-configure';
import pageConfigureBasic from './components/page-configure-basic';
import pageConfigureAdvanced from './components/page-configure-advanced';
+import pageQueries from './components/page-queries';
import gridColumnSelector from './components/grid-column-selector';
import gridItemSelected from './components/grid-item-selected';
import bsSelectMenu from './components/bs-select-menu';
import protectFromBsSelectRender from './components/protect-from-bs-select-render';
import uiGridHovering from './components/ui-grid-hovering';
import listEditable from './components/list-editable';
+import clusterSelector from './components/cluster-selector';
import igniteServices from './services';
@@ -168,7 +168,6 @@ angular.module('ignite-console', [
'ignite-console.branding',
'ignite-console.socket',
'ignite-console.agent',
- 'ignite-console.sql',
'ignite-console.nodes',
'ignite-console.demo',
// States.
@@ -197,6 +196,7 @@ angular.module('ignite-console', [
pageConfigure.name,
pageConfigureBasic.name,
pageConfigureAdvanced.name,
+ pageQueries.name,
gridColumnSelector.name,
gridItemSelected.name,
bsSelectMenu.name,
@@ -205,6 +205,7 @@ angular.module('ignite-console', [
AngularStrapTooltip.name,
AngularStrapSelect.name,
listEditable.name,
+ clusterSelector.name,
// Ignite modules.
IgniteModules.name
])
@@ -231,7 +232,6 @@ angular.module('ignite-console', [
.directive('igniteOnFocusOut', igniteOnFocusOut)
.directive('igniteRestoreInputFocus', igniteRestoreInputFocus)
.directive('igniteListOfRegisteredUsers', igniteListOfRegisteredUsers)
-.directive('igniteClusterSelect', clusterSelect)
.directive('btnIgniteLinkDashedSuccess', btnIgniteLink)
.directive('btnIgniteLinkDashedSecondary', btnIgniteLink)
// Services.
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/bs-select-menu/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/bs-select-menu/style.scss b/modules/web-console/frontend/app/components/bs-select-menu/style.scss
index 870b1bf..ccf33a3 100644
--- a/modules/web-console/frontend/app/components/bs-select-menu/style.scss
+++ b/modules/web-console/frontend/app/components/bs-select-menu/style.scss
@@ -88,7 +88,7 @@
}
& > li > .bssm-item-button__active {
- background-color: #eeeeee;
+ background-color: #e5f2f9;
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js b/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js
deleted file mode 100644
index a2d8e1e..0000000
--- a/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.
- */
-
-export default class {
- static $inject = ['AgentManager'];
-
- constructor(agentMgr) {
- const ctrl = this;
-
- ctrl.counter = 1;
-
- ctrl.cluster = null;
- ctrl.clusters = [];
-
- agentMgr.connectionSbj.subscribe({
- next: ({cluster, clusters}) => {
- if (_.isEmpty(clusters))
- return ctrl.clusters.length = 0;
-
- const removed = _.differenceBy(ctrl.clusters, clusters, 'id');
-
- if (_.nonEmpty(removed))
- _.pullAll(ctrl.clusters, removed);
-
- const added = _.differenceBy(clusters, ctrl.clusters, 'id');
-
- _.forEach(added, (cluster) => {
- ctrl.clusters.push({
- id: cluster.id,
- connected: true,
- click: () => {
- if (cluster.id === _.get(ctrl, 'cluster.id'))
- return;
-
- if (_.get(ctrl, 'cluster.connected')) {
- agentMgr.saveToStorage(cluster);
-
- window.open(window.location.href, '_blank');
- }
- else
- ctrl.cluster = _.find(ctrl.clusters, {id: cluster.id});
- }
- });
- });
-
- ctrl.cluster = cluster;
- }
- });
- }
-}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug b/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
deleted file mode 100644
index eb46e26..0000000
--- a/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
+++ /dev/null
@@ -1,47 +0,0 @@
-//-
- 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 clusterName = 'Cluster {{ ctrl.cluster.id | id8 }}'
-
-ul.nav
- li.disabled(ng-if='ctrl.clusters.length === 0')
- a(ng-if='!ctrl.cluster')
- i.icon-cluster
- label.padding-left-dflt(bs-tooltip='' data-placement='bottom' data-title='Check that Web Agent(s) started and connected to cluster(s)') No clusters available
- a(ng-if='ctrl.cluster')
- i.icon-danger
- label.padding-left-dflt(bs-tooltip='' data-placement='bottom' data-title='Connection to cluster was lost') #{clusterName}
-
- li(ng-if='ctrl.clusters.length === 1 && ctrl.cluster.connected')
- a
- i.icon-cluster
- label.padding-left-dflt #{clusterName}
-
- li(ng-if='ctrl.clusters.length > 1 || ctrl.clusters.length === 1 && !ctrl.cluster.connected')
- a.dropdown-toggle(bs-dropdown='' data-placement='bottom-left' data-trigger='hover focus' data-container='self' ng-click='$event.stopPropagation()' aria-haspopup='true' aria-expanded='expanded')
- i(ng-class='{"icon-cluster": ctrl.cluster.connected, "icon-danger": !ctrl.cluster.connected}')
- label.padding-left-dflt #{clusterName}
- span.caret
-
- ul.dropdown-menu(role='menu')
- li(ng-repeat='item in ctrl.clusters' ng-class='{active: ctrl.cluster === item}')
- div(ng-click='item.click()')
- i.icon-cluster.pull-left(style='margin: 0; padding-left: 10px;')
- div: a Cluster {{ item.id | id8 }}
-
-i.icon-help(bs-tooltip='' data-placement='bottom' data-html=true
- data-title='Multi-Cluster Support<br/>\
- <a href="https://apacheignite-tools.readme.io/docs/multi-cluster-support" target="_blank">More info</a>')
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-select/cluster-select.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-select/cluster-select.scss b/modules/web-console/frontend/app/components/cluster-select/cluster-select.scss
deleted file mode 100644
index 189ef50..0000000
--- a/modules/web-console/frontend/app/components/cluster-select/cluster-select.scss
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.
- */
-
-ignite-cluster-select {
- @import "./../../../public/stylesheets/variables.scss";
-
- display: flex;
- flex-direction: row;
- align-items: center;
-
- .icon-help {
- margin-left: 4px;
-
- color: $text-color;
- }
-}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-select/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-select/index.js b/modules/web-console/frontend/app/components/cluster-select/index.js
deleted file mode 100644
index 607b0db..0000000
--- a/modules/web-console/frontend/app/components/cluster-select/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import template from './cluster-select.pug';
-import './cluster-select.scss';
-import controller from './cluster-select.controller';
-
-export default [() => {
- return {
- restrict: 'E',
- template,
- controller,
- controllerAs: 'ctrl'
- };
-}];
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-selector/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-selector/component.js b/modules/web-console/frontend/app/components/cluster-selector/component.js
new file mode 100644
index 0000000..f6141d9
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-selector/component.js
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './template.pug';
+import controller from './controller';
+import './style.scss';
+
+export default {
+ template,
+ controller
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-selector/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-selector/controller.js b/modules/web-console/frontend/app/components/cluster-selector/controller.js
new file mode 100644
index 0000000..6a86357
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-selector/controller.js
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+export default class {
+ static $inject = ['$scope', 'AgentManager', 'IgniteConfirm'];
+
+ constructor($scope, agentMgr, Confirm) {
+ Object.assign(this, { $scope, agentMgr, Confirm });
+
+ this.clusters = [];
+ this.isDemo = agentMgr.isDemoMode();
+ }
+
+ $onInit() {
+ this.clusters$ = this.agentMgr.connectionSbj
+ .do(({ cluster, clusters }) => {
+ this.cluster = cluster;
+ this.clusters = clusters;
+ })
+ .subscribe(() => {});
+ }
+
+ $onDestroy() {
+ this.clusters$.unsubscribe();
+ }
+
+ change() {
+ this.agentMgr.switchCluster(this.cluster);
+ }
+
+ toggle($event) {
+ $event.preventDefault();
+
+ const toggleClusterState = () => {
+ this.inProgress = true;
+
+ return this.agentMgr.toggleClusterState()
+ .finally(() => this.inProgress = false);
+ };
+
+ if (this.cluster.active) {
+ return this.Confirm.confirm('Are you sure you want to deactivate cluster?')
+ .then(() => toggleClusterState());
+ }
+
+ return toggleClusterState();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-selector/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-selector/index.js b/modules/web-console/frontend/app/components/cluster-selector/index.js
new file mode 100644
index 0000000..2bdbe44
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-selector/index.js
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import component from './component';
+
+export default angular
+ .module('ignite-console.cluster-selector', [])
+ .component('clusterSelector', component);
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-selector/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-selector/style.scss b/modules/web-console/frontend/app/components/cluster-selector/style.scss
new file mode 100644
index 0000000..966be99
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-selector/style.scss
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+cluster-selector {
+ @import "./../../../public/stylesheets/variables.scss";
+
+ position: relative;
+ top: 2px;
+
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ & > .btn-ignite {
+ border-radius: 9px;
+ min-height: 0;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 17px;
+ padding-top: 0;
+ padding-bottom: 0;
+
+ button {
+ font-weight: normal;
+ margin: 0 !important;
+ }
+ }
+
+ .cluster-selector--state {
+ width: 85px;
+ }
+
+ div {
+ margin: 0 10px 0 20px;
+ font-family: Roboto;
+ font-size: 12px;
+ }
+
+ div:last-child {
+ margin-left: 10px;
+ color: #EE2B27;
+ }
+
+ [ignite-icon='info'] {
+ margin-left: 7px;
+ color: $ignite-brand-success;
+ }
+
+ .bs-select-menu {
+ color: $text-color;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/cluster-selector/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-selector/template.pug b/modules/web-console/frontend/app/components/cluster-selector/template.pug
new file mode 100644
index 0000000..c97a698
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-selector/template.pug
@@ -0,0 +1,75 @@
+//-
+ 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.
+
+include /app/helpers/jade/mixins
+
+button.btn-ignite.btn-ignite--success(
+ data-ng-if='$ctrl.isDemo'
+)
+ | Demo cluster
+
+button.btn-ignite.btn-ignite--primary(
+ data-ng-if='!$ctrl.isDemo && $ctrl.clusters.length == 0'
+)
+ | No clusters available
+
+button.btn-ignite.btn-ignite--primary(
+ data-ng-if='!$ctrl.isDemo && $ctrl.clusters.length == 1'
+)
+ | {{ $ctrl.cluster.name }}
+
+div.btn-ignite.btn-ignite--primary(
+ data-ng-if='!$ctrl.isDemo && $ctrl.clusters.length > 1'
+
+ data-ng-model='$ctrl.cluster'
+
+ bs-select=''
+ bs-options='item as item.name for item in $ctrl.clusters'
+ data-trigger='hover focus'
+ data-container='self'
+
+ data-ng-change='$ctrl.change()'
+
+ protect-from-bs-select-render
+)
+ span(ng-if='!$ctrl.cluster') No clusters available
+ span(ng-if='$ctrl.cluster') {{ $ctrl.cluster.name }}
+ span.icon-right.fa.fa-caret-down
+
+svg(
+ ng-if='!$ctrl.isDemo'
+ ignite-icon='info'
+ bs-tooltip=''
+ data-title='Multi-Cluster Support<br/>\
+ <a href="https://apacheignite-tools.readme.io/docs/multi-cluster-support" target="_blank">More info</a>'
+ data-placement='bottom'
+)
+
+.cluster-selector--state(ng-if='!$ctrl.isDemo && $ctrl.cluster')
+ | Cluster {{ $ctrl.cluster.active ? 'active' : 'inactive' }}
+
++switcher()(
+ ng-if='!$ctrl.isDemo && $ctrl.cluster'
+ ng-click='$ctrl.toggle($event)'
+ ng-checked='$ctrl.cluster.active'
+ ng-disabled='$ctrl.inProgress'
+
+ tip='Toggle cluster active state'
+ is-in-progress='{{ $ctrl.inProgress }}'
+)
+
+div(ng-if='$ctrl.inProgress')
+ | {{ !$ctrl.cluster.active ? 'Activating...' : 'Deactivating...' }}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/list-editable/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/controller.js b/modules/web-console/frontend/app/components/list-editable/controller.js
index bc864ce..7757d96 100644
--- a/modules/web-console/frontend/app/components/list-editable/controller.js
+++ b/modules/web-console/frontend/app/components/list-editable/controller.js
@@ -21,7 +21,7 @@ export default class {
static $inject = ['$animate', '$element', '$transclude'];
constructor($animate, $element, $transclude) {
- $animate.enabled(false, $element);
+ $animate.enabled($element, false);
this.hasItemView = $transclude.isSlotFilled('itemView');
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/page-queries/Notebook.data.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-queries/Notebook.data.js b/modules/web-console/frontend/app/components/page-queries/Notebook.data.js
new file mode 100644
index 0000000..3f98bed
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-queries/Notebook.data.js
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const DEMO_NOTEBOOK = {
+ name: 'SQL demo',
+ paragraphs: [
+ {
+ name: 'Query with refresh rate',
+ cacheName: 'CarCache',
+ pageSize: 100,
+ limit: 0,
+ query: [
+ 'SELECT count(*)',
+ 'FROM "CarCache".Car'
+ ].join('\n'),
+ result: 'bar',
+ timeLineSpan: '1',
+ rate: {
+ value: 3,
+ unit: 1000,
+ installed: true
+ }
+ },
+ {
+ name: 'Simple query',
+ cacheName: 'CarCache',
+ pageSize: 100,
+ limit: 0,
+ query: 'SELECT * FROM "CarCache".Car',
+ result: 'table',
+ timeLineSpan: '1',
+ rate: {
+ value: 30,
+ unit: 1000,
+ installed: false
+ }
+ },
+ {
+ name: 'Query with aggregates',
+ cacheName: 'ParkingCache',
+ pageSize: 100,
+ limit: 0,
+ query: [
+ 'SELECT p.name, count(*) AS cnt',
+ 'FROM "ParkingCache".Parking p',
+ 'INNER JOIN "CarCache".Car c',
+ ' ON (p.id) = (c.parkingId)',
+ 'GROUP BY P.NAME'
+ ].join('\n'),
+ result: 'table',
+ timeLineSpan: '1',
+ rate: {
+ value: 30,
+ unit: 1000,
+ installed: false
+ }
+ }
+ ],
+ expandedParagraphs: [0, 1, 2]
+};
+
+export default class NotebookData {
+ static $inject = ['$rootScope', '$http', '$q'];
+
+ constructor($root, $http, $q) {
+ this.demo = $root.IgniteDemoMode;
+
+ this.initLatch = null;
+ this.notebooks = null;
+
+ this.$http = $http;
+ this.$q = $q;
+ }
+
+ load() {
+ if (this.demo) {
+ if (this.initLatch)
+ return this.initLatch;
+
+ return this.initLatch = this.$q.when(this.notebooks = [DEMO_NOTEBOOK]);
+ }
+
+ return this.initLatch = this.$http.get('/api/v1/notebooks')
+ .then(({data}) => this.notebooks = data)
+ .catch(({data}) => Promise.reject(data));
+ }
+
+ read() {
+ if (this.initLatch)
+ return this.initLatch;
+
+ return this.load();
+ }
+
+ find(_id) {
+ return this.read()
+ .then(() => {
+ const notebook = this.demo ? this.notebooks[0] : _.find(this.notebooks, {_id});
+
+ if (_.isNil(notebook))
+ return this.$q.reject('Failed to load notebook.');
+
+ return notebook;
+ });
+ }
+
+ findIndex(notebook) {
+ return this.read()
+ .then(() => _.findIndex(this.notebooks, {_id: notebook._id}));
+ }
+
+ save(notebook) {
+ if (this.demo)
+ return this.$q.when(DEMO_NOTEBOOK);
+
+ return this.$http.post('/api/v1/notebooks/save', notebook)
+ .then(({data}) => {
+ const idx = _.findIndex(this.notebooks, {_id: data._id});
+
+ if (idx >= 0)
+ this.notebooks[idx] = data;
+ else
+ this.notebooks.push(data);
+
+ return data;
+ })
+ .catch(({data}) => Promise.reject(data));
+ }
+
+ remove(notebook) {
+ if (this.demo)
+ return this.$q.reject(`Removing "${notebook.name}" notebook is not supported.`);
+
+ const key = {_id: notebook._id};
+
+ return this.$http.post('/api/v1/notebooks/remove', key)
+ .then(() => {
+ const idx = _.findIndex(this.notebooks, key);
+
+ if (idx >= 0) {
+ this.notebooks.splice(idx, 1);
+
+ if (idx < this.notebooks.length)
+ return this.notebooks[idx];
+ }
+
+ if (this.notebooks.length > 0)
+ return this.notebooks[this.notebooks.length - 1];
+
+ return null;
+ })
+ .catch(({data}) => Promise.reject(data));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1367bc98/modules/web-console/frontend/app/components/page-queries/Notebook.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-queries/Notebook.service.js b/modules/web-console/frontend/app/components/page-queries/Notebook.service.js
new file mode 100644
index 0000000..b0bb64f
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-queries/Notebook.service.js
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+export default class Notebook {
+ static $inject = ['$state', 'IgniteConfirm', 'IgniteMessages', 'IgniteNotebookData'];
+
+ /**
+ * @param $state
+ * @param confirmModal
+ * @param Messages
+ * @param {NotebookData} NotebookData
+ */
+ constructor($state, confirmModal, Messages, NotebookData) {
+ this.$state = $state;
+ this.confirmModal = confirmModal;
+ this.Messages = Messages;
+ this.NotebookData = NotebookData;
+ }
+
+ read() {
+ return this.NotebookData.read();
+ }
+
+ create(name) {
+ return this.NotebookData.save({name});
+ }
+
+ save(notebook) {
+ return this.NotebookData.save(notebook);
+ }
+
+ find(_id) {
+ return this.NotebookData.find(_id);
+ }
+
+ _openNotebook(idx) {
+ return this.NotebookData.read()
+ .then((notebooks) => {
+ const nextNotebook = notebooks.length > idx ? notebooks[idx] : _.last(notebooks);
+
+ if (nextNotebook)
+ this.$state.go('base.sql.notebook', {noteId: nextNotebook._id});
+ else
+ this.$state.go('base.configuration.tabs.advanced.clusters');
+ });
+ }
+
+ remove(notebook) {
+ return this.confirmModal.confirm(`Are you sure you want to remove notebook: "${notebook.name}"?`)
+ .then(() => this.NotebookData.findIndex(notebook))
+ .then((idx) => {
+ this.NotebookData.remove(notebook)
+ .then(() => {
+ if (this.$state.includes('base.sql.notebook') && this.$state.params.noteId === notebook._id)
+ return this._openNotebook(idx);
+ })
+ .catch(this.Messages.showError);
+ });
+ }
+}